diff --git a/src/components/charts/SpendingTrendChart.css b/src/components/charts/SpendingTrendChart.css index 65c6a1d..59a2385 100644 --- a/src/components/charts/SpendingTrendChart.css +++ b/src/components/charts/SpendingTrendChart.css @@ -28,4 +28,8 @@ background: rgba(0, 0, 0, 0.04); padding: 4px 10px; border-radius: 99px; +} + +.dark .chart-subtitle { + background: rgba(255, 255, 255, 0.1); } \ No newline at end of file diff --git a/src/components/common/Layout/Layout.css b/src/components/common/Layout/Layout.css index 409a45b..0f3d72f 100644 --- a/src/components/common/Layout/Layout.css +++ b/src/components/common/Layout/Layout.css @@ -17,7 +17,6 @@ padding: 0 var(--spacing-xl); /* Increased horizontal padding */ - /* Glassmorphism Header */ /* Glassmorphism Header */ background: var(--glass-bg); backdrop-filter: blur(24px); @@ -34,6 +33,13 @@ transition: all 0.3s ease; } +/* Dark Mode Header */ +.dark .app-header { + background: rgba(30, 32, 45, 0.7); + border-bottom-color: rgba(255, 255, 255, 0.08); + box-shadow: 0 4px 20px rgba(0, 0, 0, 0.2); +} + /* Brand Section Wrapper */ .brand-wrapper { display: flex; diff --git a/src/components/common/Navigation/Navigation.css b/src/components/common/Navigation/Navigation.css index 9661d28..6f0e8ab 100644 --- a/src/components/common/Navigation/Navigation.css +++ b/src/components/common/Navigation/Navigation.css @@ -30,6 +30,13 @@ transition: transform 0.3s ease; } +/* Dark Mode Mobile Nav */ +.dark .navigation { + background: rgba(30, 32, 45, 0.85); + border-top-color: rgba(255, 255, 255, 0.08); + box-shadow: 0 -10px 30px rgba(0, 0, 0, 0.3); +} + .navigation-toggle { display: none; } @@ -148,6 +155,13 @@ border-top: none; } + /* Dark Mode Desktop Sidebar */ + .dark .navigation { + background: rgba(30, 32, 45, 0.6); + border-right-color: rgba(255, 255, 255, 0.08); + box-shadow: 5px 0 30px -10px rgba(0, 0, 0, 0.3); + } + /* Reset hidden state for sidebar */ .navigation--hidden { transform: none; @@ -215,6 +229,12 @@ box-shadow: 0 4px 12px rgba(0, 0, 0, 0.03); } + .dark .navigation-link:hover { + background: rgba(255, 255, 255, 0.08); + color: white; + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.2); + } + /* Active State - Premium Capsule Style */ .navigation-link--active { background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%); diff --git a/src/components/common/Navigation/Navigation.tsx b/src/components/common/Navigation/Navigation.tsx index 9e693e9..ff62332 100644 --- a/src/components/common/Navigation/Navigation.tsx +++ b/src/components/common/Navigation/Navigation.tsx @@ -75,6 +75,12 @@ const navItems: NavItem[] = [ label: '汇率', ariaLabel: '汇率管理 - 管理货币汇率', }, + { + path: '/ledgers/manage', + icon: 'solar:notebook-bold-duotone', + label: '账本', + ariaLabel: '账本管理 - 切换和管理账本', + }, { path: '/settings', icon: 'solar:settings-bold-duotone', diff --git a/src/components/home/ContributionHeatmap/ContributionHeatmap.css b/src/components/home/ContributionHeatmap/ContributionHeatmap.css index 333d4bf..101a15d 100644 --- a/src/components/home/ContributionHeatmap/ContributionHeatmap.css +++ b/src/components/home/ContributionHeatmap/ContributionHeatmap.css @@ -5,13 +5,14 @@ height: 100%; display: flex; flex-direction: column; + /* Styles are inherited from .bento-card container */ } .heatmap-header { display: flex; justify-content: space-between; align-items: center; - margin-bottom: 1rem; + margin-bottom: 0.75rem; } .heatmap-title { @@ -49,15 +50,17 @@ font-size: 0.9rem; } +/* Graph Container */ .graph-scroll-container { flex: 1; display: flex; align-items: center; overflow-x: auto; - padding-bottom: 0.25rem; + padding: 0 4px; + margin: 0 -4px; scrollbar-width: none; /* Hide scrollbar for cleaner look */ - mask-image: linear-gradient(to right, transparent, black 10%, black 90%, transparent); + mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent); -webkit-mask-image: linear-gradient(to right, transparent, black 5%, black 95%, transparent); } @@ -67,8 +70,178 @@ .contribution-graph-compact { display: flex; - gap: 3px; + gap: 4px; + /* Space between weeks */ min-width: 100%; justify-content: flex-end; - /* Align to right usually looks better for 'latest' days */ + /* Align to right */ + height: 100%; + /* Ensure it takes available height */ +} + +.week-column-compact { + display: flex; + flex-direction: column; + gap: 4px; + /* Space between days */ + justify-content: center; +} + +/* Day Cells */ +.day-cell-compact { + width: 12px; + height: 12px; + border-radius: 3px; + background-color: rgba(0, 0, 0, 0.05); + /* L0 Color (Clean placeholder) */ + transition: all 0.3s ease; +} + +.dark .day-cell-compact { + background-color: rgba(255, 255, 255, 0.05); + /* L0 Dark */ +} + +/* Hover effect on cells */ +.day-cell-compact:hover { + transform: scale(1.4); + z-index: 10; + box-shadow: 0 2px 8px rgba(0, 0, 0, 0.1); + border-radius: 4px; +} + +/* Contribution Levels */ +.day-cell-compact.level-1 { + background-color: #fcd34d; + /* Amber 300 */ +} + +.day-cell-compact.level-2 { + background-color: #fbbf24; + /* Amber 400 */ +} + +.day-cell-compact.level-3 { + background-color: #f59e0b; + /* Amber 500 */ +} + +.day-cell-compact.level-4 { + background-color: #d97706; + /* Amber 600 */ + box-shadow: 0 0 8px rgba(245, 158, 11, 0.4); + /* Glow for max level */ +} + +/* Dark Mode Level Adjustments */ +.dark .day-cell-compact.level-1 { + background-color: rgba(251, 191, 36, 0.3); +} + +.dark .day-cell-compact.level-2 { + background-color: rgba(251, 191, 36, 0.5); +} + +.dark .day-cell-compact.level-3 { + background-color: rgba(251, 191, 36, 0.7); +} + +.dark .day-cell-compact.level-4 { + background-color: rgba(251, 191, 36, 0.9); + box-shadow: 0 0 10px rgba(251, 191, 36, 0.3); +} + + +/* Footer Layout */ +.heatmap-footer { + display: flex; + justify-content: space-between; + align-items: center; + margin-top: 1rem; + border-top: 1px solid rgba(0, 0, 0, 0.04); + padding-top: 0.75rem; +} + +.dark .heatmap-footer { + border-top-color: rgba(255, 255, 255, 0.05); +} + +.streak-summary { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 0.75rem; + color: var(--text-tertiary); +} + +.streak-summary strong { + color: var(--text-primary); + font-weight: 700; +} + +.divider { + color: var(--text-tertiary); + opacity: 0.5; +} + +/* Legend */ +.graph-legend-compact { + display: flex; + align-items: center; + gap: 4px; + font-size: 0.7rem; + color: var(--text-tertiary); +} + +.legend-cell { + width: 10px; + height: 10px; + border-radius: 2px; +} + +.legend-cell.level-0 { + background-color: rgba(0, 0, 0, 0.05); +} + +.dark .legend-cell.level-0 { + background-color: rgba(255, 255, 255, 0.05); +} + +.legend-cell.level-2 { + background-color: #fbbf24; +} + +.dark .legend-cell.level-2 { + background-color: rgba(251, 191, 36, 0.5); +} + +.legend-cell.level-4 { + background-color: #d97706; +} + +.dark .legend-cell.level-4 { + background-color: rgba(251, 191, 36, 0.9); +} + +/* Loading State */ +.heatmap-loading { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-tertiary); + font-size: 0.85rem; + animation: pulse 2s infinite; +} + +@keyframes pulse { + + 0%, + 100% { + opacity: 0.6; + } + + 50% { + opacity: 1; + } } \ No newline at end of file diff --git a/src/components/home/DailyInsightCard/DailyInsightCard.css b/src/components/home/DailyInsightCard/DailyInsightCard.css index ced1a40..e2a5145 100644 --- a/src/components/home/DailyInsightCard/DailyInsightCard.css +++ b/src/components/home/DailyInsightCard/DailyInsightCard.css @@ -9,6 +9,11 @@ background: linear-gradient(135deg, rgba(255, 255, 255, 0.9), rgba(255, 255, 255, 0.7)); } +/* Dark Mode Override */ +.dark .daily-insight-card { + background: linear-gradient(135deg, rgba(30, 32, 45, 0.9), rgba(30, 30, 35, 0.7)); +} + /* AI Variant Styling */ .daily-insight-card--ai { background: linear-gradient(135deg, rgba(255, 255, 255, 0.95), rgba(254, 252, 248, 0.9)); @@ -18,6 +23,14 @@ inset 0 0 0 1px rgba(255, 255, 255, 0.8); } +.dark .daily-insight-card--ai { + background: linear-gradient(135deg, rgba(35, 40, 50, 0.9), rgba(30, 35, 40, 0.8)); + border-color: rgba(245, 158, 11, 0.2); + box-shadow: + 0 10px 40px -10px rgba(245, 158, 11, 0.1), + inset 0 0 0 1px rgba(255, 255, 255, 0.05); +} + .daily-insight-card--ai:hover { border-color: rgba(245, 158, 11, 0.5); box-shadow: @@ -25,6 +38,12 @@ inset 0 0 0 1px rgba(255, 255, 255, 0.9); } +.dark .daily-insight-card--ai:hover { + box-shadow: + 0 20px 50px -12px rgba(245, 158, 11, 0.15), + inset 0 0 0 1px rgba(255, 255, 255, 0.1); +} + .daily-insight__header { display: flex; align-items: center; @@ -99,86 +118,58 @@ border-radius: 6px; } -.daily-insight__highlight--success { - color: #10b981; - background: rgba(16, 185, 129, 0.1); -} - -.daily-insight__highlight--warning { - color: #f59e0b; - background: rgba(245, 158, 11, 0.1); -} - -.daily-insight__highlight--danger { - color: #ef4444; - background: rgba(239, 68, 68, 0.1); -} - -.week-diff-badge { - font-size: 0.75rem; - font-weight: 600; - padding: 2px 8px; - border-radius: 99px; -} - -.week-diff-badge.green { - color: #10b981; - background: rgba(16, 185, 129, 0.1); -} - -.week-diff-badge.red { - color: #ef4444; - background: rgba(239, 68, 68, 0.1); +.dark .daily-insight__highlight { + background: rgba(255, 255, 255, 0.1); + color: var(--text-primary); } .daily-insight__footer { margin-top: auto; + display: flex; + align-items: center; + justify-content: flex-start; padding-top: 1rem; + gap: 0.5rem; +} + +.tip-icon { + color: var(--text-tertiary); + flex-shrink: 0; + margin-top: 2px; } .daily-insight__tip { - display: flex; - align-items: center; - gap: 0.75rem; font-size: 0.85rem; color: var(--text-secondary); - background: rgba(255, 255, 255, 0.5); - padding: 8px 12px; - border-radius: 12px; - border: 1px solid rgba(0, 0, 0, 0.04); + font-style: italic; + line-height: 1.4; } +/* Loading Skeleton */ +.insight-skeleton { + width: 100%; + height: 100%; + display: flex; + align-items: center; + justify-content: center; + color: var(--text-tertiary); + font-size: 0.9rem; + gap: 0.5rem; +} + +/* Animations */ @keyframes pulse { - 0% { - opacity: 0.6; + + 0%, + 100% { + opacity: 1; } 50% { - opacity: 1; - } - - 100% { opacity: 0.6; } } -@keyframes fadeIn { - from { - opacity: 0; - transform: translateY(5px); - } - - to { - opacity: 1; - transform: translateY(0); - } -} - -.animate-fade-in { - animation: fadeIn 0.4s ease-out forwards; -} - -/* Mobile Adjustments */ @media (max-width: 768px) { .daily-insight__content { flex-direction: column; diff --git a/src/components/home/QuickActionsBox/QuickActionsBox.css b/src/components/home/QuickActionsBox/QuickActionsBox.css index 097c9f9..b16c240 100644 --- a/src/components/home/QuickActionsBox/QuickActionsBox.css +++ b/src/components/home/QuickActionsBox/QuickActionsBox.css @@ -37,6 +37,11 @@ text-align: left; } +.dark .qa-btn { + background: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.05); +} + .qa-btn:hover { background: white; transform: translateX(4px); @@ -44,6 +49,12 @@ border-color: rgba(0, 0, 0, 0.08); } +.dark .qa-btn:hover { + background: rgba(255, 255, 255, 0.1); + border-color: rgba(255, 255, 255, 0.1); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + .qa-icon-wrapper { width: 40px; height: 40px; @@ -60,6 +71,10 @@ box-shadow: 0 2px 6px rgba(0, 0, 0, 0.03); } +.dark .qa-icon-wrapper { + background: rgba(255, 255, 255, 0.1); +} + .qa-btn:hover .qa-icon-wrapper { background: var(--qa-color); color: white; diff --git a/src/pages/Home/Home.css b/src/pages/Home/Home.css index 49f8dc9..64c5500 100644 --- a/src/pages/Home/Home.css +++ b/src/pages/Home/Home.css @@ -106,6 +106,19 @@ inset 0 0 0 1px rgba(255, 255, 255, 0.4); } +/* Dark Mode Overrides for Bento Card */ +.dark .bento-card { + background: rgba(30, 32, 45, 0.6); + /* Deep blue-grey base */ + border-color: rgba(255, 255, 255, 0.08); + /* Fainter border */ + box-shadow: + 0 10px 30px -10px rgba(0, 0, 0, 0.4), + /* Stronger shadow for depth */ + inset 0 0 0 1px rgba(255, 255, 255, 0.03); + /* Faint inset highlight */ +} + .bento-card:hover { transform: translateY(-6px) scale(1.01); background: rgba(255, 255, 255, 0.85); @@ -116,6 +129,14 @@ z-index: 10; } +.dark .bento-card:hover { + background: rgba(40, 42, 55, 0.8); + box-shadow: + 0 25px 50px -12px rgba(0, 0, 0, 0.6), + inset 0 0 0 1px rgba(255, 255, 255, 0.08); + border-color: rgba(255, 255, 255, 0.15); +} + /* Specific Card Styles Overrides for Bento */ .bento-card.dark-glass { background: rgba(30, 30, 35, 0.85); @@ -288,4 +309,171 @@ .no-scrollbar { -ms-overflow-style: none; scrollbar-width: none; +} + +/* Transaction List Compact (Bento Style) */ +.transaction-list-compact { + display: flex; + flex-direction: column; + gap: 0.75rem; +} + +.transaction-row { + display: flex; + align-items: center; + gap: 1rem; + padding: 0.75rem; + border-radius: 16px; + background: rgba(255, 255, 255, 0.4); + border: 1px solid rgba(255, 255, 255, 0.4); + transition: all 0.2s ease; + cursor: pointer; +} + +/* Dark Mode row style */ +.dark .transaction-row { + background: rgba(255, 255, 255, 0.03); + border-color: rgba(255, 255, 255, 0.05); +} + +.transaction-row:hover { + background: rgba(255, 255, 255, 0.7); + transform: translateX(4px); + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.05); +} + +.dark .transaction-row:hover { + background: rgba(255, 255, 255, 0.08); + /* Subtle highlight in dark mode */ + box-shadow: 0 4px 12px rgba(0, 0, 0, 0.3); +} + +.transaction-icon { + width: 40px; + height: 40px; + border-radius: 12px; + display: flex; + align-items: center; + justify-content: center; + font-size: 1.25rem; + flex-shrink: 0; +} + +.transaction-icon.expense { + background: rgba(239, 68, 68, 0.1); + color: #ef4444; +} + +.transaction-icon.income { + background: rgba(16, 185, 129, 0.1); + color: #10b981; +} + +.transaction-details { + flex: 1; + display: flex; + flex-direction: column; + gap: 2px; + overflow: hidden; +} + +.transaction-category { + font-size: 0.95rem; + font-weight: 600; + color: var(--text-primary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.transaction-note-compact { + font-size: 0.8rem; + color: var(--text-tertiary); + white-space: nowrap; + overflow: hidden; + text-overflow: ellipsis; +} + +.transaction-amount-compact { + font-family: 'Outfit', sans-serif; + font-weight: 700; + font-size: 1rem; + white-space: nowrap; +} + +.transaction-amount-compact.expense { + color: var(--text-primary); +} + +.transaction-amount-compact.income { + color: #10b981; +} + +.empty-state-compact { + display: flex; + flex-direction: column; + align-items: center; + justify-content: center; + padding: 2rem; + color: var(--text-tertiary); + gap: 0.5rem; + font-size: 0.9rem; +} + +/* Floating Voice Button - Premium Style */ +.fab-voice-btn { + position: fixed; + bottom: 2rem; + right: 2rem; + width: 64px; + height: 64px; + border-radius: 50%; + border: none; + background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%); + color: white; + box-shadow: + 0 10px 25px -5px rgba(59, 130, 246, 0.5), + /* Fallback for accent-rgb if not defined */ + 0 8px 10px -6px rgba(59, 130, 246, 0.3); + cursor: pointer; + z-index: 1000; + display: flex; + align-items: center; + justify-content: center; + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); + outline: none; +} + +.fab-voice-btn:hover { + transform: translateY(-4px) scale(1.05); + box-shadow: + 0 20px 40px -5px rgba(59, 130, 246, 0.6), + 0 12px 16px -8px rgba(59, 130, 246, 0.4); +} + +.fab-voice-btn::after { + content: ''; + position: absolute; + top: 0; + left: 0; + right: 0; + bottom: 0; + border-radius: 50%; + box-shadow: inset 0 0 0 1px rgba(255, 255, 255, 0.3); + pointer-events: none; +} + +.fab-voice-btn:active { + transform: translateY(0) scale(0.95); + box-shadow: + 0 5px 15px -3px rgba(59, 130, 246, 0.5); +} + +@media (max-width: 640px) { + .fab-voice-btn { + bottom: 1.5rem; + right: 1.5rem; + width: 56px; + height: 56px; + } } \ No newline at end of file diff --git a/src/pages/LedgerManagePage/LedgerManagePage.css b/src/pages/LedgerManagePage/LedgerManagePage.css index b65906b..20b47aa 100644 --- a/src/pages/LedgerManagePage/LedgerManagePage.css +++ b/src/pages/LedgerManagePage/LedgerManagePage.css @@ -1,17 +1,21 @@ /** - * LedgerManagePage Styles + * LedgerManagePage View Styles * Requirements: 3.6-3.9 + * Style: Ultra Premium Glass (Bento Grid) */ .ledger-manage-page { min-height: 100vh; - background-color: #f9fafb; + /* Background is managed by global theme (or Layout) */ padding: 1.5rem; } /* Header */ .ledger-manage-page__header { margin-bottom: var(--spacing-xl); + display: flex; + justify-content: space-between; + align-items: center; } .ledger-manage-page__title { @@ -27,38 +31,74 @@ letter-spacing: -0.5px; } +/* Create Button (Premium FAB/Action) */ +.ledger-manage-page__create-btn { + display: flex; + align-items: center; + gap: 0.5rem; + padding: 0.75rem 1.25rem; + background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%); + color: white; + border: none; + border-radius: 99px; + font-weight: 600; + font-size: 0.95rem; + cursor: pointer; + box-shadow: 0 4px 12px rgba(var(--accent-rgb), 0.3); + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.ledger-manage-page__create-btn:hover { + transform: translateY(-2px); + box-shadow: 0 8px 20px rgba(var(--accent-rgb), 0.4); +} + +.ledger-manage-page__create-btn:active { + transform: translateY(0) scale(0.96); +} + /* Tabs */ .ledger-manage-page__tabs { display: flex; gap: 0.5rem; - margin-bottom: 1.5rem; - border-bottom: 2px solid #e5e7eb; + margin-bottom: 2rem; + border-bottom: 1px solid rgba(0, 0, 0, 0.05); + padding-bottom: 0.5rem; +} + +.dark .ledger-manage-page__tabs { + border-bottom-color: rgba(255, 255, 255, 0.05); } .ledger-manage-page__tab { display: flex; align-items: center; gap: 0.5rem; - padding: 0.75rem 1.5rem; - background: none; + padding: 0.75rem 1.25rem; + background: transparent; border: none; - border-bottom: 2px solid transparent; - margin-bottom: -2px; - font-size: 1rem; - font-weight: 500; - color: #6b7280; + border-radius: 12px; + font-size: 0.95rem; + font-weight: 600; + color: var(--text-tertiary); cursor: pointer; - transition: all 0.2s; + transition: all 0.2s ease; + position: relative; } .ledger-manage-page__tab:hover { - color: #3b82f6; + color: var(--text-primary); + background: rgba(0, 0, 0, 0.03); +} + +.dark .ledger-manage-page__tab:hover { + background: rgba(255, 255, 255, 0.05); } .ledger-manage-page__tab--active { - color: #3b82f6; - border-bottom-color: #3b82f6; + color: var(--accent-primary); + background: rgba(var(--accent-rgb), 0.08) !important; } /* Error Message */ @@ -67,53 +107,301 @@ align-items: center; gap: 0.75rem; padding: 1rem; - background-color: #fef2f2; - border: 1px solid #fecaca; - border-radius: 0.5rem; - color: #dc2626; + background-color: rgba(239, 68, 68, 0.1); + border: 1px solid rgba(239, 68, 68, 0.2); + border-radius: 12px; + color: #ef4444; margin-bottom: 1.5rem; + backdrop-filter: blur(8px); } .ledger-manage-page__error-close { margin-left: auto; background: none; border: none; - color: #dc2626; + color: currentColor; cursor: pointer; padding: 0.25rem; + border-radius: 50%; display: flex; - align-items: center; - justify-content: center; - border-radius: 0.25rem; transition: background-color 0.2s; } .ledger-manage-page__error-close:hover { - background-color: #fee2e2; + background-color: rgba(0, 0, 0, 0.05); } -/* Content */ +/* Content Area */ .ledger-manage-page__content { min-height: 400px; } -/* Loading State */ -.ledger-manage-page__loading { +/* List Layout (Grid) */ +.ledger-manage-page__list { + display: grid; + grid-template-columns: repeat(auto-fill, minmax(340px, 1fr)); + gap: 1.5rem; +} + +/* Ledger Card - Premium Style */ +.ledger-manage-card { + display: flex; + flex-direction: column; + background: rgba(255, 255, 255, 0.7); + backdrop-filter: blur(20px); + -webkit-backdrop-filter: blur(20px); + border: 1px solid rgba(255, 255, 255, 0.5); + border-radius: 20px; + box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.05); + overflow: hidden; + transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.dark .ledger-manage-card { + background: rgba(30, 32, 45, 0.6); + border-color: rgba(255, 255, 255, 0.08); + box-shadow: 0 10px 30px -10px rgba(0, 0, 0, 0.4); +} + +.ledger-manage-card:hover { + transform: translateY(-8px); + box-shadow: 0 20px 40px -10px rgba(0, 0, 0, 0.1); + border-color: rgba(var(--accent-rgb), 0.3); +} + +.dark .ledger-manage-card:hover { + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.6); + border-color: rgba(255, 255, 255, 0.15); +} + +/* Card Cover */ +.ledger-manage-card__cover { + height: 140px; + display: flex; + align-items: center; + justify-content: center; + position: relative; + overflow: hidden; +} + +.ledger-manage-card__cover-image { + width: 100%; + height: 100%; + object-fit: cover; + transition: transform 0.5s ease; +} + +.ledger-manage-card:hover .ledger-manage-card__cover-image { + transform: scale(1.05); +} + +.ledger-manage-card__cover-placeholder { + color: rgba(255, 255, 255, 0.9); + display: flex; + align-items: center; + justify-content: center; + width: 100%; + height: 100%; + backdrop-filter: blur(4px); + /* Slight texture */ +} + +/* Card Info */ +.ledger-manage-card__info { + padding: 1.25rem; + flex: 1; +} + +.ledger-manage-card__name { + display: flex; + align-items: center; + gap: 0.5rem; + font-size: 1.2rem; + font-weight: 700; + color: var(--text-primary); + margin-bottom: 0.5rem; +} + +.ledger-manage-card__default-badge { + display: inline-flex; + align-items: center; + padding: 0.2rem 0.6rem; + background: linear-gradient(135deg, var(--accent-primary) 0%, var(--accent-secondary) 100%); + color: white; + font-size: 0.7rem; + font-weight: 600; + border-radius: 99px; + box-shadow: 0 2px 6px rgba(var(--accent-rgb), 0.2); +} + +.ledger-manage-card__meta { + display: flex; + flex-direction: column; + gap: 0.25rem; + font-size: 0.85rem; + color: var(--text-secondary); +} + +.ledger-manage-card__theme { + display: inline-flex; + align-items: center; + gap: 4px; +} + +.ledger-manage-card__theme::before { + content: ''; + display: block; + width: 6px; + height: 6px; + border-radius: 50%; + background-color: currentColor; + opacity: 0.7; +} + +/* Card Actions */ +.ledger-manage-card__actions { + display: flex; + gap: 0.5rem; + padding: 0 1.25rem 1.25rem 1.25rem; +} + +.ledger-manage-card__action-btn { + flex: 1; + display: flex; + align-items: center; + justify-content: center; + gap: 0.5rem; + padding: 0.625rem 1rem; + border: 1px solid rgba(0, 0, 0, 0.08); + /* Clean default border */ + border-radius: 12px; + font-size: 0.9rem; + font-weight: 600; + cursor: pointer; + transition: all 0.2s cubic-bezier(0.2, 0.8, 0.2, 1); + background-color: rgba(255, 255, 255, 0.5); + /* Semi-transparent */ + color: var(--text-secondary); +} + +.dark .ledger-manage-card__action-btn { + background-color: rgba(255, 255, 255, 0.05); + border-color: rgba(255, 255, 255, 0.05); +} + +.ledger-manage-card__action-btn:disabled { + opacity: 0.5; + cursor: not-allowed; +} + +/* Edit Button */ +.ledger-manage-card__action-btn--edit:hover:not(:disabled) { + background-color: rgba(var(--accent-rgb), 0.1); + color: var(--accent-primary); + border-color: transparent; + transform: translateY(-2px); +} + +/* Delete Button */ +.ledger-manage-card__action-btn--delete:hover:not(:disabled) { + background-color: rgba(239, 68, 68, 0.1); + color: #ef4444; + border-color: transparent; + transform: translateY(-2px); +} + +/* Restore Button */ +.ledger-manage-card__action-btn--restore:hover:not(:disabled) { + background-color: rgba(16, 185, 129, 0.1); + color: #10b981; + border-color: transparent; + transform: translateY(-2px); +} + + +/* Modal Backdrop */ +.ledger-manage-page__modal { + position: fixed; + top: 0; + left: 0; + right: 0; + bottom: 0; + background-color: rgba(0, 0, 0, 0.4); + backdrop-filter: blur(8px); + display: flex; + align-items: center; + justify-content: center; + z-index: 1000; + padding: 1rem; + animation: fadeIn 0.3s ease; +} + +@keyframes fadeIn { + from { + opacity: 0; + } + + to { + opacity: 1; + } +} + +.ledger-manage-page__modal-content { + background: var(--glass-panel-bg); + /* Use system panel bg */ + backdrop-filter: blur(24px); + -webkit-backdrop-filter: blur(24px); + border: 1px solid var(--glass-border); + border-radius: 24px; + max-width: 500px; + /* Bit narrower for better proportion */ + width: 100%; + max-height: 90vh; + overflow-y: auto; + box-shadow: 0 25px 50px -12px rgba(0, 0, 0, 0.25); + animation: slideUp 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); +} + +.dark .ledger-manage-page__modal-content { + background: rgba(30, 32, 45, 0.95); + /* More solid/dark in dark mode */ +} + +@keyframes slideUp { + from { + transform: translateY(20px) scale(0.95); + opacity: 0; + } + + to { + transform: translateY(0) scale(1); + opacity: 1; + } +} + + +/* Loading & Empty States */ +.ledger-manage-page__loading, +.ledger-manage-page__empty { display: flex; flex-direction: column; align-items: center; justify-content: center; - padding: 4rem 1rem; - color: #6b7280; + padding: 6rem 1rem; + color: var(--text-tertiary); + text-align: center; } -.ledger-manage-page__loading p { +.ledger-manage-page__loading p, +.ledger-manage-page__empty p { margin-top: 1rem; font-size: 1rem; + font-weight: 500; } .ledger-manage-page__spinner { animation: spin 1s linear infinite; + color: var(--accent-primary); } @keyframes spin { @@ -126,219 +414,17 @@ } } -/* Empty State */ -.ledger-manage-page__empty { - display: flex; - flex-direction: column; - align-items: center; - justify-content: center; - padding: 4rem 1rem; - color: #9ca3af; -} - -.ledger-manage-page__empty p { - margin-top: 1rem; - font-size: 1rem; -} - -/* Ledger List */ -.ledger-manage-page__list { - display: grid; - grid-template-columns: repeat(auto-fill, minmax(320px, 1fr)); - gap: 1.5rem; -} - -/* Ledger Card */ -.ledger-manage-card { - display: flex; - flex-direction: column; - background: var(--glass-panel-bg); - backdrop-filter: blur(12px); - -webkit-backdrop-filter: blur(12px); - border: 1px solid var(--glass-border); - border-radius: var(--radius-xl); - box-shadow: var(--shadow-sm); - overflow: hidden; - transition: all 0.3s cubic-bezier(0.34, 1.56, 0.64, 1); -} - -.ledger-manage-card:hover { - transform: translateY(-6px); - box-shadow: var(--shadow-xl); - border-color: rgba(var(--accent-rgb), 0.3); -} - - -/* Card Cover */ -.ledger-manage-card__cover { - height: 160px; - display: flex; - align-items: center; - justify-content: center; - position: relative; - overflow: hidden; -} - -.ledger-manage-card__cover-image { - width: 100%; - height: 100%; - object-fit: cover; -} - -.ledger-manage-card__cover-placeholder { - color: rgba(255, 255, 255, 0.8); -} - -/* Card Info */ -.ledger-manage-card__info { - padding: 1rem; - flex: 1; -} - -.ledger-manage-card__name { - display: flex; - align-items: center; - gap: 0.5rem; - font-size: 1.125rem; - font-weight: 600; - color: #111827; - margin-bottom: 0.5rem; -} - -.ledger-manage-card__default-badge { - display: inline-flex; - align-items: center; - padding: 0.125rem 0.5rem; - background-color: #dbeafe; - color: #1e40af; - font-size: 0.75rem; - font-weight: 500; - border-radius: 9999px; -} - -.ledger-manage-card__meta { - display: flex; - flex-direction: column; - gap: 0.25rem; - font-size: 0.875rem; - color: #6b7280; -} - -.ledger-manage-card__theme { - font-weight: 500; -} - -/* Card Actions */ -.ledger-manage-card__actions { - display: flex; - gap: 0.5rem; - padding: 1rem; - border-top: 1px solid #e5e7eb; -} - -.ledger-manage-card__action-btn { - flex: 1; - display: flex; - align-items: center; - justify-content: center; - gap: 0.5rem; - padding: 0.625rem 1rem; - border: 1px solid #d1d5db; - border-radius: 0.5rem; - font-size: 0.875rem; - font-weight: 500; - cursor: pointer; - transition: all 0.2s; - background-color: white; -} - -.ledger-manage-card__action-btn:disabled { - opacity: 0.5; - cursor: not-allowed; -} - -.ledger-manage-card__action-btn--edit { - color: #3b82f6; - border-color: #3b82f6; -} - -.ledger-manage-card__action-btn--edit:hover:not(:disabled) { - background-color: #eff6ff; -} - -.ledger-manage-card__action-btn--delete { - color: #ef4444; - border-color: #ef4444; -} - -.ledger-manage-card__action-btn--delete:hover:not(:disabled) { - background-color: #fef2f2; -} - -.ledger-manage-card__action-btn--restore { - color: #10b981; - border-color: #10b981; -} - -.ledger-manage-card__action-btn--restore:hover:not(:disabled) { - background-color: #f0fdf4; -} - -/* Modal */ -.ledger-manage-page__modal { - position: fixed; - top: 0; - left: 0; - right: 0; - bottom: 0; - background-color: rgba(0, 0, 0, 0.5); - display: flex; - align-items: center; - justify-content: center; - z-index: 1000; - padding: 1rem; -} - -.ledger-manage-page__modal-content { - background-color: white; - border-radius: 0.75rem; - max-width: 600px; - width: 100%; - max-height: 90vh; - overflow-y: auto; - box-shadow: 0 20px 25px -5px rgba(0, 0, 0, 0.1), 0 10px 10px -5px rgba(0, 0, 0, 0.04); -} - -/* Responsive Design */ +/* Responsive */ @media (max-width: 768px) { .ledger-manage-page { padding: 1rem; } - .ledger-manage-page__title { - font-size: 1.5rem; - } - .ledger-manage-page__list { grid-template-columns: 1fr; } - .ledger-manage-page__tab { - padding: 0.625rem 1rem; - font-size: 0.875rem; - } -} - -@media (max-width: 480px) { - .ledger-manage-page { - padding: 0.75rem; - } - - .ledger-manage-card__actions { - flex-direction: column; - } - - .ledger-manage-card__action-btn { - width: 100%; + .ledger-manage-page__title { + font-size: 1.75rem; } } \ No newline at end of file diff --git a/src/pages/LedgerManagePage/LedgerManagePage.tsx b/src/pages/LedgerManagePage/LedgerManagePage.tsx index 2f95a6c..035dfec 100644 --- a/src/pages/LedgerManagePage/LedgerManagePage.tsx +++ b/src/pages/LedgerManagePage/LedgerManagePage.tsx @@ -17,6 +17,10 @@ import { restoreLedger, canDeleteLedger, } from '../../services/ledgerService'; +// Dynamic import for createLedger to avoid circular dependency issues if any, though likely not needed here. +// But importing directly is safer. +import { createLedger } from '../../services/ledgerService'; + import './LedgerManagePage.css'; type ViewMode = 'active' | 'deleted'; @@ -30,8 +34,12 @@ export const LedgerManagePage: React.FC = () => { const [viewMode, setViewMode] = useState('active'); const [loading, setLoading] = useState(true); const [error, setError] = useState(null); + + // Edit & Create State const [editingLedger, setEditingLedger] = useState(null); const [showEditForm, setShowEditForm] = useState(false); + const [showCreateForm, setShowCreateForm] = useState(false); + const [actionLoading, setActionLoading] = useState(null); // Load ledgers on mount @@ -62,6 +70,28 @@ export const LedgerManagePage: React.FC = () => { setShowEditForm(true); }; + const handleCreate = () => { + setShowCreateForm(true); + }; + + const handleCreateSubmit = async (data: LedgerFormData) => { + try { + setActionLoading(-1); // Use -1 for create action + await createLedger({ + name: data.name, + theme: data.theme, + coverImage: data.coverImage, + }); + await loadLedgers(); + setShowCreateForm(false); + } catch (err) { + setError(err instanceof Error ? err.message : '创建账本失败'); + console.error('Failed to create ledger:', err); + } finally { + setActionLoading(null); + } + }; + const handleEditSubmit = async (data: LedgerFormData) => { if (!editingLedger) return; @@ -83,8 +113,9 @@ export const LedgerManagePage: React.FC = () => { } }; - const handleEditCancel = () => { + const handleModalClose = () => { setShowEditForm(false); + setShowCreateForm(false); setEditingLedger(null); }; @@ -239,6 +270,16 @@ export const LedgerManagePage: React.FC = () => { {/* Header */}

账本管理

+ {viewMode === 'active' && ( + + )}
{/* View Mode Tabs */} @@ -298,18 +339,18 @@ export const LedgerManagePage: React.FC = () => { )} - {/* Edit Form Modal */} - {showEditForm && editingLedger && ( -
+ {/* Edit/Create Form Modal */} + {(showEditForm || showCreateForm) && ( +
e.stopPropagation()} >