Reorganize admin into tabbed hubs with a condensed sidebar.
Local Build and Deploy / deploy (push) Successful in 57s
Local Build and Deploy / deploy (push) Successful in 57s
Replace the long flat nav with hub entries, shared AdminHubChrome tabs, and AdminPageShell. Existing URLs stay stable; Settings/Radio and other sections now share one chrome. Co-authored-by: Cursor <[email protected]>
This commit is contained in:
1 parent
367f69a439
commit
363c9b3d56
30 files changed
+854
-432
No files matched your search
+36
-367
File diff suppressed because it is too large.
Load diff
@@ -1,5 +1,3 @@
|
||||
import { Cog, ExternalLink } from "lucide-react";
|
||||
import Link from "next/link";
|
||||
import { redirect } from "next/navigation";
|
||||
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
|
||||
import { prisma } from "@/lib/prisma";
|
||||
@@ -10,13 +8,6 @@ import { CmsSettingsForm } from "./cms-settings-form";
|
||||
export const dynamic = "force-dynamic";
|
||||
export const metadata = { title: "CMS Settings" };
|
||||
|
||||
const RELATED = [
|
||||
{ href: "/admin/theme", label: "Theme & colors" },
|
||||
{ href: "/admin/maintenance", label: "Maintenance" },
|
||||
{ href: "/admin/vpn", label: "VPN / proxy block" },
|
||||
{ href: "/admin/emulator", label: "Emulator config" },
|
||||
] as const;
|
||||
|
||||
export default async function AdminSettings() {
|
||||
const { session, permissions } = await getAdminContext();
|
||||
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
|
||||
@@ -49,34 +40,6 @@ export default async function AdminSettings() {
|
||||
|
||||
return (
|
||||
<div className="space-y-8">
|
||||
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||
<div className="flex items-center gap-3">
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-[var(--admin-accent)]/20 to-[var(--admin-accent)]/5 grid place-items-center">
|
||||
<Cog size={20} className="text-[var(--admin-accent)]" />
|
||||
</div>
|
||||
<div>
|
||||
<h1 className="m-0 text-2xl font-extrabold tracking-tight text-[var(--admin-text)]">
|
||||
CMS Settings
|
||||
</h1>
|
||||
<p className="m-0 mt-0.5 text-sm text-[var(--admin-text-muted)]">
|
||||
Configure hotel identity, imaging, client, radio and security.
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex flex-wrap gap-2">
|
||||
{RELATED.map((item) => (
|
||||
<Link
|
||||
key={item.href}
|
||||
href={item.href}
|
||||
className="inline-flex items-center gap-1.5 rounded-full border border-[var(--admin-border)] bg-[var(--admin-surface)] px-3 py-1.5 text-xs font-semibold text-[var(--admin-text)] no-underline hover:border-[var(--admin-accent)] transition-colors"
|
||||
>
|
||||
{item.label}
|
||||
<ExternalLink size={12} className="opacity-60" />
|
||||
</Link>
|
||||
))}
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div className="admin-stat-row">
|
||||
<span className="admin-stat-chip">
|
||||
{settings.length} keys in database
|
||||
|
||||
@@ -505,6 +505,12 @@ tbody tr:hover {
|
||||
scroll-margin-top: 1rem;
|
||||
}
|
||||
|
||||
/* Hub chrome already shows the section title — soften page-level heroes. */
|
||||
.admin-hub-panel > .space-y-6 > div:first-child > h1.text-3xl {
|
||||
font-size: 1.15rem;
|
||||
letter-spacing: -0.01em;
|
||||
}
|
||||
|
||||
/* Page heading */
|
||||
.admin-page main > h1:first-child,
|
||||
.admin-page > h1:first-child {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
"use client";
|
||||
|
||||
import { usePathname } from "next/navigation";
|
||||
import type { ReactNode } from "react";
|
||||
import { AdminPageShell } from "@/components/admin/admin-page-shell";
|
||||
import { AdminSectionTabs } from "@/components/admin/admin-section-tabs";
|
||||
import { findAdminHub } from "@/lib/admin-nav";
|
||||
|
||||
/**
|
||||
* When the current path belongs to a hub, wraps children with a shared
|
||||
* title + tab strip. Dashboard and unknown routes render children as-is.
|
||||
*/
|
||||
export function AdminHubChrome({ children }: { children: ReactNode }) {
|
||||
const pathname = usePathname() ?? "";
|
||||
const hub = findAdminHub(pathname);
|
||||
|
||||
if (!hub) return <>{children}</>;
|
||||
|
||||
return (
|
||||
<AdminPageShell
|
||||
icon={hub.icon}
|
||||
title={hub.title}
|
||||
subtitle={hub.subtitle}
|
||||
tabs={<AdminSectionTabs tabs={hub.tabs} />}
|
||||
className="admin-hub-panel"
|
||||
>
|
||||
{children}
|
||||
</AdminPageShell>
|
||||
);
|
||||
}
|
||||
@@ -6,25 +6,33 @@ import type { ReactNode } from "react";
|
||||
import { useAdminMobile } from "@/components/admin/admin-mobile-wrapper";
|
||||
|
||||
/**
|
||||
* Sidebar link that highlights when its route is active. "/admin" matches
|
||||
* exactly; every other entry also matches its sub-routes (e.g. /admin/radio is
|
||||
* active on /admin/radio/history) so the current section stays lit.
|
||||
* Sidebar link that highlights when its route is active.
|
||||
* Optional matchPrefixes cover multi-page hubs (e.g. Settings → theme/vpn).
|
||||
*/
|
||||
export function AdminNavLink({
|
||||
href,
|
||||
icon,
|
||||
matchPrefixes,
|
||||
children,
|
||||
}: {
|
||||
href: string;
|
||||
icon?: ReactNode;
|
||||
matchPrefixes?: string[];
|
||||
children: ReactNode;
|
||||
}) {
|
||||
const pathname = usePathname() ?? "";
|
||||
const { close } = useAdminMobile();
|
||||
const active =
|
||||
href === "/admin"
|
||||
? pathname === "/admin"
|
||||
: pathname === href || pathname.startsWith(`${href}/`);
|
||||
|
||||
let active: boolean;
|
||||
if (href === "/admin") {
|
||||
active = pathname === "/admin";
|
||||
} else if (matchPrefixes?.length) {
|
||||
active = matchPrefixes.some(
|
||||
(p) => pathname === p || pathname.startsWith(`${p}/`),
|
||||
);
|
||||
} else {
|
||||
active = pathname === href || pathname.startsWith(`${href}/`);
|
||||
}
|
||||
|
||||
return (
|
||||
<Link
|
||||
|
||||
@@ -0,0 +1,52 @@
|
||||
import type { LucideIcon } from "lucide-react";
|
||||
import type { ReactNode } from "react";
|
||||
|
||||
interface AdminPageShellProps {
|
||||
icon?: LucideIcon;
|
||||
title: string;
|
||||
subtitle?: string;
|
||||
actions?: ReactNode;
|
||||
tabs?: ReactNode;
|
||||
children: ReactNode;
|
||||
className?: string;
|
||||
}
|
||||
|
||||
/** Shared admin page chrome: icon title, optional actions/tabs, then body. */
|
||||
export function AdminPageShell({
|
||||
icon: Icon,
|
||||
title,
|
||||
subtitle,
|
||||
actions,
|
||||
tabs,
|
||||
children,
|
||||
className = "",
|
||||
}: AdminPageShellProps) {
|
||||
return (
|
||||
<div className={`space-y-5 ${className}`.trim()}>
|
||||
<div className="flex flex-wrap items-start justify-between gap-4">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
{Icon ? (
|
||||
<div className="w-10 h-10 rounded-xl bg-gradient-to-br from-[var(--admin-accent)]/20 to-[var(--admin-accent)]/5 grid place-items-center shrink-0">
|
||||
<Icon size={20} className="text-[var(--admin-accent)]" />
|
||||
</div>
|
||||
) : null}
|
||||
<div className="min-w-0">
|
||||
<h1 className="m-0 text-2xl font-extrabold tracking-tight text-[var(--admin-text)]">
|
||||
{title}
|
||||
</h1>
|
||||
{subtitle ? (
|
||||
<p className="m-0 mt-0.5 text-sm text-[var(--admin-text-muted)]">
|
||||
{subtitle}
|
||||
</p>
|
||||
) : null}
|
||||
</div>
|
||||
</div>
|
||||
{actions ? (
|
||||
<div className="flex flex-wrap items-center gap-2">{actions}</div>
|
||||
) : null}
|
||||
</div>
|
||||
{tabs}
|
||||
<div className="min-w-0">{children}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
"use client";
|
||||
|
||||
import Link from "next/link";
|
||||
import { usePathname } from "next/navigation";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
export interface AdminTab {
|
||||
href: string;
|
||||
label: string;
|
||||
/** Extra prefixes that count as active for this tab (detail routes). */
|
||||
match?: string[];
|
||||
}
|
||||
|
||||
function matchLength(pathname: string, prefix: string): number {
|
||||
if (pathname === prefix) return prefix.length + 1; // prefer exact
|
||||
if (pathname.startsWith(`${prefix}/`)) return prefix.length;
|
||||
return -1;
|
||||
}
|
||||
|
||||
export function AdminSectionTabs({ tabs }: { tabs: AdminTab[] }) {
|
||||
const pathname = usePathname() ?? "";
|
||||
|
||||
let bestIndex = -1;
|
||||
let bestScore = -1;
|
||||
tabs.forEach((tab, index) => {
|
||||
const prefixes = tab.match ?? [tab.href];
|
||||
for (const prefix of prefixes) {
|
||||
const score = matchLength(pathname, prefix);
|
||||
if (score > bestScore) {
|
||||
bestScore = score;
|
||||
bestIndex = index;
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
return (
|
||||
<nav
|
||||
className="flex gap-1 overflow-x-auto border-b border-[var(--admin-border)] -mx-1 px-1"
|
||||
aria-label="Section"
|
||||
>
|
||||
{tabs.map((tab, index) => {
|
||||
const active = index === bestIndex;
|
||||
return (
|
||||
<Link
|
||||
key={tab.href}
|
||||
href={tab.href}
|
||||
aria-current={active ? "page" : undefined}
|
||||
className={cn(
|
||||
"-mb-px shrink-0 rounded-t-lg border-b-2 px-3.5 py-2.5 text-sm font-semibold no-underline transition-colors",
|
||||
active
|
||||
? "border-[var(--admin-accent)] text-[var(--admin-text)] bg-[var(--admin-accent)]/8"
|
||||
: "border-transparent text-[var(--admin-text-muted)] hover:text-[var(--admin-text)] hover:bg-[var(--admin-accent)]/5",
|
||||
)}
|
||||
>
|
||||
{tab.label}
|
||||
</Link>
|
||||
);
|
||||
})}
|
||||
</nav>
|
||||
);
|
||||
}
|
||||
File diff suppressed because it is too large.
Load diff
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Обратно към сайта",
|
||||
"housekeeping": "Домакинство",
|
||||
"hotelManagementPanel": "Панел за управление на хотел",
|
||||
"rankLabel": "Ранг {rank}"
|
||||
"rankLabel": "Ранг {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Табло за управление",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Zpět na stránku",
|
||||
"housekeeping": "Úklid",
|
||||
"hotelManagementPanel": "Panel správy hotelu",
|
||||
"rankLabel": "Hodnost {rank}"
|
||||
"rankLabel": "Hodnost {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Tilbage til webstedet",
|
||||
"housekeeping": "Husholdning",
|
||||
"hotelManagementPanel": "Hotel management panel",
|
||||
"rankLabel": "Rangering {rank}"
|
||||
"rankLabel": "Rangering {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -719,7 +719,16 @@
|
||||
"backToSite": "Zurück zur Website",
|
||||
"housekeeping": "Hausverwaltung",
|
||||
"hotelManagementPanel": "Hotel-Verwaltungsbereich",
|
||||
"rankLabel": "Rang {rank}"
|
||||
"rankLabel": "Rang {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Επιστροφή στον ιστότοπο",
|
||||
"housekeeping": "Οικονομία",
|
||||
"hotelManagementPanel": "Πάνελ διαχείρισης ξενοδοχείου",
|
||||
"rankLabel": "Κατάταξη {rank}"
|
||||
"rankLabel": "Κατάταξη {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Ταμπλό",
|
||||
|
||||
@@ -690,6 +690,9 @@
|
||||
"overview": "Overview",
|
||||
"dashboard": "Dashboard",
|
||||
"content": "Content",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"articles": "Articles",
|
||||
"tags": "Tags",
|
||||
"navigator": "Navigator",
|
||||
@@ -703,6 +706,8 @@
|
||||
"banners": "Banners",
|
||||
"prefixes": "Prefixes",
|
||||
"usersAndAccess": "Users & access",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"users": "Users",
|
||||
"bans": "Bans",
|
||||
"ipManagement": "IP management",
|
||||
@@ -713,6 +718,8 @@
|
||||
"onlineUsers": "Online users",
|
||||
"moderation": "Moderation",
|
||||
"economy": "Economy",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"catalog": "Catalog",
|
||||
"shop": "Shop",
|
||||
"transactions": "Transactions",
|
||||
@@ -734,6 +741,8 @@
|
||||
"radioRanks": "Ranks",
|
||||
"radioAutodj": "Auto DJ",
|
||||
"system": "System",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability",
|
||||
"commandocentrum": "Commandocentrum",
|
||||
"emulator": "Emulator",
|
||||
"alerts": "Alerts",
|
||||
|
||||
+10
-1
@@ -719,7 +719,16 @@
|
||||
"backToSite": "Volver al sitio",
|
||||
"housekeeping": "Housekeeping",
|
||||
"hotelManagementPanel": "Panel de gestión del hotel",
|
||||
"rankLabel": "Rango {rank}"
|
||||
"rankLabel": "Rango {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Panel",
|
||||
|
||||
+10
-1
@@ -719,7 +719,16 @@
|
||||
"backToSite": "Retour au site",
|
||||
"housekeeping": "Gouvernance",
|
||||
"hotelManagementPanel": "Panneau de gestion de l'hôtel",
|
||||
"rankLabel": "Rang {rank}"
|
||||
"rankLabel": "Rang {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Tableau de bord",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Povratak na stranicu",
|
||||
"housekeeping": "Domaćinstvo",
|
||||
"hotelManagementPanel": "Upravljačka ploča hotela",
|
||||
"rankLabel": "Rang {rank}"
|
||||
"rankLabel": "Rang {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Nadzorna ploča",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Vissza a webhelyre",
|
||||
"housekeeping": "Takarítás",
|
||||
"hotelManagementPanel": "Hotel menedzsment panel",
|
||||
"rankLabel": "rang {rank}"
|
||||
"rankLabel": "rang {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Irányítópult",
|
||||
|
||||
+10
-1
@@ -719,7 +719,16 @@
|
||||
"settings": "Impostazioni",
|
||||
"backToSite": "Torna al sito",
|
||||
"hotelManagementPanel": "Pannello di gestione hotel",
|
||||
"rankLabel": "Grado {rank}"
|
||||
"rankLabel": "Grado {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Terug naar site",
|
||||
"housekeeping": "Housekeeping",
|
||||
"hotelManagementPanel": "Hotelbeheerpaneel",
|
||||
"rankLabel": "Rang {rank}"
|
||||
"rankLabel": "Rang {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Tilbake til nettstedet",
|
||||
"housekeeping": "Rengjøring",
|
||||
"hotelManagementPanel": "Hotellstyringspanel",
|
||||
"rankLabel": "Rangering {rank}"
|
||||
"rankLabel": "Rangering {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashbord",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Powrót do serwisu",
|
||||
"housekeeping": "Sprzątanie",
|
||||
"hotelManagementPanel": "Panel zarządzania hotelem",
|
||||
"rankLabel": "Ranga {rank}"
|
||||
"rankLabel": "Ranga {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Pulpit nawigacyjny",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Voltar ao site",
|
||||
"housekeeping": "Limpeza",
|
||||
"hotelManagementPanel": "Painel de gestão hoteleira",
|
||||
"rankLabel": "Classificação {rank}"
|
||||
"rankLabel": "Classificação {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Painel",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Înapoi la site",
|
||||
"housekeeping": "Menaj",
|
||||
"hotelManagementPanel": "Panoul de management al hotelului",
|
||||
"rankLabel": "Clasament {rank}"
|
||||
"rankLabel": "Clasament {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Tabloul de bord",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Вернуться на сайт",
|
||||
"housekeeping": "Ведение домашнего хозяйства",
|
||||
"hotelManagementPanel": "Панель управления отелем",
|
||||
"rankLabel": "Ранг {rank}"
|
||||
"rankLabel": "Ранг {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Панель управления",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Späť na stránku",
|
||||
"housekeeping": "Upratovanie",
|
||||
"hotelManagementPanel": "Panel riadenia hotela",
|
||||
"rankLabel": "Hodnotenie {rank}"
|
||||
"rankLabel": "Hodnotenie {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Dashboard",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Назад на сајт",
|
||||
"housekeeping": "Домаћинство",
|
||||
"hotelManagementPanel": "Панел за управљање хотелом",
|
||||
"rankLabel": "Ранг {rank}"
|
||||
"rankLabel": "Ранг {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Дасхбоард",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Tillbaka till webbplatsen",
|
||||
"housekeeping": "Städning",
|
||||
"hotelManagementPanel": "Hotellledningspanel",
|
||||
"rankLabel": "Rank {rank}"
|
||||
"rankLabel": "Rank {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Instrumentbräda",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Siteye geri dön",
|
||||
"housekeeping": "Temizlik",
|
||||
"hotelManagementPanel": "Otel yönetim paneli",
|
||||
"rankLabel": "Sıra {rank}"
|
||||
"rankLabel": "Sıra {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Kontrol Paneli",
|
||||
|
||||
+10
-1
@@ -755,7 +755,16 @@
|
||||
"backToSite": "Повернутися на сайт",
|
||||
"housekeeping": "Прибирання",
|
||||
"hotelManagementPanel": "Панель управління готелем",
|
||||
"rankLabel": "Рейтинг {rank}"
|
||||
"rankLabel": "Рейтинг {rank}",
|
||||
"hubNewsMedia": "News & media",
|
||||
"hubSiteContent": "Site content",
|
||||
"hubEngagement": "Engagement",
|
||||
"hubUsers": "Users",
|
||||
"hubAccess": "Access & security",
|
||||
"hubCatalog": "Catalog & rares",
|
||||
"hubShop": "Shop & payments",
|
||||
"hubTools": "Tools",
|
||||
"hubObservability": "Observability"
|
||||
},
|
||||
"dashboard": {
|
||||
"title": "Приладова панель",
|
||||
|
||||
Reference in new issue
Block a user