From 3938adf10c658f77781d5194ed73e792596d0da8 Mon Sep 17 00:00:00 2001 From: sepehr Date: Sat, 16 May 2026 12:54:29 +0200 Subject: [PATCH] feat: rewrite all dashboard views with editorial design Translate page: editorial dropzone (rounded-[40px]), config panel, progress stepper, download button, Momento promo banner. Profile page: pill tabs, dark subscription card, usage bars, language grid. Context page: preset grid (rounded-[32px]), instruction/glossary textareas. API keys page: editorial-card with production key display. Glossaries page: editorial-card grid with hover lift. Pricing page: 5-column grid, colored headers, plan badges. All pages use editorial design system: accent-pill, editorial-card, premium-button, brand colors, dark mode support. Co-Authored-By: Claude Opus 4.7 --- frontend/src/app/dashboard/api-keys/page.tsx | 139 ++-- frontend/src/app/dashboard/context/page.tsx | 215 ++--- .../src/app/dashboard/glossaries/page.tsx | 160 ++-- frontend/src/app/dashboard/profile/page.tsx | 672 +++++++++------- frontend/src/app/dashboard/translate/page.tsx | 746 ++++++++++-------- frontend/src/app/pricing/page.tsx | 353 +++++---- frontend/src/lib/i18n.tsx | 214 +++++ 7 files changed, 1506 insertions(+), 993 deletions(-) diff --git a/frontend/src/app/dashboard/api-keys/page.tsx b/frontend/src/app/dashboard/api-keys/page.tsx index 2907b73..fc28f84 100644 --- a/frontend/src/app/dashboard/api-keys/page.tsx +++ b/frontend/src/app/dashboard/api-keys/page.tsx @@ -1,11 +1,7 @@ 'use client'; import { useState, useEffect } from 'react'; -import { Zap, Plus, AlertCircle } from 'lucide-react'; -import { Card, CardContent, CardDescription, CardHeader, CardTitle } from '@/components/ui/card'; -import { Button } from '@/components/ui/button'; -import { Separator } from '@/components/ui/separator'; -import { Alert, AlertDescription } from '@/components/ui/alert'; +import { Zap, Plus, AlertCircle, Clock } from 'lucide-react'; import { useUser } from '@/app/dashboard/useUser'; import { useApiKeys } from './useApiKeys'; import { MAX_API_KEYS, type ApiKey } from './types'; @@ -16,6 +12,7 @@ import { RevokeKeyDialog } from './RevokeKeyDialog'; import { WebhookSnippet } from './WebhookSnippet'; import { useToast } from '@/components/ui/toast'; import { useI18n } from '@/lib/i18n'; +import { cn } from '@/lib/utils'; export default function ApiKeysPage() { const { t } = useI18n(); @@ -122,8 +119,8 @@ export default function ApiKeysPage() { return (
-
-

{t('apiKeys.loading')}

+
+

{t('apiKeys.loading')}

); @@ -134,70 +131,94 @@ export default function ApiKeysPage() { } return ( -
-
-

{t('apiKeys.title')}

-

- {t('apiKeys.subtitle')} -

+
+ {/* ── Editorial Header ───────────────────────────────────── */} +
+ {t('apiKeys.sectionTitle')} +

+ {t('apiKeys.title')} +

+

{t('apiKeys.subtitle')}

+ {/* API Error */} {apiError && ( - - - {apiError} - +
+ + {apiError} +
)} - - -
-
- -
-
- {t('apiKeys.sectionTitle')} - {t('apiKeys.sectionDesc')} -
+ {/* ── Main Card ──────────────────────────────────────────── */} +
+ {/* Section header */} +
+
+
- - - -
-
-

- {t('apiKeys.keysUsed', { total, max: MAX_API_KEYS })} -

-

- {maxKeysReached ? ( - {t('apiKeys.maxReached')} - ) : ( - t(MAX_API_KEYS - total !== 1 ? 'apiKeys.canGeneratePlural' : 'apiKeys.canGenerate', { count: MAX_API_KEYS - total }) - )} -

-
- +
+

+ {t('apiKeys.sectionTitle')} +

+

+ {t('apiKeys.sectionDesc')} +

+
- -
- + {/* Key count + generate button */} +
+
+

+ {t('apiKeys.keysUsed', { total, max: MAX_API_KEYS })} +

+

+ {maxKeysReached ? ( + {t('apiKeys.maxReached')} + ) : ( + t(MAX_API_KEYS - total !== 1 ? 'apiKeys.canGeneratePlural' : 'apiKeys.canGenerate', { count: MAX_API_KEYS - total }) + )} +

+
+ +
- + {/* Production key display area */} +
+
+

+ {t('apiKeys.sectionTitle')} +

+

+ {keys.length > 0 ? `${keys[0].key_prefix}************************************` : 'No keys generated'} +

+
+
+ +
+
+ {/* Key table */} + +
+ + {/* Webhook snippet */} + {/* Dialogs */} -
- +
+
-

{t('context.proTitle')}

-

- {t('context.proDesc')} -

+

{t('context.proTitle')}

+

{t('context.proDesc')}

- + + +
); } return ( -
-
-

{t('context.title')}

-

- {t('context.subtitle')} -

+
+ {/* ── Editorial Header ───────────────────────────────────── */} +
+ {t('context.presets.title')} +

+ {t('context.title')} +

+

{t('context.subtitle')}

- {/* Presets */} - - - - {t('context.presets.title')} - - {t('context.presets.desc')} - - -
- {PRESETS.map(p => ( - - ))} +
+ {/* ── Professional Presets ──────────────────────────────── */} +
+
+ +

+ {t('context.presets.title')} +

- - +

{t('context.presets.desc')}

- {/* System Prompt */} - - - - {t('context.instructions.title')} - - {t('context.instructions.desc')} - - -