@salesmind-ai/design-system 0.3.0 → 0.3.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +32 -2
- package/dist/admin/index.cjs +68 -2928
- package/dist/admin/index.cjs.map +1 -1
- package/dist/admin/index.js +5 -2915
- package/dist/admin/index.js.map +1 -1
- package/dist/blog/index.cjs +53 -1064
- package/dist/blog/index.cjs.map +1 -1
- package/dist/blog/index.js +8 -1054
- package/dist/blog/index.js.map +1 -1
- package/dist/charts/index.cjs +46 -2694
- package/dist/charts/index.cjs.map +1 -1
- package/dist/charts/index.js +3 -2680
- package/dist/charts/index.js.map +1 -1
- package/dist/chunk-2GARWEJK.js +17 -0
- package/dist/chunk-2GARWEJK.js.map +1 -0
- package/dist/chunk-3NKRFUAR.js +37 -0
- package/dist/chunk-3NKRFUAR.js.map +1 -0
- package/dist/chunk-3TGSIILM.cjs +201 -0
- package/dist/chunk-3TGSIILM.cjs.map +1 -0
- package/dist/chunk-4GM5BGBN.cjs +801 -0
- package/dist/chunk-4GM5BGBN.cjs.map +1 -0
- package/dist/chunk-5LGDEZWY.cjs +2434 -0
- package/dist/chunk-5LGDEZWY.cjs.map +1 -0
- package/dist/chunk-6H4DSTXR.js +786 -0
- package/dist/chunk-6H4DSTXR.js.map +1 -0
- package/dist/chunk-6UNG76Y2.js +153 -0
- package/dist/chunk-6UNG76Y2.js.map +1 -0
- package/dist/chunk-7PX2AZ6Y.js +39 -0
- package/dist/chunk-7PX2AZ6Y.js.map +1 -0
- package/dist/chunk-B6AVAX4F.js +1415 -0
- package/dist/chunk-B6AVAX4F.js.map +1 -0
- package/dist/chunk-BILT5KD3.js +264 -0
- package/dist/chunk-BILT5KD3.js.map +1 -0
- package/dist/chunk-C2BCDNAV.js +24 -0
- package/dist/chunk-C2BCDNAV.js.map +1 -0
- package/dist/chunk-CH42VPWE.cjs +421 -0
- package/dist/chunk-CH42VPWE.cjs.map +1 -0
- package/dist/chunk-CJ2MKVAF.cjs +46 -0
- package/dist/chunk-CJ2MKVAF.cjs.map +1 -0
- package/dist/chunk-DP74LUXG.cjs +98 -0
- package/dist/chunk-DP74LUXG.cjs.map +1 -0
- package/dist/chunk-E7D6EKJ4.cjs +44 -0
- package/dist/chunk-E7D6EKJ4.cjs.map +1 -0
- package/dist/chunk-ECXBTUH6.cjs +584 -0
- package/dist/chunk-ECXBTUH6.cjs.map +1 -0
- package/dist/chunk-EFRAP5ES.js +157 -0
- package/dist/chunk-EFRAP5ES.js.map +1 -0
- package/dist/chunk-F6YYWMME.js +485 -0
- package/dist/chunk-F6YYWMME.js.map +1 -0
- package/dist/chunk-FAFAP4L5.js +183 -0
- package/dist/chunk-FAFAP4L5.js.map +1 -0
- package/dist/chunk-GUZIMHWS.js +1608 -0
- package/dist/chunk-GUZIMHWS.js.map +1 -0
- package/dist/chunk-H2Y6BSTL.cjs +69 -0
- package/dist/chunk-H2Y6BSTL.cjs.map +1 -0
- package/dist/chunk-HN4PHABT.js +126 -0
- package/dist/chunk-HN4PHABT.js.map +1 -0
- package/dist/chunk-HRENHNDJ.js +211 -0
- package/dist/chunk-HRENHNDJ.js.map +1 -0
- package/dist/chunk-I75BFEYT.cjs +2561 -0
- package/dist/chunk-I75BFEYT.cjs.map +1 -0
- package/dist/chunk-IFRATNLU.js +562 -0
- package/dist/chunk-IFRATNLU.js.map +1 -0
- package/dist/chunk-IYPXJ6YC.cjs +69 -0
- package/dist/chunk-IYPXJ6YC.cjs.map +1 -0
- package/dist/chunk-JPJN4YBC.js +409 -0
- package/dist/chunk-JPJN4YBC.js.map +1 -0
- package/dist/chunk-KBA2LFBG.js +62 -0
- package/dist/chunk-KBA2LFBG.js.map +1 -0
- package/dist/chunk-KCKUSU2M.cjs +166 -0
- package/dist/chunk-KCKUSU2M.cjs.map +1 -0
- package/dist/chunk-KJ2OXQF4.js +287 -0
- package/dist/chunk-KJ2OXQF4.js.map +1 -0
- package/dist/chunk-KNQEIU7O.cjs +1202 -0
- package/dist/chunk-KNQEIU7O.cjs.map +1 -0
- package/dist/chunk-KVGSVGRK.cjs +569 -0
- package/dist/chunk-KVGSVGRK.cjs.map +1 -0
- package/dist/chunk-L352JRV6.cjs +105 -0
- package/dist/chunk-L352JRV6.cjs.map +1 -0
- package/dist/chunk-LJADZITX.cjs +298 -0
- package/dist/chunk-LJADZITX.cjs.map +1 -0
- package/dist/chunk-LMJPWXTZ.cjs +194 -0
- package/dist/chunk-LMJPWXTZ.cjs.map +1 -0
- package/dist/chunk-LOWEAQST.js +701 -0
- package/dist/chunk-LOWEAQST.js.map +1 -0
- package/dist/chunk-MDB2WCRQ.cjs +137 -0
- package/dist/chunk-MDB2WCRQ.cjs.map +1 -0
- package/dist/chunk-MQDEE7HC.cjs +283 -0
- package/dist/chunk-MQDEE7HC.cjs.map +1 -0
- package/dist/chunk-MQRB634A.cjs +34 -0
- package/dist/chunk-MQRB634A.cjs.map +1 -0
- package/dist/chunk-MTI27RDV.js +185 -0
- package/dist/chunk-MTI27RDV.js.map +1 -0
- package/dist/chunk-MU6GW5ZV.js +2317 -0
- package/dist/chunk-MU6GW5ZV.js.map +1 -0
- package/dist/chunk-NN3TUHIH.js +28 -0
- package/dist/chunk-NN3TUHIH.js.map +1 -0
- package/dist/chunk-NT4LBP7D.cjs +111 -0
- package/dist/chunk-NT4LBP7D.cjs.map +1 -0
- package/dist/chunk-OLV7OD3X.cjs +502 -0
- package/dist/chunk-OLV7OD3X.cjs.map +1 -0
- package/dist/chunk-OXNXEQY7.js +2538 -0
- package/dist/chunk-OXNXEQY7.js.map +1 -0
- package/dist/chunk-P5BOFE5A.js +546 -0
- package/dist/chunk-P5BOFE5A.js.map +1 -0
- package/dist/chunk-Q2MFGYTE.cjs +1449 -0
- package/dist/chunk-Q2MFGYTE.cjs.map +1 -0
- package/dist/chunk-Q75DBVDY.cjs +68 -0
- package/dist/chunk-Q75DBVDY.cjs.map +1 -0
- package/dist/chunk-REQ5Q6ZI.js +1022 -0
- package/dist/chunk-REQ5Q6ZI.js.map +1 -0
- package/dist/chunk-SICKWUWB.js +62 -0
- package/dist/chunk-SICKWUWB.js.map +1 -0
- package/dist/chunk-T343CCH5.js +1190 -0
- package/dist/chunk-T343CCH5.js.map +1 -0
- package/dist/chunk-TEC62D4A.cjs +1624 -0
- package/dist/chunk-TEC62D4A.cjs.map +1 -0
- package/dist/chunk-TW5JB35D.js +2122 -0
- package/dist/chunk-TW5JB35D.js.map +1 -0
- package/dist/chunk-VC5LMUVQ.cjs +20 -0
- package/dist/chunk-VC5LMUVQ.cjs.map +1 -0
- package/dist/chunk-VM7WFMKI.cjs +76 -0
- package/dist/chunk-VM7WFMKI.cjs.map +1 -0
- package/dist/chunk-W2WTP6HS.cjs +233 -0
- package/dist/chunk-W2WTP6HS.cjs.map +1 -0
- package/dist/chunk-WH7PYHZY.cjs +35 -0
- package/dist/chunk-WH7PYHZY.cjs.map +1 -0
- package/dist/chunk-XQZVY7JJ.cjs +717 -0
- package/dist/chunk-XQZVY7JJ.cjs.map +1 -0
- package/dist/chunk-XU3OMQ7V.js +98 -0
- package/dist/chunk-XU3OMQ7V.js.map +1 -0
- package/dist/chunk-XWPDRMZG.js +62 -0
- package/dist/chunk-XWPDRMZG.js.map +1 -0
- package/dist/chunk-Y3CPKNB7.js +67 -0
- package/dist/chunk-Y3CPKNB7.js.map +1 -0
- package/dist/chunk-YNVRDD2P.js +98 -0
- package/dist/chunk-YNVRDD2P.js.map +1 -0
- package/dist/chunk-YSYR54XR.js +92 -0
- package/dist/chunk-YSYR54XR.js.map +1 -0
- package/dist/chunk-YTYDQBVY.cjs +162 -0
- package/dist/chunk-YTYDQBVY.cjs.map +1 -0
- package/dist/chunk-ZDLOA2UT.cjs +1042 -0
- package/dist/chunk-ZDLOA2UT.cjs.map +1 -0
- package/dist/chunk-ZWUKRCOJ.cjs +2162 -0
- package/dist/chunk-ZWUKRCOJ.cjs.map +1 -0
- package/dist/core/index.cjs +807 -4333
- package/dist/core/index.cjs.map +1 -1
- package/dist/core/index.js +14 -4130
- package/dist/core/index.js.map +1 -1
- package/dist/i18n/index.cjs +86 -558
- package/dist/i18n/index.cjs.map +1 -1
- package/dist/i18n/index.js +1 -544
- package/dist/i18n/index.js.map +1 -1
- package/dist/index.cjs +1432 -17139
- package/dist/index.cjs.map +1 -1
- package/dist/index.css +11 -7
- package/dist/index.css.map +1 -1
- package/dist/index.js +31 -16784
- package/dist/index.js.map +1 -1
- package/dist/marketing/index.cjs +142 -3072
- package/dist/marketing/index.cjs.map +1 -1
- package/dist/marketing/index.js +11 -3042
- package/dist/marketing/index.js.map +1 -1
- package/dist/motion/index.cjs +26 -1222
- package/dist/motion/index.cjs.map +1 -1
- package/dist/motion/index.js +2 -1215
- package/dist/motion/index.js.map +1 -1
- package/dist/nav/index.cjs +101 -1518
- package/dist/nav/index.cjs.map +1 -1
- package/dist/nav/index.js +4 -1498
- package/dist/nav/index.js.map +1 -1
- package/dist/report/index.cjs +171 -2403
- package/dist/report/index.cjs.map +1 -1
- package/dist/report/index.js +3 -2363
- package/dist/report/index.js.map +1 -1
- package/dist/sections/index.cjs +28 -378
- package/dist/sections/index.cjs.map +1 -1
- package/dist/sections/index.css +1 -4
- package/dist/sections/index.css.map +1 -1
- package/dist/sections/index.js +4 -372
- package/dist/sections/index.js.map +1 -1
- package/dist/social-proof/index.cjs +53 -1249
- package/dist/social-proof/index.cjs.map +1 -1
- package/dist/social-proof/index.css +10 -3
- package/dist/social-proof/index.css.map +1 -1
- package/dist/social-proof/index.js +6 -1234
- package/dist/social-proof/index.js.map +1 -1
- package/dist/theme/index.cjs +38 -565
- package/dist/theme/index.cjs.map +1 -1
- package/dist/theme/index.js +2 -555
- package/dist/theme/index.js.map +1 -1
- package/dist/web/client/index.cjs +48 -0
- package/dist/web/client/index.cjs.map +1 -0
- package/dist/web/client/index.css +456 -0
- package/dist/web/client/index.css.map +1 -0
- package/dist/web/client/index.d.cts +172 -0
- package/dist/web/client/index.d.ts +172 -0
- package/dist/web/client/index.js +7 -0
- package/dist/web/client/index.js.map +1 -0
- package/dist/web/index.cjs +158 -1346
- package/dist/web/index.cjs.map +1 -1
- package/dist/web/index.d.cts +5 -893
- package/dist/web/index.d.ts +5 -893
- package/dist/web/index.js +9 -1305
- package/dist/web/index.js.map +1 -1
- package/dist/web/server/index.cjs +32 -0
- package/dist/web/server/index.cjs.map +1 -0
- package/dist/web/server/index.d.cts +725 -0
- package/dist/web/server/index.d.ts +725 -0
- package/dist/web/server/index.js +3 -0
- package/dist/web/server/index.js.map +1 -0
- package/package.json +14 -1
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
'use strict';
|
|
2
|
+
|
|
3
|
+
var chunkMDB2WCRQ_cjs = require('./chunk-MDB2WCRQ.cjs');
|
|
4
|
+
var react = require('react');
|
|
5
|
+
var clsx = require('clsx');
|
|
6
|
+
var jsxRuntime = require('react/jsx-runtime');
|
|
7
|
+
|
|
8
|
+
function _interopDefault (e) { return e && e.__esModule ? e : { default: e }; }
|
|
9
|
+
|
|
10
|
+
var clsx__default = /*#__PURE__*/_interopDefault(clsx);
|
|
11
|
+
|
|
12
|
+
var SectionHeader = react.forwardRef(
|
|
13
|
+
({ title, subtitle, eyebrow, align = "center", className, ...props }, ref) => {
|
|
14
|
+
if (!title && !subtitle && !eyebrow) return null;
|
|
15
|
+
return /* @__PURE__ */ jsxRuntime.jsxs(
|
|
16
|
+
"header",
|
|
17
|
+
{
|
|
18
|
+
ref,
|
|
19
|
+
className: clsx__default.default("ds-section-header", `ds-section-header--${align}`, className),
|
|
20
|
+
...props,
|
|
21
|
+
children: [
|
|
22
|
+
eyebrow && /* @__PURE__ */ jsxRuntime.jsx("span", { className: "ds-section-header__eyebrow", children: eyebrow }),
|
|
23
|
+
title && /* @__PURE__ */ jsxRuntime.jsx("h2", { className: "ds-section-header__title", children: title }),
|
|
24
|
+
subtitle && /* @__PURE__ */ jsxRuntime.jsx("p", { className: "ds-section-header__subtitle", children: subtitle })
|
|
25
|
+
]
|
|
26
|
+
}
|
|
27
|
+
);
|
|
28
|
+
}
|
|
29
|
+
);
|
|
30
|
+
SectionHeader.displayName = "SectionHeader";
|
|
31
|
+
var SectionShell = react.forwardRef(
|
|
32
|
+
({
|
|
33
|
+
className,
|
|
34
|
+
children,
|
|
35
|
+
background = "default",
|
|
36
|
+
padding = "md",
|
|
37
|
+
containerSize,
|
|
38
|
+
containerFluid = false,
|
|
39
|
+
...props
|
|
40
|
+
}, ref) => {
|
|
41
|
+
return /* @__PURE__ */ jsxRuntime.jsx(
|
|
42
|
+
"section",
|
|
43
|
+
{
|
|
44
|
+
ref,
|
|
45
|
+
className: clsx__default.default(
|
|
46
|
+
"ds-section",
|
|
47
|
+
`ds-section--bg-${background}`,
|
|
48
|
+
`ds-section--padding-${padding}`,
|
|
49
|
+
className
|
|
50
|
+
),
|
|
51
|
+
...props,
|
|
52
|
+
children: /* @__PURE__ */ jsxRuntime.jsx(
|
|
53
|
+
chunkMDB2WCRQ_cjs.Container,
|
|
54
|
+
{
|
|
55
|
+
size: containerSize === "fluid" ? "full" : containerSize,
|
|
56
|
+
fluid: containerFluid || containerSize === "fluid",
|
|
57
|
+
children
|
|
58
|
+
}
|
|
59
|
+
)
|
|
60
|
+
}
|
|
61
|
+
);
|
|
62
|
+
}
|
|
63
|
+
);
|
|
64
|
+
SectionShell.displayName = "SectionShell";
|
|
65
|
+
|
|
66
|
+
exports.SectionHeader = SectionHeader;
|
|
67
|
+
exports.SectionShell = SectionShell;
|
|
68
|
+
//# sourceMappingURL=out.js.map
|
|
69
|
+
//# sourceMappingURL=chunk-IYPXJ6YC.cjs.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SectionShell/SectionShell.tsx"],"names":[],"mappings":";;;;;AAAA,SAAgB,kBAAkC;AAClD,OAAO,UAAU;AAoBX,SAKc,KALd;AALC,IAAM,gBAAgB;AAAA,EAC3B,CAAC,EAAE,OAAO,UAAU,SAAS,QAAQ,UAAU,WAAW,GAAG,MAAM,GAAG,QAAQ;AAC5E,QAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAS,QAAO;AAE5C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,KAAK,qBAAqB,sBAAsB,KAAK,IAAI,SAAS;AAAA,QAC5E,GAAG;AAAA,QAEH;AAAA,qBAAW,oBAAC,UAAK,WAAU,8BAA8B,mBAAQ;AAAA,UACjE,SAAS,oBAAC,QAAG,WAAU,4BAA4B,iBAAM;AAAA,UACzD,YAAY,oBAAC,OAAE,WAAU,+BAA+B,oBAAS;AAAA;AAAA;AAAA,IACpE;AAAA,EAEJ;AACF;AACA,cAAc,cAAc;AAarB,IAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB,GAAG;AAAA,EACL,GACA,QACG;AACH,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,kBAAkB,UAAU;AAAA,UAC5B,uBAAuB,OAAO;AAAA,UAC9B;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,kBAAkB,UAAU,SAAU;AAAA,YAC5C,OAAO,kBAAkB,kBAAkB;AAAA,YAE1C;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AACA,aAAa,cAAc","sourcesContent":["import React, { forwardRef, HTMLAttributes } from 'react';\nimport clsx from 'clsx';\nimport { Container } from '../LayoutPrimitives';\nimport './SectionShell.css';\n\n/* ============================================================================\n Section Header Component\n ============================================================================ */\n\nexport interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: React.ReactNode;\n subtitle?: React.ReactNode;\n eyebrow?: React.ReactNode;\n align?: 'left' | 'center' | 'right';\n}\n\nexport const SectionHeader = forwardRef<HTMLDivElement, SectionHeaderProps>(\n ({ title, subtitle, eyebrow, align = 'center', className, ...props }, ref) => {\n if (!title && !subtitle && !eyebrow) return null;\n\n return (\n <header\n ref={ref}\n className={clsx('ds-section-header', `ds-section-header--${align}`, className)}\n {...props}\n >\n {eyebrow && <span className=\"ds-section-header__eyebrow\">{eyebrow}</span>}\n {title && <h2 className=\"ds-section-header__title\">{title}</h2>}\n {subtitle && <p className=\"ds-section-header__subtitle\">{subtitle}</p>}\n </header>\n );\n },\n);\nSectionHeader.displayName = 'SectionHeader';\n\n/* ============================================================================\n Section Shell Component\n ============================================================================ */\n\nexport interface SectionShellProps extends HTMLAttributes<HTMLDivElement> {\n background?: 'default' | 'muted' | 'brand' | 'transparent';\n padding?: 'none' | 'sm' | 'md' | 'lg';\n containerSize?: 'sm' | 'md' | 'lg' | 'xl' | 'fluid'; // Maps to Container max-width\n containerFluid?: boolean;\n}\n\nexport const SectionShell = forwardRef<HTMLDivElement, SectionShellProps>(\n (\n {\n className,\n children,\n background = 'default',\n padding = 'md',\n containerSize,\n containerFluid = false,\n ...props\n },\n ref,\n ) => {\n return (\n <section\n ref={ref}\n className={clsx(\n 'ds-section',\n `ds-section--bg-${background}`,\n `ds-section--padding-${padding}`,\n className,\n )}\n {...props}\n >\n <Container\n size={containerSize === 'fluid' ? 'full' : (containerSize as 'sm' | 'md' | 'lg' | 'xl' | undefined)}\n fluid={containerFluid || containerSize === 'fluid'}\n >\n {children}\n </Container>\n </section>\n );\n },\n);\nSectionShell.displayName = 'SectionShell';\n"]}
|
|
@@ -0,0 +1,409 @@
|
|
|
1
|
+
import React2, { createContext, useId, useContext, useState, useEffect, useCallback } from 'react';
|
|
2
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
|
|
5
|
+
// src/theme/AppearanceProvider.tsx
|
|
6
|
+
var STORAGE_KEY = "void-appearance-settings";
|
|
7
|
+
var DEFAULT_SETTINGS = {
|
|
8
|
+
theme: "dark",
|
|
9
|
+
brand: "default",
|
|
10
|
+
navPlacement: "left",
|
|
11
|
+
density: "comfortable",
|
|
12
|
+
radius: "playful",
|
|
13
|
+
customColor: "#f97316"
|
|
14
|
+
// Default orange as fallback
|
|
15
|
+
};
|
|
16
|
+
function hexToRgb(hex) {
|
|
17
|
+
const cleanHex = hex.replace(/^#/, "");
|
|
18
|
+
const r = parseInt(cleanHex.substring(0, 2), 16);
|
|
19
|
+
const g = parseInt(cleanHex.substring(2, 4), 16);
|
|
20
|
+
const b = parseInt(cleanHex.substring(4, 6), 16);
|
|
21
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) {
|
|
22
|
+
return "249, 115, 22";
|
|
23
|
+
}
|
|
24
|
+
return `${r}, ${g}, ${b}`;
|
|
25
|
+
}
|
|
26
|
+
function generateSecondaryColor(hex) {
|
|
27
|
+
const cleanHex = hex.replace(/^#/, "");
|
|
28
|
+
const r = parseInt(cleanHex.substring(0, 2), 16);
|
|
29
|
+
const g = parseInt(cleanHex.substring(2, 4), 16);
|
|
30
|
+
const b = parseInt(cleanHex.substring(4, 6), 16);
|
|
31
|
+
if (isNaN(r) || isNaN(g) || isNaN(b)) {
|
|
32
|
+
return "255, 208, 0";
|
|
33
|
+
}
|
|
34
|
+
const secondary = {
|
|
35
|
+
r: Math.min(255, g + 50),
|
|
36
|
+
g: Math.min(255, b + 100),
|
|
37
|
+
b: Math.min(255, r)
|
|
38
|
+
};
|
|
39
|
+
return `${secondary.r}, ${secondary.g}, ${secondary.b}`;
|
|
40
|
+
}
|
|
41
|
+
function loadSettings() {
|
|
42
|
+
if (typeof window === "undefined") return DEFAULT_SETTINGS;
|
|
43
|
+
try {
|
|
44
|
+
const stored = localStorage.getItem(STORAGE_KEY);
|
|
45
|
+
if (stored) {
|
|
46
|
+
const parsed = JSON.parse(stored);
|
|
47
|
+
return {
|
|
48
|
+
theme: parsed.theme || DEFAULT_SETTINGS.theme,
|
|
49
|
+
brand: parsed.brand || DEFAULT_SETTINGS.brand,
|
|
50
|
+
navPlacement: parsed.navPlacement || DEFAULT_SETTINGS.navPlacement,
|
|
51
|
+
density: parsed.density || DEFAULT_SETTINGS.density,
|
|
52
|
+
radius: parsed.radius || DEFAULT_SETTINGS.radius,
|
|
53
|
+
customColor: parsed.customColor || DEFAULT_SETTINGS.customColor
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
} catch {
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
...DEFAULT_SETTINGS,
|
|
60
|
+
theme: "dark"
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function saveSettings(settings) {
|
|
64
|
+
if (typeof window === "undefined") return;
|
|
65
|
+
try {
|
|
66
|
+
localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));
|
|
67
|
+
} catch {
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
function applySettings(settings) {
|
|
71
|
+
if (typeof document === "undefined") return;
|
|
72
|
+
const root = document.documentElement;
|
|
73
|
+
root.setAttribute("data-theme", settings.theme);
|
|
74
|
+
root.setAttribute("data-brand", settings.brand);
|
|
75
|
+
root.setAttribute("data-nav", settings.navPlacement);
|
|
76
|
+
root.setAttribute("data-density", settings.density);
|
|
77
|
+
root.setAttribute("data-radius", settings.radius);
|
|
78
|
+
if (settings.brand === "custom") {
|
|
79
|
+
const primaryRgb = hexToRgb(settings.customColor);
|
|
80
|
+
const secondaryRgb = generateSecondaryColor(settings.customColor);
|
|
81
|
+
root.style.setProperty("--custom-accent-rgb", primaryRgb);
|
|
82
|
+
root.style.setProperty("--custom-accent2-rgb", secondaryRgb);
|
|
83
|
+
} else {
|
|
84
|
+
root.style.removeProperty("--custom-accent-rgb");
|
|
85
|
+
root.style.removeProperty("--custom-accent2-rgb");
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
function prefersReducedMotion() {
|
|
89
|
+
if (typeof window === "undefined") return false;
|
|
90
|
+
return window.matchMedia("(prefers-reduced-motion: reduce)").matches;
|
|
91
|
+
}
|
|
92
|
+
var AppearanceContext = createContext(null);
|
|
93
|
+
function AppearanceProvider({
|
|
94
|
+
initialSettings,
|
|
95
|
+
disablePersistence = false,
|
|
96
|
+
children
|
|
97
|
+
}) {
|
|
98
|
+
const [settings, setSettings] = useState(() => ({
|
|
99
|
+
...DEFAULT_SETTINGS,
|
|
100
|
+
...initialSettings
|
|
101
|
+
}));
|
|
102
|
+
const [hydrated, setHydrated] = useState(false);
|
|
103
|
+
useEffect(() => {
|
|
104
|
+
if (!disablePersistence) {
|
|
105
|
+
const loaded = loadSettings();
|
|
106
|
+
setSettings({
|
|
107
|
+
...loaded,
|
|
108
|
+
// initialSettings still take priority over localStorage
|
|
109
|
+
...initialSettings
|
|
110
|
+
});
|
|
111
|
+
}
|
|
112
|
+
setHydrated(true);
|
|
113
|
+
}, []);
|
|
114
|
+
useEffect(() => {
|
|
115
|
+
applySettings(settings);
|
|
116
|
+
if (!disablePersistence && hydrated) {
|
|
117
|
+
saveSettings(settings);
|
|
118
|
+
}
|
|
119
|
+
}, [settings, disablePersistence, hydrated]);
|
|
120
|
+
useEffect(() => {
|
|
121
|
+
if (typeof window === "undefined") return;
|
|
122
|
+
const mediaQuery = window.matchMedia("(prefers-color-scheme: light)");
|
|
123
|
+
const handleChange = (e) => {
|
|
124
|
+
setSettings((prev) => {
|
|
125
|
+
if (prev.theme === "light-contrast" || prev.theme === "dark-contrast") {
|
|
126
|
+
return prev;
|
|
127
|
+
}
|
|
128
|
+
return {
|
|
129
|
+
...prev,
|
|
130
|
+
theme: e.matches ? "light" : "dark"
|
|
131
|
+
};
|
|
132
|
+
});
|
|
133
|
+
};
|
|
134
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
135
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
136
|
+
}, []);
|
|
137
|
+
useEffect(() => {
|
|
138
|
+
if (typeof window === "undefined") return;
|
|
139
|
+
const mediaQuery = window.matchMedia("(prefers-reduced-motion: reduce)");
|
|
140
|
+
const handleChange = () => {
|
|
141
|
+
applySettings(settings);
|
|
142
|
+
};
|
|
143
|
+
mediaQuery.addEventListener("change", handleChange);
|
|
144
|
+
return () => mediaQuery.removeEventListener("change", handleChange);
|
|
145
|
+
}, [settings]);
|
|
146
|
+
const setTheme = useCallback((theme) => {
|
|
147
|
+
setSettings((prev) => ({ ...prev, theme }));
|
|
148
|
+
}, []);
|
|
149
|
+
const setBrand = useCallback((brand) => {
|
|
150
|
+
setSettings((prev) => ({ ...prev, brand }));
|
|
151
|
+
}, []);
|
|
152
|
+
const setNavPlacement = useCallback((navPlacement) => {
|
|
153
|
+
setSettings((prev) => ({ ...prev, navPlacement }));
|
|
154
|
+
}, []);
|
|
155
|
+
const setDensity = useCallback((density) => {
|
|
156
|
+
setSettings((prev) => ({ ...prev, density }));
|
|
157
|
+
}, []);
|
|
158
|
+
const setRadius = useCallback((radius) => {
|
|
159
|
+
setSettings((prev) => ({ ...prev, radius }));
|
|
160
|
+
}, []);
|
|
161
|
+
const setCustomColor = useCallback((customColor) => {
|
|
162
|
+
setSettings((prev) => ({ ...prev, customColor, brand: "custom" }));
|
|
163
|
+
}, []);
|
|
164
|
+
const setAppearance = useCallback((partial) => {
|
|
165
|
+
setSettings((prev) => ({ ...prev, ...partial }));
|
|
166
|
+
}, []);
|
|
167
|
+
const resetToDefaults = useCallback(() => {
|
|
168
|
+
setSettings(DEFAULT_SETTINGS);
|
|
169
|
+
}, []);
|
|
170
|
+
const contextValue = {
|
|
171
|
+
...settings,
|
|
172
|
+
setTheme,
|
|
173
|
+
setBrand,
|
|
174
|
+
setNavPlacement,
|
|
175
|
+
setDensity,
|
|
176
|
+
setRadius,
|
|
177
|
+
setCustomColor,
|
|
178
|
+
setAppearance,
|
|
179
|
+
resetToDefaults
|
|
180
|
+
};
|
|
181
|
+
return /* @__PURE__ */ jsx(AppearanceContext.Provider, { value: contextValue, children });
|
|
182
|
+
}
|
|
183
|
+
function useAppearance() {
|
|
184
|
+
const context = useContext(AppearanceContext);
|
|
185
|
+
if (!context) {
|
|
186
|
+
throw new Error("useAppearance must be used within an AppearanceProvider");
|
|
187
|
+
}
|
|
188
|
+
return context;
|
|
189
|
+
}
|
|
190
|
+
function initializeAppearance(settings) {
|
|
191
|
+
const loaded = loadSettings();
|
|
192
|
+
const merged = { ...loaded, ...settings };
|
|
193
|
+
applySettings(merged);
|
|
194
|
+
}
|
|
195
|
+
var AppearancePanel = React2.forwardRef(
|
|
196
|
+
({ className, labels: l }, ref) => {
|
|
197
|
+
const {
|
|
198
|
+
theme,
|
|
199
|
+
brand,
|
|
200
|
+
navPlacement,
|
|
201
|
+
density,
|
|
202
|
+
radius,
|
|
203
|
+
customColor,
|
|
204
|
+
setTheme,
|
|
205
|
+
setBrand,
|
|
206
|
+
setNavPlacement,
|
|
207
|
+
setDensity,
|
|
208
|
+
setRadius,
|
|
209
|
+
setCustomColor,
|
|
210
|
+
resetToDefaults
|
|
211
|
+
} = useAppearance();
|
|
212
|
+
const colorPickerId = useId();
|
|
213
|
+
const themeOptions = [
|
|
214
|
+
{ value: "light", label: l?.themeLight ?? "Light" },
|
|
215
|
+
{ value: "light-contrast", label: l?.themeLightContrast ?? "Light (High Contrast)" },
|
|
216
|
+
{ value: "dark", label: l?.themeDark ?? "Dark" },
|
|
217
|
+
{ value: "dark-contrast", label: l?.themeDarkContrast ?? "Dark (High Contrast)" }
|
|
218
|
+
];
|
|
219
|
+
const brandOptions = [
|
|
220
|
+
{ value: "default", label: l?.brandDefault ?? "Default", description: l?.brandDefaultDescription ?? "Warm Intelligence" },
|
|
221
|
+
{ value: "salesmind", label: l?.brandSalesmind ?? "SalesMind", description: l?.brandSalesmindDescription ?? "Pink-red + Gold" },
|
|
222
|
+
{ value: "custom", label: l?.brandCustom ?? "Custom", description: l?.brandCustomDescription ?? "Your color" }
|
|
223
|
+
];
|
|
224
|
+
const navOptions = [
|
|
225
|
+
{ value: "left", label: l?.navLeft ?? "Left Sidebar" },
|
|
226
|
+
{ value: "right", label: l?.navRight ?? "Right Sidebar" },
|
|
227
|
+
{ value: "bottom", label: l?.navBottom ?? "Bottom Tabs" }
|
|
228
|
+
];
|
|
229
|
+
const densityOptions = [
|
|
230
|
+
{ value: "comfortable", label: l?.densityComfortable ?? "Comfortable", description: l?.densityComfortableDescription ?? "Generous spacing" },
|
|
231
|
+
{ value: "compact", label: l?.densityCompact ?? "Compact", description: l?.densityCompactDescription ?? "Higher density" }
|
|
232
|
+
];
|
|
233
|
+
const radiusOptions = [
|
|
234
|
+
{ value: "playful", label: l?.radiusPlayful ?? "Playful", description: l?.radiusPlayfulDescription ?? "Rounded corners" },
|
|
235
|
+
{ value: "sharp", label: l?.radiusSharp ?? "Sharp", description: l?.radiusSharpDescription ?? "Technical feel" }
|
|
236
|
+
];
|
|
237
|
+
return /* @__PURE__ */ jsxs("div", { ref, className: clsx("ds-appearance-panel", className), children: [
|
|
238
|
+
/* @__PURE__ */ jsx("h3", { className: "ds-appearance-panel__title", children: l?.title ?? "Appearance Settings" }),
|
|
239
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "ds-appearance-panel__section", children: [
|
|
240
|
+
/* @__PURE__ */ jsx("legend", { className: "ds-appearance-panel__legend", children: l?.themeHeading ?? "Theme" }),
|
|
241
|
+
/* @__PURE__ */ jsx("div", { className: "ds-appearance-panel__options", children: themeOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
242
|
+
"label",
|
|
243
|
+
{
|
|
244
|
+
className: clsx(
|
|
245
|
+
"ds-appearance-panel__option",
|
|
246
|
+
theme === option.value && "ds-appearance-panel__option--active"
|
|
247
|
+
),
|
|
248
|
+
children: [
|
|
249
|
+
/* @__PURE__ */ jsx(
|
|
250
|
+
"input",
|
|
251
|
+
{
|
|
252
|
+
type: "radio",
|
|
253
|
+
name: "theme",
|
|
254
|
+
value: option.value,
|
|
255
|
+
checked: theme === option.value,
|
|
256
|
+
onChange: () => setTheme(option.value),
|
|
257
|
+
className: "ds-appearance-panel__radio"
|
|
258
|
+
}
|
|
259
|
+
),
|
|
260
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-label", children: option.label })
|
|
261
|
+
]
|
|
262
|
+
},
|
|
263
|
+
option.value
|
|
264
|
+
)) })
|
|
265
|
+
] }),
|
|
266
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "ds-appearance-panel__section", children: [
|
|
267
|
+
/* @__PURE__ */ jsx("legend", { className: "ds-appearance-panel__legend", children: l?.brandHeading ?? "Brand" }),
|
|
268
|
+
/* @__PURE__ */ jsx("div", { className: "ds-appearance-panel__options", children: brandOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
269
|
+
"label",
|
|
270
|
+
{
|
|
271
|
+
className: clsx(
|
|
272
|
+
"ds-appearance-panel__option",
|
|
273
|
+
brand === option.value && "ds-appearance-panel__option--active"
|
|
274
|
+
),
|
|
275
|
+
children: [
|
|
276
|
+
/* @__PURE__ */ jsx(
|
|
277
|
+
"input",
|
|
278
|
+
{
|
|
279
|
+
type: "radio",
|
|
280
|
+
name: "brand",
|
|
281
|
+
value: option.value,
|
|
282
|
+
checked: brand === option.value,
|
|
283
|
+
onChange: () => setBrand(option.value),
|
|
284
|
+
className: "ds-appearance-panel__radio"
|
|
285
|
+
}
|
|
286
|
+
),
|
|
287
|
+
/* @__PURE__ */ jsxs("span", { className: "ds-appearance-panel__option-content", children: [
|
|
288
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-label", children: option.label }),
|
|
289
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-description", children: option.description })
|
|
290
|
+
] })
|
|
291
|
+
]
|
|
292
|
+
},
|
|
293
|
+
option.value
|
|
294
|
+
)) }),
|
|
295
|
+
brand === "custom" && /* @__PURE__ */ jsxs("div", { className: "ds-appearance-panel__color-picker", children: [
|
|
296
|
+
/* @__PURE__ */ jsx("label", { htmlFor: colorPickerId, className: "ds-appearance-panel__color-label", children: l?.accentColorLabel ?? "Accent Color" }),
|
|
297
|
+
/* @__PURE__ */ jsxs("div", { className: "ds-appearance-panel__color-input-wrapper", children: [
|
|
298
|
+
/* @__PURE__ */ jsx(
|
|
299
|
+
"input",
|
|
300
|
+
{
|
|
301
|
+
type: "color",
|
|
302
|
+
id: colorPickerId,
|
|
303
|
+
value: customColor,
|
|
304
|
+
onChange: (e) => setCustomColor(e.target.value),
|
|
305
|
+
className: "ds-appearance-panel__color-input"
|
|
306
|
+
}
|
|
307
|
+
),
|
|
308
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__color-value", children: customColor.toUpperCase() })
|
|
309
|
+
] })
|
|
310
|
+
] })
|
|
311
|
+
] }),
|
|
312
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "ds-appearance-panel__section", children: [
|
|
313
|
+
/* @__PURE__ */ jsx("legend", { className: "ds-appearance-panel__legend", children: l?.densityHeading ?? "Density" }),
|
|
314
|
+
/* @__PURE__ */ jsx("div", { className: "ds-appearance-panel__options ds-appearance-panel__options--row", children: densityOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
315
|
+
"label",
|
|
316
|
+
{
|
|
317
|
+
className: clsx(
|
|
318
|
+
"ds-appearance-panel__option",
|
|
319
|
+
"ds-appearance-panel__option--toggle",
|
|
320
|
+
density === option.value && "ds-appearance-panel__option--active"
|
|
321
|
+
),
|
|
322
|
+
children: [
|
|
323
|
+
/* @__PURE__ */ jsx(
|
|
324
|
+
"input",
|
|
325
|
+
{
|
|
326
|
+
type: "radio",
|
|
327
|
+
name: "density",
|
|
328
|
+
value: option.value,
|
|
329
|
+
checked: density === option.value,
|
|
330
|
+
onChange: () => setDensity(option.value),
|
|
331
|
+
className: "ds-appearance-panel__radio"
|
|
332
|
+
}
|
|
333
|
+
),
|
|
334
|
+
/* @__PURE__ */ jsxs("span", { className: "ds-appearance-panel__option-content", children: [
|
|
335
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-label", children: option.label }),
|
|
336
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-description", children: option.description })
|
|
337
|
+
] })
|
|
338
|
+
]
|
|
339
|
+
},
|
|
340
|
+
option.value
|
|
341
|
+
)) })
|
|
342
|
+
] }),
|
|
343
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "ds-appearance-panel__section", children: [
|
|
344
|
+
/* @__PURE__ */ jsx("legend", { className: "ds-appearance-panel__legend", children: l?.geometryHeading ?? "Geometry" }),
|
|
345
|
+
/* @__PURE__ */ jsx("div", { className: "ds-appearance-panel__options ds-appearance-panel__options--row", children: radiusOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
346
|
+
"label",
|
|
347
|
+
{
|
|
348
|
+
className: clsx(
|
|
349
|
+
"ds-appearance-panel__option",
|
|
350
|
+
"ds-appearance-panel__option--toggle",
|
|
351
|
+
radius === option.value && "ds-appearance-panel__option--active"
|
|
352
|
+
),
|
|
353
|
+
children: [
|
|
354
|
+
/* @__PURE__ */ jsx(
|
|
355
|
+
"input",
|
|
356
|
+
{
|
|
357
|
+
type: "radio",
|
|
358
|
+
name: "radius",
|
|
359
|
+
value: option.value,
|
|
360
|
+
checked: radius === option.value,
|
|
361
|
+
onChange: () => setRadius(option.value),
|
|
362
|
+
className: "ds-appearance-panel__radio"
|
|
363
|
+
}
|
|
364
|
+
),
|
|
365
|
+
/* @__PURE__ */ jsxs("span", { className: "ds-appearance-panel__option-content", children: [
|
|
366
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-label", children: option.label }),
|
|
367
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-description", children: option.description })
|
|
368
|
+
] })
|
|
369
|
+
]
|
|
370
|
+
},
|
|
371
|
+
option.value
|
|
372
|
+
)) })
|
|
373
|
+
] }),
|
|
374
|
+
/* @__PURE__ */ jsxs("fieldset", { className: "ds-appearance-panel__section", children: [
|
|
375
|
+
/* @__PURE__ */ jsx("legend", { className: "ds-appearance-panel__legend", children: l?.navHeading ?? "Navigation Layout" }),
|
|
376
|
+
/* @__PURE__ */ jsx("div", { className: "ds-appearance-panel__options", children: navOptions.map((option) => /* @__PURE__ */ jsxs(
|
|
377
|
+
"label",
|
|
378
|
+
{
|
|
379
|
+
className: clsx(
|
|
380
|
+
"ds-appearance-panel__option",
|
|
381
|
+
navPlacement === option.value && "ds-appearance-panel__option--active"
|
|
382
|
+
),
|
|
383
|
+
children: [
|
|
384
|
+
/* @__PURE__ */ jsx(
|
|
385
|
+
"input",
|
|
386
|
+
{
|
|
387
|
+
type: "radio",
|
|
388
|
+
name: "nav",
|
|
389
|
+
value: option.value,
|
|
390
|
+
checked: navPlacement === option.value,
|
|
391
|
+
onChange: () => setNavPlacement(option.value),
|
|
392
|
+
className: "ds-appearance-panel__radio"
|
|
393
|
+
}
|
|
394
|
+
),
|
|
395
|
+
/* @__PURE__ */ jsx("span", { className: "ds-appearance-panel__option-label", children: option.label })
|
|
396
|
+
]
|
|
397
|
+
},
|
|
398
|
+
option.value
|
|
399
|
+
)) })
|
|
400
|
+
] }),
|
|
401
|
+
/* @__PURE__ */ jsx("button", { type: "button", onClick: resetToDefaults, className: "ds-appearance-panel__reset", children: l?.resetLabel ?? "Reset to Defaults" })
|
|
402
|
+
] });
|
|
403
|
+
}
|
|
404
|
+
);
|
|
405
|
+
AppearancePanel.displayName = "AppearancePanel";
|
|
406
|
+
|
|
407
|
+
export { AppearancePanel, AppearanceProvider, hexToRgb, initializeAppearance, prefersReducedMotion, useAppearance };
|
|
408
|
+
//# sourceMappingURL=out.js.map
|
|
409
|
+
//# sourceMappingURL=chunk-JPJN4YBC.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/theme/AppearanceProvider.tsx","../src/components/AppearancePanel/AppearancePanel.tsx"],"names":["React","jsx"],"mappings":"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","sourcesContent":["import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';\n\n/* ============================================================================\n APPEARANCE TYPES\n ============================================================================ */\n\nexport type Theme = 'light' | 'light-contrast' | 'dark' | 'dark-contrast';\nexport type Brand = 'default' | 'salesmind' | 'custom';\nexport type NavPlacement = 'left' | 'right' | 'bottom';\nexport type Density = 'comfortable' | 'compact';\nexport type Radius = 'playful' | 'sharp';\n\nexport interface AppearanceSettings {\n theme: Theme;\n brand: Brand;\n navPlacement: NavPlacement;\n density: Density;\n radius: Radius;\n /** Hex color for custom brand (e.g., \"#ff2d8a\") */\n customColor: string;\n}\n\nexport interface AppearanceContextValue extends AppearanceSettings {\n setTheme: (theme: Theme) => void;\n setBrand: (brand: Brand) => void;\n setNavPlacement: (nav: NavPlacement) => void;\n setDensity: (density: Density) => void;\n setRadius: (radius: Radius) => void;\n setCustomColor: (color: string) => void;\n setAppearance: (settings: Partial<AppearanceSettings>) => void;\n resetToDefaults: () => void;\n}\n\n/* ============================================================================\n CONSTANTS\n ============================================================================ */\n\nconst STORAGE_KEY = 'void-appearance-settings';\n\nconst DEFAULT_SETTINGS: AppearanceSettings = {\n theme: 'dark',\n brand: 'default',\n navPlacement: 'left',\n density: 'comfortable',\n radius: 'playful',\n customColor: '#f97316', // Default orange as fallback\n};\n\n/* ============================================================================\n UTILITIES\n ============================================================================ */\n\n/** Detect system color scheme preference */\n\n\n/** Convert hex color to RGB triplet string (e.g., \"255, 45, 138\") */\nfunction hexToRgb(hex: string): string {\n // Remove # if present\n const cleanHex = hex.replace(/^#/, '');\n\n // Parse hex values\n const r = parseInt(cleanHex.substring(0, 2), 16);\n const g = parseInt(cleanHex.substring(2, 4), 16);\n const b = parseInt(cleanHex.substring(4, 6), 16);\n\n // Validate parsed values\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n // Fallback to default orange if parsing fails\n return '249, 115, 22';\n }\n\n return `${r}, ${g}, ${b}`;\n}\n\n/** Generate a complementary/secondary color from primary */\nfunction generateSecondaryColor(hex: string): string {\n const cleanHex = hex.replace(/^#/, '');\n const r = parseInt(cleanHex.substring(0, 2), 16);\n const g = parseInt(cleanHex.substring(2, 4), 16);\n const b = parseInt(cleanHex.substring(4, 6), 16);\n\n if (isNaN(r) || isNaN(g) || isNaN(b)) {\n return '255, 208, 0'; // Default yellow\n }\n\n // Shift hue by ~60 degrees for a harmonious secondary\n // Simple approach: rotate RGB channels and boost brightness\n const secondary = {\n r: Math.min(255, g + 50),\n g: Math.min(255, b + 100),\n b: Math.min(255, r),\n };\n\n return `${secondary.r}, ${secondary.g}, ${secondary.b}`;\n}\n\n/** Load settings from localStorage */\nfunction loadSettings(): AppearanceSettings {\n if (typeof window === 'undefined') return DEFAULT_SETTINGS;\n\n try {\n const stored = localStorage.getItem(STORAGE_KEY);\n if (stored) {\n const parsed = JSON.parse(stored) as Partial<AppearanceSettings>;\n return {\n theme: parsed.theme || DEFAULT_SETTINGS.theme,\n brand: parsed.brand || DEFAULT_SETTINGS.brand,\n navPlacement: parsed.navPlacement || DEFAULT_SETTINGS.navPlacement,\n density: parsed.density || DEFAULT_SETTINGS.density,\n radius: parsed.radius || DEFAULT_SETTINGS.radius,\n customColor: parsed.customColor || DEFAULT_SETTINGS.customColor,\n };\n }\n } catch {\n // Ignore parse errors\n }\n\n // Use default dark preference for initial theme if no stored value\n return {\n ...DEFAULT_SETTINGS,\n theme: 'dark',\n };\n}\n\n/** Save settings to localStorage */\nfunction saveSettings(settings: AppearanceSettings): void {\n if (typeof window === 'undefined') return;\n\n try {\n localStorage.setItem(STORAGE_KEY, JSON.stringify(settings));\n } catch {\n // Ignore storage errors (e.g., private browsing)\n }\n}\n\n/** Apply settings to document.documentElement */\nfunction applySettings(settings: AppearanceSettings): void {\n if (typeof document === 'undefined') return;\n\n const root = document.documentElement;\n\n // Apply data attributes\n root.setAttribute('data-theme', settings.theme);\n root.setAttribute('data-brand', settings.brand);\n root.setAttribute('data-nav', settings.navPlacement);\n root.setAttribute('data-density', settings.density);\n root.setAttribute('data-radius', settings.radius);\n\n // Handle custom brand RGB injection\n if (settings.brand === 'custom') {\n const primaryRgb = hexToRgb(settings.customColor);\n const secondaryRgb = generateSecondaryColor(settings.customColor);\n\n // Inject custom CSS variables\n root.style.setProperty('--custom-accent-rgb', primaryRgb);\n root.style.setProperty('--custom-accent2-rgb', secondaryRgb);\n } else {\n // Clean up injected variables when switching away from custom brand\n root.style.removeProperty('--custom-accent-rgb');\n root.style.removeProperty('--custom-accent2-rgb');\n }\n}\n\n/** Check if user prefers reduced motion */\nfunction prefersReducedMotion(): boolean {\n if (typeof window === 'undefined') return false;\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches;\n}\n\n/* ============================================================================\n CONTEXT\n ============================================================================ */\n\nconst AppearanceContext = createContext<AppearanceContextValue | null>(null);\n\n/* ============================================================================\n PROVIDER COMPONENT\n ============================================================================ */\n\nexport interface AppearanceProviderProps {\n /** Initial settings (overrides localStorage) */\n initialSettings?: Partial<AppearanceSettings>;\n /** Disable localStorage persistence */\n disablePersistence?: boolean;\n /** Children */\n children: React.ReactNode;\n}\n\nexport function AppearanceProvider({\n initialSettings,\n disablePersistence = false,\n children,\n}: AppearanceProviderProps) {\n // Start with deterministic defaults to avoid SSR/client hydration mismatch.\n // localStorage is read after mount in the effect below.\n const [settings, setSettings] = useState<AppearanceSettings>(() => ({\n ...DEFAULT_SETTINGS,\n ...initialSettings,\n }));\n\n // After hydration, sync with localStorage (runs once on mount)\n const [hydrated, setHydrated] = useState(false);\n useEffect(() => {\n if (!disablePersistence) {\n const loaded = loadSettings();\n setSettings({\n ...loaded,\n // initialSettings still take priority over localStorage\n ...initialSettings,\n });\n }\n setHydrated(true);\n }, []); // eslint-disable-line react-hooks/exhaustive-deps\n\n // Apply settings to DOM whenever they change\n useEffect(() => {\n applySettings(settings);\n if (!disablePersistence && hydrated) {\n saveSettings(settings);\n }\n }, [settings, disablePersistence, hydrated]);\n\n // Listen for system theme changes\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const mediaQuery = window.matchMedia('(prefers-color-scheme: light)');\n\n const handleChange = (e: MediaQueryListEvent) => {\n // Only auto-switch if user hasn't explicitly set a contrast variant\n setSettings((prev) => {\n if (prev.theme === 'light-contrast' || prev.theme === 'dark-contrast') {\n return prev; // Don't override contrast preferences\n }\n return {\n ...prev,\n theme: e.matches ? 'light' : 'dark',\n };\n });\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, []);\n\n // Listen for reduced motion preference changes\n useEffect(() => {\n if (typeof window === 'undefined') return;\n\n const mediaQuery = window.matchMedia('(prefers-reduced-motion: reduce)');\n\n // Initial check is handled by CSS media queries in tokens.css\n // This effect ensures we respect the preference dynamically\n const handleChange = () => {\n // Re-apply settings to ensure any motion-dependent values are updated\n applySettings(settings);\n };\n\n mediaQuery.addEventListener('change', handleChange);\n return () => mediaQuery.removeEventListener('change', handleChange);\n }, [settings]);\n\n const setTheme = useCallback((theme: Theme) => {\n setSettings((prev) => ({ ...prev, theme }));\n }, []);\n\n const setBrand = useCallback((brand: Brand) => {\n setSettings((prev) => ({ ...prev, brand }));\n }, []);\n\n const setNavPlacement = useCallback((navPlacement: NavPlacement) => {\n setSettings((prev) => ({ ...prev, navPlacement }));\n }, []);\n\n const setDensity = useCallback((density: Density) => {\n setSettings((prev) => ({ ...prev, density }));\n }, []);\n\n const setRadius = useCallback((radius: Radius) => {\n setSettings((prev) => ({ ...prev, radius }));\n }, []);\n\n const setCustomColor = useCallback((customColor: string) => {\n setSettings((prev) => ({ ...prev, customColor, brand: 'custom' }));\n }, []);\n\n const setAppearance = useCallback((partial: Partial<AppearanceSettings>) => {\n setSettings((prev) => ({ ...prev, ...partial }));\n }, []);\n\n const resetToDefaults = useCallback(() => {\n setSettings(DEFAULT_SETTINGS);\n }, []);\n\n const contextValue: AppearanceContextValue = {\n ...settings,\n setTheme,\n setBrand,\n setNavPlacement,\n setDensity,\n setRadius,\n setCustomColor,\n setAppearance,\n resetToDefaults,\n };\n\n return <AppearanceContext.Provider value={contextValue}>{children}</AppearanceContext.Provider>;\n}\n\n/* ============================================================================\n HOOK\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport function useAppearance(): AppearanceContextValue {\n const context = useContext(AppearanceContext);\n\n if (!context) {\n throw new Error('useAppearance must be used within an AppearanceProvider');\n }\n\n return context;\n}\n\n/* ============================================================================\n STANDALONE UTILITY (for use outside React, e.g., SSR or initial load)\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport function initializeAppearance(settings?: Partial<AppearanceSettings>): void {\n const loaded = loadSettings();\n const merged = { ...loaded, ...settings };\n applySettings(merged);\n}\n\n/* ============================================================================\n UTILITY EXPORTS\n ============================================================================ */\n\n// eslint-disable-next-line react-refresh/only-export-components\nexport { hexToRgb, prefersReducedMotion };\n","import React, { useId } from 'react';\nimport clsx from 'clsx';\nimport {\n useAppearance,\n Theme,\n Brand,\n NavPlacement,\n Density,\n Radius,\n} from '../../theme/AppearanceProvider';\nimport './AppearancePanel.css';\n\n/* ============================================================================\n APPEARANCE PANEL — Internal Settings UI\n ============================================================================ */\n\n/** All translatable labels for the AppearancePanel. */\nexport interface AppearancePanelLabels {\n /** Panel heading. @default \"Appearance Settings\" */\n title?: string;\n /** Theme section heading. @default \"Theme\" */\n themeHeading?: string;\n /** Brand section heading. @default \"Brand\" */\n brandHeading?: string;\n /** Density section heading. @default \"Density\" */\n densityHeading?: string;\n /** Geometry section heading. @default \"Geometry\" */\n geometryHeading?: string;\n /** Navigation section heading. @default \"Navigation Layout\" */\n navHeading?: string;\n /** Accent color label (shown for Custom brand). @default \"Accent Color\" */\n accentColorLabel?: string;\n /** Reset button text. @default \"Reset to Defaults\" */\n resetLabel?: string;\n\n /* Theme options */\n themeLight?: string;\n themeLightContrast?: string;\n themeDark?: string;\n themeDarkContrast?: string;\n\n /* Brand options */\n brandDefault?: string;\n brandDefaultDescription?: string;\n brandSalesmind?: string;\n brandSalesmindDescription?: string;\n brandCustom?: string;\n brandCustomDescription?: string;\n\n /* Density options */\n densityComfortable?: string;\n densityComfortableDescription?: string;\n densityCompact?: string;\n densityCompactDescription?: string;\n\n /* Radius / geometry options */\n radiusPlayful?: string;\n radiusPlayfulDescription?: string;\n radiusSharp?: string;\n radiusSharpDescription?: string;\n\n /* Navigation options */\n navLeft?: string;\n navRight?: string;\n navBottom?: string;\n}\n\nexport interface AppearancePanelProps {\n /** Custom class name */\n className?: string;\n /** Override default English labels for i18n. */\n labels?: AppearancePanelLabels;\n}\n\nexport const AppearancePanel = React.forwardRef<HTMLDivElement, AppearancePanelProps>(\n ({ className, labels: l }, ref) => {\n const {\n theme,\n brand,\n navPlacement,\n density,\n radius,\n customColor,\n setTheme,\n setBrand,\n setNavPlacement,\n setDensity,\n setRadius,\n setCustomColor,\n resetToDefaults,\n } = useAppearance();\n\n // Generate unique IDs for accessibility\n const colorPickerId = useId();\n\n // Build option arrays from labels (fallback to English defaults)\n const themeOptions: { value: Theme; label: string }[] = [\n { value: 'light', label: l?.themeLight ?? 'Light' },\n { value: 'light-contrast', label: l?.themeLightContrast ?? 'Light (High Contrast)' },\n { value: 'dark', label: l?.themeDark ?? 'Dark' },\n { value: 'dark-contrast', label: l?.themeDarkContrast ?? 'Dark (High Contrast)' },\n ];\n\n const brandOptions: { value: Brand; label: string; description: string }[] = [\n { value: 'default', label: l?.brandDefault ?? 'Default', description: l?.brandDefaultDescription ?? 'Warm Intelligence' },\n { value: 'salesmind', label: l?.brandSalesmind ?? 'SalesMind', description: l?.brandSalesmindDescription ?? 'Pink-red + Gold' },\n { value: 'custom', label: l?.brandCustom ?? 'Custom', description: l?.brandCustomDescription ?? 'Your color' },\n ];\n\n const navOptions: { value: NavPlacement; label: string }[] = [\n { value: 'left', label: l?.navLeft ?? 'Left Sidebar' },\n { value: 'right', label: l?.navRight ?? 'Right Sidebar' },\n { value: 'bottom', label: l?.navBottom ?? 'Bottom Tabs' },\n ];\n\n const densityOptions: { value: Density; label: string; description: string }[] = [\n { value: 'comfortable', label: l?.densityComfortable ?? 'Comfortable', description: l?.densityComfortableDescription ?? 'Generous spacing' },\n { value: 'compact', label: l?.densityCompact ?? 'Compact', description: l?.densityCompactDescription ?? 'Higher density' },\n ];\n\n const radiusOptions: { value: Radius; label: string; description: string }[] = [\n { value: 'playful', label: l?.radiusPlayful ?? 'Playful', description: l?.radiusPlayfulDescription ?? 'Rounded corners' },\n { value: 'sharp', label: l?.radiusSharp ?? 'Sharp', description: l?.radiusSharpDescription ?? 'Technical feel' },\n ];\n\n return (\n <div ref={ref} className={clsx('ds-appearance-panel', className)}>\n <h3 className=\"ds-appearance-panel__title\">{l?.title ?? 'Appearance Settings'}</h3>\n\n {/* Theme Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.themeHeading ?? 'Theme'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {themeOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n theme === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"theme\"\n value={option.value}\n checked={theme === option.value}\n onChange={() => setTheme(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Brand Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.brandHeading ?? 'Brand'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {brandOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n brand === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"brand\"\n value={option.value}\n checked={brand === option.value}\n onChange={() => setBrand(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n\n {/* Color Picker (shown only for Custom brand) */}\n {brand === 'custom' && (\n <div className=\"ds-appearance-panel__color-picker\">\n <label htmlFor={colorPickerId} className=\"ds-appearance-panel__color-label\">\n {l?.accentColorLabel ?? 'Accent Color'}\n </label>\n <div className=\"ds-appearance-panel__color-input-wrapper\">\n <input\n type=\"color\"\n id={colorPickerId}\n value={customColor}\n onChange={(e) => setCustomColor(e.target.value)}\n className=\"ds-appearance-panel__color-input\"\n />\n <span className=\"ds-appearance-panel__color-value\">\n {customColor.toUpperCase()}\n </span>\n </div>\n </div>\n )}\n </fieldset>\n\n {/* Density Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.densityHeading ?? 'Density'}</legend>\n <div className=\"ds-appearance-panel__options ds-appearance-panel__options--row\">\n {densityOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n 'ds-appearance-panel__option--toggle',\n density === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"density\"\n value={option.value}\n checked={density === option.value}\n onChange={() => setDensity(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Geometry Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.geometryHeading ?? 'Geometry'}</legend>\n <div className=\"ds-appearance-panel__options ds-appearance-panel__options--row\">\n {radiusOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n 'ds-appearance-panel__option--toggle',\n radius === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"radius\"\n value={option.value}\n checked={radius === option.value}\n onChange={() => setRadius(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-content\">\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n <span className=\"ds-appearance-panel__option-description\">\n {option.description}\n </span>\n </span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Navigation Section */}\n <fieldset className=\"ds-appearance-panel__section\">\n <legend className=\"ds-appearance-panel__legend\">{l?.navHeading ?? 'Navigation Layout'}</legend>\n <div className=\"ds-appearance-panel__options\">\n {navOptions.map((option) => (\n <label\n key={option.value}\n className={clsx(\n 'ds-appearance-panel__option',\n navPlacement === option.value && 'ds-appearance-panel__option--active',\n )}\n >\n <input\n type=\"radio\"\n name=\"nav\"\n value={option.value}\n checked={navPlacement === option.value}\n onChange={() => setNavPlacement(option.value)}\n className=\"ds-appearance-panel__radio\"\n />\n <span className=\"ds-appearance-panel__option-label\">{option.label}</span>\n </label>\n ))}\n </div>\n </fieldset>\n\n {/* Reset Button */}\n <button type=\"button\" onClick={resetToDefaults} className=\"ds-appearance-panel__reset\">\n {l?.resetLabel ?? 'Reset to Defaults'}\n </button>\n </div>\n );\n },\n);\n\nAppearancePanel.displayName = 'AppearancePanel';\n"]}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { Container } from './chunk-HN4PHABT.js';
|
|
2
|
+
import { forwardRef } from 'react';
|
|
3
|
+
import clsx from 'clsx';
|
|
4
|
+
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
|
+
|
|
6
|
+
var SectionHeader = forwardRef(
|
|
7
|
+
({ title, subtitle, eyebrow, align = "center", className, ...props }, ref) => {
|
|
8
|
+
if (!title && !subtitle && !eyebrow) return null;
|
|
9
|
+
return /* @__PURE__ */ jsxs(
|
|
10
|
+
"header",
|
|
11
|
+
{
|
|
12
|
+
ref,
|
|
13
|
+
className: clsx("ds-section-header", `ds-section-header--${align}`, className),
|
|
14
|
+
...props,
|
|
15
|
+
children: [
|
|
16
|
+
eyebrow && /* @__PURE__ */ jsx("span", { className: "ds-section-header__eyebrow", children: eyebrow }),
|
|
17
|
+
title && /* @__PURE__ */ jsx("h2", { className: "ds-section-header__title", children: title }),
|
|
18
|
+
subtitle && /* @__PURE__ */ jsx("p", { className: "ds-section-header__subtitle", children: subtitle })
|
|
19
|
+
]
|
|
20
|
+
}
|
|
21
|
+
);
|
|
22
|
+
}
|
|
23
|
+
);
|
|
24
|
+
SectionHeader.displayName = "SectionHeader";
|
|
25
|
+
var SectionShell = forwardRef(
|
|
26
|
+
({
|
|
27
|
+
className,
|
|
28
|
+
children,
|
|
29
|
+
background = "default",
|
|
30
|
+
padding = "md",
|
|
31
|
+
containerSize,
|
|
32
|
+
containerFluid = false,
|
|
33
|
+
...props
|
|
34
|
+
}, ref) => {
|
|
35
|
+
return /* @__PURE__ */ jsx(
|
|
36
|
+
"section",
|
|
37
|
+
{
|
|
38
|
+
ref,
|
|
39
|
+
className: clsx(
|
|
40
|
+
"ds-section",
|
|
41
|
+
`ds-section--bg-${background}`,
|
|
42
|
+
`ds-section--padding-${padding}`,
|
|
43
|
+
className
|
|
44
|
+
),
|
|
45
|
+
...props,
|
|
46
|
+
children: /* @__PURE__ */ jsx(
|
|
47
|
+
Container,
|
|
48
|
+
{
|
|
49
|
+
size: containerSize === "fluid" ? "full" : containerSize,
|
|
50
|
+
fluid: containerFluid || containerSize === "fluid",
|
|
51
|
+
children
|
|
52
|
+
}
|
|
53
|
+
)
|
|
54
|
+
}
|
|
55
|
+
);
|
|
56
|
+
}
|
|
57
|
+
);
|
|
58
|
+
SectionShell.displayName = "SectionShell";
|
|
59
|
+
|
|
60
|
+
export { SectionHeader, SectionShell };
|
|
61
|
+
//# sourceMappingURL=out.js.map
|
|
62
|
+
//# sourceMappingURL=chunk-KBA2LFBG.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/components/SectionShell/SectionShell.tsx"],"names":[],"mappings":";;;;;AAAA,SAAgB,kBAAkC;AAClD,OAAO,UAAU;AAoBX,SAKc,KALd;AALC,IAAM,gBAAgB;AAAA,EAC3B,CAAC,EAAE,OAAO,UAAU,SAAS,QAAQ,UAAU,WAAW,GAAG,MAAM,GAAG,QAAQ;AAC5E,QAAI,CAAC,SAAS,CAAC,YAAY,CAAC,QAAS,QAAO;AAE5C,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW,KAAK,qBAAqB,sBAAsB,KAAK,IAAI,SAAS;AAAA,QAC5E,GAAG;AAAA,QAEH;AAAA,qBAAW,oBAAC,UAAK,WAAU,8BAA8B,mBAAQ;AAAA,UACjE,SAAS,oBAAC,QAAG,WAAU,4BAA4B,iBAAM;AAAA,UACzD,YAAY,oBAAC,OAAE,WAAU,+BAA+B,oBAAS;AAAA;AAAA;AAAA,IACpE;AAAA,EAEJ;AACF;AACA,cAAc,cAAc;AAarB,IAAM,eAAe;AAAA,EAC1B,CACE;AAAA,IACE;AAAA,IACA;AAAA,IACA,aAAa;AAAA,IACb,UAAU;AAAA,IACV;AAAA,IACA,iBAAiB;AAAA,IACjB,GAAG;AAAA,EACL,GACA,QACG;AACH,WACE;AAAA,MAAC;AAAA;AAAA,QACC;AAAA,QACA,WAAW;AAAA,UACT;AAAA,UACA,kBAAkB,UAAU;AAAA,UAC5B,uBAAuB,OAAO;AAAA,UAC9B;AAAA,QACF;AAAA,QACC,GAAG;AAAA,QAEJ;AAAA,UAAC;AAAA;AAAA,YACC,MAAM,kBAAkB,UAAU,SAAU;AAAA,YAC5C,OAAO,kBAAkB,kBAAkB;AAAA,YAE1C;AAAA;AAAA,QACH;AAAA;AAAA,IACF;AAAA,EAEJ;AACF;AACA,aAAa,cAAc","sourcesContent":["import React, { forwardRef, HTMLAttributes } from 'react';\nimport clsx from 'clsx';\nimport { Container } from '../LayoutPrimitives';\nimport './SectionShell.css';\n\n/* ============================================================================\n Section Header Component\n ============================================================================ */\n\nexport interface SectionHeaderProps extends Omit<HTMLAttributes<HTMLDivElement>, 'title'> {\n title?: React.ReactNode;\n subtitle?: React.ReactNode;\n eyebrow?: React.ReactNode;\n align?: 'left' | 'center' | 'right';\n}\n\nexport const SectionHeader = forwardRef<HTMLDivElement, SectionHeaderProps>(\n ({ title, subtitle, eyebrow, align = 'center', className, ...props }, ref) => {\n if (!title && !subtitle && !eyebrow) return null;\n\n return (\n <header\n ref={ref}\n className={clsx('ds-section-header', `ds-section-header--${align}`, className)}\n {...props}\n >\n {eyebrow && <span className=\"ds-section-header__eyebrow\">{eyebrow}</span>}\n {title && <h2 className=\"ds-section-header__title\">{title}</h2>}\n {subtitle && <p className=\"ds-section-header__subtitle\">{subtitle}</p>}\n </header>\n );\n },\n);\nSectionHeader.displayName = 'SectionHeader';\n\n/* ============================================================================\n Section Shell Component\n ============================================================================ */\n\nexport interface SectionShellProps extends HTMLAttributes<HTMLDivElement> {\n background?: 'default' | 'muted' | 'brand' | 'transparent';\n padding?: 'none' | 'sm' | 'md' | 'lg';\n containerSize?: 'sm' | 'md' | 'lg' | 'xl' | 'fluid'; // Maps to Container max-width\n containerFluid?: boolean;\n}\n\nexport const SectionShell = forwardRef<HTMLDivElement, SectionShellProps>(\n (\n {\n className,\n children,\n background = 'default',\n padding = 'md',\n containerSize,\n containerFluid = false,\n ...props\n },\n ref,\n ) => {\n return (\n <section\n ref={ref}\n className={clsx(\n 'ds-section',\n `ds-section--bg-${background}`,\n `ds-section--padding-${padding}`,\n className,\n )}\n {...props}\n >\n <Container\n size={containerSize === 'fluid' ? 'full' : (containerSize as 'sm' | 'md' | 'lg' | 'xl' | undefined)}\n fluid={containerFluid || containerSize === 'fluid'}\n >\n {children}\n </Container>\n </section>\n );\n },\n);\nSectionShell.displayName = 'SectionShell';\n"]}
|