Mobile-responsive admin nav/thread header, real dark theme pass

Nav overflowed the viewport on phones (confirmed via screenshot) — header
now wraps, nav row scrolls horizontally instead of pushing user/theme/
logout off-screen, ticket-thread's status/assignee selects stack full-width
below the subject on narrow screens.

Dark theme got a real pass instead of reusing near-identical values:
deeper/richer surfaces, punchier accent (#8b5cf6, matches the already-
validated dark chart-1), a subtle violet glow behind the page, and a
dark-appropriate card shadow (inset highlight + soft shadow — the flat
black shadow from light mode was invisible on a dark surface).

Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01QcXH24ky6zjk2UyK5oZUPH
This commit is contained in:
ogrechkoandClaude Sonnet 5 committed 2026-07-26 15:10:57 +00:00
1 parent 9f1413f0b9
commit cda92de9d2
4 files changed
+42 -29

No files matched your search

+8 -6
View File
@@ -14,22 +14,24 @@ export default async function AdminLayout({ children }: { children: React.ReactN
return ( return (
<div className="flex min-h-screen flex-col bg-bg"> <div className="flex min-h-screen flex-col bg-bg">
<header className="border-b border-border bg-surface"> <header className="border-b border-border bg-surface">
<div className="mx-auto flex max-w-7xl items-center gap-6 px-6 py-3"> <div className="mx-auto flex max-w-7xl flex-wrap items-center gap-x-6 gap-y-2 px-4 py-3 sm:px-6">
<div className="flex items-center gap-2 font-display text-[15px] font-bold tracking-tight"> <div className="flex items-center gap-2 font-display text-[15px] font-bold tracking-tight">
<div className="flex h-7 w-7 items-center justify-center rounded-md bg-accent text-white"> <div className="flex h-7 w-7 shrink-0 items-center justify-center rounded-md bg-accent text-white">
<Ticket size={15} strokeWidth={2.5} /> <Ticket size={15} strokeWidth={2.5} />
</div> </div>
top-tickets top-tickets
</div> </div>
<NavLinks /> <div className="ml-auto flex items-center gap-2 sm:gap-3">
<div className="ml-auto flex items-center gap-3"> <span className="hidden text-sm text-text-muted sm:inline">{session.user.name}</span>
<span className="text-sm text-text-muted">{session.user.name}</span>
<ThemeToggle /> <ThemeToggle />
<LogoutButton /> <LogoutButton />
</div> </div>
<div className="order-last w-full overflow-x-auto sm:order-none sm:w-auto sm:overflow-visible">
<NavLinks />
</div>
</div> </div>
</header> </header>
<main className="mx-auto w-full max-w-7xl flex-1 px-6 py-6">{children}</main> <main className="mx-auto w-full max-w-7xl flex-1 px-4 py-6 sm:px-6">{children}</main>
</div> </div>
); );
} }
+1 -1
View File
@@ -23,7 +23,7 @@ export function NavLinks() {
<Link <Link
key={href} key={href}
href={href} href={href}
className={`flex items-center gap-1.5 rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${ className={`flex shrink-0 items-center gap-1.5 whitespace-nowrap rounded-md px-3 py-1.5 text-sm font-medium transition-colors ${
active ? "bg-accent-soft text-accent-soft-text" : "text-text-muted hover:bg-surface-hover hover:text-text" active ? "bg-accent-soft text-accent-soft-text" : "text-text-muted hover:bg-surface-hover hover:text-text"
}`} }`}
> >
@@ -82,8 +82,8 @@ export function TicketThread({
} }
return ( return (
<div className="flex h-[calc(100vh-6.5rem)] flex-col"> <div className="flex h-[calc(100vh-11rem)] flex-col sm:h-[calc(100vh-6.5rem)]">
<div className="mb-4 flex items-start justify-between gap-4"> <div className="mb-4 flex flex-wrap items-start justify-between gap-3">
<div className="min-w-0"> <div className="min-w-0">
<Link href="/dashboard" className="mb-1 flex items-center gap-1 text-xs text-text-muted hover:text-text"> <Link href="/dashboard" className="mb-1 flex items-center gap-1 text-xs text-text-muted hover:text-text">
<ArrowLeft size={13} /> <ArrowLeft size={13} />
@@ -96,11 +96,11 @@ export function TicketThread({
</span> </span>
</div> </div>
<div className="flex shrink-0 items-center gap-2"> <div className="flex w-full shrink-0 items-center gap-2 sm:w-auto">
<select <select
value={ticket.status} value={ticket.status}
onChange={(e) => updateStatus(e.target.value as TicketStatus)} onChange={(e) => updateStatus(e.target.value as TicketStatus)}
className="rounded-md border border-border bg-surface px-2 py-1.5 text-sm outline-none focus:border-accent" className="min-w-0 flex-1 rounded-md border border-border bg-surface px-2 py-1.5 text-sm outline-none focus:border-accent sm:flex-none"
> >
{Object.entries(STATUS_LABEL).map(([value, label]) => ( {Object.entries(STATUS_LABEL).map(([value, label]) => (
<option key={value} value={value}> <option key={value} value={value}>
@@ -111,7 +111,7 @@ export function TicketThread({
<select <select
value={ticket.assigneeId ?? ""} value={ticket.assigneeId ?? ""}
onChange={(e) => updateAssignee(e.target.value)} onChange={(e) => updateAssignee(e.target.value)}
className="rounded-md border border-border bg-surface px-2 py-1.5 text-sm outline-none focus:border-accent" className="min-w-0 flex-1 rounded-md border border-border bg-surface px-2 py-1.5 text-sm outline-none focus:border-accent sm:flex-none"
> >
<option value="">Не назначено</option> <option value="">Не назначено</option>
{agents.map((agent) => ( {agents.map((agent) => (
+28 -17
View File
@@ -99,23 +99,26 @@
--radius-md-val: 12px; --radius-md-val: 12px;
--radius-lg-val: 18px; --radius-lg-val: 18px;
--bg-glow: none;
--card-shadow: 0 1px 2px rgba(0, 0, 0, 0.04);
color-scheme: light; color-scheme: light;
} }
@media (prefers-color-scheme: dark) { @media (prefers-color-scheme: dark) {
:root:not([data-theme="light"]) { :root:not([data-theme="light"]) {
--bg: #0f0d17; --bg: #0b0a12;
--surface: #17141f; --surface: #161320;
--surface-hover: #1e1a2b; --surface-hover: #1d1929;
--border: #2b2438; --border: #2d2640;
--border-strong: #3a3150; --border-strong: #453c60;
--text: #f1eefb; --text: #f1eefb;
--text-muted: #a79fc4; --text-muted: #a79fc4;
--text-faint: #6f6790; --text-faint: #6f6790;
--accent: #a78bfa; --accent: #8b5cf6;
--accent-hover: #c4b5fd; --accent-hover: #7c3aed;
--accent-soft: #241b3d; --accent-soft: #251c3f;
--accent-soft-text: #c4b5fd; --accent-soft-text: #c4b5fd;
--danger: #f87171; --danger: #f87171;
@@ -146,23 +149,26 @@
--chart-4: #d97706; --chart-4: #d97706;
--chart-muted: var(--border-strong); --chart-muted: var(--border-strong);
--bg-glow: radial-gradient(ellipse 80% 50% at 50% -10%, rgba(139, 92, 246, 0.12), transparent 60%);
--card-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset, 0 8px 24px rgba(0, 0, 0, 0.35);
color-scheme: dark; color-scheme: dark;
} }
} }
:root[data-theme="dark"] { :root[data-theme="dark"] {
--bg: #0f0d17; --bg: #0b0a12;
--surface: #17141f; --surface: #161320;
--surface-hover: #1e1a2b; --surface-hover: #1d1929;
--border: #2b2438; --border: #2d2640;
--border-strong: #3a3150; --border-strong: #453c60;
--text: #f1eefb; --text: #f1eefb;
--text-muted: #a79fc4; --text-muted: #a79fc4;
--text-faint: #6f6790; --text-faint: #6f6790;
--accent: #a78bfa; --accent: #8b5cf6;
--accent-hover: #c4b5fd; --accent-hover: #7c3aed;
--accent-soft: #241b3d; --accent-soft: #251c3f;
--accent-soft-text: #c4b5fd; --accent-soft-text: #c4b5fd;
--danger: #f87171; --danger: #f87171;
@@ -191,6 +197,9 @@
--chart-4: #d97706; --chart-4: #d97706;
--chart-muted: var(--border-strong); --chart-muted: var(--border-strong);
--bg-glow: radial-gradient(ellipse 80% 50% at 50% -10%, rgba(139, 92, 246, 0.12), transparent 60%);
--card-shadow: 0 1px 0 rgba(255, 255, 255, 0.05) inset, 0 8px 24px rgba(0, 0, 0, 0.35);
color-scheme: dark; color-scheme: dark;
} }
@@ -228,6 +237,8 @@ body {
body { body {
background: var(--bg); background: var(--bg);
background-image: var(--bg-glow, none);
background-attachment: fixed;
color: var(--text); color: var(--text);
font-family: var(--font-sans); font-family: var(--font-sans);
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@@ -261,7 +272,7 @@ body {
background: var(--surface); background: var(--surface);
border: 1px solid var(--border); border: 1px solid var(--border);
border-radius: var(--radius-md); border-radius: var(--radius-md);
box-shadow: 0 1px 2px rgba(0, 0, 0, 0.04); box-shadow: var(--card-shadow);
} }
.btn { .btn {