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";
|
||||
|
||||
|
||||
// REUSABLE GLASS SURFACE
|
||||
const glassSurface = {
|
||||
bg: {base: "rgba(255, 255, 255, 0.4)", _dark: "rgba(255, 255, 255, 0.04)"},
|
||||
@@ -69,8 +68,7 @@ const sidebarRecipe = defineSlotRecipe({
|
||||
root: {
|
||||
// 1. Semi-transparent backgrounds
|
||||
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%)", // colors from: https://colorhunt.co/palette/972828e45742eb7f31fcad38
|
||||
base: "linear-gradient(to bottom right, #97282880 20%, #EB7F3160 60%, #FCAD3840 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)
|
||||
const glassPanelRecipe = defineSlotRecipe({
|
||||
// 5. Dashboard Widget Card
|
||||
const widgetRecipe = defineSlotRecipe({
|
||||
slots: ["root", "header", "body"],
|
||||
|
||||
// 🧊 THE GLASS MATH (Applies to everything)
|
||||
base: {
|
||||
root: {
|
||||
display: "flex",
|
||||
flexDirection: "column",
|
||||
position: "relative",
|
||||
...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: {
|
||||
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: {
|
||||
editing: {
|
||||
root: {
|
||||
@@ -549,9 +342,108 @@ const glassPanelRecipe = defineSlotRecipe({
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
defaultVariants: {
|
||||
layout: "widget",
|
||||
// 6. TRUE POPOVER: Compact floating card for 3-dots menus
|
||||
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: {
|
||||
header: headerRecipe,
|
||||
sidebar: sidebarRecipe,
|
||||
glassPanel: glassPanelRecipe,
|
||||
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