vietsub UI
This commit is contained in:
+9
-8
@@ -1,4 +1,5 @@
|
||||
import type { Metadata } from "next";
|
||||
import Link from "next/link";
|
||||
import PublicPreviewWrapper from "@/uhm/components/preview/PublicPreviewWrapper";
|
||||
|
||||
export const metadata: Metadata = {
|
||||
@@ -27,10 +28,10 @@ export default function Page() {
|
||||
{/* Header (SSR & SEO) */}
|
||||
<header style={srOnlyStyle}>
|
||||
<nav>
|
||||
<a href="/">Trang chủ</a>
|
||||
<a href="/faq">Hướng dẫn / FAQ</a>
|
||||
<a href="/about-us">Về chúng tôi</a>
|
||||
<a href="/user">Quản trị viên</a>
|
||||
<Link href="/">Trang chủ</Link>
|
||||
<Link href="/faq">Hướng dẫn / Hỏi đáp</Link>
|
||||
<Link href="/about-us">Về chúng tôi</Link>
|
||||
<Link href="/user">Quản trị viên</Link>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
@@ -43,9 +44,9 @@ export default function Page() {
|
||||
</p>
|
||||
<p>
|
||||
Tính năng chính bao gồm:
|
||||
- Xem bản đồ lịch sử theo dòng thời gian (Timeline).
|
||||
- Trình phát diễn biến lịch sử và chiến trận (Replay).
|
||||
- Tra cứu thông tin sự kiện lịch sử (Wiki & Entities).
|
||||
- Xem bản đồ lịch sử theo dòng thời gian.
|
||||
- Trình phát diễn biến lịch sử và chiến trận.
|
||||
- Tra cứu thông tin sự kiện lịch sử.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
@@ -55,7 +56,7 @@ export default function Page() {
|
||||
|
||||
{/* Footer (SSR & SEO) */}
|
||||
<footer style={srOnlyStyle}>
|
||||
<p>© {new Date().getFullYear()} Ultimate History Map. All rights reserved.</p>
|
||||
<p>© {new Date().getFullYear()} Ultimate History Map. Đã đăng ký bản quyền.</p>
|
||||
</footer>
|
||||
</div>
|
||||
);
|
||||
|
||||
+16
-16
@@ -333,7 +333,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
}}
|
||||
>
|
||||
<div style={{ fontWeight: 800, marginBottom: "6px" }}>
|
||||
Map khong khoi tao duoc
|
||||
Không khởi tạo được bản đồ
|
||||
</div>
|
||||
<div style={{ color: "#cbd5e1", fontSize: "13px" }}>
|
||||
{fatalInitError}
|
||||
@@ -478,8 +478,8 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
<label
|
||||
title={
|
||||
isGlobeProjection
|
||||
? "Dang o che do hinh cau (globe)"
|
||||
: "Dang o che do trai phang (flat)"
|
||||
? "Đang ở chế độ hình cầu"
|
||||
: "Đang ở chế độ bản đồ phẳng"
|
||||
}
|
||||
style={{
|
||||
display: "inline-flex",
|
||||
@@ -495,7 +495,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
type="checkbox"
|
||||
checked={isGlobeProjection}
|
||||
onChange={(e) => setIsGlobeProjection(e.target.checked)}
|
||||
aria-label="Toggle globe projection"
|
||||
aria-label="Chuyển chế độ hiển thị hình cầu"
|
||||
style={{ display: "none" }}
|
||||
/>
|
||||
<div className={`premium-toggle-track ${isGlobeProjection ? "active" : ""}`}>
|
||||
@@ -511,7 +511,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
}}
|
||||
className="hidden sm:block"
|
||||
>
|
||||
{isGlobeProjection ? "Globe" : "Flat"}
|
||||
{isGlobeProjection ? "Cầu" : "Phẳng"}
|
||||
</span>
|
||||
</label>
|
||||
|
||||
@@ -532,7 +532,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
transition: "background 150ms, color 150ms",
|
||||
}}
|
||||
>
|
||||
LOCAL
|
||||
CỤC BỘ
|
||||
</button>
|
||||
<button
|
||||
type="button"
|
||||
@@ -549,7 +549,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
transition: "background 150ms, color 150ms",
|
||||
}}
|
||||
>
|
||||
GLOBAL
|
||||
TOÀN CỤC
|
||||
</button>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -568,10 +568,10 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
color: isPreviewMode ? "#ffffff" : "#34d399",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
aria-label={isPreviewMode ? "Exit preview" : "Enter preview"}
|
||||
title={isPreviewMode ? "Thoat preview" : "Xem nhu nguoi dung"}
|
||||
aria-label={isPreviewMode ? "Thoát xem trước" : "Vào chế độ xem trước"}
|
||||
title={isPreviewMode ? "Thoát xem trước" : "Xem như người dùng"}
|
||||
>
|
||||
{isPreviewMode ? "Editor" : "Preview"}
|
||||
{isPreviewMode ? "Trình sửa" : "Xem trước"}
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
@@ -592,8 +592,8 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
fontSize: "13px",
|
||||
flexShrink: 0,
|
||||
}}
|
||||
aria-label="Play selected replay"
|
||||
title="Play replay của geometry đang chọn"
|
||||
aria-label="Phát diễn biến đã chọn"
|
||||
title="Phát diễn biến của hình đang chọn"
|
||||
>
|
||||
<span
|
||||
aria-hidden="true"
|
||||
@@ -605,7 +605,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
borderLeft: "8px solid currentColor",
|
||||
}}
|
||||
/>
|
||||
Play
|
||||
Phát
|
||||
</button>
|
||||
) : null}
|
||||
|
||||
@@ -615,7 +615,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
onClick={() => handleZoomByStep(-0.8)}
|
||||
className="premium-zoom-btn"
|
||||
style={{ flexShrink: 0 }}
|
||||
aria-label="Zoom out"
|
||||
aria-label="Thu nhỏ bản đồ"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
@@ -648,7 +648,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
onPointerCancel={endZoomSliderDrag}
|
||||
onBlur={endZoomSliderDrag}
|
||||
onChange={(event) => handleZoomSliderChange(Number(event.target.value))}
|
||||
aria-label="Map zoom"
|
||||
aria-label="Mức thu phóng bản đồ"
|
||||
/>
|
||||
|
||||
<button
|
||||
@@ -656,7 +656,7 @@ const Map = memo(forwardRef<MapHandle, MapProps>(function Map({
|
||||
onClick={() => handleZoomByStep(0.8)}
|
||||
className="premium-zoom-btn"
|
||||
style={{ flexShrink: 0 }}
|
||||
aria-label="Zoom in"
|
||||
aria-label="Phóng to bản đồ"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
|
||||
@@ -117,7 +117,7 @@ export default function PresentPlaceSearch({
|
||||
.catch((err) => {
|
||||
if (controller.signal.aborted || requestSeqRef.current !== seq) return;
|
||||
setResults([]);
|
||||
setError(err instanceof Error ? err.message : "Không search được địa điểm.");
|
||||
setError(err instanceof Error ? err.message : "Không tìm được địa điểm.");
|
||||
})
|
||||
.finally(() => {
|
||||
if (requestSeqRef.current === seq) {
|
||||
@@ -159,7 +159,7 @@ export default function PresentPlaceSearch({
|
||||
.catch((err) => {
|
||||
if (historicalRequestSeqRef.current !== seq) return;
|
||||
setHistoricalResults([]);
|
||||
setHistoricalError(err instanceof Error ? err.message : "Không search được entity lịch sử.");
|
||||
setHistoricalError(err instanceof Error ? err.message : "Không tìm được thực thể lịch sử.");
|
||||
})
|
||||
.finally(() => {
|
||||
if (historicalRequestSeqRef.current === seq) {
|
||||
@@ -196,7 +196,7 @@ export default function PresentPlaceSearch({
|
||||
.catch((err) => {
|
||||
if (wikiRequestSeqRef.current !== seq) return;
|
||||
setWikiResults([]);
|
||||
setWikiError(err instanceof Error ? err.message : "Không search được wiki.");
|
||||
setWikiError(err instanceof Error ? err.message : "Không tìm được bài viết wiki.");
|
||||
})
|
||||
.finally(() => {
|
||||
if (wikiRequestSeqRef.current === seq) {
|
||||
@@ -364,11 +364,11 @@ export default function PresentPlaceSearch({
|
||||
<button
|
||||
type="button"
|
||||
onClick={cycleMode}
|
||||
title={`Switch search mode (current: ${mode})`}
|
||||
aria-label={`Switch search mode (current: ${mode})`}
|
||||
title={`Đổi chế độ tìm kiếm (hiện tại: ${getSearchModeLabel(mode)})`}
|
||||
aria-label={`Đổi chế độ tìm kiếm (hiện tại: ${getSearchModeLabel(mode)})`}
|
||||
style={modeSwitchStyle}
|
||||
>
|
||||
{mode === "present" ? "Present" : mode === "history" ? "History" : "Wiki"}
|
||||
{getSearchModeLabel(mode)}
|
||||
</button>
|
||||
<input
|
||||
value={activeQuery}
|
||||
@@ -408,7 +408,7 @@ export default function PresentPlaceSearch({
|
||||
mode === "present"
|
||||
? "Tìm địa điểm hiện tại"
|
||||
: mode === "history"
|
||||
? "Tìm entity lịch sử"
|
||||
? "Tìm thực thể lịch sử"
|
||||
: "Tìm bài viết wiki"
|
||||
}
|
||||
style={inputStyle}
|
||||
@@ -417,8 +417,8 @@ export default function PresentPlaceSearch({
|
||||
<button
|
||||
type="button"
|
||||
onClick={clearSearch}
|
||||
title="Clear"
|
||||
aria-label="Clear place search"
|
||||
title="Xóa tìm kiếm"
|
||||
aria-label="Xóa ô tìm kiếm"
|
||||
style={clearButtonStyle}
|
||||
>
|
||||
x
|
||||
@@ -535,9 +535,9 @@ function HistoricalResults({
|
||||
onSelectEntity: (item: EntityGeometriesSearchItem) => void;
|
||||
onSelectGeometry: (item: EntityGeometriesSearchItem, geometry: EntityGeometrySearchGeo) => void;
|
||||
}) {
|
||||
if (isLoading) return <div style={statusStyle}>Đang tìm entity...</div>;
|
||||
if (isLoading) return <div style={statusStyle}>Đang tìm thực thể...</div>;
|
||||
if (error) return <div style={{ ...statusStyle, color: "#fecaca" }}>{error}</div>;
|
||||
if (!results.length && query.trim().length >= 2) return <div style={statusStyle}>Không có entity phù hợp.</div>;
|
||||
if (!results.length && query.trim().length >= 2) return <div style={statusStyle}>Không có thực thể phù hợp.</div>;
|
||||
|
||||
return (
|
||||
<>
|
||||
@@ -563,8 +563,8 @@ function HistoricalResults({
|
||||
<span style={primaryResultTextStyle}>{item.name || item.entity_id}</span>
|
||||
<span style={secondaryResultTextStyle}>
|
||||
{item.geometries.length
|
||||
? `${item.geometries.length} geometry${item.geometries.length > 1 ? "s" : ""}`
|
||||
: "Không có geometry"}
|
||||
? `${item.geometries.length} hình bản đồ`
|
||||
: "Không có hình bản đồ"}
|
||||
{item.description ? ` · ${item.description}` : ""}
|
||||
</span>
|
||||
</button>
|
||||
@@ -672,7 +672,7 @@ function formatAdminLabel(state: AdminLabelState | undefined): string {
|
||||
}
|
||||
|
||||
function formatGeometryMeta(geometry: EntityGeometrySearchGeo): string {
|
||||
const type = geometry.type || "geometry";
|
||||
const type = geometry.type || "hình bản đồ";
|
||||
const timeStart = geometry.time_start ?? null;
|
||||
const timeEnd = geometry.time_end ?? null;
|
||||
const time =
|
||||
@@ -780,3 +780,9 @@ const statusStyle = {
|
||||
fontSize: 12,
|
||||
fontWeight: 700,
|
||||
} satisfies CSSProperties;
|
||||
|
||||
function getSearchModeLabel(mode: SearchMode): string {
|
||||
if (mode === "present") return "Hiện tại";
|
||||
if (mode === "history") return "Lịch sử";
|
||||
return "Wiki";
|
||||
}
|
||||
|
||||
@@ -2,7 +2,6 @@
|
||||
|
||||
import type { BackgroundLayerId } from "@/uhm/lib/map/styles/backgroundLayers";
|
||||
import { BACKGROUND_LAYER_OPTIONS } from "@/uhm/lib/map/styles/backgroundLayers";
|
||||
import { GEO_TYPE_KEYS } from "@/uhm/lib/map/geo/geoTypeMap";
|
||||
|
||||
type Props = {
|
||||
backgroundVisibility: Record<string, boolean>;
|
||||
@@ -165,9 +164,6 @@ const LAYER_ICONS: Record<string, React.ReactNode> = {
|
||||
),
|
||||
};
|
||||
|
||||
// Class name helper for tooltips using CSS
|
||||
const buttonClassName = "preview-layer-btn";
|
||||
|
||||
export default function ReplayPreviewLayerPanel({
|
||||
backgroundVisibility,
|
||||
geometryVisibility,
|
||||
@@ -245,7 +241,7 @@ export default function ReplayPreviewLayerPanel({
|
||||
}}
|
||||
>
|
||||
{/* Background layers */}
|
||||
<div style={groupHeaderStyle}>Map</div>
|
||||
<div style={groupHeaderStyle}>Bản đồ</div>
|
||||
<div style={gridStyle}>
|
||||
{BACKGROUND_LAYER_OPTIONS.map((layer) => {
|
||||
const active = Boolean(backgroundVisibility[layer.id]);
|
||||
@@ -266,11 +262,11 @@ export default function ReplayPreviewLayerPanel({
|
||||
<div style={dividerStyle} />
|
||||
|
||||
{/* Territories / Polygons */}
|
||||
<div style={groupHeaderStyle}>Areas</div>
|
||||
<div style={groupHeaderStyle}>Khu vực</div>
|
||||
<div style={gridStyle}>
|
||||
{polygonKeys.map((typeKey) => {
|
||||
const active = geometryVisibility[typeKey] !== false;
|
||||
const label = typeKey.replace("_", " ").toUpperCase();
|
||||
const label = getGeometryTypeLabel(typeKey);
|
||||
return (
|
||||
<button
|
||||
key={typeKey}
|
||||
@@ -288,11 +284,11 @@ export default function ReplayPreviewLayerPanel({
|
||||
<div style={dividerStyle} />
|
||||
|
||||
{/* Routes / Lines */}
|
||||
<div style={groupHeaderStyle}>Routes</div>
|
||||
<div style={groupHeaderStyle}>Tuyến</div>
|
||||
<div style={gridStyle}>
|
||||
{lineKeys.map((typeKey) => {
|
||||
const active = geometryVisibility[typeKey] !== false;
|
||||
const label = typeKey.replace("_", " ").toUpperCase();
|
||||
const label = getGeometryTypeLabel(typeKey);
|
||||
return (
|
||||
<button
|
||||
key={typeKey}
|
||||
@@ -310,11 +306,11 @@ export default function ReplayPreviewLayerPanel({
|
||||
<div style={dividerStyle} />
|
||||
|
||||
{/* Places & Events / Points */}
|
||||
<div style={groupHeaderStyle}>Points</div>
|
||||
<div style={groupHeaderStyle}>Điểm</div>
|
||||
<div style={gridStyle}>
|
||||
{pointKeys.map((typeKey) => {
|
||||
const active = geometryVisibility[typeKey] !== false;
|
||||
const label = typeKey.replace("_", " ").toUpperCase();
|
||||
const label = getGeometryTypeLabel(typeKey);
|
||||
return (
|
||||
<button
|
||||
key={typeKey}
|
||||
@@ -383,3 +379,26 @@ const dividerStyle: React.CSSProperties = {
|
||||
width: "80%",
|
||||
margin: "6px 0",
|
||||
};
|
||||
|
||||
function getGeometryTypeLabel(typeKey: string): string {
|
||||
const labels: Record<string, string> = {
|
||||
country: "Quốc gia",
|
||||
state: "Nhà nước / vùng",
|
||||
faction: "Phe phái",
|
||||
rebellion_zone: "Vùng nổi dậy",
|
||||
defense_line: "Tuyến phòng thủ",
|
||||
military_route: "Đường hành quân",
|
||||
retreat_route: "Đường rút lui",
|
||||
migration_route: "Đường di cư",
|
||||
trade_route: "Tuyến thương mại",
|
||||
battle: "Trận đánh",
|
||||
person_event: "Nhân vật / sự kiện",
|
||||
temple: "Đền miếu",
|
||||
capital: "Kinh đô",
|
||||
city: "Thành phố",
|
||||
fortification: "Công sự",
|
||||
ruin: "Di tích",
|
||||
port: "Cảng",
|
||||
};
|
||||
return labels[typeKey] || typeKey.replaceAll("_", " ");
|
||||
}
|
||||
|
||||
@@ -121,7 +121,7 @@ export default function ReplayPreviewOverlay({
|
||||
{dialog.image_url?.trim() ? (
|
||||
<img
|
||||
src={dialog.image_url}
|
||||
alt="Historical"
|
||||
alt="Hình ảnh lịch sử"
|
||||
style={{
|
||||
width: "100%",
|
||||
display: "block",
|
||||
@@ -212,7 +212,7 @@ export default function ReplayPreviewOverlay({
|
||||
textTransform: "uppercase",
|
||||
}}
|
||||
>
|
||||
Preview
|
||||
Xem trước
|
||||
</span>
|
||||
{activeStepLabel ? (
|
||||
<span
|
||||
@@ -252,7 +252,7 @@ export default function ReplayPreviewOverlay({
|
||||
/>
|
||||
</div>
|
||||
<div style={{ fontSize: 11, color: "#94a3b8" }}>
|
||||
Step {activeStepNumber || 0}/{totalSteps}
|
||||
Bước {activeStepNumber || 0}/{totalSteps}
|
||||
</div>
|
||||
</div>
|
||||
) : null}
|
||||
@@ -289,7 +289,7 @@ export default function ReplayPreviewOverlay({
|
||||
onClick={onExitPreview}
|
||||
style={previewButtonStyle("#334155")}
|
||||
>
|
||||
Thoát preview
|
||||
Thoát xem trước
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -83,7 +83,7 @@ export default function GeometrySelectionPanel({
|
||||
color: "#94a3b8",
|
||||
}}
|
||||
>
|
||||
Geometry
|
||||
Hình bản đồ
|
||||
</div>
|
||||
<div
|
||||
style={{
|
||||
@@ -94,7 +94,7 @@ export default function GeometrySelectionPanel({
|
||||
color: "#f8fafc",
|
||||
}}
|
||||
>
|
||||
Chọn entity để zoom
|
||||
Chọn thực thể để phóng tới
|
||||
</div>
|
||||
{wikiSlug ? (
|
||||
<div
|
||||
@@ -132,7 +132,7 @@ export default function GeometrySelectionPanel({
|
||||
outline: "none",
|
||||
}}
|
||||
className="hover:bg-slate-700/50 hover:text-slate-100"
|
||||
aria-label="Close geometry chooser"
|
||||
aria-label="Đóng bảng chọn hình bản đồ"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
@@ -234,7 +234,7 @@ export default function GeometrySelectionPanel({
|
||||
</div>
|
||||
) : (
|
||||
<div style={{ fontSize: 14, lineHeight: "20px", color: "#94a3b8" }}>
|
||||
Wiki này chưa có entity hoặc geometry liên quan.
|
||||
Wiki này chưa có thực thể hoặc hình bản đồ liên quan.
|
||||
</div>
|
||||
)}
|
||||
</div>
|
||||
|
||||
@@ -28,7 +28,7 @@ export default function MapPlaceholder({ onEnter }: MapPlaceholderProps) {
|
||||
{/* eslint-disable-next-line @next/next/no-img-element */}
|
||||
<img
|
||||
src="/images/map_placeholder.webp"
|
||||
alt="Map Background"
|
||||
alt="Nền bản đồ"
|
||||
fetchPriority="high"
|
||||
loading="eager"
|
||||
decoding="sync"
|
||||
@@ -119,7 +119,7 @@ export default function MapPlaceholder({ onEnter }: MapPlaceholderProps) {
|
||||
textShadow: "0 1px 2px rgba(0, 0, 0, 0.8)",
|
||||
}}
|
||||
>
|
||||
hiện dự án chỉ đang hỗ trợ người dùng máy tính, các phiên bản di động hiên không ổn định
|
||||
Hiện dự án chỉ hỗ trợ tốt trên máy tính; phiên bản di động chưa ổn định.
|
||||
</p>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -186,7 +186,7 @@ const PreviewLayout = forwardRef<PreviewLayoutHandle, Props>(({
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return `Stage #${replayPreviewActiveCursor.stageId} · Step ${replayPreviewActiveCursor.stepIndex + 1}`;
|
||||
return `Cảnh #${replayPreviewActiveCursor.stageId} · Bước ${replayPreviewActiveCursor.stepIndex + 1}`;
|
||||
}, [replayPreviewActiveCursor.stageId, replayPreviewActiveCursor.stepIndex]);
|
||||
|
||||
// Active wiki snapshot
|
||||
|
||||
@@ -300,12 +300,12 @@ export default function PreviewMapShell({
|
||||
type="button"
|
||||
onClick={() => {
|
||||
if (isMobileOrTablet) {
|
||||
alert("Tính năng quản trị và chỉnh sửa chỉ hỗ trợ trên máy tính (Desktop)");
|
||||
alert("Tính năng quản trị và chỉnh sửa chỉ hỗ trợ trên máy tính.");
|
||||
} else {
|
||||
window.location.href = "/user";
|
||||
}
|
||||
}}
|
||||
title={isMobileOrTablet ? "Tính năng này chỉ hoạt động trên Desktop" : "Quản trị & Chỉnh sửa (Edit)"}
|
||||
title={isMobileOrTablet ? "Tính năng này chỉ hoạt động trên máy tính" : "Quản trị và chỉnh sửa"}
|
||||
style={{
|
||||
...menuOptionStyle,
|
||||
opacity: isMobileOrTablet ? 0.5 : 1,
|
||||
@@ -349,7 +349,7 @@ export default function PreviewMapShell({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { window.location.href = "/faq"; }}
|
||||
title="Hỏi đáp & Hướng dẫn (FAQ)"
|
||||
title="Hỏi đáp và hướng dẫn"
|
||||
style={menuOptionStyle}
|
||||
>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
@@ -360,7 +360,7 @@ export default function PreviewMapShell({
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => { window.location.href = "/about-us"; }}
|
||||
title="Về chúng tôi (About Us)"
|
||||
title="Về chúng tôi"
|
||||
style={menuOptionStyle}
|
||||
>
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
|
||||
|
||||
@@ -349,7 +349,7 @@ export default function PublicPreviewClientPage({
|
||||
wikiSlug: nextSlug,
|
||||
rows: [],
|
||||
isLoading: false,
|
||||
error: "Wiki này chưa có entity liên quan.",
|
||||
error: "Wiki này chưa có thực thể liên quan.",
|
||||
});
|
||||
return;
|
||||
}
|
||||
@@ -727,7 +727,7 @@ export default function PublicPreviewClientPage({
|
||||
) {
|
||||
return null;
|
||||
}
|
||||
return `Stage #${replayPreview.activeCursor.stageId} · Step ${replayPreview.activeCursor.stepIndex + 1}`;
|
||||
return `Cảnh #${replayPreview.activeCursor.stageId} · Bước ${replayPreview.activeCursor.stepIndex + 1}`;
|
||||
}, [replayPreview.activeCursor.stageId, replayPreview.activeCursor.stepIndex]);
|
||||
|
||||
const isWikiChooserOpen = rightPanelMode === "selection" && Boolean(wikiSelectionPanelAnchor);
|
||||
@@ -1292,14 +1292,14 @@ function PublicMapZoomPanel({
|
||||
type="button"
|
||||
onClick={toggleProjection}
|
||||
className="uhm-public-projection-toggle"
|
||||
aria-label="Toggle globe projection"
|
||||
title={isGlobeProjection ? "Dang o che do hinh cau (globe)" : "Dang o che do trai phang (flat)"}
|
||||
aria-label="Chuyển chế độ hiển thị hình cầu"
|
||||
title={isGlobeProjection ? "Đang ở chế độ hình cầu" : "Đang ở chế độ bản đồ phẳng"}
|
||||
>
|
||||
<span className={`uhm-public-projection-track ${isGlobeProjection ? "active" : ""}`}>
|
||||
<span className="uhm-public-projection-thumb" />
|
||||
</span>
|
||||
<span className={`uhm-public-projection-label ${isGlobeProjection ? "active" : ""}`}>
|
||||
{isGlobeProjection ? "Globe" : "Flat"}
|
||||
{isGlobeProjection ? "Cầu" : "Phẳng"}
|
||||
</span>
|
||||
</button>
|
||||
{onPlayPreviewReplay ? (
|
||||
@@ -1307,11 +1307,11 @@ function PublicMapZoomPanel({
|
||||
type="button"
|
||||
onClick={onPlayPreviewReplay}
|
||||
className="uhm-public-play-btn"
|
||||
aria-label="Play selected replay"
|
||||
title="Play replay cua geometry dang chon"
|
||||
aria-label="Phát diễn biến đã chọn"
|
||||
title="Phát diễn biến của hình đang chọn"
|
||||
>
|
||||
<span aria-hidden="true" className="uhm-public-play-icon" />
|
||||
Play
|
||||
Phát
|
||||
</button>
|
||||
) : null}
|
||||
{onResumePreviewReplay ? (
|
||||
@@ -1319,8 +1319,8 @@ function PublicMapZoomPanel({
|
||||
type="button"
|
||||
onClick={onResumePreviewReplay}
|
||||
className="uhm-public-play-btn resume"
|
||||
aria-label="Resume selected replay"
|
||||
title="Tiep tuc replay dang tam dung"
|
||||
aria-label="Tiếp tục diễn biến đã chọn"
|
||||
title="Tiếp tục diễn biến đang tạm dừng"
|
||||
>
|
||||
<span aria-hidden="true" className="uhm-public-play-icon" />
|
||||
Tiếp tục
|
||||
@@ -1331,8 +1331,8 @@ function PublicMapZoomPanel({
|
||||
type="button"
|
||||
onClick={onStopPreviewReplay}
|
||||
className="uhm-public-play-btn stop"
|
||||
aria-label="Stop selected replay"
|
||||
title="Dung replay dang phat"
|
||||
aria-label="Dừng diễn biến đã chọn"
|
||||
title="Dừng diễn biến đang phát"
|
||||
>
|
||||
<span aria-hidden="true" className="uhm-public-stop-icon" />
|
||||
Dừng
|
||||
@@ -1342,7 +1342,7 @@ function PublicMapZoomPanel({
|
||||
type="button"
|
||||
onClick={() => zoomByStep(-0.8)}
|
||||
className="uhm-public-zoom-btn"
|
||||
aria-label="Zoom out"
|
||||
aria-label="Thu nhỏ bản đồ"
|
||||
>
|
||||
-
|
||||
</button>
|
||||
@@ -1368,13 +1368,13 @@ function PublicMapZoomPanel({
|
||||
isDraggingRef.current = false;
|
||||
}}
|
||||
onChange={(event) => handleSliderChange(Number(event.target.value))}
|
||||
aria-label="Map zoom"
|
||||
aria-label="Mức thu phóng bản đồ"
|
||||
/>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => zoomByStep(0.8)}
|
||||
className="uhm-public-zoom-btn"
|
||||
aria-label="Zoom in"
|
||||
aria-label="Phóng to bản đồ"
|
||||
>
|
||||
+
|
||||
</button>
|
||||
|
||||
@@ -104,7 +104,7 @@ export default function WikiSelectionPanel({
|
||||
outline: "none",
|
||||
}}
|
||||
className="hover:bg-slate-700/50 hover:text-slate-100"
|
||||
aria-label="Close wiki chooser"
|
||||
aria-label="Đóng bảng chọn wiki"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
|
||||
@@ -596,7 +596,7 @@ function PublicWikiSidebar({
|
||||
outline: "none",
|
||||
}}
|
||||
className="hover:bg-slate-700/50 hover:text-slate-100"
|
||||
aria-label="Close wiki sidebar"
|
||||
aria-label="Đóng khung wiki"
|
||||
>
|
||||
x
|
||||
</button>
|
||||
|
||||
Reference in New Issue
Block a user