theme changes
This commit is contained in:
@@ -23,15 +23,21 @@ export interface DashboardSection {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ColorDefinition {
|
||||||
|
primary: string;
|
||||||
|
background?: string;
|
||||||
|
text?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ThemeAwarePalette {
|
||||||
|
light: ColorDefinition;
|
||||||
|
dark: ColorDefinition;
|
||||||
|
}
|
||||||
|
|
||||||
export interface DashboardConfig {
|
export interface DashboardConfig {
|
||||||
sections: DashboardSection[];
|
sections: DashboardSection[];
|
||||||
style?: {
|
style?: {
|
||||||
palette: Record<DashboardMode, {
|
palette?: Record<DashboardMode, ThemeAwarePalette>;
|
||||||
primary: string;
|
|
||||||
light: string;
|
|
||||||
dark: string;
|
|
||||||
text: string;
|
|
||||||
}>;
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
ToggleButton,
|
ToggleButton,
|
||||||
ToggleButtonGroup
|
ToggleButtonGroup
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { useTheme, alpha } from "@mui/material/styles";
|
||||||
import { DashboardProps, DashboardState } from "./Dashboard.models";
|
import { DashboardProps, DashboardState } from "./Dashboard.models";
|
||||||
|
|
||||||
interface ViewProps extends DashboardProps {
|
interface ViewProps extends DashboardProps {
|
||||||
@@ -22,8 +23,31 @@ export default function DashboardView({
|
|||||||
setState,
|
setState,
|
||||||
onModeChange
|
onModeChange
|
||||||
}: ViewProps) {
|
}: ViewProps) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const themeMode = theme.palette.mode;
|
||||||
const { mode, period, comparison } = state;
|
const { mode, period, comparison } = state;
|
||||||
const colors = config.style?.palette[mode] || { primary: '#000', light: '#fff' };
|
|
||||||
|
// Resolve colors with fallbacks
|
||||||
|
const colors = React.useMemo(() => {
|
||||||
|
const palette = config.style?.palette?.[mode];
|
||||||
|
const modeColors = palette ? palette[themeMode] : null;
|
||||||
|
|
||||||
|
if (modeColors) {
|
||||||
|
return {
|
||||||
|
primary: modeColors.primary,
|
||||||
|
light: modeColors.background || alpha(modeColors.primary, 0.1),
|
||||||
|
text: modeColors.text || (themeMode === 'light' ? theme.palette.text.primary : '#fff')
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Fallback to standard theme colors
|
||||||
|
const themeColor = mode === 'expense' ? theme.palette.error : theme.palette.success;
|
||||||
|
return {
|
||||||
|
primary: themeColor.main,
|
||||||
|
light: alpha(themeColor.main, themeMode === 'light' ? 0.08 : 0.15),
|
||||||
|
text: themeColor.main
|
||||||
|
};
|
||||||
|
}, [config.style?.palette, mode, themeMode, theme.palette]);
|
||||||
|
|
||||||
const handleModeChange = (_: any, newMode: any) => {
|
const handleModeChange = (_: any, newMode: any) => {
|
||||||
if (newMode && onModeChange) {
|
if (newMode && onModeChange) {
|
||||||
@@ -39,7 +63,8 @@ export default function DashboardView({
|
|||||||
mb: 4,
|
mb: 4,
|
||||||
background: `linear-gradient(180deg, ${colors.light} 0%, transparent 100%)`,
|
background: `linear-gradient(180deg, ${colors.light} 0%, transparent 100%)`,
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
p: 2
|
p: 2,
|
||||||
|
transition: 'background 0.3s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Box sx={{ display: "flex", justifyContent: "center", mb: 3 }}>
|
<Box sx={{ display: "flex", justifyContent: "center", mb: 3 }}>
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import {
|
|||||||
ToggleButton,
|
ToggleButton,
|
||||||
Paper
|
Paper
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { useTheme, alpha } from "@mui/material/styles";
|
||||||
import IconButton from "@mui/material/IconButton";
|
import IconButton from "@mui/material/IconButton";
|
||||||
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
import ChevronLeftIcon from "@mui/icons-material/ChevronLeft";
|
||||||
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
import ChevronRightIcon from "@mui/icons-material/ChevronRight";
|
||||||
@@ -48,6 +49,9 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
activeDataKey,
|
activeDataKey,
|
||||||
} = props;
|
} = props;
|
||||||
|
|
||||||
|
const theme = useTheme();
|
||||||
|
const isDark = theme.palette.mode === "dark";
|
||||||
|
|
||||||
const handleTabChange = (_: React.MouseEvent<HTMLElement>, newTab: string | null) => {
|
const handleTabChange = (_: React.MouseEvent<HTMLElement>, newTab: string | null) => {
|
||||||
if (newTab !== null) setActiveTab(newTab);
|
if (newTab !== null) setActiveTab(newTab);
|
||||||
};
|
};
|
||||||
@@ -66,16 +70,17 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
sx={{
|
sx={{
|
||||||
p: { xs: 2, sm: 4 },
|
p: { xs: 2.5, sm: 4 },
|
||||||
borderRadius: 4,
|
borderRadius: 4,
|
||||||
width: "100%",
|
width: "100%",
|
||||||
boxShadow: "none",
|
boxShadow: "none",
|
||||||
border: "1px solid",
|
border: "1px solid",
|
||||||
borderColor: "divider",
|
borderColor: "divider",
|
||||||
bgcolor: colorScheme.light,
|
bgcolor: isDark ? "background.paper" : colorScheme.light,
|
||||||
|
transition: 'background-color 0.3s ease, border-color 0.3s ease'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
<Typography variant="h6" fontWeight={700} gutterBottom color={colorScheme.text}>
|
<Typography variant="h6" fontWeight={700} gutterBottom sx={{ color: isDark ? 'text.primary' : colorScheme.text }}>
|
||||||
{header}
|
{header}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -157,7 +162,7 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
|
|
||||||
return (
|
return (
|
||||||
<Box key={point.id} sx={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-end", height: "100%" }}>
|
<Box key={point.id} sx={{ flex: 1, display: "flex", flexDirection: "column", alignItems: "center", justifyContent: "flex-end", height: "100%" }}>
|
||||||
<Box sx={{ display: "flex", alignItems: "flex-end", gap: comparison ? 0.5 : 0, height: "100%", position: "relative" }}>
|
<Box sx={{ display: "flex", alignItems: "flex-end", gap: comparison ? 1 : 0.5, height: "100%", position: "relative" }}>
|
||||||
<Typography
|
<Typography
|
||||||
variant="caption"
|
variant="caption"
|
||||||
sx={{
|
sx={{
|
||||||
@@ -167,30 +172,31 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
transform: "translate(-50%, -6px)",
|
transform: "translate(-50%, -6px)",
|
||||||
fontSize: "0.65rem",
|
fontSize: "0.65rem",
|
||||||
whiteSpace: "nowrap",
|
whiteSpace: "nowrap",
|
||||||
pointerEvents: "none"
|
pointerEvents: "none",
|
||||||
|
color: 'text.secondary',
|
||||||
|
fontWeight: 600
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{formatDisplay(point, activeTab.toLowerCase(), comparison)}
|
{formatDisplay(point, activeTab.toLowerCase(), comparison)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
{comparison && (
|
{comparison && (
|
||||||
<Box sx={{ width: 6, height: `${compareHeight}%`, bgcolor: `${colorScheme.primary}55`, borderRadius: 2 }} />
|
<Box sx={{ width: 8, height: `${compareHeight}%`, bgcolor: isDark ? alpha(colorScheme.primary, 0.3) : alpha(colorScheme.primary, 0.4), borderRadius: '4px 4px 0 0' }} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<Box sx={{ width: 4 }} />
|
|
||||||
|
|
||||||
<Box
|
<Box
|
||||||
sx={{
|
sx={{
|
||||||
width: 10,
|
width: comparison ? 10 : 16,
|
||||||
height: `${currentHeight}%`,
|
height: `${currentHeight}%`,
|
||||||
bgcolor: point.highlighted ? colorScheme.primary : `${colorScheme.primary}99`,
|
bgcolor: point.highlighted ? colorScheme.primary : isDark ? alpha(colorScheme.primary, 0.8) : alpha(colorScheme.primary, 0.9),
|
||||||
borderRadius: 2
|
borderRadius: '4px 4px 0 0',
|
||||||
|
boxShadow: point.highlighted ? `0 0 10px ${alpha(colorScheme.primary, 0.5)}` : 'none'
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
<Box sx={{ mt: 1, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", lineHeight: 1.1 }}>
|
<Box sx={{ mt: 1.5, textAlign: "center", display: "flex", flexDirection: "column", alignItems: "center", lineHeight: 1.1 }}>
|
||||||
<Typography variant="caption" sx={{ fontSize: "0.7rem", opacity: 0.7 }}>
|
<Typography variant="caption" sx={{ fontSize: "0.7rem", opacity: 0.8, color: 'text.primary', fontWeight: 500 }}>
|
||||||
{formatLabel(point.id, activeDataKey)}
|
{formatLabel(point.id, activeDataKey)}
|
||||||
</Typography>
|
</Typography>
|
||||||
|
|
||||||
@@ -198,7 +204,7 @@ export default function HistoryChartView(props: ViewProps) {
|
|||||||
variant="caption"
|
variant="caption"
|
||||||
sx={{
|
sx={{
|
||||||
fontSize: "0.65rem",
|
fontSize: "0.65rem",
|
||||||
color: "grey.400",
|
color: "text.disabled",
|
||||||
visibility: comparison && point.compare && activeDataKey !== "daily" ? "visible" : "hidden"
|
visibility: comparison && point.compare && activeDataKey !== "daily" ? "visible" : "hidden"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import {
|
|||||||
Divider,
|
Divider,
|
||||||
linearProgressClasses
|
linearProgressClasses
|
||||||
} from "@mui/material";
|
} from "@mui/material";
|
||||||
|
import { useTheme, alpha } from "@mui/material/styles";
|
||||||
import { ProgressCardProps } from "./ProgressCard.models";
|
import { ProgressCardProps } from "./ProgressCard.models";
|
||||||
|
|
||||||
interface ViewProps extends ProgressCardProps {
|
interface ViewProps extends ProgressCardProps {
|
||||||
@@ -23,6 +24,9 @@ export default function ProgressCardView({
|
|||||||
formattedTotal,
|
formattedTotal,
|
||||||
compact = false,
|
compact = false,
|
||||||
}: ViewProps) {
|
}: ViewProps) {
|
||||||
|
const theme = useTheme();
|
||||||
|
const isDark = theme.palette.mode === "dark";
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Paper
|
<Paper
|
||||||
elevation={compact ? 2 : 4}
|
elevation={compact ? 2 : 4}
|
||||||
@@ -30,10 +34,13 @@ export default function ProgressCardView({
|
|||||||
width: "100%",
|
width: "100%",
|
||||||
p: compact ? { xs: 2.5, md: 3 } : { xs: 3, md: 4 },
|
p: compact ? { xs: 2.5, md: 3 } : { xs: 3, md: 4 },
|
||||||
borderRadius: compact ? 3 : 4,
|
borderRadius: compact ? 3 : 4,
|
||||||
background: (theme) =>
|
background: (theme) => {
|
||||||
colorTheme === "info"
|
const baseColor = theme.palette[colorTheme]?.main || theme.palette.primary.main;
|
||||||
? "linear-gradient(135deg, #0284c7 0%, #06b6d4 100%)"
|
const lightColor = theme.palette[colorTheme]?.light || theme.palette.primary.light;
|
||||||
: `linear-gradient(135deg, ${theme.palette[colorTheme].main} 0%, ${theme.palette[colorTheme].light} 100%)`,
|
return isDark
|
||||||
|
? `linear-gradient(135deg, ${alpha(baseColor, 0.9)} 0%, ${alpha(baseColor, 0.3)} 100%)`
|
||||||
|
: `linear-gradient(135deg, ${baseColor} 0%, ${lightColor} 100%)`;
|
||||||
|
},
|
||||||
color: "#fff",
|
color: "#fff",
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
@@ -41,11 +48,12 @@ export default function ProgressCardView({
|
|||||||
justifyContent: "center",
|
justifyContent: "center",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
overflow: "hidden",
|
overflow: "hidden",
|
||||||
|
border: isDark ? "1px solid rgba(255,255,255,0.1)" : "none",
|
||||||
boxShadow: (theme) =>
|
boxShadow: (theme) =>
|
||||||
`0 ${compact ? 6 : 12}px ${compact ? 12 : 24}px -10px ${
|
`0 ${compact ? 6 : 12}px ${compact ? 12 : 24}px -10px ${
|
||||||
theme.palette.mode === "dark"
|
isDark
|
||||||
? "#000"
|
? "rgba(0,0,0,0.5)"
|
||||||
: theme.palette[colorTheme].main
|
: theme.palette[colorTheme]?.main || theme.palette.primary.main
|
||||||
}`,
|
}`,
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
@@ -53,13 +61,14 @@ export default function ProgressCardView({
|
|||||||
variant={compact ? "body2" : "subtitle1"}
|
variant={compact ? "body2" : "subtitle1"}
|
||||||
fontWeight={700}
|
fontWeight={700}
|
||||||
sx={{
|
sx={{
|
||||||
opacity: 0.9,
|
opacity: 0.95,
|
||||||
mb: compact ? 1.5 : 2,
|
mb: compact ? 1.5 : 2,
|
||||||
width: '100%',
|
width: '100%',
|
||||||
overflow: 'hidden',
|
overflow: 'hidden',
|
||||||
textOverflow: 'ellipsis',
|
textOverflow: 'ellipsis',
|
||||||
whiteSpace: 'nowrap',
|
whiteSpace: 'nowrap',
|
||||||
letterSpacing: 0.5
|
letterSpacing: 0.5,
|
||||||
|
textShadow: isDark ? '0 1px 2px rgba(0,0,0,0.3)' : 'none'
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{header}
|
{header}
|
||||||
@@ -69,7 +78,7 @@ export default function ProgressCardView({
|
|||||||
<Typography
|
<Typography
|
||||||
variant={compact ? "h5" : "h3"}
|
variant={compact ? "h5" : "h3"}
|
||||||
fontWeight={900}
|
fontWeight={900}
|
||||||
sx={{ mb: 0.5, lineHeight: 1.2 }}
|
sx={{ mb: 0.5, lineHeight: 1.2, textShadow: isDark ? '0 2px 4px rgba(0,0,0,0.3)' : 'none' }}
|
||||||
>
|
>
|
||||||
{formattedProgress}
|
{formattedProgress}
|
||||||
</Typography>
|
</Typography>
|
||||||
@@ -77,7 +86,7 @@ export default function ProgressCardView({
|
|||||||
<Divider
|
<Divider
|
||||||
sx={{
|
sx={{
|
||||||
my: 1,
|
my: 1,
|
||||||
borderColor: "rgba(255,255,255,0.4)",
|
borderColor: "rgba(255,255,255,0.25)",
|
||||||
width: "100%",
|
width: "100%",
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
@@ -85,12 +94,13 @@ export default function ProgressCardView({
|
|||||||
<Typography
|
<Typography
|
||||||
variant={compact ? "caption" : "body2"}
|
variant={compact ? "caption" : "body2"}
|
||||||
sx={{
|
sx={{
|
||||||
opacity: 0.8,
|
opacity: 0.85,
|
||||||
fontWeight: 400,
|
fontWeight: 500,
|
||||||
display: "block"
|
display: "block",
|
||||||
|
color: "rgba(255,255,255,0.9)"
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{formattedTotal}
|
of {formattedTotal}
|
||||||
</Typography>
|
</Typography>
|
||||||
</Box>
|
</Box>
|
||||||
|
|
||||||
@@ -102,11 +112,12 @@ export default function ProgressCardView({
|
|||||||
height: compact ? 6 : 10,
|
height: compact ? 6 : 10,
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
[`&.${linearProgressClasses.colorPrimary}`]: {
|
[`&.${linearProgressClasses.colorPrimary}`]: {
|
||||||
backgroundColor: "rgba(0, 0, 0, 0.2)",
|
backgroundColor: "rgba(0, 0, 0, 0.25)",
|
||||||
},
|
},
|
||||||
[`& .${linearProgressClasses.bar}`]: {
|
[`& .${linearProgressClasses.bar}`]: {
|
||||||
borderRadius: 5,
|
borderRadius: 5,
|
||||||
backgroundColor: "#fff",
|
backgroundColor: "#fff",
|
||||||
|
boxShadow: '0 0 8px rgba(255,255,255,0.4)'
|
||||||
},
|
},
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
@@ -44,16 +44,28 @@ export const configuration: DashboardConfig = {
|
|||||||
style: {
|
style: {
|
||||||
palette: {
|
palette: {
|
||||||
expense: {
|
expense: {
|
||||||
|
light: {
|
||||||
primary: "#d32f2f",
|
primary: "#d32f2f",
|
||||||
light: "#fdecea",
|
background: "#fdecea",
|
||||||
dark: "#9a0007",
|
|
||||||
text: "#b71c1c"
|
text: "#b71c1c"
|
||||||
},
|
},
|
||||||
|
dark: {
|
||||||
|
primary: "#f44336",
|
||||||
|
background: "rgba(244, 67, 54, 0.15)",
|
||||||
|
text: "#ffcdd2"
|
||||||
|
}
|
||||||
|
},
|
||||||
income: {
|
income: {
|
||||||
|
light: {
|
||||||
primary: "#2e7d32",
|
primary: "#2e7d32",
|
||||||
light: "#e8f5e9",
|
background: "#e8f5e9",
|
||||||
dark: "#1b5e20",
|
|
||||||
text: "#1b5e20"
|
text: "#1b5e20"
|
||||||
|
},
|
||||||
|
dark: {
|
||||||
|
primary: "#4caf50",
|
||||||
|
background: "rgba(76, 175, 80, 0.15)",
|
||||||
|
text: "#c8e6c9"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user