Refactor theme.js to split components out more.
This commit is contained in:
+133
-239
@@ -1,6 +1,5 @@
|
|||||||
import {defineSlotRecipe, createSystem, defaultConfig, defineConfig, defineRecipe} from "@chakra-ui/react";
|
import {defineSlotRecipe, createSystem, defaultConfig, defineConfig, defineRecipe} from "@chakra-ui/react";
|
||||||
|
|
||||||
|
|
||||||
// REUSABLE GLASS SURFACE
|
// REUSABLE GLASS SURFACE
|
||||||
const glassSurface = {
|
const glassSurface = {
|
||||||
bg: {base: "rgba(255, 255, 255, 0.4)", _dark: "rgba(255, 255, 255, 0.04)"},
|
bg: {base: "rgba(255, 255, 255, 0.4)", _dark: "rgba(255, 255, 255, 0.04)"},
|
||||||
@@ -69,8 +68,7 @@ const sidebarRecipe = defineSlotRecipe({
|
|||||||
root: {
|
root: {
|
||||||
// 1. Semi-transparent backgrounds
|
// 1. Semi-transparent backgrounds
|
||||||
bg: {
|
bg: {
|
||||||
// base: "linear-gradient(to bottom right, #99000040 20%, #FF660040 60%, #EEEE0040 100%)", // this is too pale for light mode imo
|
base: "linear-gradient(to bottom right, #97282880 20%, #EB7F3160 60%, #FCAD3840 100%)",
|
||||||
base: "linear-gradient(to bottom right, #97282880 20%, #EB7F3160 60%, #FCAD3840 100%)", // colors from: https://colorhunt.co/palette/972828e45742eb7f31fcad38
|
|
||||||
_dark: "linear-gradient(to bottom right, #9900003C 20%, #FF66003C 60%, #FFC0003C 100%)"
|
_dark: "linear-gradient(to bottom right, #9900003C 20%, #FF66003C 60%, #FFC0003C 100%)"
|
||||||
},
|
},
|
||||||
|
|
||||||
@@ -295,248 +293,43 @@ const homeRecipe = defineSlotRecipe({
|
|||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
// 5. Glass Panel Surfaces (Separated: Widget, Dropdown, Popover, Dialog)
|
// 5. Dashboard Widget Card
|
||||||
const glassPanelRecipe = defineSlotRecipe({
|
const widgetRecipe = defineSlotRecipe({
|
||||||
slots: ["root", "header", "body"],
|
slots: ["root", "header", "body"],
|
||||||
|
|
||||||
// 🧊 THE GLASS MATH (Applies to everything)
|
|
||||||
base: {
|
base: {
|
||||||
root: {
|
root: {
|
||||||
display: "flex",
|
display: "flex",
|
||||||
flexDirection: "column",
|
flexDirection: "column",
|
||||||
position: "relative",
|
position: "relative",
|
||||||
...glassSurface,
|
...glassSurface,
|
||||||
|
width: "100%",
|
||||||
|
height: "100%",
|
||||||
|
borderRadius: "3xl",
|
||||||
|
overflow: "hidden",
|
||||||
},
|
},
|
||||||
|
header: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
px: 3,
|
||||||
|
pt: 2,
|
||||||
|
pb: 0,
|
||||||
|
"& > p": {
|
||||||
|
color: "titleColor",
|
||||||
|
fontWeight: "500",
|
||||||
|
fontSize: "16px",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
overflow: "hidden",
|
||||||
|
textOverflow: "clip",
|
||||||
|
},
|
||||||
|
"& > button": {
|
||||||
|
borderRadius: "xl",
|
||||||
|
_hover: {color: "white", bg: "gray.500"},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
body: {flex: "1", overflow: "hidden", position: "relative", px: 1, pb: 1, pt: 0},
|
||||||
},
|
},
|
||||||
|
|
||||||
// 📏 THE LAYOUTS (Applies selectively)
|
|
||||||
variants: {
|
variants: {
|
||||||
layout: {
|
|
||||||
// Dashboard Widget Card
|
|
||||||
widget: {
|
|
||||||
root: {
|
|
||||||
width: "100%",
|
|
||||||
height: "100%",
|
|
||||||
borderRadius: "3xl",
|
|
||||||
overflow: "hidden",
|
|
||||||
},
|
|
||||||
header: {
|
|
||||||
display: "flex",
|
|
||||||
justifyContent: "space-between",
|
|
||||||
alignItems: "center",
|
|
||||||
px: 3,
|
|
||||||
pt: 2,
|
|
||||||
pb: 0,
|
|
||||||
|
|
||||||
"& > p": {
|
|
||||||
color: "titleColor",
|
|
||||||
fontWeight: "500",
|
|
||||||
fontSize: "16px",
|
|
||||||
|
|
||||||
// the following three specifications are equivalent to Chakra's 'truncate' prop
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
overflow: "hidden",
|
|
||||||
textOverflow: "clip",
|
|
||||||
},
|
|
||||||
|
|
||||||
"& > button": {
|
|
||||||
borderRadius: "xl",
|
|
||||||
|
|
||||||
_hover: {
|
|
||||||
color: "white",
|
|
||||||
bg: "gray.500",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
body: {
|
|
||||||
flex: "1",
|
|
||||||
overflow: "hidden",
|
|
||||||
position: "relative",
|
|
||||||
px: 1,
|
|
||||||
pb: 1,
|
|
||||||
pt: 0,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
dropdown: {
|
|
||||||
root: {
|
|
||||||
borderRadius: "xl",
|
|
||||||
p: 1,
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// 🎯 TRUE POPOVER: Compact floating card for Widget Settings (3-dots menu)
|
|
||||||
popover: {
|
|
||||||
root: {
|
|
||||||
borderRadius: "xl",
|
|
||||||
p: 3,
|
|
||||||
boxShadow: "lg",
|
|
||||||
bg: {
|
|
||||||
base: "rgba(255, 255, 255, 0.85)",
|
|
||||||
_dark: "rgba(20, 22, 25, 0.85)",
|
|
||||||
},
|
|
||||||
backdropFilter: "blur(15px)",
|
|
||||||
WebkitBackdropFilter: "blur(15px)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// 🎯 MODAL DIALOG: Large view for the Widget Shop
|
|
||||||
dialog: {
|
|
||||||
root: {
|
|
||||||
borderRadius: "2xl",
|
|
||||||
p: 2,
|
|
||||||
boxShadow: "xl",
|
|
||||||
minW: "240px",
|
|
||||||
maxW: "60%",
|
|
||||||
minH: "80%",
|
|
||||||
overflow: "hidden",
|
|
||||||
// OVERRIDES: Make the background 85-90% opaque instead of 40%
|
|
||||||
bg: {
|
|
||||||
base: "rgba(255, 255, 255, 0.75)",
|
|
||||||
_dark: "rgba(20, 22, 25, 0.8)"
|
|
||||||
},
|
|
||||||
|
|
||||||
// OVERRIDES: Increase the blur just to smooth out any stubborn gridlines
|
|
||||||
backdropFilter: "blur(15px)",
|
|
||||||
WebkitBackdropFilter: "blur(15px)",
|
|
||||||
|
|
||||||
|
|
||||||
// IMPORTANT: everything below is specific to the widget menu found in the settingsButton component
|
|
||||||
// dialog header
|
|
||||||
"& > div.chakra-dialog__header": {
|
|
||||||
bg: "transparent",
|
|
||||||
color: {
|
|
||||||
base: "gray.800",
|
|
||||||
_dark: "white"
|
|
||||||
},
|
|
||||||
py: 4,
|
|
||||||
borderColor: {
|
|
||||||
base: "gray.200",
|
|
||||||
_dark: "whiteAlpha.200"
|
|
||||||
},
|
|
||||||
|
|
||||||
// title
|
|
||||||
"& h2": {
|
|
||||||
fontSize: "xl",
|
|
||||||
fontWeight: "bold"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
// Dialog Body (Category Tabs & Masked Navigators)
|
|
||||||
"& > div.chakra-dialog__body": {
|
|
||||||
p: 0,
|
|
||||||
|
|
||||||
// box container of the widget category menu
|
|
||||||
"& div.chakra-tabs__root > div:first-child": {
|
|
||||||
position: "relative",
|
|
||||||
display: "flex",
|
|
||||||
maxW: "100%",
|
|
||||||
mx: 5,
|
|
||||||
mt: 4,
|
|
||||||
mb: 6
|
|
||||||
},
|
|
||||||
|
|
||||||
// the horizontal widget categories menu
|
|
||||||
"& div.chakra-tabs__list": {
|
|
||||||
bg: {
|
|
||||||
base: "rgba(0, 0, 0, 0.04)",
|
|
||||||
_dark: "rgba(255, 255, 255, 0.05)"
|
|
||||||
},
|
|
||||||
p: 1,
|
|
||||||
borderRadius: "full",
|
|
||||||
display: "flex",
|
|
||||||
flexWrap: "nowrap",
|
|
||||||
overflowX: "auto",
|
|
||||||
maxW: "100%",
|
|
||||||
border: "1px solid",
|
|
||||||
borderColor: {
|
|
||||||
base: "blackAlpha.50",
|
|
||||||
_dark: "whiteAlpha.100"
|
|
||||||
},
|
|
||||||
scrollbarWidth: "none",
|
|
||||||
"&::-webkit-scrollbar": {display: "none"},
|
|
||||||
|
|
||||||
// the pill shaped menu options
|
|
||||||
"& button.chakra-tabs__trigger": {
|
|
||||||
px: 5,
|
|
||||||
py: 2,
|
|
||||||
borderRadius: "full",
|
|
||||||
whiteSpace: "nowrap",
|
|
||||||
flexShrink: 0,
|
|
||||||
color: {
|
|
||||||
base: "gray.500",
|
|
||||||
_dark: "gray.400"
|
|
||||||
},
|
|
||||||
fontWeight: "medium",
|
|
||||||
transition: "background-color 0.2s, color 0.2s, box-shadow 0.2s",
|
|
||||||
_hover: {
|
|
||||||
color: {
|
|
||||||
base: "gray.800",
|
|
||||||
_dark: "gray.200"
|
|
||||||
},
|
|
||||||
},
|
|
||||||
_selected: {
|
|
||||||
bg: {
|
|
||||||
base: "white",
|
|
||||||
_dark: "rgba(255, 255, 255, 0.12)"
|
|
||||||
},
|
|
||||||
color: {
|
|
||||||
base: "blue.600",
|
|
||||||
_dark: "blue.200"
|
|
||||||
},
|
|
||||||
boxShadow: "sm",
|
|
||||||
fontWeight: "bold",
|
|
||||||
}
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
// base styling applied to both chevron navigators
|
|
||||||
"& div.chakra-tabs__root > div:first-child div:has(svg)": {
|
|
||||||
position: "absolute",
|
|
||||||
top: "0",
|
|
||||||
bottom: "0",
|
|
||||||
w: "50px",
|
|
||||||
alignItems: "center",
|
|
||||||
justifyContent: "center",
|
|
||||||
zIndex: 2,
|
|
||||||
cursor: "pointer",
|
|
||||||
bg: {
|
|
||||||
base: "rgba(255, 255, 255, 0.7)",
|
|
||||||
_dark: "rgba(30, 30, 30, 0.8)",
|
|
||||||
},
|
|
||||||
color: { base: "gray.600", _dark: "gray.300" },
|
|
||||||
backdropFilter: "blur(1px)",
|
|
||||||
transition: "background-color 0.2s",
|
|
||||||
|
|
||||||
_hover: {
|
|
||||||
color: { base: "blue.500", _dark: "blue.300" },
|
|
||||||
bg: {
|
|
||||||
base: "rgba(255, 255, 255, 0.9)",
|
|
||||||
_dark: "rgba(40, 40, 40, 0.95)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
|
|
||||||
"&:has(.lucide-chevron-left)": {
|
|
||||||
left: 0,
|
|
||||||
borderTopLeftRadius: "full",
|
|
||||||
borderBottomLeftRadius: "full",
|
|
||||||
// Bites a transparent circle out of the flat right side!
|
|
||||||
WebkitMaskImage: "radial-gradient(circle at 100% 50%, transparent 30px, black 19px)",
|
|
||||||
maskImage: "radial-gradient(circle at 100% 50%, transparent 30px, black 35px)",
|
|
||||||
},
|
|
||||||
|
|
||||||
"&:has(.lucide-chevron-right)": {
|
|
||||||
right: 0,
|
|
||||||
borderTopRightRadius: "full",
|
|
||||||
borderBottomRightRadius: "full",
|
|
||||||
// THE MAGIC: Bites a transparent circle out of the flat left side!
|
|
||||||
WebkitMaskImage: "radial-gradient(circle at 0% 50%, transparent 30px, black 19px)",
|
|
||||||
maskImage: "radial-gradient(circle at 0% 50%, transparent 30px, black 35px)",
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
},
|
|
||||||
mode: {
|
mode: {
|
||||||
editing: {
|
editing: {
|
||||||
root: {
|
root: {
|
||||||
@@ -549,9 +342,108 @@ const glassPanelRecipe = defineSlotRecipe({
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
});
|
||||||
|
|
||||||
defaultVariants: {
|
// 6. TRUE POPOVER: Compact floating card for 3-dots menus
|
||||||
layout: "widget",
|
const glassPopoverRecipe = defineSlotRecipe({
|
||||||
|
slots: ["content", "arrow", "positioner"],
|
||||||
|
base: {
|
||||||
|
content: {
|
||||||
|
...glassSurface,
|
||||||
|
borderRadius: "xl",
|
||||||
|
p: 3,
|
||||||
|
boxShadow: "lg",
|
||||||
|
bg: {base: "rgba(255, 255, 255, 0.85)", _dark: "rgba(20, 22, 25, 0.85)"},
|
||||||
|
backdropFilter: "blur(15px)",
|
||||||
|
WebkitBackdropFilter: "blur(15px)",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
// 7. MODAL DIALOG: Large view for the Widget Shop
|
||||||
|
const glassDialogRecipe = defineSlotRecipe({
|
||||||
|
slots: ["content", "header", "body", "backdrop"],
|
||||||
|
base: {
|
||||||
|
backdrop: {
|
||||||
|
bg: "rgba(0, 0, 0, 0.4)",
|
||||||
|
backdropFilter: "blur(4px)",
|
||||||
|
WebkitBackdropFilter: "blur(4px)",
|
||||||
|
},
|
||||||
|
content: {
|
||||||
|
display: "flex",
|
||||||
|
flexDirection: "column",
|
||||||
|
position: "relative",
|
||||||
|
...glassSurface,
|
||||||
|
borderRadius: "2xl",
|
||||||
|
p: 2,
|
||||||
|
boxShadow: "xl",
|
||||||
|
minW: "240px",
|
||||||
|
maxW: "60%",
|
||||||
|
minH: "80%",
|
||||||
|
overflow: "hidden",
|
||||||
|
bg: {base: "rgba(255, 255, 255, 0.75)", _dark: "rgba(20, 22, 25, 0.8)"},
|
||||||
|
backdropFilter: "blur(15px)",
|
||||||
|
WebkitBackdropFilter: "blur(15px)",
|
||||||
|
},
|
||||||
|
header: {
|
||||||
|
bg: "transparent",
|
||||||
|
color: {base: "gray.800", _dark: "white"},
|
||||||
|
py: 4,
|
||||||
|
borderColor: {base: "gray.200", _dark: "whiteAlpha.200"},
|
||||||
|
"& h2": {fontSize: "xl", fontWeight: "bold"},
|
||||||
|
},
|
||||||
|
body: {
|
||||||
|
p: 0,
|
||||||
|
"& div.chakra-tabs__root > div:first-child": {
|
||||||
|
position: "relative",
|
||||||
|
display: "flex",
|
||||||
|
maxW: "100%",
|
||||||
|
mx: 5,
|
||||||
|
mt: 4,
|
||||||
|
mb: 6
|
||||||
|
},
|
||||||
|
"& div.chakra-tabs__list": {
|
||||||
|
bg: {base: "rgba(0, 0, 0, 0.04)", _dark: "rgba(255, 255, 255, 0.05)"},
|
||||||
|
p: 1, borderRadius: "full", display: "flex", flexWrap: "nowrap", overflowX: "auto", maxW: "100%",
|
||||||
|
border: "1px solid", borderColor: {base: "blackAlpha.50", _dark: "whiteAlpha.100"},
|
||||||
|
scrollbarWidth: "none", "&::-webkit-scrollbar": {display: "none"},
|
||||||
|
"& button.chakra-tabs__trigger": {
|
||||||
|
px: 5, py: 2, borderRadius: "full", whiteSpace: "nowrap", flexShrink: 0,
|
||||||
|
color: {base: "gray.500", _dark: "gray.400"},
|
||||||
|
fontWeight: "medium", transition: "background-color 0.2s, color 0.2s, box-shadow 0.2s",
|
||||||
|
_hover: {color: {base: "gray.800", _dark: "gray.200"}},
|
||||||
|
_selected: {
|
||||||
|
bg: {base: "white", _dark: "rgba(255, 255, 255, 0.12)"},
|
||||||
|
color: {base: "blue.600", _dark: "blue.200"},
|
||||||
|
boxShadow: "sm",
|
||||||
|
fontWeight: "bold"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"& div.chakra-tabs__root > div:first-child div:has(svg)": {
|
||||||
|
position: "absolute", top: "0", bottom: "0", w: "50px", alignItems: "center", justifyContent: "center",
|
||||||
|
zIndex: 2, cursor: "pointer", bg: {base: "rgba(255, 255, 255, 0.7)", _dark: "rgba(30, 30, 30, 0.8)"},
|
||||||
|
color: {base: "gray.600", _dark: "gray.300"}, backdropFilter: "blur(1px)", transition: "background-color 0.2s",
|
||||||
|
_hover: {
|
||||||
|
color: {base: "blue.500", _dark: "blue.300"},
|
||||||
|
bg: {base: "rgba(255, 255, 255, 0.9)", _dark: "rgba(40, 40, 40, 0.95)"}
|
||||||
|
},
|
||||||
|
"&:has(.lucide-chevron-left)": {
|
||||||
|
left: 0,
|
||||||
|
borderTopLeftRadius: "full",
|
||||||
|
borderBottomLeftRadius: "full",
|
||||||
|
WebkitMaskImage: "radial-gradient(circle at 100% 50%, transparent 30px, black 19px)",
|
||||||
|
maskImage: "radial-gradient(circle at 100% 50%, transparent 30px, black 35px)"
|
||||||
|
},
|
||||||
|
"&:has(.lucide-chevron-right)": {
|
||||||
|
right: 0,
|
||||||
|
borderTopRightRadius: "full",
|
||||||
|
borderBottomRightRadius: "full",
|
||||||
|
WebkitMaskImage: "radial-gradient(circle at 0% 50%, transparent 30px, black 19px)",
|
||||||
|
maskImage: "radial-gradient(circle at 0% 50%, transparent 30px, black 35px)"
|
||||||
|
},
|
||||||
|
},
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -694,10 +586,12 @@ const config = defineConfig({
|
|||||||
slotRecipes: {
|
slotRecipes: {
|
||||||
header: headerRecipe,
|
header: headerRecipe,
|
||||||
sidebar: sidebarRecipe,
|
sidebar: sidebarRecipe,
|
||||||
glassPanel: glassPanelRecipe,
|
|
||||||
home: homeRecipe,
|
home: homeRecipe,
|
||||||
|
widget: widgetRecipe,
|
||||||
|
glassPopover: glassPopoverRecipe,
|
||||||
|
glassDialog: glassDialogRecipe,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
export const system = createSystem(defaultConfig, config);
|
export const system = createSystem(defaultConfig, config);
|
||||||
Reference in New Issue
Block a user