feat: 新增首页和账本管理页面,并引入导航、卡片、图表等多个UI组件及玻璃拟物化布局样式。
This commit is contained in:
@@ -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);
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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%);
|
||||
|
||||
@@ -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',
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
@@ -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<ViewMode>('active');
|
||||
const [loading, setLoading] = useState(true);
|
||||
const [error, setError] = useState<string | null>(null);
|
||||
|
||||
// Edit & Create State
|
||||
const [editingLedger, setEditingLedger] = useState<Ledger | null>(null);
|
||||
const [showEditForm, setShowEditForm] = useState(false);
|
||||
const [showCreateForm, setShowCreateForm] = useState(false);
|
||||
|
||||
const [actionLoading, setActionLoading] = useState<number | null>(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 */}
|
||||
<div className="ledger-manage-page__header">
|
||||
<h1 className="ledger-manage-page__title">账本管理</h1>
|
||||
{viewMode === 'active' && (
|
||||
<button
|
||||
className="ledger-manage-page__create-btn"
|
||||
onClick={handleCreate}
|
||||
aria-label="新建账本"
|
||||
>
|
||||
<Icon icon="mdi:plus" width="20" />
|
||||
<span>新建账本</span>
|
||||
</button>
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* View Mode Tabs */}
|
||||
@@ -298,18 +339,18 @@ export const LedgerManagePage: React.FC = () => {
|
||||
)}
|
||||
</div>
|
||||
|
||||
{/* Edit Form Modal */}
|
||||
{showEditForm && editingLedger && (
|
||||
<div className="ledger-manage-page__modal" onClick={handleEditCancel}>
|
||||
{/* Edit/Create Form Modal */}
|
||||
{(showEditForm || showCreateForm) && (
|
||||
<div className="ledger-manage-page__modal" onClick={handleModalClose}>
|
||||
<div
|
||||
className="ledger-manage-page__modal-content"
|
||||
onClick={(e) => e.stopPropagation()}
|
||||
>
|
||||
<LedgerForm
|
||||
ledger={editingLedger}
|
||||
onSubmit={handleEditSubmit}
|
||||
onCancel={handleEditCancel}
|
||||
loading={actionLoading === editingLedger.id}
|
||||
ledger={editingLedger || undefined} // undefined for create mode
|
||||
onSubmit={showCreateForm ? handleCreateSubmit : handleEditSubmit}
|
||||
onCancel={handleModalClose}
|
||||
loading={actionLoading === (editingLedger?.id || -1)}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
Reference in New Issue
Block a user