From 5aa268970a4fdf15a4947d71466c265137a330fb Mon Sep 17 00:00:00 2001 From: Yun Chan Date: Wed, 16 Sep 2026 23:24:35 +0900 Subject: [PATCH] feat(admin): read live back-office data in every console view Models, pipelines, users, subscriptions, usage, audit log, ads, and releases still rendered placeholder or duplicated implementations from the earlier admin split. They now read the live back-office API, share one sidebar and console theme, and the license issuer dialog uses the rotated signing key. --- apps/admin/AGENTS.md | 9 +++ apps/admin/CLAUDE.md | 1 + apps/admin/next-env.d.ts | 3 +- apps/admin/src/app/(admin)/ads/page.tsx | 2 +- .../src/app/(admin)/audit-log/[id]/page.tsx | 4 +- apps/admin/src/app/(admin)/audit-log/page.tsx | 4 +- apps/admin/src/app/(admin)/models/page.tsx | 80 +++++++++---------- apps/admin/src/app/(admin)/page.tsx | 14 ++-- apps/admin/src/app/(admin)/pipelines/page.tsx | 48 +++++------ apps/admin/src/app/(admin)/releases/page.tsx | 2 +- .../app/(admin)/subscriptions/[id]/page.tsx | 2 +- .../app/(admin)/subscriptions/new/client.tsx | 2 +- .../app/(admin)/subscriptions/new/page.tsx | 2 +- .../src/app/(admin)/subscriptions/page.tsx | 4 +- apps/admin/src/app/(admin)/usage/page.tsx | 6 +- .../admin/src/app/(admin)/users/[id]/page.tsx | 14 ++-- apps/admin/src/app/(admin)/users/page.tsx | 14 ++-- apps/admin/src/app/globals.css | 62 +++++++------- apps/admin/src/app/login/page.tsx | 28 +++---- apps/admin/src/app/unauthorized/page.tsx | 10 +-- apps/admin/src/components/admin-sidebar.tsx | 42 +++++----- .../src/components/license-issuer-button.tsx | 2 +- .../src/components/license-issuer-dialog.tsx | 6 +- 23 files changed, 187 insertions(+), 174 deletions(-) create mode 100644 apps/admin/AGENTS.md create mode 100644 apps/admin/CLAUDE.md diff --git a/apps/admin/AGENTS.md b/apps/admin/AGENTS.md new file mode 100644 index 0000000..643577d --- /dev/null +++ b/apps/admin/AGENTS.md @@ -0,0 +1,9 @@ + + +# This is NOT the Next.js you know + +This version has breaking changes โ€” APIs, conventions, and file structure may all differ from your training data. Read the relevant guide in `node_modules/next/dist/docs/` (resolved from this file's directory; in monorepos the `next` package may not be visible from the repo root) before writing any code. Heed deprecation notices. + +This block is written and re-added by `next dev` โ€” verify at `node_modules/next/dist/server/lib/generate-agent-files.js`. Removing it from a diff only re-creates the uncommitted change; committing it with your work keeps the tree clean. + + diff --git a/apps/admin/CLAUDE.md b/apps/admin/CLAUDE.md new file mode 100644 index 0000000..43c994c --- /dev/null +++ b/apps/admin/CLAUDE.md @@ -0,0 +1 @@ +@AGENTS.md diff --git a/apps/admin/next-env.d.ts b/apps/admin/next-env.d.ts index 830fb59..ce4e94a 100644 --- a/apps/admin/next-env.d.ts +++ b/apps/admin/next-env.d.ts @@ -1,6 +1,7 @@ /// /// -/// +import "./.next/types/routes.d.ts"; +import "./.next/types/root-params.d.ts"; // NOTE: This file should not be edited // see https://nextjs.org/docs/app/api-reference/config/typescript for more information. diff --git a/apps/admin/src/app/(admin)/ads/page.tsx b/apps/admin/src/app/(admin)/ads/page.tsx index 745ba9f..82ce061 100644 --- a/apps/admin/src/app/(admin)/ads/page.tsx +++ b/apps/admin/src/app/(admin)/ads/page.tsx @@ -99,7 +99,7 @@ function RewardKpis({ stats }: { stats: AdRewardStats }): React.ReactElement { > {card.title} - + {card.value} {card.subtext} diff --git a/apps/admin/src/app/(admin)/audit-log/[id]/page.tsx b/apps/admin/src/app/(admin)/audit-log/[id]/page.tsx index 21c64b6..e205a5a 100644 --- a/apps/admin/src/app/(admin)/audit-log/[id]/page.tsx +++ b/apps/admin/src/app/(admin)/audit-log/[id]/page.tsx @@ -71,7 +71,7 @@ export default async function AuditLogDetailPage({ params }: PageProps): Promise width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%)', + background: 'linear-gradient(180deg, var(--d3-accent-main) 0%, var(--d3-tag-purple) 100%)', }} /> @@ -131,7 +131,7 @@ export default async function AuditLogDetailPage({ params }: PageProps): Promise sx={{ p: 2, borderRadius: '12px', - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}`, fontFamily: FONT_SANS, fontSize: '13px', diff --git a/apps/admin/src/app/(admin)/audit-log/page.tsx b/apps/admin/src/app/(admin)/audit-log/page.tsx index b8e3543..b071118 100644 --- a/apps/admin/src/app/(admin)/audit-log/page.tsx +++ b/apps/admin/src/app/(admin)/audit-log/page.tsx @@ -72,7 +72,7 @@ export default async function AuditLogPage({ searchParams }: PageProps): Promise width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #60a5fa 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-accent-light) 0%, var(--d3-accent-main) 100%)', }} /> @@ -182,7 +182,7 @@ export default async function AuditLogPage({ searchParams }: PageProps): Promise borderRadius: '8px', textTransform: 'none', px: 1.5, - '&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight }, + '&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight }, }} > Inspect โ†’ diff --git a/apps/admin/src/app/(admin)/models/page.tsx b/apps/admin/src/app/(admin)/models/page.tsx index 4f134b6..221b4bb 100644 --- a/apps/admin/src/app/(admin)/models/page.tsx +++ b/apps/admin/src/app/(admin)/models/page.tsx @@ -345,7 +345,7 @@ export default function ServiceModelsPage(): React.ReactElement { width: 4, height: 34, borderRadius: '999px', - background: 'linear-gradient(180deg, #06b6d4 0%, #8b5cf6 50%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-tag-purple) 50%, var(--d3-accent-main) 100%)', }} /> @@ -457,8 +457,8 @@ export default function ServiceModelsPage(): React.ReactElement { width: 44, height: 44, borderRadius: '12px', - bgcolor: 'rgba(6, 182, 212, 0.15)', - border: '1px solid rgba(6, 182, 212, 0.3)', + bgcolor: 'var(--d3-tag-cyan)', + border: '1px solid var(--d3-tag-cyan)', display: 'flex', alignItems: 'center', justifyContent: 'center', @@ -483,7 +483,7 @@ export default function ServiceModelsPage(): React.ReactElement { - + ๐Ÿ›ก๏ธ Auto Failover Route: {sttEndpoints.map((e) => e.providerType).join(' โž” ')} @@ -530,7 +530,7 @@ export default function ServiceModelsPage(): React.ReactElement { ) : ( sttEndpoints.map((ep) => ( - + #{ep.fallbackPriority} @@ -556,7 +556,7 @@ export default function ServiceModelsPage(): React.ReactElement { {ep.isDefault ? ( - + โญ DEFAULT ) : ( @@ -576,10 +576,10 @@ export default function ServiceModelsPage(): React.ReactElement { fontFamily: FONT_SANS, fontSize: '10px', color: C.green400, - borderColor: 'rgba(34, 197, 94, 0.4)', + borderColor: 'var(--d3-status-success)', px: 1, py: 0.25, - '&:hover': { bgcolor: 'rgba(34, 197, 94, 0.15)', borderColor: C.green400 }, + '&:hover': { bgcolor: 'var(--d3-status-success)', borderColor: C.green400 }, }} > Set Default @@ -596,7 +596,7 @@ export default function ServiceModelsPage(): React.ReactElement { borderColor: C.borderHl, px: 1, py: 0.25, - '&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight }, + '&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight }, }} > {sttPingStatus[ep.id] || 'โšก Test'} @@ -676,7 +676,7 @@ export default function ServiceModelsPage(): React.ReactElement { {ep.modelId} {ep.isDefault && ( - + DEFAULT )} @@ -716,7 +716,7 @@ export default function ServiceModelsPage(): React.ReactElement { borderColor: C.borderHl, px: 1, py: 0.25, - '&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight }, + '&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight }, }} > Delete @@ -740,11 +740,11 @@ export default function ServiceModelsPage(): React.ReactElement { fullWidth PaperProps={{ sx: { - bgcolor: 'rgba(17, 26, 48, 0.95)', + bgcolor: 'var(--d3-bg-card-soft)', backdropFilter: 'blur(32px)', border: `1px solid ${C.borderHl}`, borderRadius: '20px', - boxShadow: '0 24px 60px rgba(3, 7, 18, 0.8)', + boxShadow: '0 24px 60px var(--d3-scrim)', }, }} > @@ -772,7 +772,7 @@ export default function ServiceModelsPage(): React.ReactElement { if (preset.prompt) setSttPrompt(preset.prompt) }} sx={{ - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', '& fieldset': { borderColor: C.border }, @@ -796,7 +796,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder="e.g. Groq Whisper LPU Fast" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -807,7 +807,7 @@ export default function ServiceModelsPage(): React.ReactElement { label="Provider Type" onChange={(e) => setSttProviderType(e.target.value as STTProviderCategory)} sx={{ - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', '& fieldset': { borderColor: C.border }, @@ -834,7 +834,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder="https://api.groq.com/openai/v1/audio/transcriptions" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -849,7 +849,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder={sttEditingId ? 'โ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ขโ€ข (๋ณ€๊ฒฝ ์‹œ ์ž…๋ ฅ)' : 'gsk_... or sk-... or token'} sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -862,7 +862,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder="e.g. whisper-large-v3-turbo, nova-3" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -876,7 +876,7 @@ export default function ServiceModelsPage(): React.ReactElement { label="Dispatch Method" onChange={(e) => setSttMethod(e.target.value as SttProviderEndpoint['method'])} sx={{ - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', '& fieldset': { borderColor: C.border }, @@ -897,7 +897,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder="ko, en, auto" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -911,7 +911,7 @@ export default function ServiceModelsPage(): React.ReactElement { required size="small" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -926,7 +926,7 @@ export default function ServiceModelsPage(): React.ReactElement { required size="small" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -937,7 +937,7 @@ export default function ServiceModelsPage(): React.ReactElement { size="small" placeholder="e.g. D3RO, Kubernetes, React, LLM" sx={{ - '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' }, + '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' }, '& .MuiInputLabel-root': { color: C.dim }, }} /> @@ -950,11 +950,11 @@ export default function ServiceModelsPage(): React.ReactElement { required helperText="๋ณ€๊ฒฝ ์‚ฌ์œ ๋ฅผ 3์ž ์ด์ƒ ์ž…๋ ฅํ•˜์„ธ์š”." size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' } }} /> {/* Test Connection Inside Modal */} - + Live Connection Test (Synthetic Audio Ping) @@ -970,7 +970,7 @@ export default function ServiceModelsPage(): React.ReactElement { color: C.bright, borderColor: C.borderHl, textTransform: 'none', - '&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(59, 130, 246, 0.15)' }, + '&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-accent-glow)' }, }} > {testingInModal ? : null} @@ -985,8 +985,8 @@ export default function ServiceModelsPage(): React.ReactElement { sx={{ fontFamily: FONT_SANS, fontSize: '12px', - borderColor: sttTestModalResult.success ? 'rgba(34, 197, 94, 0.5)' : 'rgba(239, 68, 68, 0.5)', - color: sttTestModalResult.success ? C.green400 : '#f87171', + borderColor: sttTestModalResult.success ? 'var(--d3-status-success)' : 'var(--d3-status-danger)', + color: sttTestModalResult.success ? C.green400 : 'var(--d3-status-danger)', }} > {sttTestModalResult.message} @@ -1013,11 +1013,11 @@ export default function ServiceModelsPage(): React.ReactElement { fullWidth PaperProps={{ sx: { - bgcolor: 'rgba(17, 26, 48, 0.95)', + bgcolor: 'var(--d3-bg-card-soft)', backdropFilter: 'blur(32px)', border: `1px solid ${C.borderHl}`, borderRadius: '20px', - boxShadow: '0 24px 60px rgba(3, 7, 18, 0.8)', + boxShadow: '0 24px 60px var(--d3-scrim)', }, }} > @@ -1042,7 +1042,7 @@ export default function ServiceModelsPage(): React.ReactElement { setLlmCompletionCost(preset.completionCost) }} sx={{ - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', '& fieldset': { borderColor: C.border }, @@ -1062,7 +1062,7 @@ export default function ServiceModelsPage(): React.ReactElement { required fullWidth size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} /> Provider Category @@ -1079,7 +1079,7 @@ export default function ServiceModelsPage(): React.ReactElement { value={llmProvider} label="Provider Category" onChange={(e) => setLlmProvider(e.target.value)} - sx={{ bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px' }} + sx={{ bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px' }} > Local Sidecar Ollama Local Engine @@ -1095,7 +1095,7 @@ export default function ServiceModelsPage(): React.ReactElement { required fullWidth size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} /> setLlmApiKey(e.target.value)} fullWidth size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} /> setLlmPromptCost(e.target.value)} required size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} /> setLlmCompletionCost(e.target.value)} required size="small" - sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'rgba(10, 17, 31, 0.7)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} + sx={{ '& .MuiOutlinedInput-root': { bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO } }} /> diff --git a/apps/admin/src/app/(admin)/page.tsx b/apps/admin/src/app/(admin)/page.tsx index dd0a21f..00df8c2 100644 --- a/apps/admin/src/app/(admin)/page.tsx +++ b/apps/admin/src/app/(admin)/page.tsx @@ -128,7 +128,7 @@ export default async function AdminOverviewPage(): Promise { width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 50%, var(--d3-tag-purple) 100%)', }} /> @@ -174,11 +174,11 @@ export default async function AdminOverviewPage(): Promise { fontSize: '12px', color: C.bright, borderColor: C.borderHl, - bgcolor: 'rgba(17, 26, 48, 0.6)', + bgcolor: 'var(--d3-bg-card-soft)', borderRadius: '10px', textTransform: 'none', px: 2, - '&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(26, 38, 68, 0.8)' }, + '&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-bg-raised-soft)' }, }} > View Pipelines Console โ†’ @@ -352,12 +352,12 @@ export default async function AdminOverviewPage(): Promise { sx={{ p: 2, borderRadius: '14px', - bgcolor: 'rgba(10, 17, 31, 0.65)', + bgcolor: 'var(--d3-bg-inset-soft)', border: `1px solid ${C.border}`, transition: 'all 0.2s ease', '&:hover': { borderColor: C.accentLight, - bgcolor: 'rgba(17, 26, 48, 0.8)', + bgcolor: 'var(--d3-bg-card-soft)', transform: 'translateY(-2px)', }, }} @@ -371,8 +371,8 @@ export default async function AdminOverviewPage(): Promise { width: 8, height: 8, borderRadius: '50%', - bgcolor: node.status === 'operational' ? '#10b981' : node.status === 'degraded' ? '#f59e0b' : '#ef4444', - boxShadow: `0 0 8px ${node.status === 'operational' ? '#10b981' : node.status === 'degraded' ? '#f59e0b' : '#ef4444'}`, + bgcolor: node.status === 'operational' ? 'var(--d3-status-success)' : node.status === 'degraded' ? 'var(--d3-status-warning)' : 'var(--d3-status-danger)', + boxShadow: `0 0 8px ${node.status === 'operational' ? 'var(--d3-status-success)' : node.status === 'degraded' ? 'var(--d3-status-warning)' : 'var(--d3-status-danger)'}`, }} /> diff --git a/apps/admin/src/app/(admin)/pipelines/page.tsx b/apps/admin/src/app/(admin)/pipelines/page.tsx index 6801825..773e275 100644 --- a/apps/admin/src/app/(admin)/pipelines/page.tsx +++ b/apps/admin/src/app/(admin)/pipelines/page.tsx @@ -44,7 +44,7 @@ export default async function PipelinesPage(): Promise { width: 4, height: 28, borderRadius: '999px', - background: 'linear-gradient(180deg, #06b6d4 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 100%)', }} /> @@ -89,11 +89,11 @@ export default async function PipelinesPage(): Promise { fontSize: '12px', color: C.bright, borderColor: C.borderHl, - bgcolor: 'rgba(17, 26, 48, 0.6)', + bgcolor: 'var(--d3-bg-card-soft)', borderRadius: '10px', textTransform: 'none', px: 2, - '&:hover': { borderColor: C.accentLight, bgcolor: 'rgba(26, 38, 68, 0.8)' }, + '&:hover': { borderColor: C.accentLight, bgcolor: 'var(--d3-bg-raised-soft)' }, }} > โšก Run Diagnostic Ping @@ -129,19 +129,19 @@ export default async function PipelinesPage(): Promise { - + AVG LATENCY {whisper.avgLatencyMs}ms - + SPEEDUP FACTOR {whisper.speedupFactor} - + GPU VRAM {whisper.gpuVramUsage} @@ -149,7 +149,7 @@ export default async function PipelinesPage(): Promise { - + โ€ข Dual-Condition Flush: Audio buffer flushes parallel with model warm-up.
โ€ข Realtime Streaming: {whisper.partialStreamingFps} fps interim partial transcription in RecordingTip popup.
@@ -182,19 +182,19 @@ export default async function PipelinesPage(): Promise {
- + THROUGHPUT {ollama.tokensPerSecond} tok/s - + CONTEXT LIMIT {ollama.activeContextLimit} - + VRAM OCCUPANCY {ollama.vramAllocated} @@ -202,7 +202,7 @@ export default async function PipelinesPage(): Promise { - + โ€ข Loaded Models: {ollama.loadedModels.join(', ')}
โ€ข NDJSON Streaming: Zero-latency token streaming for Auto Polish & AI Chat.
@@ -238,19 +238,19 @@ export default async function PipelinesPage(): Promise {
- + LIVE STREAMS {realtimeVoice.activeStreams} Active - + AUDIO RTT {realtimeVoice.avgAudioRttMs}ms - + LOCAL FALLBACK {realtimeVoice.localFallbackRate} @@ -258,7 +258,7 @@ export default async function PipelinesPage(): Promise { - + โ€ข Ultra-low Latency: Full-duplex bidirectional voice-to-voice stream.
โ€ข Auto Failover: Drops gracefully to Local STT + Ollama + TTS if network drops.
@@ -291,19 +291,19 @@ export default async function PipelinesPage(): Promise {
- + INDEXED DOCS {ragVector.indexedDocuments.toLocaleString()} - + VECTOR CHUNKS {ragVector.totalVectorChunks.toLocaleString()} - + SEARCH HIT RATE {ragVector.topHitRatePercent}% @@ -311,7 +311,7 @@ export default async function PipelinesPage(): Promise { - + โ€ข Local Vector Store: Zero-cloud-leakage SQLite embeddings with cosine similarity.
โ€ข Average Search Latency: {ragVector.avgSearchLatencyMs}ms per 512-dim query.
@@ -345,7 +345,7 @@ export default async function PipelinesPage(): Promise {
- + SPEAKER ACCURACY {meetingIntelligence.speakerAccuracyPercent}% @@ -354,7 +354,7 @@ export default async function PipelinesPage(): Promise { Pyannote + LLM Consensus - + ACTIVE MEETINGS {meetingIntelligence.activeMeetingSessions} Live @@ -363,7 +363,7 @@ export default async function PipelinesPage(): Promise { Realtime Captions & Record - + TEMPLATES TODAY {meetingIntelligence.templatesGeneratedToday} Docs @@ -372,7 +372,7 @@ export default async function PipelinesPage(): Promise { Summary, Action Items, Jira - + MINDMAP EXPORTS {meetingIntelligence.mindmapsExported} Maps @@ -383,7 +383,7 @@ export default async function PipelinesPage(): Promise { - + โ€ข Speaker Attribution Architecture: Hybrid pipeline combining Pyannote 3.1 voiceprint embeddings with LLM conversational speaker inference.
โ€ข Multi-Document Synthesis (Phase 14.5): Simultaneous generation of Executive Summary, Action Item Checklist, Jira Issue Drafts, and Interactive Markdown Mindmaps.
diff --git a/apps/admin/src/app/(admin)/releases/page.tsx b/apps/admin/src/app/(admin)/releases/page.tsx index b915a94..f377684 100644 --- a/apps/admin/src/app/(admin)/releases/page.tsx +++ b/apps/admin/src/app/(admin)/releases/page.tsx @@ -165,7 +165,7 @@ function KpiCards({ hub }: { hub: ReleaseHub }): React.ReactElement { > {card.title}
- + {card.value} {card.subtext} diff --git a/apps/admin/src/app/(admin)/subscriptions/[id]/page.tsx b/apps/admin/src/app/(admin)/subscriptions/[id]/page.tsx index 6fb932c..7d97fef 100644 --- a/apps/admin/src/app/(admin)/subscriptions/[id]/page.tsx +++ b/apps/admin/src/app/(admin)/subscriptions/[id]/page.tsx @@ -80,7 +80,7 @@ export default async function SubscriptionDetailPage({ params }: PageProps): Pro width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)', }} /> diff --git a/apps/admin/src/app/(admin)/subscriptions/new/client.tsx b/apps/admin/src/app/(admin)/subscriptions/new/client.tsx index 21d7fca..a1ca5bc 100644 --- a/apps/admin/src/app/(admin)/subscriptions/new/client.tsx +++ b/apps/admin/src/app/(admin)/subscriptions/new/client.tsx @@ -31,7 +31,7 @@ export function NewSubscriptionClient({ initialUserId }: NewSubscriptionClientPr placeholder="Supabase user UUID" sx={{ '& .MuiOutlinedInput-root': { - bgcolor: 'rgba(10, 17, 31, 0.7)', + bgcolor: 'var(--d3-bg-inset-soft)', color: C.bright, borderRadius: '10px', fontFamily: FONT_MONO, diff --git a/apps/admin/src/app/(admin)/subscriptions/new/page.tsx b/apps/admin/src/app/(admin)/subscriptions/new/page.tsx index d4a417d..0d182d1 100644 --- a/apps/admin/src/app/(admin)/subscriptions/new/page.tsx +++ b/apps/admin/src/app/(admin)/subscriptions/new/page.tsx @@ -39,7 +39,7 @@ export default async function NewSubscriptionPage({ searchParams }: PageProps): width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)', }} /> diff --git a/apps/admin/src/app/(admin)/subscriptions/page.tsx b/apps/admin/src/app/(admin)/subscriptions/page.tsx index c17e0f7..d5b925e 100644 --- a/apps/admin/src/app/(admin)/subscriptions/page.tsx +++ b/apps/admin/src/app/(admin)/subscriptions/page.tsx @@ -115,7 +115,7 @@ export default async function AdminSubscriptionsPage({ searchParams }: PageProps width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #a855f7 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)', }} /> @@ -305,7 +305,7 @@ export default async function AdminSubscriptionsPage({ searchParams }: PageProps borderRadius: '8px', textTransform: 'none', px: 1.5, - '&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight }, + '&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight }, }} > Edit โ†’ diff --git a/apps/admin/src/app/(admin)/usage/page.tsx b/apps/admin/src/app/(admin)/usage/page.tsx index d8af0fd..cd4480c 100644 --- a/apps/admin/src/app/(admin)/usage/page.tsx +++ b/apps/admin/src/app/(admin)/usage/page.tsx @@ -84,7 +84,7 @@ export default async function AdminUsagePage(): Promise { width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #10b981 0%, #3b82f6 100%)', + background: 'linear-gradient(180deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)', }} /> @@ -221,12 +221,12 @@ export default async function AdminUsagePage(): Promise { {(f.totalCalls ?? f.callCount ?? 0).toLocaleString()} calls ({(f.percentage ?? 10).toFixed(1)}%) โ€ข ${(f.estimatedCostUsd ?? f.totalCost).toFixed(2)}
- + @@ -138,15 +138,15 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis height: 48, borderRadius: '14px', background: isProPlus - ? 'linear-gradient(135deg, #a855f7 0%, #3b82f6 100%)' - : 'linear-gradient(135deg, #10b981 0%, #3b82f6 100%)', + ? 'linear-gradient(135deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)' + : 'linear-gradient(135deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', - color: '#ffffff', + color: 'var(--d3-text-inverse)', fontWeight: 500, fontSize: '20px', - boxShadow: '0 0 20px rgba(59, 130, 246, 0.4)', + boxShadow: '0 0 20px var(--d3-accent-glow)', }} > {((profile.name as string) || (profile.email as string) || '?').charAt(0).toUpperCase()} @@ -188,7 +188,7 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis - + Entitlement source @@ -200,7 +200,7 @@ export default async function AdminUserDetailPage({ params }: PageProps): Promis {/* Tier-based Enabled Features */} - + Enabled Features diff --git a/apps/admin/src/app/(admin)/users/page.tsx b/apps/admin/src/app/(admin)/users/page.tsx index 66afb0d..dd63001 100644 --- a/apps/admin/src/app/(admin)/users/page.tsx +++ b/apps/admin/src/app/(admin)/users/page.tsx @@ -68,7 +68,7 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi width: 4, height: 32, borderRadius: '999px', - background: 'linear-gradient(180deg, #3b82f6 0%, #8b5cf6 100%)', + background: 'linear-gradient(180deg, var(--d3-accent-main) 0%, var(--d3-tag-purple) 100%)', }} /> @@ -163,17 +163,17 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi height: 34, borderRadius: '10px', background: isProPlus - ? 'linear-gradient(135deg, #a855f7 0%, #3b82f6 100%)' + ? 'linear-gradient(135deg, var(--d3-tag-purple) 0%, var(--d3-accent-main) 100%)' : isPro - ? 'linear-gradient(135deg, #10b981 0%, #3b82f6 100%)' - : 'linear-gradient(135deg, #64748b 0%, #475569 100%)', + ? 'linear-gradient(135deg, var(--d3-status-success) 0%, var(--d3-accent-main) 100%)' + : 'linear-gradient(135deg, var(--d3-text-label) 0%, var(--d3-text-label) 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', - color: '#ffffff', + color: 'var(--d3-text-inverse)', fontWeight: 500, fontSize: '13px', - boxShadow: isProPlus ? '0 0 12px rgba(168, 85, 247, 0.4)' : 'none', + boxShadow: isProPlus ? '0 0 12px var(--d3-tag-purple)' : 'none', }} > {u.name.charAt(0)} @@ -238,7 +238,7 @@ export default async function AdminUsersPage({ searchParams }: PageProps): Promi borderRadius: '8px', textTransform: 'none', px: 1.5, - '&:hover': { bgcolor: 'rgba(59, 130, 246, 0.15)', borderColor: C.accentLight }, + '&:hover': { bgcolor: 'var(--d3-accent-glow)', borderColor: C.accentLight }, }} > Manage โ†’ diff --git a/apps/admin/src/app/globals.css b/apps/admin/src/app/globals.css index edd29fe..c334475 100644 --- a/apps/admin/src/app/globals.css +++ b/apps/admin/src/app/globals.css @@ -1,29 +1,28 @@ -/* D3RO Voice Admin CRM โ€” "Midnight Glass v2" Global Styles */ +/* D3RO Voice Admin CRM โ€” "Midnight Glass v3" Global Styles */ /* ํฐํŠธ๋Š” layout.tsx ์˜ Pretendard Variable ๋‹ค์ด๋‚˜๋ฏน ์„œ๋ธŒ์…‹ ๋งํฌ๋กœ ๋กœ๋“œํ•œ๋‹ค (๋ Œ๋”๋ฅผ ๋ง‰๋Š” @import ์ด์ค‘ ๋กœ๋“œ๋Š” ์ œ๊ฑฐ). - ์ƒ‰ ๋ณ€์ˆ˜๋Š” @d3ro/ui SSOT๊ฐ€ MuiCssBaseline๋กœ ์ฃผ์ž…ํ•˜๋Š” --d3-*๋ฅผ ๊ทธ๋Œ€๋กœ ์“ด๋‹ค - (๊ด€๋ฆฌ์ž๋Š” ๊ณ ์ • ๋‹คํฌ: ๊ฐ’ ๋ฏธ์ง€์ • ์‹œ ์•„๋ž˜ ํด๋ฐฑ). */ + ์ƒ‰์€ @d3ro/ui SSOT๊ฐ€ MuiCssBaseline๋กœ ์ฃผ์ž…ํ•˜๋Š” --d3-* ๋งŒ ์“ด๋‹ค (๋กœ์ปฌ hex ํด๋ฐฑ ์—†์Œ). */ * { box-sizing: border-box; } /* ์˜๋ฏธ์  ๊ฐ•์กฐ๋Š” ์„ธ๋ฏธ๋ณผ๋“œ(600)๊นŒ์ง€ โ€” ๋ณผ๋“œ(700+) ํƒ€์ดํฌ๊ทธ๋ž˜ํ”ผ ๊ธˆ์ง€ */ -strong, b { font-weight: 600; } +strong, b { font-weight: var(--d3-weight-strong); } body { margin: 0; padding: 0; - background-color: var(--d3-bg-app, #070b16); - color: var(--d3-text-primary, #eef2fb); + background-color: var(--d3-bg-app); + color: var(--d3-text-primary); font-family: 'Pretendard Variable', Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, 'Helvetica Neue', 'Segoe UI', 'Apple SD Gothic Neo', 'Noto Sans KR', sans-serif; -webkit-font-smoothing: antialiased; -moz-osx-font-smoothing: grayscale; overflow-x: hidden; - background-image: - radial-gradient(ellipse 60% 40% at 10% 0%, rgba(6, 182, 212, 0.08) 0%, transparent 60%), - radial-gradient(ellipse 50% 50% at 90% 10%, rgba(59, 130, 246, 0.09) 0%, transparent 60%), - radial-gradient(ellipse 40% 40% at 50% 90%, rgba(139, 92, 246, 0.06) 0%, transparent 50%); + background-image: + radial-gradient(ellipse 60% 40% at 10% 0%, color-mix(in srgb, var(--d3-tag-cyan) 8%, transparent) 0%, transparent 60%), + radial-gradient(ellipse 50% 50% at 90% 10%, color-mix(in srgb, var(--d3-accent-main) 9%, transparent) 0%, transparent 60%), + radial-gradient(ellipse 40% 40% at 50% 90%, color-mix(in srgb, var(--d3-tag-purple) 6%, transparent) 0%, transparent 50%); background-attachment: fixed; } @@ -34,7 +33,12 @@ body { left: 0; right: 0; height: 320px; - background: radial-gradient(50% 100% at 50% 0%, rgba(59, 130, 246, 0.12) 0%, rgba(6, 182, 212, 0.04) 40%, transparent 100%); + background: radial-gradient( + 50% 100% at 50% 0%, + color-mix(in srgb, var(--d3-accent-main) 12%, transparent) 0%, + color-mix(in srgb, var(--d3-tag-cyan) 4%, transparent) 40%, + transparent 100% + ); pointer-events: none; z-index: 0; } @@ -42,8 +46,8 @@ body { /* High-End Subtle Grid Pattern */ .bg-grid { background-image: - linear-gradient(to right, rgba(148, 180, 255, 0.03) 1px, transparent 1px), - linear-gradient(to bottom, rgba(148, 180, 255, 0.03) 1px, transparent 1px); + linear-gradient(to right, var(--d3-glass-hairline) 1px, transparent 1px), + linear-gradient(to bottom, var(--d3-glass-hairline) 1px, transparent 1px); background-size: 32px 32px; } @@ -57,25 +61,24 @@ body { position: absolute; inset: 0; border-radius: inherit; - background: radial-gradient(ellipse 70% 55% at 18% -8%, rgba(59, 130, 246, 0.12) 0%, transparent 55%), - linear-gradient(180deg, rgba(148, 180, 255, 0.05) 0%, rgba(148, 180, 255, 0) 40%); + background: var(--d3-glass-sheen); pointer-events: none; } /* Glow effects */ -.glow-white { text-shadow: 0 0 15px rgba(255, 255, 255, 0.4); } -.glow-green { text-shadow: 0 0 15px rgba(16, 185, 129, 0.5); } -.glow-orange { text-shadow: 0 0 15px rgba(245, 158, 11, 0.5); } -.glow-red { text-shadow: 0 0 15px rgba(239, 68, 68, 0.5); } -.glow-blue { text-shadow: 0 0 15px rgba(59, 130, 246, 0.5); } -.glow-purple { text-shadow: 0 0 15px rgba(139, 92, 246, 0.5); } -.glow-cyan { text-shadow: 0 0 15px rgba(6, 182, 212, 0.5); } +.glow-white { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-text-primary) 40%, transparent); } +.glow-green { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-status-success) 50%, transparent); } +.glow-orange { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-status-warning) 50%, transparent); } +.glow-red { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-status-danger) 50%, transparent); } +.glow-blue { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-accent-main) 50%, transparent); } +.glow-purple { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-tag-purple) 50%, transparent); } +.glow-cyan { text-shadow: 0 0 15px color-mix(in srgb, var(--d3-tag-cyan) 50%, transparent); } /* Custom Sleek Scrollbar */ ::-webkit-scrollbar { width: 6px; height: 6px; } -::-webkit-scrollbar-track { background: rgba(7, 11, 22, 0.4); } -::-webkit-scrollbar-thumb { background: rgba(148, 180, 255, 0.15); border-radius: 999px; } -::-webkit-scrollbar-thumb:hover { background: rgba(148, 180, 255, 0.3); } +::-webkit-scrollbar-track { background: var(--d3-bg-inset-soft); } +::-webkit-scrollbar-thumb { background: var(--d3-glass-hairline); border-radius: 999px; } +::-webkit-scrollbar-thumb:hover { background: var(--d3-glass-hairlineStrong); } /* Pulse animation for live status */ @keyframes pulse-ring { @@ -91,13 +94,12 @@ body { position: absolute; inset: 0; border-radius: 50%; - background: #10b981; - animation: pulse-ring 2s cubic-bezier(0.24, 0, 0.38, 1) infinite; + background: var(--d3-status-success); + animation: pulse-ring 2s var(--d3-ease-out) infinite; } /* Selection */ ::selection { - background: rgba(59, 130, 246, 0.35); - color: #ffffff; + background: color-mix(in srgb, var(--d3-accent-main) 35%, transparent); + color: var(--d3-accent-ink); } - diff --git a/apps/admin/src/app/login/page.tsx b/apps/admin/src/app/login/page.tsx index b6621d9..5ccfa90 100644 --- a/apps/admin/src/app/login/page.tsx +++ b/apps/admin/src/app/login/page.tsx @@ -94,8 +94,8 @@ function LoginForm(): React.ReactElement { alignItems: 'center', justifyContent: 'center', minHeight: '100vh', - bgcolor: '#070b16', - backgroundImage: 'radial-gradient(ellipse 60% 50% at 50% 40%, rgba(59, 130, 246, 0.15) 0%, transparent 80%)', + bgcolor: 'var(--d3-bg-crtGlass)', + backgroundImage: 'radial-gradient(ellipse 60% 50% at 50% 40%, var(--d3-accent-glow) 0%, transparent 80%)', p: 2, position: 'relative', overflow: 'hidden', @@ -110,7 +110,7 @@ function LoginForm(): React.ReactElement { sx={{ width: '100%', maxWidth: 440, - boxShadow: '0 25px 60px rgba(0, 0, 0, 0.8), 0 0 40px rgba(59, 130, 246, 0.15)', + boxShadow: '0 25px 60px var(--d3-scrim), 0 0 40px var(--d3-accent-glow)', }} > {/* Brand Header */} @@ -120,15 +120,15 @@ function LoginForm(): React.ReactElement { width: 52, height: 52, borderRadius: '16px', - background: 'linear-gradient(135deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)', + background: 'linear-gradient(135deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 50%, var(--d3-tag-purple) 100%)', display: 'inline-flex', alignItems: 'center', justifyContent: 'center', - boxShadow: '0 0 25px rgba(59, 130, 246, 0.5)', + boxShadow: '0 0 25px var(--d3-accent-glow)', mb: 2, }} > - + @@ -290,7 +290,7 @@ function LoginForm(): React.ReactElement { export default function AdminLoginPage(): React.ReactElement { return ( - }> + }> ) diff --git a/apps/admin/src/app/unauthorized/page.tsx b/apps/admin/src/app/unauthorized/page.tsx index 64eb25d..6da3dbe 100644 --- a/apps/admin/src/app/unauthorized/page.tsx +++ b/apps/admin/src/app/unauthorized/page.tsx @@ -14,8 +14,8 @@ export default function UnauthorizedPage(): React.ReactElement { alignItems: 'center', justifyContent: 'center', minHeight: '100vh', - bgcolor: '#070b16', - backgroundImage: 'radial-gradient(ellipse 60% 50% at 50% 40%, rgba(239, 68, 68, 0.15) 0%, transparent 80%)', + bgcolor: 'var(--d3-bg-crtGlass)', + backgroundImage: 'radial-gradient(ellipse 60% 50% at 50% 40%, var(--d3-status-danger) 0%, transparent 80%)', p: 2, }} > @@ -26,7 +26,7 @@ export default function UnauthorizedPage(): React.ReactElement { width: '100%', maxWidth: 440, textAlign: 'center', - boxShadow: '0 25px 60px rgba(0, 0, 0, 0.8), 0 0 40px rgba(239, 68, 68, 0.2)', + boxShadow: '0 25px 60px var(--d3-scrim), 0 0 40px var(--d3-status-danger)', }} > @@ -66,7 +66,7 @@ export default function UnauthorizedPage(): React.ReactElement { sx={{ borderColor: C.borderHl, color: C.bright, - bgcolor: 'rgba(17, 26, 48, 0.5)', + bgcolor: 'var(--d3-bg-card-soft)', borderRadius: '10px', fontFamily: FONT_SANS, fontSize: '13px', @@ -75,7 +75,7 @@ export default function UnauthorizedPage(): React.ReactElement { py: 1.1, '&:hover': { borderColor: C.accentLight, - bgcolor: 'rgba(26, 38, 68, 0.8)', + bgcolor: 'var(--d3-bg-raised-soft)', }, }} > diff --git a/apps/admin/src/components/admin-sidebar.tsx b/apps/admin/src/components/admin-sidebar.tsx index 3a9ccf9..c21a3b0 100644 --- a/apps/admin/src/components/admin-sidebar.tsx +++ b/apps/admin/src/components/admin-sidebar.tsx @@ -168,14 +168,14 @@ export function AdminSidebar({ identity }: { height: '100%', display: 'flex', flexDirection: 'column', - bgcolor: 'rgba(11, 16, 31, 0.82)', + bgcolor: 'var(--d3-bg-card-soft)', backdropFilter: 'blur(28px)', border: `1px solid ${C.border}`, borderRadius: '22px', flexShrink: 0, position: 'relative', overflow: 'hidden', - boxShadow: '0 24px 60px rgba(3, 7, 18, 0.7), inset 0 1px 0 rgba(148, 180, 255, 0.1)', + boxShadow: '0 24px 60px var(--d3-scrim), inset 0 1px 0 var(--d3-glass-hairlineStrong)', }} > {/* Top Ambient Sheen */} @@ -186,7 +186,7 @@ export function AdminSidebar({ identity }: { left: 0, right: 0, height: 120, - background: 'radial-gradient(ellipse 80% 60% at 50% -10%, rgba(59, 130, 246, 0.18) 0%, transparent 80%)', + background: 'radial-gradient(ellipse 80% 60% at 50% -10%, var(--d3-accent-glow) 0%, transparent 80%)', pointerEvents: 'none', }} /> @@ -210,11 +210,11 @@ export function AdminSidebar({ identity }: { width: 34, height: 34, borderRadius: '10px', - background: 'linear-gradient(135deg, #06b6d4 0%, #3b82f6 50%, #8b5cf6 100%)', + background: 'linear-gradient(135deg, var(--d3-tag-cyan) 0%, var(--d3-accent-main) 50%, var(--d3-tag-purple) 100%)', display: 'flex', alignItems: 'center', justifyContent: 'center', - boxShadow: '0 0 20px rgba(59, 130, 246, 0.45)', + boxShadow: '0 0 20px var(--d3-accent-glow)', }} > @@ -260,8 +260,8 @@ export function AdminSidebar({ identity }: { px: 1, py: 0.35, borderRadius: '999px', - bgcolor: 'rgba(16, 185, 129, 0.12)', - border: '1px solid rgba(16, 185, 129, 0.25)', + bgcolor: 'var(--d3-status-success)', + border: '1px solid var(--d3-status-success)', }} > - + SESSION @@ -328,14 +328,14 @@ export function AdminSidebar({ identity }: { borderRadius: '12px', cursor: 'pointer', position: 'relative', - border: `1px solid ${active ? 'rgba(59, 130, 246, 0.35)' : 'transparent'}`, - bgcolor: active ? 'rgba(59, 130, 246, 0.14)' : 'transparent', + border: `1px solid ${active ? 'var(--d3-accent-glow)' : 'transparent'}`, + bgcolor: active ? 'var(--d3-accent-glow)' : 'transparent', color: active ? C.bright : C.text, - boxShadow: active ? '0 0 20px rgba(59, 130, 246, 0.15), inset 0 1px 0 rgba(255, 255, 255, 0.1)' : 'none', + boxShadow: active ? '0 0 20px var(--d3-accent-glow), inset 0 1px 0 var(--d3-overlay-strong)' : 'none', transition: 'all 0.18s cubic-bezier(0.16, 1, 0.3, 1)', '&:hover': { - bgcolor: active ? 'rgba(59, 130, 246, 0.2)' : 'rgba(26, 38, 68, 0.5)', - borderColor: active ? 'rgba(96, 165, 250, 0.5)' : C.border, + bgcolor: active ? 'var(--d3-accent-glow)' : 'var(--d3-bg-raised-soft)', + borderColor: active ? 'var(--d3-accent-light)' : C.border, color: C.bright, transform: 'translateX(3px)', }, @@ -379,7 +379,7 @@ export function AdminSidebar({ identity }: { {identity.email.slice(0, 1).toUpperCase()} @@ -442,7 +442,7 @@ export function AdminSidebar({ identity }: { transition: 'all 0.15s ease', '&:hover': { color: C.red400, - bgcolor: 'rgba(239, 68, 68, 0.12)', + bgcolor: 'var(--d3-status-danger)', }, }} > diff --git a/apps/admin/src/components/license-issuer-button.tsx b/apps/admin/src/components/license-issuer-button.tsx index ffdea27..a39a3f0 100644 --- a/apps/admin/src/components/license-issuer-button.tsx +++ b/apps/admin/src/components/license-issuer-button.tsx @@ -20,7 +20,7 @@ export function LicenseIssuerButton(): React.ReactElement { sx={{ ...primaryButtonSx, background: `linear-gradient(135deg, ${C.purple} 0%, ${C.accent} 100%)`, - boxShadow: '0 0 12px rgba(139, 92, 246, 0.4)' + boxShadow: '0 0 12px var(--d3-tag-purple)' }} > โšก Issue Ed25519 License Key diff --git a/apps/admin/src/components/license-issuer-dialog.tsx b/apps/admin/src/components/license-issuer-dialog.tsx index 765f974..a891693 100644 --- a/apps/admin/src/components/license-issuer-dialog.tsx +++ b/apps/admin/src/components/license-issuer-dialog.tsx @@ -117,7 +117,7 @@ export function LicenseIssuerDialog({ open, onClose }: LicenseIssuerDialogProps) bgcolor: C.app, border: `1px solid ${C.borderHl}`, borderRadius: '16px', - boxShadow: '0 20px 40px rgba(0, 0, 0, 0.8)', + boxShadow: '0 20px 40px var(--d3-scrim)', p: 1 } }} @@ -208,7 +208,7 @@ export function LicenseIssuerDialog({ open, onClose }: LicenseIssuerDialogProps) {generatedKey && ( - + {!auditRecorded && ( ๋ผ์ด์„ ์Šค๋Š” ๋ฐœ๊ธ‰๋˜์—ˆ์œผ๋‚˜ ๊ฐ์‚ฌ ๋กœ๊ทธ ๊ธฐ๋ก์— ์‹คํŒจํ–ˆ์Šต๋‹ˆ๋‹ค. ๋ฐฑ์—”๋“œ ์—ฐ๊ฒฐ์„ ํ™•์ธํ•˜์„ธ์š”. @@ -223,7 +223,7 @@ export function LicenseIssuerDialog({ open, onClose }: LicenseIssuerDialogProps) fontSize: '11px', color: C.bright, p: 1.5, - bgcolor: 'rgba(255, 255, 255, 0.05)', + bgcolor: 'var(--d3-overlay-strong)', borderRadius: '6px', wordBreak: 'break-all', userSelect: 'all',