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 (