diff --git a/src/admin/pages/InvoiceDetail.tsx b/src/admin/pages/InvoiceDetail.tsx
index a767590..ccebc2c 100644
--- a/src/admin/pages/InvoiceDetail.tsx
+++ b/src/admin/pages/InvoiceDetail.tsx
@@ -1140,7 +1140,11 @@ export default function InvoiceDetail() {
)}
{hasPermission("invoices.delete") && (
-
))}
{hasPermission("invoices.delete") && (
- setDeleteConfirm(true)} color="error">
+ setDeleteConfirm(true)}
+ variant="outlined"
+ color="error"
+ >
Smazat
)}
diff --git a/src/admin/pages/OfferDetail.tsx b/src/admin/pages/OfferDetail.tsx
index 96fc44a..c45780c 100644
--- a/src/admin/pages/OfferDetail.tsx
+++ b/src/admin/pages/OfferDetail.tsx
@@ -1184,7 +1184,11 @@ export default function OfferDetail() {
)}
{isEdit && hasPermission("offers.delete") && (
- setDeleteConfirm(true)} color="error">
+ setDeleteConfirm(true)}
+ variant="outlined"
+ color="error"
+ >
Smazat
)}
diff --git a/src/admin/pages/WarehouseInventory.tsx b/src/admin/pages/WarehouseInventory.tsx
index c15a8b8..9509950 100644
--- a/src/admin/pages/WarehouseInventory.tsx
+++ b/src/admin/pages/WarehouseInventory.tsx
@@ -157,7 +157,7 @@ export default function WarehouseInventory() {
/>
{statusFilter && (
-
+
Zrušit filtry
)}
diff --git a/src/admin/pages/WarehouseIssues.tsx b/src/admin/pages/WarehouseIssues.tsx
index 88e3ffb..30c6bb3 100644
--- a/src/admin/pages/WarehouseIssues.tsx
+++ b/src/admin/pages/WarehouseIssues.tsx
@@ -248,7 +248,7 @@ export default function WarehouseIssues() {
/>
{hasActiveFilters && (
-
+
Zrušit filtry
)}
diff --git a/src/admin/pages/WarehouseReceipts.tsx b/src/admin/pages/WarehouseReceipts.tsx
index ab56396..840bf53 100644
--- a/src/admin/pages/WarehouseReceipts.tsx
+++ b/src/admin/pages/WarehouseReceipts.tsx
@@ -247,7 +247,7 @@ export default function WarehouseReceipts() {
/>
{hasActiveFilters && (
-
+
Zrušit filtry
)}
diff --git a/src/admin/pages/WarehouseReservations.tsx b/src/admin/pages/WarehouseReservations.tsx
index 5ea3ba6..8827fdb 100644
--- a/src/admin/pages/WarehouseReservations.tsx
+++ b/src/admin/pages/WarehouseReservations.tsx
@@ -376,7 +376,7 @@ export default function WarehouseReservations() {
)}
{hasActiveFilters && (
-
+
Zrušit filtry
)}
diff --git a/src/admin/theme.ts b/src/admin/theme.ts
index a340268..d5e5a99 100644
--- a/src/admin/theme.ts
+++ b/src/admin/theme.ts
@@ -7,6 +7,19 @@ const FONT_MONO = "'DM Mono', Menlo, monospace";
// Standard Material easing (matches the legacy --transition cubic-bezier).
const EASE = "cubic-bezier(0.4, 0, 0.2, 1)";
+// Dark-mode fills for FILLED colored surfaces (contained buttons, filled chips,
+// StatCard badges). The palette .main stays BRIGHT in dark mode (it drives text,
+// outlined buttons and row tints), but a bright fill makes WHITE text/glyphs
+// illegible — so filled surfaces drop to these darker shades (≈ the light-scheme
+// values) in dark mode. One rule everywhere: filled colored = white text,
+// readable in both themes. Light mode needs no override (its .main is dark).
+export const FILLED_DARK_BG = {
+ error: { bg: "#dc2626", hover: "#b91c1c" },
+ success: { bg: "#15803d", hover: "#166534" },
+ warning: { bg: "#b45309", hover: "#92400e" },
+ info: { bg: "#1d4ed8", hover: "#1e40af" },
+} as const;
+
export const theme = createTheme({
cssVariables: {
colorSchemeSelector: "[data-theme='%s']",
@@ -80,6 +93,47 @@ export const theme = createTheme({
},
"&:active": { transform: "translateY(0) scale(0.97)" },
},
+ // Filled colored buttons: WHITE text in BOTH themes (was per-scheme
+ // contrastText → near-black text on colored fills in dark mode, which
+ // also clashed with the always-white primary — "black text on one red
+ // button, white on another"). In dark mode the fill drops to a darker
+ // shade so white stays legible.
+ containedError: ({ theme }) => ({
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ "&:not(.Mui-disabled)": {
+ backgroundColor: FILLED_DARK_BG.error.bg,
+ "&:hover": { backgroundColor: FILLED_DARK_BG.error.hover },
+ },
+ }),
+ }),
+ containedSuccess: ({ theme }) => ({
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ "&:not(.Mui-disabled)": {
+ backgroundColor: FILLED_DARK_BG.success.bg,
+ "&:hover": { backgroundColor: FILLED_DARK_BG.success.hover },
+ },
+ }),
+ }),
+ containedWarning: ({ theme }) => ({
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ "&:not(.Mui-disabled)": {
+ backgroundColor: FILLED_DARK_BG.warning.bg,
+ "&:hover": { backgroundColor: FILLED_DARK_BG.warning.hover },
+ },
+ }),
+ }),
+ containedInfo: ({ theme }) => ({
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ "&:not(.Mui-disabled)": {
+ backgroundColor: FILLED_DARK_BG.info.bg,
+ "&:hover": { backgroundColor: FILLED_DARK_BG.info.hover },
+ },
+ }),
+ }),
},
},
MuiCard: {
@@ -99,6 +153,54 @@ export const theme = createTheme({
fontWeight: 700,
transition: `background-color 200ms ${EASE}, box-shadow 200ms ${EASE}`,
},
+ // Filled colored chips follow the same rule as filled buttons: white
+ // label in both themes, darker fill in dark mode so white stays legible.
+ // (Chip has no per-color `filledX` key, so target the color class and
+ // scope to the filled variant.)
+ colorError: ({ theme }) => ({
+ "&.MuiChip-filled": {
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ backgroundColor: FILLED_DARK_BG.error.bg,
+ "&.MuiChip-clickable:hover": {
+ backgroundColor: FILLED_DARK_BG.error.hover,
+ },
+ }),
+ },
+ }),
+ colorSuccess: ({ theme }) => ({
+ "&.MuiChip-filled": {
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ backgroundColor: FILLED_DARK_BG.success.bg,
+ "&.MuiChip-clickable:hover": {
+ backgroundColor: FILLED_DARK_BG.success.hover,
+ },
+ }),
+ },
+ }),
+ colorWarning: ({ theme }) => ({
+ "&.MuiChip-filled": {
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ backgroundColor: FILLED_DARK_BG.warning.bg,
+ "&.MuiChip-clickable:hover": {
+ backgroundColor: FILLED_DARK_BG.warning.hover,
+ },
+ }),
+ },
+ }),
+ colorInfo: ({ theme }) => ({
+ "&.MuiChip-filled": {
+ color: "#fff",
+ ...theme.applyStyles("dark", {
+ backgroundColor: FILLED_DARK_BG.info.bg,
+ "&.MuiChip-clickable:hover": {
+ backgroundColor: FILLED_DARK_BG.info.hover,
+ },
+ }),
+ },
+ }),
},
},
MuiOutlinedInput: {
diff --git a/src/admin/ui/StatCard.tsx b/src/admin/ui/StatCard.tsx
index ec9cdaa..ff5d55a 100644
--- a/src/admin/ui/StatCard.tsx
+++ b/src/admin/ui/StatCard.tsx
@@ -2,6 +2,7 @@ import type { ReactNode } from "react";
import Box from "@mui/material/Box";
import Typography from "@mui/material/Typography";
import Card from "./Card";
+import { FILLED_DARK_BG } from "../theme";
export type StatCardColor =
| "default"
@@ -31,16 +32,19 @@ export default function StatCard({
footer,
}: StatCardProps) {
// Solid tile + white glyph: high-contrast in both themes (the old light tint
- // left the icon dark/low-visibility, esp. for the default variant).
+ // left the icon dark/low-visibility, esp. for the default variant). In dark
+ // mode the bright .main fill is darkened (same rule as filled buttons/chips)
+ // so the white glyph stays legible on success/warning/info/error tiles.
const iconBg = color === "default" ? "grey.600" : `${color}.main`;
- const iconColor = "common.white";
+ const iconDarkBg = (FILLED_DARK_BG as Record)[color]
+ ?.bg;
return (
{icon && (
({
display: "flex",
alignItems: "center",
justifyContent: "center",
@@ -48,9 +52,12 @@ export default function StatCard({
height: 40,
borderRadius: 2,
bgcolor: iconBg,
- color: iconColor,
+ color: "common.white",
flexShrink: 0,
- }}
+ ...(iconDarkBg
+ ? theme.applyStyles("dark", { backgroundColor: iconDarkBg })
+ : {}),
+ })}
>
{icon}