diff --git a/frontend/package-lock.json b/frontend/package-lock.json index bf99bb5..babed5f 100644 --- a/frontend/package-lock.json +++ b/frontend/package-lock.json @@ -23,6 +23,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.22.0", + "rosewood-ui": "github:voidreamer/rosewood-ui", "zustand": "^4.5.0" }, "devDependencies": { @@ -10960,6 +10961,15 @@ "fsevents": "~2.3.2" } }, + "node_modules/rosewood-ui": { + "version": "0.1.0", + "resolved": "git+ssh://git@github.com/voidreamer/rosewood-ui.git#1a30a21369a13400aac88f093764940e0a85dc85", + "license": "MIT", + "workspaces": [ + "packages/*", + "apps/*" + ] + }, "node_modules/run-parallel": { "version": "1.2.0", "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", diff --git a/frontend/package.json b/frontend/package.json index 2f1e651..9d6d97a 100644 --- a/frontend/package.json +++ b/frontend/package.json @@ -31,6 +31,7 @@ "react": "^18.2.0", "react-dom": "^18.2.0", "react-router-dom": "^6.22.0", + "rosewood-ui": "github:voidreamer/rosewood-ui", "zustand": "^4.5.0" }, "devDependencies": { diff --git a/frontend/src/App.tsx b/frontend/src/App.tsx index 31e6672..4f73a97 100644 --- a/frontend/src/App.tsx +++ b/frontend/src/App.tsx @@ -13,7 +13,7 @@ import HouseholdPage from './pages/HouseholdPage'; import ListPage from './pages/ListPage'; import InvitePage from './pages/InvitePage'; import SettingsPage from './pages/SettingsPage'; -import ThemeShowcase from './pages/ThemeShowcase'; +// import ThemeShowcase from './pages/ThemeShowcase'; import InfraLearn from './pages/InfraLearn'; // Components @@ -82,7 +82,7 @@ function App() { } /> } /> } /> - } /> + {/* } /> */} } /> {/* Protected routes */} diff --git a/frontend/src/components/AttachmentList.module.css b/frontend/src/components/AttachmentList.module.css index 58b9c60..9209ec0 100644 --- a/frontend/src/components/AttachmentList.module.css +++ b/frontend/src/components/AttachmentList.module.css @@ -31,15 +31,6 @@ border-color: var(--color-primary); } -[data-theme="brutalist"] .card { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .card:hover { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .preview { display: flex; align-items: center; @@ -139,15 +130,6 @@ background: color-mix(in srgb, var(--color-error) 80%, black); } -[data-theme="brutalist"] .actionButton { - box-shadow: 2px 2px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .actionButton:hover:not(:disabled) { - transform: translate(1px, 1px); - box-shadow: 1px 1px 0 var(--color-shadow); -} - /* Empty state */ .empty { display: flex; diff --git a/frontend/src/components/AttachmentUploader.module.css b/frontend/src/components/AttachmentUploader.module.css index 7d897c7..2f29598 100644 --- a/frontend/src/components/AttachmentUploader.module.css +++ b/frontend/src/components/AttachmentUploader.module.css @@ -135,20 +135,6 @@ color: var(--color-error); } -[data-theme="brutalist"] .dropzone { - border-style: solid; - border-width: 3px; - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .dropzone:hover:not(.disabled) { - transform: translate(1px, 1px); - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .uploadItem { - box-shadow: 2px 2px 0 var(--color-shadow); -} @media (max-width: 768px) { .dropzone { diff --git a/frontend/src/components/ChecklistView.module.css b/frontend/src/components/ChecklistView.module.css index 709b342..bc1f3b5 100644 --- a/frontend/src/components/ChecklistView.module.css +++ b/frontend/src/components/ChecklistView.module.css @@ -65,11 +65,6 @@ border-radius: var(--border-radius); outline: none; } - -[data-theme="brutalist"] .addInput { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .addInput:focus { border-color: var(--color-primary); } @@ -92,15 +87,6 @@ transition: all var(--transition-fast); } -[data-theme="brutalist"] .addButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .addButton:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .addButton:hover { opacity: 0.9; } @@ -169,14 +155,6 @@ background: var(--color-surface-hover); } -[data-theme="brutalist"] .item:global(.dragOver) { - box-shadow: 0 0 0 2px var(--color-primary); -} - -[data-theme="brutalist"] .item { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .item:hover { background: var(--color-surface-hover); } @@ -354,14 +332,23 @@ border: var(--border-width) dashed var(--color-border); border-radius: var(--border-radius); } - -[data-theme="brutalist"] .emptyState { - box-shadow: 4px 4px 0 var(--color-shadow); -} - /* Responsive */ @media (max-width: 768px) { .itemActions { opacity: 1; } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .item { + background: rgba(32, 28, 26, 0.5); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-color: rgba(232, 168, 192, 0.06); + border-radius: 14px; +} + +:global([data-theme="rosewood"]) .item:hover { + background: rgba(53, 47, 43, 0.6); + border-color: rgba(232, 168, 192, 0.12); +} diff --git a/frontend/src/components/EncryptionSetup.module.css b/frontend/src/components/EncryptionSetup.module.css index 9d7f2e3..8abe8ee 100644 --- a/frontend/src/components/EncryptionSetup.module.css +++ b/frontend/src/components/EncryptionSetup.module.css @@ -324,3 +324,20 @@ transform: rotate(360deg); } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .container { + background: rgba(32, 28, 26, 0.92); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border: 1px solid rgba(232, 168, 192, 0.1); + border-radius: 24px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} + +:global([data-theme="rosewood"]) .setupButton { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + color: #1a1614; + border: none; + border-radius: 12px; +} diff --git a/frontend/src/components/KeyboardShortcutsModal.module.css b/frontend/src/components/KeyboardShortcutsModal.module.css index f89482b..4addd8b 100644 --- a/frontend/src/components/KeyboardShortcutsModal.module.css +++ b/frontend/src/components/KeyboardShortcutsModal.module.css @@ -34,13 +34,6 @@ transform: translateY(0); } } - -[data-theme="brutalist"] .modal, -[data-theme="sketchy"] .modal, -[data-theme="sketchyDark"] .modal { - box-shadow: 6px 6px 0 var(--color-shadow); -} - .header { display: flex; align-items: center; diff --git a/frontend/src/components/Layout.module.css b/frontend/src/components/Layout.module.css index 995ae6b..5ecf203 100644 --- a/frontend/src/components/Layout.module.css +++ b/frontend/src/components/Layout.module.css @@ -254,3 +254,62 @@ background: var(--bg-primary); overflow-y: auto; } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .sidebar, +:global([data-theme="rosewood-light"]) .sidebar { + background: rgba(32, 28, 26, 0.65); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border-right-color: rgba(232, 168, 192, 0.08); +} + +:global([data-theme="rosewood-light"]) .sidebar { + background: rgba(255, 255, 255, 0.72); + border-right-color: rgba(0, 0, 0, 0.06); +} + +:global([data-theme="rosewood"]) .mobileHeader, +:global([data-theme="rosewood-light"]) .mobileHeader { + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); +} + +:global([data-theme="rosewood"]) .mobileHeader { + background: rgba(26, 22, 20, 0.8); + border-bottom-color: rgba(232, 168, 192, 0.08); +} + +:global([data-theme="rosewood-light"]) .mobileHeader { + background: rgba(255, 255, 255, 0.8); + border-bottom-color: rgba(0, 0, 0, 0.06); +} + +:global([data-theme="rosewood"]) .sidebarLogo { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +:global([data-theme="rosewood-light"]) .sidebarLogo { + background: linear-gradient(135deg, #d4849c, #9878b8); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + +:global([data-theme="rosewood"]) .navItem:hover, +:global([data-theme="rosewood-light"]) .navItem:hover { + background: rgba(232, 168, 192, 0.08); +} + +:global([data-theme="rosewood"]) .navItemActive { + background: rgba(232, 168, 192, 0.12); + border-color: rgba(232, 168, 192, 0.2); +} + +:global([data-theme="rosewood-light"]) .navItemActive { + background: rgba(212, 132, 156, 0.08); + border-color: rgba(212, 132, 156, 0.15); +} diff --git a/frontend/src/components/Layout.tsx b/frontend/src/components/Layout.tsx index 3efaa63..184aa66 100644 --- a/frontend/src/components/Layout.tsx +++ b/frontend/src/components/Layout.tsx @@ -36,7 +36,7 @@ export default function Layout({ children }: LayoutProps) { } else { // Save current light theme and switch to dark setPreviousLightTheme(theme); - setTheme('dark'); + setTheme('rosewood'); } }; diff --git a/frontend/src/components/NoteEditor.module.css b/frontend/src/components/NoteEditor.module.css index 0b66c48..a1c58bb 100644 --- a/frontend/src/components/NoteEditor.module.css +++ b/frontend/src/components/NoteEditor.module.css @@ -43,20 +43,9 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .saveButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .saveButton:hover:not(:disabled) { opacity: 0.9; } - -[data-theme="brutalist"] .saveButton:hover:not(:disabled) { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .saveButton:disabled { opacity: 0.5; cursor: not-allowed; @@ -78,11 +67,6 @@ outline: none; transition: border-color var(--transition-fast); } - -[data-theme="brutalist"] .textarea { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .textarea:focus { border-color: var(--color-primary); } diff --git a/frontend/src/components/ShoppingListView.module.css b/frontend/src/components/ShoppingListView.module.css index 4945730..0259c7c 100644 --- a/frontend/src/components/ShoppingListView.module.css +++ b/frontend/src/components/ShoppingListView.module.css @@ -61,11 +61,6 @@ border: var(--border-width) solid var(--color-border); border-radius: var(--border-radius); } - -[data-theme="brutalist"] .addForm { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .addFormRow { display: flex; gap: var(--spacing-sm); @@ -190,11 +185,6 @@ transition: all var(--transition-fast); font-family: var(--font-body); } - -[data-theme="brutalist"] .submitButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .submitButton:hover:not(:disabled) { opacity: 0.9; } @@ -267,14 +257,6 @@ background: var(--color-surface-hover); } -[data-theme="brutalist"] .item:global(.dragOver) { - box-shadow: 0 0 0 2px var(--color-primary); -} - -[data-theme="brutalist"] .item { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .item:hover { background: var(--color-surface-hover); } @@ -504,11 +486,6 @@ border: var(--border-width) dashed var(--color-border); border-radius: var(--border-radius); } - -[data-theme="brutalist"] .emptyState { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .emptyState p { font-weight: 600; color: var(--color-text); @@ -537,3 +514,17 @@ flex-direction: column; } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .item { + background: rgba(32, 28, 26, 0.5); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-color: rgba(232, 168, 192, 0.06); + border-radius: 14px; +} + +:global([data-theme="rosewood"]) .item:hover { + background: rgba(53, 47, 43, 0.6); + border-color: rgba(232, 168, 192, 0.12); +} diff --git a/frontend/src/components/ThemeSwitcher.css b/frontend/src/components/ThemeSwitcher.css index e6f74d7..c73e887 100644 --- a/frontend/src/components/ThemeSwitcher.css +++ b/frontend/src/components/ThemeSwitcher.css @@ -22,15 +22,6 @@ background: var(--color-surface-hover); } -[data-theme="brutalist"] .theme-switcher__button { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .theme-switcher__button:hover { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .theme-switcher__icon { font-size: 1rem; } @@ -52,15 +43,6 @@ overflow: hidden; } -[data-theme="brutalist"] .theme-switcher__menu { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="paper"] .theme-switcher__menu, -[data-theme="mono"] .theme-switcher__menu { - box-shadow: 0 4px 12px var(--color-shadow); -} - .theme-switcher__header { padding: 0.75rem 1rem; font-size: 0.75rem; diff --git a/frontend/src/components/UnlockPrompt.module.css b/frontend/src/components/UnlockPrompt.module.css index 4cd2adc..e592c21 100644 --- a/frontend/src/components/UnlockPrompt.module.css +++ b/frontend/src/components/UnlockPrompt.module.css @@ -274,3 +274,45 @@ transform: rotate(360deg); } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .overlay { + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); +} + +:global([data-theme="rosewood"]) .modal { + background: rgba(32, 28, 26, 0.92); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border: 1px solid rgba(232, 168, 192, 0.1); + border-radius: 24px; + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} + +:global([data-theme="rosewood"]) .icon { + background: rgba(232, 168, 192, 0.1); + color: #e8a8c0; +} + +:global([data-theme="rosewood"]) .unlockButton { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + color: #1a1614; + border: none; + border-radius: 12px; +} + +:global([data-theme="rosewood"]) .unlockButton:hover { + box-shadow: 0 4px 20px rgba(232, 168, 192, 0.35); +} + +:global([data-theme="rosewood"]) .input { + background: rgba(26, 22, 20, 0.6); + border-color: rgba(232, 168, 192, 0.15); + border-radius: 12px; +} + +:global([data-theme="rosewood"]) .input:focus { + border-color: #e8a8c0; + box-shadow: 0 0 0 3px rgba(232, 168, 192, 0.15); +} diff --git a/frontend/src/components/ui/Button.module.css b/frontend/src/components/ui/Button.module.css index 2b8174c..a84bffc 100644 --- a/frontend/src/components/ui/Button.module.css +++ b/frontend/src/components/ui/Button.module.css @@ -42,31 +42,15 @@ color: var(--color-primary-text); border-color: var(--color-border); } - -[data-theme="brutalist"] .primary { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .primary:hover:not(:disabled) { opacity: 0.9; transform: translateY(-1px); } - -[data-theme="brutalist"] .primary:hover:not(:disabled) { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .secondary { background: var(--color-surface); color: var(--color-text); border-color: var(--color-border); } - -[data-theme="brutalist"] .secondary { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .secondary:hover:not(:disabled) { background: var(--color-surface-hover); border-color: var(--color-text-muted); @@ -88,11 +72,6 @@ color: var(--color-error); border-color: color-mix(in srgb, var(--color-error) 30%, transparent); } - -[data-theme="brutalist"] .danger { - box-shadow: 3px 3px 0 color-mix(in srgb, var(--color-error) 30%, transparent); -} - .danger:hover:not(:disabled) { background: color-mix(in srgb, var(--color-error) 20%, transparent); } diff --git a/frontend/src/components/ui/Modal.module.css b/frontend/src/components/ui/Modal.module.css index 5637888..fafe15d 100644 --- a/frontend/src/components/ui/Modal.module.css +++ b/frontend/src/components/ui/Modal.module.css @@ -20,11 +20,6 @@ overflow-y: auto; animation: slideUp var(--transition-normal) ease-out; } - -[data-theme="brutalist"] .modal { - box-shadow: 6px 6px 0 var(--color-shadow); -} - /* Size variants */ .sizeSm { max-width: 320px; diff --git a/frontend/src/index.css b/frontend/src/index.css index 010de9a..2052bab 100644 --- a/frontend/src/index.css +++ b/frontend/src/index.css @@ -1,3 +1,8 @@ +/* Rosewood UI — design tokens + glass utilities */ +@import 'rosewood-ui/src/css/variables.css'; +@import 'rosewood-ui/src/css/components/glass.css'; +@import 'rosewood-ui/src/css/components/animations.css'; + /* SimpleNotes - Global Styles Themeable design system */ @@ -116,27 +121,6 @@ body { min-height: 100vh; overflow-x: hidden; } - -/* Background Pattern - only for terminal theme */ -[data-theme="terminal"] body::before { - content: ''; - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background: - repeating-linear-gradient( - 0deg, - rgba(0, 255, 0, 0.03) 0px, - rgba(0, 255, 0, 0.03) 1px, - transparent 1px, - transparent 2px - ); - pointer-events: none; - z-index: -1; -} - #root { min-height: 100vh; display: flex; @@ -195,15 +179,6 @@ a:hover { border-color: var(--color-border); } -[data-theme="brutalist"] .btn-primary { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .btn-primary:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .btn-primary:hover { opacity: 0.9; } @@ -217,11 +192,6 @@ a:hover { color: var(--color-text); border: var(--border-width) solid var(--color-border); } - -[data-theme="brutalist"] .btn-secondary { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .btn-secondary:hover { background: var(--color-surface-hover); } @@ -263,15 +233,6 @@ a:hover { transition: all var(--transition-normal); } -[data-theme="brutalist"] .card { - box-shadow: 6px 6px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .card:hover { - transform: translate(-2px, -2px); - box-shadow: 8px 8px 0 var(--color-shadow); -} - .card:hover { border-color: var(--color-border); } @@ -306,14 +267,6 @@ a:hover { transition: all var(--transition-fast); } -[data-theme="brutalist"] .input { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .input:focus { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .input:focus { border-color: var(--color-primary); } @@ -387,11 +340,6 @@ textarea:focus-visible, border-radius: var(--border-radius); transition: all var(--transition-fast); } - -[data-theme="brutalist"] .list-item { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .list-item:hover { background: var(--color-surface-hover); } @@ -538,6 +486,83 @@ textarea:focus-visible, background-clip: text; } +/* ── Rosewood Glass Theme ── */ +@import url('https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;700;800&display=swap'); + +[data-theme="rosewood"] body, +[data-theme="rosewood-light"] body { + font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif; +} + +/* Glass surfaces for rosewood themes */ +[data-theme="rosewood"] .card, +[data-theme="rosewood"] .list-item, +[data-theme="rosewood"] .input { + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-color: rgba(232, 168, 192, 0.1); +} + +[data-theme="rosewood-light"] .card, +[data-theme="rosewood-light"] .list-item, +[data-theme="rosewood-light"] .input { + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border-color: rgba(0, 0, 0, 0.06); + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.04); +} + +/* Rosewood buttons */ +[data-theme="rosewood"] .btn-primary, +[data-theme="rosewood-light"] .btn-primary { + border-radius: 12px; + border: none; + font-weight: 600; + letter-spacing: -0.01em; +} + +[data-theme="rosewood"] .btn-primary:hover, +[data-theme="rosewood-light"] .btn-primary:hover { + transform: translateY(-1px); + box-shadow: 0 4px 20px rgba(232, 168, 192, 0.3); +} + +/* Rosewood card hover */ +[data-theme="rosewood"] .card:hover { + border-color: rgba(232, 168, 192, 0.2); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.3); +} + +[data-theme="rosewood-light"] .card:hover { + border-color: rgba(212, 132, 156, 0.15); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.08); +} + +/* Rosewood inputs */ +[data-theme="rosewood"] .input:focus, +[data-theme="rosewood-light"] .input:focus { + border-color: var(--color-primary); + box-shadow: 0 0 0 3px rgba(232, 168, 192, 0.15); +} + +/* Rosewood scrollbar */ +[data-theme="rosewood"] ::-webkit-scrollbar-thumb { + background: rgba(232, 168, 192, 0.2); +} + +[data-theme="rosewood"] ::-webkit-scrollbar-thumb:hover { + background: rgba(232, 168, 192, 0.35); +} + +/* Rosewood selection */ +[data-theme="rosewood"] ::selection { + background: rgba(232, 168, 192, 0.3); +} + +[data-theme="rosewood-light"] ::selection { + background: rgba(212, 132, 156, 0.2); +} + /* Mobile Responsiveness */ @media (max-width: 768px) { :root { diff --git a/frontend/src/pages/DashboardPage.module.css b/frontend/src/pages/DashboardPage.module.css index 5fbc3ce..9d430cf 100644 --- a/frontend/src/pages/DashboardPage.module.css +++ b/frontend/src/pages/DashboardPage.module.css @@ -1,27 +1,26 @@ +/* Dashboard — Minimal Design */ + .page { max-width: 640px; margin: 0 auto; - padding: var(--spacing-md); + padding: var(--spacing-lg) var(--spacing-md); + padding-bottom: calc(var(--spacing-2xl) + env(safe-area-inset-bottom, 0px)); } .loading { display: flex; - flex-direction: column; align-items: center; justify-content: center; - min-height: 50vh; - gap: var(--spacing-md); - color: var(--color-text-muted); - font-family: var(--font-body); + min-height: 60vh; } .spinner { - width: 40px; - height: 40px; - border: 3px solid var(--color-border); + width: 24px; + height: 24px; + border: 2px solid var(--color-border); border-top-color: var(--color-primary); border-radius: 50%; - animation: spin 0.8s linear infinite; + animation: spin 0.6s linear infinite; } @keyframes spin { @@ -34,17 +33,24 @@ } .greeting { - font-size: 1.5rem; - font-weight: 600; + font-size: 1.75rem; + font-weight: 800; font-family: var(--font-heading); color: var(--color-text); - line-height: 1.3; + letter-spacing: -0.03em; } .userName { color: var(--color-primary); } +:global([data-theme="rosewood"]) .userName { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + -webkit-background-clip: text; + -webkit-text-fill-color: transparent; + background-clip: text; +} + /* Sections */ .section { margin-bottom: var(--spacing-xl); @@ -58,380 +64,289 @@ } .sectionTitle { - font-size: 1.125rem; + font-size: 0.75rem; font-weight: 600; - font-family: var(--font-heading); - color: var(--color-text); -} - -.listCount { - font-size: 0.875rem; + text-transform: uppercase; + letter-spacing: 0.08em; color: var(--color-text-muted); - font-family: var(--font-body); } -/* Empty state button (dashed) */ -.emptyButton { +.addBtn { + width: 28px; + height: 28px; display: flex; align-items: center; justify-content: center; - gap: var(--spacing-sm); - width: 100%; - padding: var(--spacing-lg); - background: transparent; - border: var(--border-width) dashed var(--color-border); - border-radius: var(--border-radius); + background: var(--color-surface); + border: var(--border-width) solid var(--color-border); + border-radius: 8px; color: var(--color-text-muted); - font-size: 1rem; - font-family: var(--font-body); cursor: pointer; transition: all var(--transition-fast); } -.emptyButton:hover { - border-color: var(--color-primary); +.addBtn:hover { color: var(--color-primary); + border-color: var(--color-primary); } -/* Personal card */ -.personalCard { +/* Household Chips */ +.householdRow { + display: flex; + flex-wrap: wrap; + gap: var(--spacing-sm); +} + +.householdChip { display: flex; align-items: center; - gap: var(--spacing-md); - width: 100%; - padding: var(--spacing-md); + gap: 8px; + padding: 10px 14px; background: var(--color-surface); border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); + border-radius: 12px; cursor: pointer; transition: all var(--transition-fast); - text-align: left; + font-family: var(--font-body); + font-size: 0.875rem; + color: var(--color-text); } -[data-theme="brutalist"] .personalCard { - box-shadow: 4px 4px 0 var(--color-shadow); +.householdChip:hover { + border-color: var(--color-primary); + transform: translateY(-1px); } -[data-theme="brutalist"] .personalCard:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); +:global([data-theme="rosewood"]) .householdChip { + background: rgba(32, 28, 26, 0.6); + backdrop-filter: blur(12px); + -webkit-backdrop-filter: blur(12px); + border-color: rgba(232, 168, 192, 0.1); } -.personalCard:hover { - background: var(--color-surface-hover); +:global([data-theme="rosewood"]) .householdChip:hover { + background: rgba(53, 47, 43, 0.7); + border-color: rgba(232, 168, 192, 0.2); + box-shadow: 0 4px 16px rgba(0, 0, 0, 0.2); } -.personalIcon { - width: 48px; - height: 48px; - border-radius: var(--border-radius); - background: var(--color-primary); - display: flex; - align-items: center; - justify-content: center; - color: var(--color-primary-text); +.chipDot { + width: 8px; + height: 8px; + border-radius: 50%; flex-shrink: 0; } -/* Shared card info */ -.cardInfo { - flex: 1; - min-width: 0; +.chipName { + font-weight: 600; } -.cardInfo h3 { - font-size: 1rem; +.chipCount { + font-size: 0.75rem; + color: var(--color-text-muted); font-weight: 500; - font-family: var(--font-heading); - color: var(--color-text); - margin: 0 0 2px 0; } -.cardInfo p { - font-size: 0.875rem; +.chipArrow { color: var(--color-text-muted); - font-family: var(--font-body); - margin: 0; + opacity: 0.5; } -/* Household list */ -.householdList { +/* Notes List */ +.notesList { display: flex; flex-direction: column; - gap: var(--spacing-md); -} - -.householdCard { - display: flex; - align-items: center; - gap: var(--spacing-md); - width: 100%; - padding: var(--spacing-md); + gap: 2px; background: var(--color-surface); border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); - cursor: pointer; - transition: all var(--transition-fast); - text-align: left; -} - -[data-theme="brutalist"] .householdCard { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .householdCard:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - -.householdCard:hover { - background: var(--color-surface-hover); + border-radius: 14px; + overflow: hidden; } -.householdIcon { - width: 48px; - height: 48px; - border-radius: var(--border-radius); - display: flex; - align-items: center; - justify-content: center; - font-size: 1.25rem; - font-weight: 600; - color: white; - flex-shrink: 0; +:global([data-theme="rosewood"]) .notesList { + background: rgba(32, 28, 26, 0.5); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-color: rgba(232, 168, 192, 0.08); } -/* Add Household Button */ -.addHouseholdButton { +.noteRow { display: flex; align-items: center; - justify-content: center; - gap: var(--spacing-sm); - width: 100%; - padding: var(--spacing-md); - background: transparent; - border: var(--border-width) dashed var(--color-border); - border-radius: var(--border-radius); - color: var(--color-primary); - font-size: 1rem; - font-weight: 500; - font-family: var(--font-body); - cursor: pointer; - transition: all var(--transition-fast); -} - -.addHouseholdButton:hover { - border-color: var(--color-primary); - background: var(--color-surface-hover); -} - -/* Recent lists */ -.recentList { - display: flex; - flex-direction: column; - gap: var(--spacing-md); -} - -.recentCard { - display: flex; - flex-direction: column; gap: var(--spacing-md); - width: 100%; - padding: var(--spacing-md); - background: var(--color-surface); - border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); + padding: 14px 16px; + background: transparent; + border: none; cursor: pointer; - transition: all var(--transition-fast); + transition: background var(--transition-fast); text-align: left; + font-family: var(--font-body); + width: 100%; + color: var(--color-text); } -[data-theme="brutalist"] .recentCard { - box-shadow: 4px 4px 0 var(--color-shadow); +.noteRow:hover { + background: var(--color-surface-hover); } -[data-theme="brutalist"] .recentCard:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); +:global([data-theme="rosewood"]) .noteRow:hover { + background: rgba(232, 168, 192, 0.06); } -.recentCard:hover { - background: var(--color-surface-hover); +.noteRow + .noteRow { + border-top: 1px solid var(--color-border); } -.recentHeader { - display: flex; - align-items: center; - gap: var(--spacing-md); +:global([data-theme="rosewood"]) .noteRow + .noteRow { + border-top-color: rgba(232, 168, 192, 0.06); } -.recentIcon { - width: 40px; - height: 40px; - border-radius: var(--border-radius); +.noteIcon { + width: 32px; + height: 32px; display: flex; align-items: center; justify-content: center; flex-shrink: 0; + opacity: 0.7; } -.recentInfo { +.noteInfo { flex: 1; min-width: 0; -} - -.recentTitleRow { display: flex; - align-items: center; - gap: var(--spacing-sm); - margin-bottom: 2px; -} - -.recentTitleRow h3 { - font-size: 1rem; - font-weight: 500; - font-family: var(--font-heading); - color: var(--color-text); - margin: 0; + flex-direction: column; + gap: 2px; } -.listBadge { - font-size: 0.625rem; +.noteTitle { + font-size: 0.9375rem; font-weight: 600; - font-family: var(--font-body); - padding: 2px 6px; - background: var(--color-background); - color: var(--color-text-muted); - border-radius: var(--border-radius); - letter-spacing: 0.5px; -} - -.recentInfo p { - font-size: 0.875rem; - color: var(--color-text-muted); - font-family: var(--font-body); - margin: 0; -} - -/* Progress bar */ -.progressBar { - height: 6px; - background: var(--color-background); - border-radius: var(--border-radius); + color: var(--color-text); + white-space: nowrap; overflow: hidden; + text-overflow: ellipsis; + display: flex; + align-items: center; + gap: 6px; } -.progressFill { - height: 100%; - background: var(--color-primary); - border-radius: var(--border-radius); - transition: width var(--transition-normal); -} - -/* Color classes */ -.colorShopping { - background: var(--color-shopping-light); - color: var(--color-shopping); -} - -.colorShopping.progressFill { - background: var(--color-shopping); +.lockIcon { + flex-shrink: 0; + opacity: 0.4; + color: var(--color-success, #10b981); } -.colorChecklist { - background: var(--color-checklist-light); - color: var(--color-checklist); +.encryptedTitle { + font-style: italic; + opacity: 0.6; } -.colorChecklist.progressFill { - background: var(--color-checklist); +.noteMeta { + font-size: 0.75rem; + color: var(--color-text-muted); } -.colorNote { - background: var(--color-note-light); - color: var(--color-note); +.noteTime { + font-size: 0.75rem; + color: var(--color-text-muted); + flex-shrink: 0; + white-space: nowrap; } -.colorNote.progressFill { - background: var(--color-note); +/* Empty state */ +.empty { + text-align: center; + padding: var(--spacing-2xl) var(--spacing-md); + color: var(--color-text-muted); + font-size: 0.875rem; } /* Modal */ .modalOverlay { position: fixed; inset: 0; + z-index: 200; background: rgba(0, 0, 0, 0.5); display: flex; align-items: center; justify-content: center; - padding: var(--spacing-lg); - z-index: 1000; + padding: var(--spacing-md); +} + +:global([data-theme="rosewood"]) .modalOverlay { + background: rgba(0, 0, 0, 0.6); + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); } .modal { background: var(--color-surface); border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); + border-radius: 20px; padding: var(--spacing-xl); width: 100%; max-width: 400px; } -[data-theme="brutalist"] .modal { - box-shadow: 6px 6px 0 var(--color-shadow); +:global([data-theme="rosewood"]) .modal { + background: rgba(32, 28, 26, 0.92); + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border-color: rgba(232, 168, 192, 0.1); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); } .modalTitle { font-size: 1.25rem; - font-weight: 600; - font-family: var(--font-heading); - color: var(--color-text); - margin: 0 0 var(--spacing-xs) 0; -} - -.modalSubtitle { - color: var(--color-text-muted); - font-family: var(--font-body); - margin: 0 0 var(--spacing-lg) 0; + font-weight: 700; + margin-bottom: var(--spacing-lg); } .modalInput { width: 100%; - padding: var(--spacing-md); - font-family: var(--font-body); - font-size: 1rem; - color: var(--color-text); - background: var(--color-surface); + padding: 12px 16px; + background: var(--color-background); border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); + border-radius: 12px; + color: var(--color-text); + font-family: var(--font-body); + font-size: 0.9375rem; outline: none; - margin-bottom: var(--spacing-lg); transition: border-color var(--transition-fast); -} - -[data-theme="brutalist"] .modalInput { - box-shadow: 3px 3px 0 var(--color-shadow); + margin-bottom: var(--spacing-lg); } .modalInput:focus { border-color: var(--color-primary); } +:global([data-theme="rosewood"]) .modalInput { + background: rgba(26, 22, 20, 0.6); + border-color: rgba(232, 168, 192, 0.15); +} + +:global([data-theme="rosewood"]) .modalInput:focus { + border-color: #e8a8c0; + box-shadow: 0 0 0 3px rgba(232, 168, 192, 0.12); +} + .modalActions { display: flex; - gap: var(--spacing-md); + gap: var(--spacing-sm); justify-content: flex-end; } .cancelButton { - padding: var(--spacing-sm) var(--spacing-lg); + padding: 10px 20px; background: transparent; - color: var(--color-text-muted); - font-weight: 500; - font-family: var(--font-body); border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); + border-radius: 10px; + color: var(--color-text-muted); cursor: pointer; + font-family: var(--font-body); + font-size: 0.875rem; + font-weight: 500; transition: all var(--transition-fast); } @@ -441,38 +356,49 @@ } .submitButton { - padding: var(--spacing-sm) var(--spacing-lg); + padding: 10px 20px; background: var(--color-primary); + border: none; + border-radius: 10px; color: var(--color-primary-text); - font-weight: 500; - font-family: var(--font-body); - border: var(--border-width) solid var(--color-border); - border-radius: var(--border-radius); cursor: pointer; + font-family: var(--font-body); + font-size: 0.875rem; + font-weight: 600; transition: all var(--transition-fast); } -[data-theme="brutalist"] .submitButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .submitButton:hover { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .submitButton:hover { opacity: 0.9; + transform: translateY(-1px); } .submitButton:disabled { opacity: 0.5; cursor: not-allowed; + transform: none; +} + +:global([data-theme="rosewood"]) .submitButton { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + color: #1a1614; } -/* Responsive */ +:global([data-theme="rosewood"]) .submitButton:hover { + box-shadow: 0 4px 20px rgba(232, 168, 192, 0.3); +} + +/* Mobile */ @media (max-width: 480px) { .greeting { - font-size: 1.375rem; + font-size: 1.5rem; + } + + .householdRow { + flex-direction: column; + } + + .householdChip { + width: 100%; } } diff --git a/frontend/src/pages/DashboardPage.tsx b/frontend/src/pages/DashboardPage.tsx index e1aec2a..eb98d93 100644 --- a/frontend/src/pages/DashboardPage.tsx +++ b/frontend/src/pages/DashboardPage.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from 'react'; import { useNavigate, useSearchParams } from 'react-router-dom'; -import { Plus, ShoppingCart, CheckCircle2, FileText, Lock } from 'lucide-react'; -import { isNoteEncrypted } from '../utils/encryptionHelpers'; +import { Plus, ShoppingCart, CheckCircle2, FileText, Lock, ChevronRight } from 'lucide-react'; import { useAuthStore, useHouseholdStore, useListsStore, Household, List } from '../stores/store'; import { api } from '../utils/api'; +import { isNoteEncrypted, isEncryptedValue } from '../utils/encryptionHelpers'; import styles from './DashboardPage.module.css'; export default function DashboardPage() { @@ -30,7 +30,6 @@ export default function DashboardPage() { const householdsData = await api.getHouseholds() as Household[]; setHouseholds(householdsData); - // Load lists for all households const allLists: List[] = []; for (const household of householdsData) { const householdLists = await api.getLists(household.household_id) as List[]; @@ -67,155 +66,159 @@ export default function DashboardPage() { const getListIcon = (type: string) => { switch (type) { - case 'shopping': - return ShoppingCart; - case 'checklist': - return CheckCircle2; - default: - return FileText; + case 'shopping': return ShoppingCart; + case 'checklist': return CheckCircle2; + default: return FileText; } }; - const getListColorClass = (type: string) => { + const getTypeColor = (type: string) => { switch (type) { - case 'shopping': - return styles.colorShopping; - case 'checklist': - return styles.colorChecklist; - default: - return styles.colorNote; + case 'shopping': return 'var(--color-shopping)'; + case 'checklist': return 'var(--color-checklist)'; + default: return 'var(--color-note)'; } }; - const recentLists = lists - .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()) - .slice(0, 5); + const getHouseholdName = (householdId: string) => { + return households.find(h => h.household_id === householdId)?.name || ''; + }; - // Generate consistent color for household based on name const getHouseholdColor = (name: string) => { - const colors = ['#f59e0b', '#10b981', '#6366f1', '#ec4899', '#8b5cf6', '#14b8a6']; + const colors = ['#e8a8c0', '#88c8a8', '#b898d0', '#e8c070', '#70b8e8', '#e87070']; const index = name.charCodeAt(0) % colors.length; return colors[index]; }; + const formatRelativeDate = (dateString: string) => { + if (!dateString) return ''; + const date = new Date(dateString); + const now = new Date(); + const diffMs = now.getTime() - date.getTime(); + const diffMins = Math.floor(diffMs / (1000 * 60)); + const diffHours = Math.floor(diffMs / (1000 * 60 * 60)); + const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24)); + + if (diffMins < 1) return 'now'; + if (diffMins < 60) return `${diffMins}m`; + if (diffHours < 24) return `${diffHours}h`; + if (diffDays === 1) return 'yesterday'; + if (diffDays < 7) return `${diffDays}d`; + return date.toLocaleDateString([], { month: 'short', day: 'numeric' }); + }; + + // All lists sorted by recent + const recentLists = [...lists] + .sort((a, b) => new Date(b.updated_at).getTime() - new Date(a.updated_at).getTime()); + if (loading) { return (
-

