Reorganize admin into tabbed hubs with a condensed sidebar.
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:
SimoandCursor committed 2026-07-15 21:29:36 +02:00
1 parent 367f69a439
commit 363c9b3d56
30 files changed
+854 -432

No files matched your search

+36 -367
View File
File diff suppressed because it is too large. Load diff
-37
View File
@@ -1,5 +1,3 @@
import { Cog, ExternalLink } from "lucide-react";
import Link from "next/link";
import { redirect } from "next/navigation"; import { redirect } from "next/navigation";
import { canAccess, getAdminContext, PERMS } from "@/lib/permissions"; import { canAccess, getAdminContext, PERMS } from "@/lib/permissions";
import { prisma } from "@/lib/prisma"; import { prisma } from "@/lib/prisma";
@@ -10,13 +8,6 @@ import { CmsSettingsForm } from "./cms-settings-form";
export const dynamic = "force-dynamic"; export const dynamic = "force-dynamic";
export const metadata = { title: "CMS Settings" }; 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() { export default async function AdminSettings() {
const { session, permissions } = await getAdminContext(); const { session, permissions } = await getAdminContext();
if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) { if (!canAccess(permissions, PERMS.SETTINGS_VIEW, session.user.rank)) {
@@ -49,34 +40,6 @@ export default async function AdminSettings() {
return ( return (
<div className="space-y-8"> <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"> <div className="admin-stat-row">
<span className="admin-stat-chip"> <span className="admin-stat-chip">
{settings.length} keys in database {settings.length} keys in database
+6
View File
@@ -505,6 +505,12 @@ tbody tr:hover {
scroll-margin-top: 1rem; 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 */ /* Page heading */
.admin-page main > h1:first-child, .admin-page main > h1:first-child,
.admin-page > h1:first-child { .admin-page > h1:first-child {
+30
View File
@@ -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>
);
}
+15 -7
View File
@@ -6,25 +6,33 @@ import type { ReactNode } from "react";
import { useAdminMobile } from "@/components/admin/admin-mobile-wrapper"; import { useAdminMobile } from "@/components/admin/admin-mobile-wrapper";
/** /**
* Sidebar link that highlights when its route is active. "/admin" matches * Sidebar link that highlights when its route is active.
* exactly; every other entry also matches its sub-routes (e.g. /admin/radio is * Optional matchPrefixes cover multi-page hubs (e.g. Settings → theme/vpn).
* active on /admin/radio/history) so the current section stays lit.
*/ */
export function AdminNavLink({ export function AdminNavLink({
href, href,
icon, icon,
matchPrefixes,
children, children,
}: { }: {
href: string; href: string;
icon?: ReactNode; icon?: ReactNode;
matchPrefixes?: string[];
children: ReactNode; children: ReactNode;
}) { }) {
const pathname = usePathname() ?? ""; const pathname = usePathname() ?? "";
const { close } = useAdminMobile(); const { close } = useAdminMobile();
const active =
href === "/admin" let active: boolean;
? pathname === "/admin" if (href === "/admin") {
: pathname === href || pathname.startsWith(`${href}/`); active = pathname === "/admin";
} else if (matchPrefixes?.length) {
active = matchPrefixes.some(
(p) => pathname === p || pathname.startsWith(`${p}/`),
);
} else {
active = pathname === href || pathname.startsWith(`${href}/`);
}
return ( return (
<Link <Link
+52
View File
@@ -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
View File
@@ -755,7 +755,16 @@
"backToSite": "Обратно към сайта", "backToSite": "Обратно към сайта",
"housekeeping": "Домакинство", "housekeeping": "Домакинство",
"hotelManagementPanel": "Панел за управление на хотел", "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": { "dashboard": {
"title": "Табло за управление", "title": "Табло за управление",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Zpět na stránku", "backToSite": "Zpět na stránku",
"housekeeping": "Úklid", "housekeeping": "Úklid",
"hotelManagementPanel": "Panel správy hotelu", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Tilbage til webstedet", "backToSite": "Tilbage til webstedet",
"housekeeping": "Husholdning", "housekeeping": "Husholdning",
"hotelManagementPanel": "Hotel management panel", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -719,7 +719,16 @@
"backToSite": "Zurück zur Website", "backToSite": "Zurück zur Website",
"housekeeping": "Hausverwaltung", "housekeeping": "Hausverwaltung",
"hotelManagementPanel": "Hotel-Verwaltungsbereich", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Επιστροφή στον ιστότοπο", "backToSite": "Επιστροφή στον ιστότοπο",
"housekeeping": "Οικονομία", "housekeeping": "Οικονομία",
"hotelManagementPanel": "Πάνελ διαχείρισης ξενοδοχείου", "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": { "dashboard": {
"title": "Ταμπλό", "title": "Ταμπλό",
+9
View File
@@ -690,6 +690,9 @@
"overview": "Overview", "overview": "Overview",
"dashboard": "Dashboard", "dashboard": "Dashboard",
"content": "Content", "content": "Content",
"hubNewsMedia": "News & media",
"hubSiteContent": "Site content",
"hubEngagement": "Engagement",
"articles": "Articles", "articles": "Articles",
"tags": "Tags", "tags": "Tags",
"navigator": "Navigator", "navigator": "Navigator",
@@ -703,6 +706,8 @@
"banners": "Banners", "banners": "Banners",
"prefixes": "Prefixes", "prefixes": "Prefixes",
"usersAndAccess": "Users & access", "usersAndAccess": "Users & access",
"hubUsers": "Users",
"hubAccess": "Access & security",
"users": "Users", "users": "Users",
"bans": "Bans", "bans": "Bans",
"ipManagement": "IP management", "ipManagement": "IP management",
@@ -713,6 +718,8 @@
"onlineUsers": "Online users", "onlineUsers": "Online users",
"moderation": "Moderation", "moderation": "Moderation",
"economy": "Economy", "economy": "Economy",
"hubCatalog": "Catalog & rares",
"hubShop": "Shop & payments",
"catalog": "Catalog", "catalog": "Catalog",
"shop": "Shop", "shop": "Shop",
"transactions": "Transactions", "transactions": "Transactions",
@@ -734,6 +741,8 @@
"radioRanks": "Ranks", "radioRanks": "Ranks",
"radioAutodj": "Auto DJ", "radioAutodj": "Auto DJ",
"system": "System", "system": "System",
"hubTools": "Tools",
"hubObservability": "Observability",
"commandocentrum": "Commandocentrum", "commandocentrum": "Commandocentrum",
"emulator": "Emulator", "emulator": "Emulator",
"alerts": "Alerts", "alerts": "Alerts",
+10 -1
View File
@@ -719,7 +719,16 @@
"backToSite": "Volver al sitio", "backToSite": "Volver al sitio",
"housekeeping": "Housekeeping", "housekeeping": "Housekeeping",
"hotelManagementPanel": "Panel de gestión del hotel", "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": { "dashboard": {
"title": "Panel", "title": "Panel",
+10 -1
View File
@@ -719,7 +719,16 @@
"backToSite": "Retour au site", "backToSite": "Retour au site",
"housekeeping": "Gouvernance", "housekeeping": "Gouvernance",
"hotelManagementPanel": "Panneau de gestion de l'hôtel", "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": { "dashboard": {
"title": "Tableau de bord", "title": "Tableau de bord",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Povratak na stranicu", "backToSite": "Povratak na stranicu",
"housekeeping": "Domaćinstvo", "housekeeping": "Domaćinstvo",
"hotelManagementPanel": "Upravljačka ploča hotela", "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": { "dashboard": {
"title": "Nadzorna ploča", "title": "Nadzorna ploča",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Vissza a webhelyre", "backToSite": "Vissza a webhelyre",
"housekeeping": "Takarítás", "housekeeping": "Takarítás",
"hotelManagementPanel": "Hotel menedzsment panel", "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": { "dashboard": {
"title": "Irányítópult", "title": "Irányítópult",
+10 -1
View File
@@ -719,7 +719,16 @@
"settings": "Impostazioni", "settings": "Impostazioni",
"backToSite": "Torna al sito", "backToSite": "Torna al sito",
"hotelManagementPanel": "Pannello di gestione hotel", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Terug naar site", "backToSite": "Terug naar site",
"housekeeping": "Housekeeping", "housekeeping": "Housekeeping",
"hotelManagementPanel": "Hotelbeheerpaneel", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Tilbake til nettstedet", "backToSite": "Tilbake til nettstedet",
"housekeeping": "Rengjøring", "housekeeping": "Rengjøring",
"hotelManagementPanel": "Hotellstyringspanel", "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": { "dashboard": {
"title": "Dashbord", "title": "Dashbord",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Powrót do serwisu", "backToSite": "Powrót do serwisu",
"housekeeping": "Sprzątanie", "housekeeping": "Sprzątanie",
"hotelManagementPanel": "Panel zarządzania hotelem", "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": { "dashboard": {
"title": "Pulpit nawigacyjny", "title": "Pulpit nawigacyjny",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Voltar ao site", "backToSite": "Voltar ao site",
"housekeeping": "Limpeza", "housekeeping": "Limpeza",
"hotelManagementPanel": "Painel de gestão hoteleira", "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": { "dashboard": {
"title": "Painel", "title": "Painel",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Înapoi la site", "backToSite": "Înapoi la site",
"housekeeping": "Menaj", "housekeeping": "Menaj",
"hotelManagementPanel": "Panoul de management al hotelului", "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": { "dashboard": {
"title": "Tabloul de bord", "title": "Tabloul de bord",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Вернуться на сайт", "backToSite": "Вернуться на сайт",
"housekeeping": "Ведение домашнего хозяйства", "housekeeping": "Ведение домашнего хозяйства",
"hotelManagementPanel": "Панель управления отелем", "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": { "dashboard": {
"title": "Панель управления", "title": "Панель управления",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Späť na stránku", "backToSite": "Späť na stránku",
"housekeeping": "Upratovanie", "housekeeping": "Upratovanie",
"hotelManagementPanel": "Panel riadenia hotela", "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": { "dashboard": {
"title": "Dashboard", "title": "Dashboard",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Назад на сајт", "backToSite": "Назад на сајт",
"housekeeping": "Домаћинство", "housekeeping": "Домаћинство",
"hotelManagementPanel": "Панел за управљање хотелом", "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": { "dashboard": {
"title": "Дасхбоард", "title": "Дасхбоард",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Tillbaka till webbplatsen", "backToSite": "Tillbaka till webbplatsen",
"housekeeping": "Städning", "housekeeping": "Städning",
"hotelManagementPanel": "Hotellledningspanel", "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": { "dashboard": {
"title": "Instrumentbräda", "title": "Instrumentbräda",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Siteye geri dön", "backToSite": "Siteye geri dön",
"housekeeping": "Temizlik", "housekeeping": "Temizlik",
"hotelManagementPanel": "Otel yönetim paneli", "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": { "dashboard": {
"title": "Kontrol Paneli", "title": "Kontrol Paneli",
+10 -1
View File
@@ -755,7 +755,16 @@
"backToSite": "Повернутися на сайт", "backToSite": "Повернутися на сайт",
"housekeeping": "Прибирання", "housekeeping": "Прибирання",
"hotelManagementPanel": "Панель управління готелем", "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": { "dashboard": {
"title": "Приладова панель", "title": "Приладова панель",