diff --git a/frontend/src/lib/types.ts b/frontend/src/lib/types.ts index 0d44331..f64bd77 100644 --- a/frontend/src/lib/types.ts +++ b/frontend/src/lib/types.ts @@ -1,4 +1,4 @@ -export type Theme = 'light' | 'dark' | 'glass' | 'neon' | 'impeccable' | 'impeccable-dark'; +export type Theme = 'light' | 'dark' | 'glass' | 'neon' | 'impeccable' | 'impeccable-dark' | 'cosmic'; /** Lifecycle of the NIP-46 remote signer. */ export type SignerPhase = 'stopped' | 'connecting' | 'connected'; diff --git a/frontend/src/screens/SettingsScreen.tsx b/frontend/src/screens/SettingsScreen.tsx index c8b402d..db2a0d8 100644 --- a/frontend/src/screens/SettingsScreen.tsx +++ b/frontend/src/screens/SettingsScreen.tsx @@ -108,6 +108,7 @@ export function SettingsScreen() { +
- “Light” and “Dark” follow your manual selection. “Aurora”, “Neon”, “Impeccable” and - “Impeccable Dark” are aesthetic themes with distinctive color palettes. + "Light" and "Dark" follow your manual selection. "Aurora", "Neon", "Impeccable", + "Impeccable Dark", and "Cosmic" are aesthetic themes with distinctive color palettes.
diff --git a/frontend/src/styles.css b/frontend/src/styles.css index fc7d2fe..6037e1b 100644 --- a/frontend/src/styles.css +++ b/frontend/src/styles.css @@ -348,6 +348,230 @@ html[data-theme='impeccable-dark'] .sidebar { border-right-color: var(--border); } +/* "Cosmic" — Stardust color scheme from https://github.com/kaymade/cosmic + Deep space backgrounds with warm golden accents. + Fonts: Source Serif 4 for body, Cormorant Garamond for headings. + Sidebar: Deep (darker background). Workspace: Deep Space (dramatic vignette). */ + +@import url('https://fonts.googleapis.com/css2?family=Cormorant+Garamond:ital,wght@0,400;0,500;0,600;0,700;1,400;1,500;1,600;1,700&family=Source+Serif+4:ital,opsz,wght@0,8..60,400;0,8..60,500;0,8..60,600;0,8..60,700;1,8..60,400;1,8..60,500;1,8..60,600;1,8..60,700&display=swap'); + +:root[data-theme='cosmic'] { + /* Stardust dark mode colors */ + --bg: #171109; + --surface: #0d0a06; + --surface-2: #21180c; + --surface-hover: #140f08; + --border: #2d2418; + --border-strong: #3d3220; + --text: #fff5dc; + --text-muted: #d5bd8d; + --primary: #efbd62; + --primary-hover: #ffdb91; + --primary-soft: rgba(239, 189, 98, 0.15); + --on-primary: #171109; + --danger: #f08e7d; + --danger-soft: rgba(240, 142, 125, 0.15); + --warning: #f08e7d; + --warning-soft: rgba(240, 142, 125, 0.15); + --success: #74d7cb; + --success-soft: rgba(116, 215, 203, 0.15); + --info: #74d7cb; + --info-soft: rgba(116, 215, 203, 0.15); + --focus: #efbd62; + --shadow: 0 2px 8px rgba(0, 0, 0, 0.4); + --shadow-modal: 0 12px 40px rgba(0, 0, 0, 0.6); + --radius: 8px; + --radius-sm: 4px; + color-scheme: dark; +} + +/* Cosmic typography - Cormorant Garamond for headings, Source Serif 4 for body */ +html[data-theme='cosmic'] body { + font-family: 'Source Serif 4', 'Georgia', serif; + font-size: 15px; + line-height: 1.6; +} + +html[data-theme='cosmic'] h1, +html[data-theme='cosmic'] h2, +html[data-theme='cosmic'] h3, +html[data-theme='cosmic'] h4 { + font-family: 'Cormorant Garamond', 'Georgia', serif; + font-weight: 600; + letter-spacing: 0.02em; +} + +html[data-theme='cosmic'] h1 { + font-size: 28px; + color: #efbd62; +} + +html[data-theme='cosmic'] h2 { + font-size: 20px; + color: #74d7cb; +} + +html[data-theme='cosmic'] h3 { + font-size: 18px; + color: #f08e7d; +} + +/* Cosmic sidebar - Deep background (darker) */ +html[data-theme='cosmic'] .sidebar { + background: #0d0a06; + border-right-color: var(--border); +} + +/* Cosmic workspace - Deep Space background with vignette effect */ +html[data-theme='cosmic'] .app-shell { + background: + radial-gradient(circle at 8% 13%, rgba(255, 245, 220, 0.72) 0 1px, transparent 1.7px), + radial-gradient(circle at 27% 7%, rgba(116, 215, 203, 0.82) 0 1px, transparent 1.8px), + radial-gradient(circle at 73% 19%, rgba(255, 245, 220, 0.68) 0 1.2px, transparent 1.9px), + radial-gradient(circle at 91% 42%, rgba(240, 142, 125, 0.78) 0 1px, transparent 1.8px), + radial-gradient(circle at 61% 78%, rgba(255, 245, 220, 0.64) 0 1px, transparent 1.7px), + radial-gradient(circle at 18% 84%, rgba(239, 189, 98, 0.82) 0 1.2px, transparent 2px), + radial-gradient(circle at 12% 4%, rgba(239, 189, 98, 0.52), transparent 58rem), + radial-gradient(circle at 88% 12%, rgba(116, 215, 203, 0.42), transparent 46rem), + radial-gradient(circle at 52% 100%, rgba(240, 142, 125, 0.36), transparent 50rem), + radial-gradient(ellipse at center, transparent 34%, rgba(13, 10, 6, 0.48) 100%), + linear-gradient(145deg, #171109, #0d0a06); +} + +html[data-theme='cosmic'] .main { + background: transparent; +} + +/* Cosmic cards and surfaces */ +html[data-theme='cosmic'] .card, +html[data-theme='cosmic'] .profile-card, +html[data-theme='cosmic'] .relay-row { + background: var(--surface); + border-color: var(--border); + box-shadow: var(--shadow); +} + +html[data-theme='cosmic'] .card:hover, +html[data-theme='cosmic'] .profile-card:hover { + border-color: var(--primary); +} + +/* Cosmic buttons */ +html[data-theme='cosmic'] .btn-primary { + background: var(--primary); + color: var(--on-primary); +} + +html[data-theme='cosmic'] .btn-primary:hover:not(:disabled) { + background: var(--primary-hover); +} + +html[data-theme='cosmic'] .btn-secondary { + background: var(--surface); + border-color: var(--border-strong); + color: var(--text); +} + +html[data-theme='cosmic'] .btn-ghost { + color: var(--text-muted); +} + +html[data-theme='cosmic'] .btn-ghost:hover { + background: var(--surface-2); + color: var(--text); +} + +/* Cosmic navigation */ +html[data-theme='cosmic'] .nav-item { + color: var(--text-muted); +} + +html[data-theme='cosmic'] .nav-item:hover { + background: var(--surface-2); + color: var(--text); +} + +html[data-theme='cosmic'] .nav-item.is-active { + background: var(--primary-soft); + color: var(--primary); +} + +/* Cosmic inputs */ +html[data-theme='cosmic'] input[type='text'], +html[data-theme='cosmic'] input[type='search'], +html[data-theme='cosmic'] input[type='password'], +html[data-theme='cosmic'] select, +html[data-theme='cosmic'] textarea { + background: var(--surface); + border-color: var(--border-strong); + color: var(--text); +} + +html[data-theme='cosmic'] input:focus, +html[data-theme='cosmic'] select:focus, +html[data-theme='cosmic'] textarea:focus { + border-color: var(--focus); + box-shadow: 0 0 0 2px var(--primary-soft); +} + +/* Cosmic code blocks */ +html[data-theme='cosmic'] code, +html[data-theme='cosmic'] .mono { + background: var(--surface-2); + border-color: var(--border); + color: var(--primary); +} + +/* Cosmic badges */ +html[data-theme='cosmic'] .badge { + border-radius: 4px; + font-size: 11px; + font-weight: 600; +} + +html[data-theme='cosmic'] .badge-neutral { + background: var(--surface-2); + color: var(--text-muted); + border-color: var(--border); +} + +html[data-theme='cosmic'] .badge-success { + background: var(--success-soft); + color: var(--success); +} + +html[data-theme='cosmic'] .badge-warning { + background: var(--warning-soft); + color: var(--warning); +} + +html[data-theme='cosmic'] .badge-danger { + background: var(--danger-soft); + color: var(--danger); +} + +html[data-theme='cosmic'] .badge-info { + background: var(--info-soft); + color: var(--info); +} + +/* Cosmic modal */ +html[data-theme='cosmic'] .modal { + background: var(--surface); + border-color: var(--border); + box-shadow: var(--shadow-modal); +} + +html[data-theme='cosmic'] .modal-backdrop { + background: rgba(13, 10, 6, 0.8); +} + +/* Cosmic empty state */ +html[data-theme='cosmic'] .empty-state { + background: var(--surface); + border-color: var(--border); +} + * { box-sizing: border-box; } @@ -1944,3 +2168,97 @@ select { align-items: flex-start; gap: 12px; } + +/* ------------------------------------------------------------------------- + Motion system + Purposeful motion for feedback, state, and continuity. + ------------------------------------------------------------------------- */ + +@keyframes modal-enter { + from { + opacity: 0; + transform: scale(0.96) translateY(8px); + } + to { + opacity: 1; + transform: scale(1) translateY(0); + } +} + +@keyframes modal-backdrop-enter { + from { + opacity: 0; + } + to { + opacity: 1; + } +} + +@keyframes alert-enter { + from { + opacity: 0; + transform: translateY(-6px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +@keyframes undo-enter { + from { + opacity: 0; + transform: translateY(10px); + } + to { + opacity: 1; + transform: translateY(0); + } +} + +.modal-backdrop { + animation: modal-backdrop-enter 200ms cubic-bezier(0.16, 1, 0.3, 1); +} + +.modal { + animation: modal-enter 220ms cubic-bezier(0.16, 1, 0.3, 1); +} + +.alert { + animation: alert-enter 200ms cubic-bezier(0.16, 1, 0.3, 1); +} + +.undo-bar { + animation: undo-enter 250ms cubic-bezier(0.16, 1, 0.3, 1); +} + +.btn:active:not(:disabled) { + transform: scale(0.97); + transition: transform 80ms ease; +} + +.profile-card:active:not(.is-active) { + transform: scale(0.985); + transition: transform 100ms ease; +} + +.nav-item:active { + transform: scale(0.98); + transition: transform 80ms ease; +} + +@media (prefers-reduced-motion: reduce) { + .modal-backdrop, + .modal, + .alert, + .undo-bar { + animation: none; + } + + .btn:active:not(:disabled), + .profile-card:active:not(.is-active), + .nav-item:active { + transform: none; + transition: none; + } +} diff --git a/src/settings.rs b/src/settings.rs index c475df6..d4eb9d3 100644 --- a/src/settings.rs +++ b/src/settings.rs @@ -27,6 +27,7 @@ pub enum Theme { Impeccable, #[serde(rename = "impeccable-dark")] ImpeccableDark, + Cosmic, } impl Theme { @@ -39,6 +40,7 @@ impl Theme { "neon" => Some(Self::Neon), "impeccable" => Some(Self::Impeccable), "impeccable-dark" => Some(Self::ImpeccableDark), + "cosmic" => Some(Self::Cosmic), _ => None, } }