Loading your dashboard...

); } return (
- {/* Welcome Header */} + {/* Greeting */}

- Welcome back, {user?.name?.split(' ')[0] || 'there'} + Hi, {user?.name?.split(' ')[0] || 'there'}

- {/* Households Section */} + {/* Households — compact row */}
-

Your Households

+
+

Households

+ +
-
+
{households.map((household) => { - const householdLists = lists.filter(l => l.household_id === household.household_id); + const count = lists.filter(l => l.household_id === household.household_id).length; return ( ); })} - -
- {/* Recent Lists Section */} - {recentLists.length > 0 && ( -
-

Recent Lists

+ {/* All Notes — clean list */} +
+

All Notes

-
+ {recentLists.length === 0 ? ( +
+

No notes yet. Pick a household and create one!

+
+ ) : ( +
{recentLists.map((list) => { const Icon = getListIcon(list.type); - const colorClass = getListColorClass(list.type); - const checkedCount = list.items.filter(i => i.checked).length; - const totalCount = list.items.length; - const progress = totalCount > 0 ? (checkedCount / totalCount) * 100 : 0; + const householdName = getHouseholdName(list.household_id); + const encrypted = isNoteEncrypted(list); + const displayTitle = isEncryptedValue(list.title) ? 'Encrypted note' : list.title; return ( ); })}
-
- )} + )} +
{/* Create Household Modal */} {showCreateModal && (
setShowCreateModal(false)}>
e.stopPropagation()}> -

Create a Household

-

- Give your household a name to get started -

+

New Household

setNewHouseholdName(e.target.value)} - placeholder="e.g., Home, Work, Vacation House" + placeholder="e.g., Home, Work" className={styles.modalInput} autoFocus /> @@ -232,7 +235,7 @@ export default function DashboardPage() { disabled={creating || !newHouseholdName.trim()} className={styles.submitButton} > - {creating ? 'Creating...' : 'Create Household'} + {creating ? 'Creating...' : 'Create'}
diff --git a/frontend/src/pages/HouseholdPage.module.css b/frontend/src/pages/HouseholdPage.module.css index 14e711a..689eb1a 100644 --- a/frontend/src/pages/HouseholdPage.module.css +++ b/frontend/src/pages/HouseholdPage.module.css @@ -50,11 +50,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .backButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .backButton:hover { background: var(--color-surface-hover); color: var(--color-text); @@ -124,11 +119,6 @@ width: 100%; max-width: 300px; } - -[data-theme="brutalist"] .nameInput { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .memberCount { font-size: 0.875rem; color: var(--color-text-muted); @@ -157,15 +147,6 @@ transition: all var(--transition-fast); } -[data-theme="brutalist"] .inviteButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .inviteButton:hover { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .optionsWrapper { position: relative; } @@ -183,11 +164,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .optionsButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .optionsButton:hover { background: var(--color-surface-hover); } @@ -204,11 +180,6 @@ z-index: 100; overflow: hidden; } - -[data-theme="brutalist"] .optionsMenu { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .optionsMenuItem { display: flex; align-items: center; @@ -317,11 +288,6 @@ z-index: 100; overflow: hidden; } - -[data-theme="brutalist"] .sortMenu { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .sortOption { display: block; width: 100%; @@ -397,16 +363,9 @@ cursor: pointer; transition: all var(--transition-fast); text-align: left; - min-height: 100px; -} - -[data-theme="brutalist"] .listCard { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .listCard:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); + min-height: 80px; + max-height: 160px; + overflow: hidden; } .listCard:hover { @@ -669,11 +628,6 @@ width: 100%; max-width: 440px; } - -[data-theme="brutalist"] .modal { - box-shadow: 6px 6px 0 var(--color-shadow); -} - .modalTitle { font-size: 1.25rem; font-weight: 600; @@ -751,11 +705,6 @@ margin-bottom: var(--spacing-lg); transition: border-color var(--transition-fast); } - -[data-theme="brutalist"] .modalInput { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .modalInput:focus { border-color: var(--color-primary); } @@ -795,15 +744,6 @@ transition: all var(--transition-fast); } -[data-theme="brutalist"] .submitButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .submitButton:hover { - transform: translate(1px, 1px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .submitButton:hover { opacity: 0.9; } @@ -824,11 +764,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .dangerButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .dangerButton:hover:not(:disabled) { opacity: 0.9; } @@ -931,3 +866,108 @@ grid-template-columns: 1fr; } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .listCard { + background: rgba(32, 28, 26, 0.6); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-color: rgba(232, 168, 192, 0.08); + border-radius: 16px; +} + +:global([data-theme="rosewood"]) .listCard:hover { + background: rgba(53, 47, 43, 0.7); + border-color: rgba(232, 168, 192, 0.18); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.3); + transform: translateY(-2px); +} + +:global([data-theme="rosewood-light"]) .listCard { + background: rgba(255, 255, 255, 0.65); + backdrop-filter: blur(16px); + -webkit-backdrop-filter: blur(16px); + border-color: rgba(0, 0, 0, 0.06); + border-radius: 16px; +} + +:global([data-theme="rosewood-light"]) .listCard:hover { + background: rgba(255, 255, 255, 0.85); + border-color: rgba(212, 132, 156, 0.15); + box-shadow: 0 8px 32px rgba(0, 0, 0, 0.08); + transform: translateY(-2px); +} + +:global([data-theme="rosewood"]) .modal, +:global([data-theme="rosewood-light"]) .modal { + border-radius: 20px; + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); +} + +:global([data-theme="rosewood"]) .modal { + background: rgba(32, 28, 26, 0.92); + border: 1px solid rgba(232, 168, 192, 0.1); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.5); +} + +:global([data-theme="rosewood-light"]) .modal { + background: rgba(255, 255, 255, 0.92); + border: 1px solid rgba(0, 0, 0, 0.06); + box-shadow: 0 20px 60px rgba(0, 0, 0, 0.12); +} + +:global([data-theme="rosewood"]) .modalOverlay, +:global([data-theme="rosewood-light"]) .modalOverlay { + backdrop-filter: blur(8px); + -webkit-backdrop-filter: blur(8px); +} + +:global([data-theme="rosewood"]) .addListCard { + background: rgba(232, 168, 192, 0.06); + border-color: rgba(232, 168, 192, 0.12); + border-radius: 16px; + border-style: dashed; +} + +:global([data-theme="rosewood"]) .addListCard:hover { + background: rgba(232, 168, 192, 0.1); + border-color: rgba(232, 168, 192, 0.25); +} + +:global([data-theme="rosewood-light"]) .addListCard { + background: rgba(212, 132, 156, 0.04); + border-color: rgba(212, 132, 156, 0.12); + border-radius: 16px; + border-style: dashed; +} + +:global([data-theme="rosewood"]) .header { + border-bottom-color: rgba(232, 168, 192, 0.08); +} + +:global([data-theme="rosewood-light"]) .header { + border-bottom-color: rgba(0, 0, 0, 0.06); +} + +:global([data-theme="rosewood"]) .householdIcon { + border-radius: 14px; +} + +:global([data-theme="rosewood"]) .submitButton { + background: linear-gradient(135deg, #e8a8c0, #b898d0); + color: #1a1614; + border: none; + border-radius: 12px; +} + +:global([data-theme="rosewood"]) .submitButton:hover { + box-shadow: 0 4px 20px rgba(232, 168, 192, 0.35); +} + +:global([data-theme="rosewood-light"]) .submitButton { + background: linear-gradient(135deg, #d4849c, #9878b8); + color: #ffffff; + border: none; + border-radius: 12px; +} diff --git a/frontend/src/pages/HouseholdPage.tsx b/frontend/src/pages/HouseholdPage.tsx index 3da766b..e8ee2b0 100644 --- a/frontend/src/pages/HouseholdPage.tsx +++ b/frontend/src/pages/HouseholdPage.tsx @@ -1,7 +1,7 @@ import { useEffect, useState, useCallback } from 'react'; import { useParams, useNavigate } from 'react-router-dom'; import { Plus, UserPlus, ShoppingCart, CheckCircle2, FileText, ArrowLeft, Trash2, MoreVertical, LogOut, ArrowUpDown, Pencil, UserMinus, Shield, AlertTriangle, Lock } from 'lucide-react'; -import { isNoteEncrypted } from '../utils/encryptionHelpers'; +import { isNoteEncrypted, isEncryptedValue } from '../utils/encryptionHelpers'; import { useHouseholdStore, useListsStore, useAuthStore, Household, List } from '../stores/store'; import { api } from '../utils/api'; import { useShortcutEvent } from '../hooks/useKeyboardShortcuts'; @@ -393,16 +393,24 @@ export default function HouseholdPage() { const totalCount = list.items.length; const progress = totalCount > 0 ? (checkedCount / totalCount) * 100 : 0; + const encrypted = isNoteEncrypted(list); + const displayTitle = isEncryptedValue(list.title) ? 'Encrypted note' : list.title; + // Generate preview content const getPreview = () => { + if (encrypted) { + return '🔒 Unlock to view contents'; + } if (list.type === 'note') { - // Strip HTML tags and get first ~80 chars const text = list.content?.replace(/<[^>]*>/g, '') || ''; + if (isEncryptedValue(text)) return '🔒 Unlock to view contents'; return text.slice(0, 80) + (text.length > 80 ? '...' : ''); } else { - // Show first 3 unchecked items const uncheckedItems = list.items.filter(i => !i.checked).slice(0, 3); - return uncheckedItems.map(i => i.text).join(' · ') || 'No items yet'; + const texts = uncheckedItems.map(i => + isEncryptedValue(i.text) ? '••••' : i.text + ); + return texts.join(' · ') || 'No items yet'; } }; @@ -416,14 +424,11 @@ export default function HouseholdPage() { >
- - + + {encrypted ? : }

- {list.title} - {isNoteEncrypted(list) && ( - - )} + {displayTitle}

{(list.updated_at || list.created_at) && ( diff --git a/frontend/src/pages/InvitePage.module.css b/frontend/src/pages/InvitePage.module.css index 7b173c0..52af051 100644 --- a/frontend/src/pages/InvitePage.module.css +++ b/frontend/src/pages/InvitePage.module.css @@ -35,11 +35,6 @@ max-width: 400px; width: 100%; } - -[data-theme="brutalist"] .card { - box-shadow: 8px 8px 0 var(--color-shadow); -} - .logo { display: flex; align-items: center; @@ -114,15 +109,6 @@ transition: all var(--transition-normal); } -[data-theme="brutalist"] .acceptButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .acceptButton:hover:not(:disabled) { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .acceptButton:hover:not(:disabled) { opacity: 0.9; } @@ -144,11 +130,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .declineButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .declineButton:hover { background: var(--color-surface-hover); color: var(--color-text); @@ -175,15 +156,6 @@ transition: all var(--transition-normal); } -[data-theme="brutalist"] .loginButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .loginButton:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .loginButton:hover { opacity: 0.9; } @@ -233,7 +205,3 @@ border: var(--border-width) solid var(--color-border); border-radius: var(--border-radius); } - -[data-theme="brutalist"] .button { - box-shadow: 4px 4px 0 var(--color-shadow); -} diff --git a/frontend/src/pages/ListPage.module.css b/frontend/src/pages/ListPage.module.css index dc3c230..b7c0fac 100644 --- a/frontend/src/pages/ListPage.module.css +++ b/frontend/src/pages/ListPage.module.css @@ -42,11 +42,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .backButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .backButton:hover { background: var(--color-surface-hover); color: var(--color-text); @@ -105,11 +100,6 @@ outline: none; width: 100%; } - -[data-theme="brutalist"] .titleInput { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .meta { display: flex; align-items: center; @@ -152,11 +142,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .actionButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .actionButton:hover { background: var(--color-surface-hover); color: var(--color-text); @@ -230,11 +215,6 @@ border-radius: var(--border-radius); outline: none; } - -[data-theme="brutalist"] .addInput { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .addInput:focus { border-color: var(--color-primary); } @@ -257,15 +237,6 @@ transition: all var(--transition-fast); } -[data-theme="brutalist"] .addButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .addButton:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .addButton:hover { opacity: 0.9; } @@ -293,11 +264,6 @@ border-radius: var(--border-radius); transition: all var(--transition-fast); } - -[data-theme="brutalist"] .item { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .item:hover { background: var(--color-surface-hover); } @@ -389,11 +355,6 @@ border: var(--border-width) dashed var(--color-border); border-radius: var(--border-radius); } - -[data-theme="brutalist"] .emptyState { - box-shadow: 4px 4px 0 var(--color-shadow); -} - /* Responsive */ @media (max-width: 768px) { .deleteButton { @@ -404,3 +365,35 @@ opacity: 0.4; } } + +/* ── Rosewood Glass Theme ── */ +:global([data-theme="rosewood"]) .header { + background: rgba(26, 22, 20, 0.8); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border-bottom-color: rgba(232, 168, 192, 0.08); +} + +:global([data-theme="rosewood-light"]) .header { + background: rgba(255, 255, 255, 0.8); + backdrop-filter: saturate(180%) blur(20px); + -webkit-backdrop-filter: saturate(180%) blur(20px); + border-bottom-color: rgba(0, 0, 0, 0.06); +} + +:global([data-theme="rosewood"]) .actionButton { + background: rgba(32, 28, 26, 0.6); + border-color: rgba(232, 168, 192, 0.1); + border-radius: 10px; +} + +:global([data-theme="rosewood"]) .actionButton:hover { + background: rgba(232, 168, 192, 0.12); + border-color: rgba(232, 168, 192, 0.2); +} + +:global([data-theme="rosewood"]) .actionButton.encryptedActive { + background: rgba(136, 200, 168, 0.12); + border-color: rgba(136, 200, 168, 0.25); + color: #88c8a8; +} diff --git a/frontend/src/pages/LoginPage.module.css b/frontend/src/pages/LoginPage.module.css index 3834b64..80206ac 100644 --- a/frontend/src/pages/LoginPage.module.css +++ b/frontend/src/pages/LoginPage.module.css @@ -94,11 +94,6 @@ width: 100%; max-width: 400px; } - -[data-theme="brutalist"] .formCard { - box-shadow: 8px 8px 0 var(--color-shadow); -} - .formTitle { font-size: 1.5rem; font-weight: 700; @@ -138,20 +133,9 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .googleButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .googleButton:hover { background: #f5f5f5; } - -[data-theme="brutalist"] .googleButton:hover { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .googleButton:disabled { opacity: 0.6; cursor: not-allowed; @@ -217,11 +201,6 @@ outline: none; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .input { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .input:focus { border-color: var(--color-primary); } @@ -248,15 +227,6 @@ margin-top: var(--spacing-sm); } -[data-theme="brutalist"] .submitButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .submitButton:hover:not(:disabled) { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .submitButton:hover:not(:disabled) { opacity: 0.9; } @@ -332,11 +302,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .demoButton { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .demoButton:hover { background: var(--color-surface-hover); } diff --git a/frontend/src/pages/SettingsPage.module.css b/frontend/src/pages/SettingsPage.module.css index 154c003..67723d0 100644 --- a/frontend/src/pages/SettingsPage.module.css +++ b/frontend/src/pages/SettingsPage.module.css @@ -27,11 +27,6 @@ margin-bottom: var(--spacing-lg); overflow: hidden; } - -[data-theme="brutalist"] .section { - box-shadow: 4px 4px 0 var(--color-shadow); -} - .sectionHeader { display: flex; align-items: center; @@ -109,11 +104,6 @@ border-radius: var(--border-radius); outline: none; } - -[data-theme="brutalist"] .input { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .input:focus { border-color: var(--color-primary); } @@ -130,15 +120,6 @@ transition: all var(--transition-normal); } -[data-theme="brutalist"] .saveButton { - box-shadow: 4px 4px 0 var(--color-shadow); -} - -[data-theme="brutalist"] .saveButton:hover:not(:disabled) { - transform: translate(2px, 2px); - box-shadow: 2px 2px 0 var(--color-shadow); -} - .saveButton:hover:not(:disabled) { opacity: 0.9; } @@ -173,11 +154,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .themeOption { - box-shadow: 3px 3px 0 var(--color-shadow); -} - .themeOption:hover { background: var(--color-surface-hover); border-color: var(--color-primary); @@ -271,11 +247,6 @@ cursor: pointer; transition: all var(--transition-fast); } - -[data-theme="brutalist"] .logoutButton { - box-shadow: 3px 3px 0 color-mix(in srgb, var(--color-error) 30%, transparent); -} - .logoutButton:hover { background: color-mix(in srgb, var(--color-error) 20%, transparent); } diff --git a/frontend/src/stores/themeStore.ts b/frontend/src/stores/themeStore.ts index b7e89fe..94c620a 100644 --- a/frontend/src/stores/themeStore.ts +++ b/frontend/src/stores/themeStore.ts @@ -1,7 +1,7 @@ import { create } from 'zustand'; import { persist } from 'zustand/middleware'; -export type ThemeName = 'brutalist' | 'paper' | 'sketchy' | 'terminal' | 'dark'; +export type ThemeName = 'rosewood' | 'rosewood-light'; interface ThemeState { theme: ThemeName; @@ -11,33 +11,35 @@ interface ThemeState { } // Light themes (non-dark) -export const lightThemes: ThemeName[] = ['brutalist', 'paper', 'sketchy']; -export const darkThemes: ThemeName[] = ['terminal', 'dark']; - -// Valid theme names for migration -const validThemeNames = ['brutalist', 'paper', 'sketchy', 'terminal', 'dark']; +export const lightThemes: ThemeName[] = ['rosewood-light']; +export const darkThemes: ThemeName[] = ['rosewood']; export const useThemeStore = create()( persist( (set) => ({ - theme: 'paper', - previousLightTheme: 'paper', + theme: 'rosewood', + previousLightTheme: 'rosewood-light', setTheme: (theme) => set({ theme }), setPreviousLightTheme: (theme) => set({ previousLightTheme: theme }), }), { name: 'theme-storage', - // Migrate old theme values to valid ones + // Migrate ALL old themes to rosewood migrate: (persistedState: any) => { - if (persistedState && !validThemeNames.includes(persistedState.theme)) { - persistedState.theme = 'paper'; - } - if (persistedState && !validThemeNames.includes(persistedState.previousLightTheme)) { - persistedState.previousLightTheme = 'paper'; + if (persistedState) { + const darkNames = ['terminal', 'dark', 'rosewood']; + const lightNames = ['brutalist', 'paper', 'sketchy', 'rosewood-light']; + + if (darkNames.includes(persistedState.theme)) { + persistedState.theme = 'rosewood'; + } else { + persistedState.theme = 'rosewood-light'; + } + persistedState.previousLightTheme = 'rosewood-light'; } return persistedState; }, - version: 1, + version: 2, // bump version to force migration } ) ); @@ -65,123 +67,56 @@ export const themes: Record = { - brutalist: { - name: 'Neo-Brutalist', - icon: '◼️', + rosewood: { + name: 'Rosewood', + icon: '🌹', colors: { - background: '#e8e8e8', - surface: '#ffffff', - surfaceHover: '#f5f5f5', - border: '#000000', - text: '#000000', - textMuted: '#333333', - primary: '#ff3366', - primaryText: '#ffffff', - accent: '#00d4ff', - shadow: '#000000', - }, - fonts: { - heading: "'Arial Black', 'Helvetica Bold', sans-serif", - body: "'Arial', 'Helvetica', sans-serif", - }, - borderRadius: '0px', - borderWidth: '3px', - }, - paper: { - name: 'Paper', - icon: '📄', - colors: { - background: '#e8e0d0', - surface: '#fffef8', - surfaceHover: '#fff9eb', - border: '#8a8070', - text: '#2c2c2c', - textMuted: '#4a4a4a', - primary: '#e6a800', - primaryText: '#2c2c2c', - accent: '#e56e4a', - shadow: 'rgba(0,0,0,0.15)', - }, - fonts: { - heading: "'Georgia', 'Times New Roman', serif", - body: "'Georgia', 'Times New Roman', serif", - }, - borderRadius: '4px', - borderWidth: '1px', - }, - sketchy: { - name: 'Sketchy', - icon: '✏️', - colors: { - background: '#f0f0f0', - surface: '#fffef9', - surfaceHover: '#fff8e8', - border: '#333333', - text: '#222222', - textMuted: '#444444', - primary: '#e6c600', - primaryText: '#222222', - accent: '#d41a5c', - shadow: 'rgba(0,0,0,0.15)', - }, - fonts: { - heading: "'Comic Neue', 'Comic Sans MS', cursive", - body: "'Comic Neue', 'Comic Sans MS', cursive", - }, - borderRadius: '255px 15px 225px 15px/15px 225px 15px 255px', - borderWidth: '2px', - }, - terminal: { - name: 'Terminal', - icon: '💻', - colors: { - background: '#0a0a0a', - surface: '#121212', - surfaceHover: '#1a1a1a', - border: '#00ff00', - text: '#00ff00', - textMuted: '#00cc00', - primary: '#00ff00', - primaryText: '#0a0a0a', - accent: '#00ffff', - shadow: 'rgba(0,255,0,0.15)', + background: '#1a1614', + surface: 'rgba(32, 28, 26, 0.72)', + surfaceHover: '#352f2b', + border: 'rgba(232, 168, 192, 0.12)', + text: '#f5f0ec', + textMuted: '#a89e98', + primary: '#e8a8c0', + primaryText: '#1a1614', + accent: '#b898d0', + shadow: 'rgba(0,0,0,0.4)', }, fonts: { - heading: "'Courier Prime', 'Courier New', monospace", - body: "'Courier Prime', 'Courier New', monospace", + heading: "'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif", + body: "'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif", }, - borderRadius: '0px', + borderRadius: '16px', borderWidth: '1px', }, - dark: { - name: 'Dark', - icon: '🌙', + 'rosewood-light': { + name: 'Rosewood Light', + icon: '🌸', colors: { - background: '#121212', - surface: '#1e1e1e', - surfaceHover: '#2a2a2a', - border: '#3a3a3a', - text: '#e4e4e4', - textMuted: '#a0a0a0', - primary: '#6b8afd', + background: '#fefdfb', + surface: 'rgba(255, 249, 245, 0.85)', + surfaceHover: '#f0ebe5', + border: 'rgba(0, 0, 0, 0.08)', + text: '#1d1d1f', + textMuted: '#6e6e73', + primary: '#d4849c', primaryText: '#ffffff', - accent: '#ff6b9d', - shadow: 'rgba(0,0,0,0.4)', + accent: '#9878b8', + shadow: 'rgba(0,0,0,0.06)', }, fonts: { - heading: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif", - body: "'Inter', -apple-system, BlinkMacSystemFont, sans-serif", + heading: "'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif", + body: "'Inter', -apple-system, BlinkMacSystemFont, 'SF Pro Display', sans-serif", }, - borderRadius: '8px', + borderRadius: '16px', borderWidth: '1px', }, }; // Apply theme to CSS variables export function applyTheme(themeName: ThemeName) { - // Fallback to 'paper' if theme doesn't exist (handles old localStorage values) - const theme = themes[themeName] || themes.paper; - const validThemeName = themes[themeName] ? themeName : 'paper'; + const theme = themes[themeName] || themes.rosewood; + const validThemeName = themes[themeName] ? themeName : 'rosewood'; const root = document.documentElement; root.style.setProperty('--color-background', theme.colors.background); @@ -199,6 +134,5 @@ export function applyTheme(themeName: ThemeName) { root.style.setProperty('--border-radius', theme.borderRadius); root.style.setProperty('--border-width', theme.borderWidth); - // Set data attribute for theme-specific CSS root.setAttribute('data-theme', validThemeName); }