@clarify-labs/renderer 0.7.0 → 0.7.1

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.
Files changed (63) hide show
  1. package/output/{OpenApiOperation-ZXToVSFC.cjs → OpenApiOperation-C4xZu4i0.cjs} +69 -65
  2. package/output/OpenApiOperation-C4xZu4i0.cjs.map +1 -0
  3. package/output/{OpenApiOperation-CWSOhUVa.js → OpenApiOperation-LIL7bqxW.js} +48 -44
  4. package/output/OpenApiOperation-LIL7bqxW.js.map +1 -0
  5. package/output/{shell-xxhV0p7k.cjs → PageActions-1RDCHcUY.cjs} +280 -308
  6. package/output/PageActions-1RDCHcUY.cjs.map +1 -0
  7. package/output/{shell-CumiARRe.js → PageActions-yoDRjkq8.js} +235 -263
  8. package/output/PageActions-yoDRjkq8.js.map +1 -0
  9. package/output/{ThemeRoot-C_ZdzSMu.js → ThemeRoot-CLa0yvRQ.js} +406 -53
  10. package/output/ThemeRoot-CLa0yvRQ.js.map +1 -0
  11. package/output/{ThemeRoot-CEvwrGp5.cjs → ThemeRoot-DYS-lcK-.cjs} +457 -80
  12. package/output/ThemeRoot-DYS-lcK-.cjs.map +1 -0
  13. package/output/app/AppShell.d.ts +3 -2
  14. package/output/app/PageActions.d.ts +12 -0
  15. package/output/app/PageBanner.d.ts +7 -0
  16. package/output/app/SectionProvider.d.ts +1 -0
  17. package/output/client.cjs +14 -7
  18. package/output/client.d.ts +4 -2
  19. package/output/client.js +4 -4
  20. package/output/context.d.ts +1 -1
  21. package/output/core/context.d.ts +5 -5
  22. package/output/core/index.d.ts +1 -1
  23. package/output/core/types.d.ts +70 -61
  24. package/output/index.cjs +56 -28
  25. package/output/index.cjs.map +1 -1
  26. package/output/index.d.ts +7 -5
  27. package/output/index.js +37 -12
  28. package/output/index.js.map +1 -1
  29. package/output/mdx/components.d.ts +1 -0
  30. package/output/mdx/primitives.d.ts +1 -0
  31. package/output/preview.cjs +7 -7
  32. package/output/preview.cjs.map +1 -1
  33. package/output/preview.js +4 -4
  34. package/output/preview.js.map +1 -1
  35. package/output/{render-zHU25Nm9.cjs → render-CRTqZzyY.cjs} +8 -7
  36. package/output/render-CRTqZzyY.cjs.map +1 -0
  37. package/output/{render-CnUd0XwZ.js → render-D0ls3d2j.js} +6 -5
  38. package/output/render-D0ls3d2j.js.map +1 -0
  39. package/output/renderer.css +365 -261
  40. package/output/server.cjs +8 -7
  41. package/output/server.cjs.map +1 -1
  42. package/output/server.js +5 -4
  43. package/output/server.js.map +1 -1
  44. package/output/shell/ContentActions.d.ts +0 -1
  45. package/output/shell/Header.d.ts +3 -2
  46. package/output/shell/SiteLogo.d.ts +2 -2
  47. package/output/shell/mobile.d.ts +2 -2
  48. package/output/theme/ThemeEditor.d.ts +53 -17
  49. package/output/theme/ThemeProvider.d.ts +2 -1
  50. package/output/theme/ThemeRoot.d.ts +2 -2
  51. package/output/theme/cookies.d.ts +11 -0
  52. package/output/theme/randomTheme.d.ts +2 -2
  53. package/output/theme/variables.d.ts +58 -20
  54. package/output/utils/href.d.ts +3 -3
  55. package/package.json +1 -1
  56. package/output/OpenApiOperation-CWSOhUVa.js.map +0 -1
  57. package/output/OpenApiOperation-ZXToVSFC.cjs.map +0 -1
  58. package/output/ThemeRoot-CEvwrGp5.cjs.map +0 -1
  59. package/output/ThemeRoot-C_ZdzSMu.js.map +0 -1
  60. package/output/render-CnUd0XwZ.js.map +0 -1
  61. package/output/render-zHU25Nm9.cjs.map +0 -1
  62. package/output/shell-CumiARRe.js.map +0 -1
  63. package/output/shell-xxhV0p7k.cjs.map +0 -1
@@ -1,7 +1,7 @@
1
- import { C as isExternalHref, D as useBuiltInText, E as copyTextToClipboard, S as ContentActions, _ as resolveThemeColorValue, g as cloneTheme, h as clarifyThemePresets, i as SectionProvider, j as useClarifyConfig, k as ClarifyLocaleContext, l as isSameRoutePath, m as applyThemeCssVariables, n as Navigation, p as useTheme, r as safeDecodeURIComponent, t as Header, u as normalizeRoutePath, v as resolveThemeVariableTargets, w as localizeHref, x as themeToCssVariables } from "./shell-CumiARRe.js";
1
+ import { C as isExternalHref, D as useBuiltInText, E as copyTextToClipboard, S as themeCookieName, a as safeDecodeURIComponent, b as storeLocalePreference, d as isSameRoutePath, f as normalizeRoutePath, g as getStoredLocalePreference, h as useTheme, i as Navigation, j as useConfig, k as LocaleContext, o as SectionProvider, r as Header, t as PageActionsProvider, w as localizeHref } from "./PageActions-yoDRjkq8.js";
2
2
  import clsx from "clsx";
3
3
  import { Component, Suspense, lazy, useEffect, useMemo, useState } from "react";
4
- import { Link, Route, Routes, useLocation } from "react-router-dom";
4
+ import { Link, Route, Routes, useLocation, useNavigate } from "react-router-dom";
5
5
  import { ChevronDown, ChevronLeft, ChevronRight, Settings, WandSparkles, X } from "lucide-react";
6
6
  import { Fragment as Fragment$1, jsx, jsxs } from "react/jsx-runtime";
7
7
  //#region source/app/ErrorBoundary.tsx
@@ -147,6 +147,86 @@ var PageErrorBoundary = class extends Component {
147
147
  }
148
148
  };
149
149
  //#endregion
150
+ //#region source/app/PageBanner.tsx
151
+ function resolveLocalizedText$1(text, locale, fallbackLocale) {
152
+ if (typeof text === "string") return text;
153
+ return (locale ? text[locale] : void 0) ?? (fallbackLocale ? text[fallbackLocale] : void 0) ?? Object.values(text)[0] ?? "";
154
+ }
155
+ function bannerStorageKey(config, content) {
156
+ return `clarify:banner:dismissed:${config.title}:${content}`;
157
+ }
158
+ function PageBannerLink(props) {
159
+ const { href, label, external: externalProp, config, locale } = props;
160
+ const external = externalProp ?? isExternalHref(href);
161
+ const resolvedHref = external ? href : localizeHref(href, config, locale);
162
+ const className = "clarify-banner-link shrink-0 rounded-full bg-(--clarify-theme-tokens-colors-primary) px-3 py-1 text-xs/5 font-semibold text-white no-underline transition hover:opacity-90";
163
+ if (external) return /* @__PURE__ */ jsx("a", {
164
+ href: resolvedHref,
165
+ target: "_blank",
166
+ rel: "noreferrer",
167
+ className,
168
+ children: label
169
+ });
170
+ return /* @__PURE__ */ jsx(Link, {
171
+ to: resolvedHref,
172
+ className,
173
+ children: label
174
+ });
175
+ }
176
+ function PageBanner(props) {
177
+ const { component: CustomBanner, currentLocale, onDismiss } = props;
178
+ const config = useConfig();
179
+ const banner = config.banner;
180
+ const builtInBanner = banner && typeof banner === "object" ? banner : void 0;
181
+ const content = builtInBanner ? resolveLocalizedText$1(builtInBanner.content, currentLocale, config.i18n?.defaultLocale) : "";
182
+ const link = builtInBanner?.link;
183
+ const linkLabel = link ? resolveLocalizedText$1(link.label, currentLocale, config.i18n?.defaultLocale) : "";
184
+ const storageKey = useMemo(() => content ? bannerStorageKey(config, content) : "", [config, content]);
185
+ const [dismissed, setDismissed] = useState(() => {
186
+ if (!storageKey || !builtInBanner?.dismissible || typeof window === "undefined") return false;
187
+ return window.localStorage.getItem(storageKey) === "1";
188
+ });
189
+ useEffect(() => {
190
+ if (dismissed) onDismiss?.();
191
+ }, [dismissed, onDismiss]);
192
+ if (CustomBanner) return /* @__PURE__ */ jsx("div", {
193
+ className: "clarify-banner clarify-banner-custom flex min-h-12 items-center border-b border-(--clarify-theme-tokens-colors-border) bg-(--clarify-theme-tokens-colors-background) px-4 text-sm text-(--clarify-theme-tokens-colors-foreground) dark:border-white/10 dark:bg-zinc-950",
194
+ children: /* @__PURE__ */ jsx("div", {
195
+ className: "mx-auto w-full max-w-(--clarify-theme-layout-max-width)",
196
+ children: /* @__PURE__ */ jsx(CustomBanner, {})
197
+ })
198
+ });
199
+ if (!builtInBanner || !content || dismissed) return null;
200
+ return /* @__PURE__ */ jsxs("div", {
201
+ className: "clarify-banner relative flex min-h-12 items-center border-b border-(--clarify-ui-accent-border) bg-(--clarify-ui-accent-background) px-4 text-sm text-(--clarify-ui-text) dark:border-white/10",
202
+ children: [/* @__PURE__ */ jsxs("div", {
203
+ className: "mx-auto flex w-full max-w-(--clarify-theme-layout-max-width) items-center justify-center gap-3 pr-8 sm:pr-0",
204
+ children: [/* @__PURE__ */ jsx("p", {
205
+ className: "clarify-banner-content m-0 text-center font-medium",
206
+ children: content
207
+ }), link ? /* @__PURE__ */ jsx(PageBannerLink, {
208
+ href: link.href,
209
+ label: linkLabel,
210
+ external: link.external,
211
+ config,
212
+ locale: currentLocale
213
+ }) : null]
214
+ }), builtInBanner.dismissible ? /* @__PURE__ */ jsx("button", {
215
+ type: "button",
216
+ className: "clarify-banner-dismiss absolute right-3 inline-flex size-8 items-center justify-center rounded-full text-(--clarify-ui-text-soft) transition hover:bg-(--clarify-ui-hover-background) hover:text-(--clarify-ui-text-strong)",
217
+ "aria-label": "Dismiss announcement",
218
+ onClick: () => {
219
+ if (storageKey) window.localStorage.setItem(storageKey, "1");
220
+ setDismissed(true);
221
+ },
222
+ children: /* @__PURE__ */ jsx(X, {
223
+ className: "size-4",
224
+ "aria-hidden": "true"
225
+ })
226
+ }) : null]
227
+ });
228
+ }
229
+ //#endregion
150
230
  //#region source/assets/clarify.svg?url
151
231
  var clarify_default = "data:image/svg+xml,%3c?xml%20version='1.0'%20encoding='UTF-8'?%3e%3csvg%20width='279px'%20height='200px'%20viewBox='0%200%20279%20200'%20version='1.1'%20xmlns='http://www.w3.org/2000/svg'%20xmlns:xlink='http://www.w3.org/1999/xlink'%3e%3ctitle%3eclarify%3c/title%3e%3cg%20id='页面-1'%20stroke='none'%20stroke-width='1'%20fill='none'%20fill-rule='evenodd'%3e%3cg%20id='clarify'%20transform='translate(-0,%200.0054)'%3e%3cpath%20d='M44.867217,0.0054376148%20C130.715579,1.00591567%20200,70.9091172%20200,156.994562%20L199.986321,155.127494%20C199.384888,180.009127%20179.026368,199.994562%20154,199.994562%20L46,199.994562%20C20.5949015,199.994562%200,179.399661%200,153.994562%20L0,45.9945624%20C0,21.0975659%2019.7793434,0.820282524%2044.4815926,0.0191499894%20Z'%20fill='%2300D492'%3e%3c/path%3e%3cpath%20d='M123.867217,0.0054376148%20C209.715579,1.00591567%20279,70.9091172%20279,156.994562%20L278.986321,155.127494%20C278.384888,180.009127%20258.026368,199.994562%20233,199.994562%20L125,199.994562%20C99.5949015,199.994562%2079,179.399661%2079,153.994562%20L79,45.9945624%20C79,21.0975659%2098.7793434,0.820282524%20123.481593,0.0191499894%20Z'%20id='clarify-right'%20fill-opacity='0.6'%20fill='%2300F6C9'%20transform='translate(179,%20100)%20rotate(-90)%20translate(-179,%20-100)'%3e%3c/path%3e%3cpath%20d='M199.979267,154.416906%20L199.984438,155.157125%20L199.962366,155.872459%20C198.977251,180.406837%20178.776104,199.994562%20154,199.994562%20L124.372438,199.994125%20L124.249053,199.994081%20C99.6939678,199.603921%2079.8122712,179.973634%2079.01915,155.518407%20L79.0054376,155.132783%20C79.5830823,105.566626%20103.129768,61.5221348%20139.498462,33.1463428%20C175.69419,61.3871018%20199.186123,105.143863%20199.979267,154.416906%20Z'%20id='形状结合'%20fill='%2300F692'%3e%3c/path%3e%3c/g%3e%3c/g%3e%3c/svg%3e";
152
232
  //#endregion
@@ -179,7 +259,7 @@ function resolveLocalizedText(text, locale, fallbackLocale) {
179
259
  if (typeof text === "string") return text;
180
260
  return (locale ? text[locale] : void 0) ?? (fallbackLocale ? text[fallbackLocale] : void 0) ?? Object.values(text)[0] ?? "";
181
261
  }
182
- function localeForPath$1(config, pathname) {
262
+ function localeForPath(config, pathname) {
183
263
  const i18n = config.i18n;
184
264
  if (!i18n) return void 0;
185
265
  const firstSegment = pathname.split("/").filter(Boolean)[0];
@@ -215,8 +295,8 @@ function SocialLink(arg0) {
215
295
  });
216
296
  }
217
297
  function PageFooter(props = {}) {
218
- const config = useClarifyConfig();
219
- const locale = localeForPath$1(config, useLocation().pathname);
298
+ const config = useConfig();
299
+ const locale = localeForPath(config, useLocation().pathname);
220
300
  const footer = config.footer;
221
301
  const builtInFooter = footer && typeof footer === "object" ? footer : void 0;
222
302
  const CustomFooter = props.component;
@@ -225,7 +305,7 @@ function PageFooter(props = {}) {
225
305
  const copyright = builtInFooter?.copyright ? resolveLocalizedText(builtInFooter.copyright, locale, config.i18n?.defaultLocale) : void 0;
226
306
  const hasBuiltInFooter = Boolean(copyright || links.length > 0 || socials.length > 0);
227
307
  return /* @__PURE__ */ jsxs("footer", {
228
- className: "clarify-page-footer mx-auto flex w-full max-w-(--clarify-theme-layout-max-width) flex-col gap-4 border-t border-(--clarify-theme-tokens-colors-border) px-4 py-8 sm:px-6 lg:mt-24 lg:px-5",
308
+ className: "clarify-page-footer mt-16 flex w-full flex-col gap-4 border-t border-(--clarify-theme-tokens-colors-border) py-8 lg:mt-24",
229
309
  children: [CustomFooter ? /* @__PURE__ */ jsx("div", {
230
310
  className: "clarify-footer-custom w-full",
231
311
  children: /* @__PURE__ */ jsx(CustomFooter, {})
@@ -419,6 +499,7 @@ function sectionsForRoute(route) {
419
499
  return route?.sections?.map((section) => ({
420
500
  id: section.id,
421
501
  title: section.title,
502
+ level: section.level,
422
503
  badge: section.badge,
423
504
  tags: section.tags
424
505
  })) ?? [];
@@ -437,12 +518,20 @@ function scrollToHash(hash) {
437
518
  });
438
519
  });
439
520
  }
440
- function localeForPath(config, pathname, route) {
441
- if (route?.locale) return route.locale;
521
+ function explicitLocaleForPath(config, pathname) {
442
522
  const i18n = config.i18n;
443
523
  if (!i18n) return void 0;
444
524
  const firstSegment = pathname.split("/").filter(Boolean)[0];
445
- return i18n.locales.find((locale) => locale.code === firstSegment)?.code ?? i18n.defaultLocale;
525
+ return i18n.locales.find((locale) => locale.code === firstSegment)?.code;
526
+ }
527
+ function fallbackLocale(config) {
528
+ return config.i18n?.defaultLocale;
529
+ }
530
+ function storedLocaleForConfig(config) {
531
+ return getStoredLocalePreference(config.i18n?.locales.map((locale) => locale.code));
532
+ }
533
+ function isDefaultLocale(config, locale) {
534
+ return Boolean(locale && config.i18n?.defaultLocale === locale);
446
535
  }
447
536
  function isTabbedNavigation(navigation) {
448
537
  return !Array.isArray(navigation) && "tabs" in navigation;
@@ -521,22 +610,46 @@ function NotFoundRouteElement(props) {
521
610
  return /* @__PURE__ */ jsx(RouteComponent, {});
522
611
  }
523
612
  function AppShell(arg0) {
524
- const { config, routes, navigation, footerComponent } = arg0;
613
+ const { config, routes, navigation, bannerComponent, footerComponent } = arg0;
525
614
  const location = useLocation();
615
+ const navigate = useNavigate();
526
616
  const pathname = normalizeRoutePath(location.pathname);
527
617
  const currentRoute = routeForPath(routes, pathname);
528
- const currentLocale = localeForPath(config, pathname, currentRoute);
618
+ const explicitLocale = explicitLocaleForPath(config, pathname);
619
+ const [storedLocale] = useState(() => storedLocaleForConfig(config));
620
+ const currentLocale = explicitLocale ?? storedLocale ?? fallbackLocale(config);
529
621
  const currentLocaleConfig = config.i18n?.locales.find((locale) => locale.code === currentLocale);
530
622
  const notFoundRoute = currentRoute ? void 0 : notFoundRouteForPath(routes, pathname, currentLocale);
531
623
  const text = useBuiltInText(currentLocale);
532
624
  const currentNavigation = navigationForLocale(navigation, currentLocale, pathname);
533
625
  const sections = sectionsForRoute(currentRoute);
626
+ const [dismissedBannerKey, setDismissedBannerKey] = useState();
627
+ const activeBannerKey = config.banner ? JSON.stringify(config.banner) : void 0;
628
+ const hasBanner = Boolean(config.banner) && dismissedBannerKey !== activeBannerKey;
534
629
  const hasTabs = Boolean(currentNavigation.tabs?.length);
535
630
  const renderRoutes = useMemo(() => routes.map((route) => ({
536
631
  ...route,
537
632
  component: resolveRouteComponent(route)
538
633
  })), [routes]);
539
634
  const NotFoundRouteComponent = notFoundRoute ? renderRoutes.find((route) => isSameRoutePath(route.path, notFoundRoute.path))?.component : void 0;
635
+ useEffect(() => {
636
+ if (explicitLocale) storeLocalePreference(explicitLocale);
637
+ }, [explicitLocale]);
638
+ useEffect(() => {
639
+ if (explicitLocale || !storedLocale || isDefaultLocale(config, storedLocale)) return;
640
+ const localizedPath = currentRoute?.alternates?.[storedLocale];
641
+ if (!localizedPath || isSameRoutePath(localizedPath, pathname)) return;
642
+ navigate(`${localizedPath}${location.search}${location.hash}`, { replace: true });
643
+ }, [
644
+ config,
645
+ currentRoute,
646
+ explicitLocale,
647
+ location.hash,
648
+ location.search,
649
+ navigate,
650
+ pathname,
651
+ storedLocale
652
+ ]);
540
653
  useEffect(() => {
541
654
  if (location.hash) {
542
655
  scrollToHash(location.hash);
@@ -563,33 +676,37 @@ function AppShell(arg0) {
563
676
  currentRoute,
564
677
  notFoundRoute
565
678
  ]);
566
- return /* @__PURE__ */ jsx(ClarifyLocaleContext.Provider, {
679
+ return /* @__PURE__ */ jsx(LocaleContext.Provider, {
567
680
  value: currentLocale,
568
681
  children: /* @__PURE__ */ jsxs(SectionProvider, {
569
682
  sections,
570
- children: [
571
- /* @__PURE__ */ jsx(Header, {
572
- config,
573
- navigation: currentNavigation.items,
574
- tabs: currentNavigation.tabs,
575
- routes,
683
+ children: [/* @__PURE__ */ jsx(Header, {
684
+ config,
685
+ navigation: currentNavigation.items,
686
+ tabs: currentNavigation.tabs,
687
+ routes,
688
+ currentLocale,
689
+ currentRoute,
690
+ banner: hasBanner ? /* @__PURE__ */ jsx(PageBanner, {
691
+ component: bannerComponent,
576
692
  currentLocale,
577
- currentRoute
578
- }),
579
- /* @__PURE__ */ jsxs("div", {
580
- className: "clarify-layout pb-12 mx-auto grid w-full max-w-(--clarify-theme-layout-max-width) grid-cols-1 lg:grid-cols-(--clarify-layout-sidebar-grid) xl:grid-cols-(--clarify-layout-sidebar-grid-wide)",
581
- children: [/* @__PURE__ */ jsx("aside", {
582
- "data-pagefind-ignore": true,
583
- className: clsx("clarify-sidebar hidden lg:sticky lg:z-30 lg:block lg:h-(--clarify-sidebar-height) lg:self-start lg:overflow-y-auto lg:bg-(--clarify-theme-tokens-colors-background) lg:px-5 lg:pb-8 xl:px-6", hasTabs ? "lg:top-28 lg:h-(--clarify-sidebar-height-with-tabs) lg:pt-6" : "lg:top-14 lg:pt-6"),
693
+ onDismiss: () => setDismissedBannerKey(activeBannerKey)
694
+ }) : void 0
695
+ }), /* @__PURE__ */ jsxs("div", {
696
+ className: "clarify-layout mx-auto grid w-full max-w-(--clarify-theme-layout-max-width) grid-cols-1 lg:grid-cols-(--clarify-layout-sidebar-grid) xl:grid-cols-(--clarify-layout-sidebar-grid-wide)",
697
+ children: [/* @__PURE__ */ jsx("aside", {
698
+ "data-pagefind-ignore": true,
699
+ className: "clarify-sidebar hidden lg:block lg:self-stretch lg:bg-(--clarify-theme-tokens-colors-background) lg:px-5 xl:px-6",
700
+ children: /* @__PURE__ */ jsx("div", {
701
+ className: clsx("clarify-sidebar-scroll lg:sticky lg:z-30 lg:overflow-y-auto lg:pb-8", hasTabs && hasBanner && "lg:top-40 lg:h-(--clarify-sidebar-height-with-tabs-and-banner) lg:pt-10", hasTabs && !hasBanner && "lg:top-28 lg:h-(--clarify-sidebar-height-with-tabs) lg:pt-10", !hasTabs && hasBanner && "lg:top-[6.5rem] lg:h-(--clarify-sidebar-height-with-banner) lg:pt-10", !hasTabs && !hasBanner && "lg:top-14 lg:h-(--clarify-sidebar-height) lg:pt-10"),
584
702
  children: /* @__PURE__ */ jsx(Navigation, { navigation: currentNavigation.items })
585
- }), /* @__PURE__ */ jsxs("div", {
586
- className: clsx("clarify-content @container relative flex min-h-screen min-w-0 flex-col px-4 sm:px-6 lg:px-8 xl:px-10", hasTabs ? "pt-14 lg:pt-28" : "pt-14"),
703
+ })
704
+ }), /* @__PURE__ */ jsx("div", {
705
+ className: clsx("clarify-content @container relative flex min-h-screen min-w-0 flex-col px-4 pb-12 sm:px-6 lg:px-8 xl:px-10", hasTabs && hasBanner && "pt-[6.5rem] lg:pt-40", hasTabs && !hasBanner && "pt-14 lg:pt-28", !hasTabs && hasBanner && "pt-[6.5rem]", !hasTabs && !hasBanner && "pt-14"),
706
+ children: /* @__PURE__ */ jsxs(PageActionsProvider, {
707
+ route: currentRoute,
708
+ routePrefix: config.routePrefix,
587
709
  children: [
588
- /* @__PURE__ */ jsx(ContentActions, {
589
- hasTabs,
590
- route: currentRoute,
591
- routePrefix: config.routePrefix
592
- }),
593
710
  /* @__PURE__ */ jsx("main", {
594
711
  className: "clarify-main min-w-0 flex-auto",
595
712
  "data-pagefind-body": true,
@@ -622,12 +739,12 @@ function AppShell(arg0) {
622
739
  /* @__PURE__ */ jsx(PageNavigation, {
623
740
  navigation: currentNavigation.items,
624
741
  currentRoute
625
- })
742
+ }),
743
+ /* @__PURE__ */ jsx(PageFooter, { component: footerComponent })
626
744
  ]
627
- })]
628
- }),
629
- /* @__PURE__ */ jsx(PageFooter, { component: footerComponent })
630
- ]
745
+ })
746
+ })]
747
+ })]
631
748
  })
632
749
  });
633
750
  }
@@ -1284,6 +1401,183 @@ function createRandomTheme() {
1284
1401
  };
1285
1402
  }
1286
1403
  //#endregion
1404
+ //#region source/theme/variables.ts
1405
+ var themeStorageKey = themeCookieName;
1406
+ var themePresets = {
1407
+ default: {
1408
+ preset: "default",
1409
+ tokens: {
1410
+ colors: {
1411
+ primary: "#047857",
1412
+ accent: "#0D9488",
1413
+ background: {
1414
+ light: "#ffffff",
1415
+ dark: "#09090b"
1416
+ },
1417
+ foreground: {
1418
+ light: "#111827",
1419
+ dark: "#ffffff"
1420
+ },
1421
+ surface: {
1422
+ light: "#ffffff",
1423
+ dark: "#18181b"
1424
+ },
1425
+ muted: {
1426
+ light: "#64748b",
1427
+ dark: "#a1a1aa"
1428
+ },
1429
+ border: {
1430
+ light: "rgb(15 23 42 / 0.12)",
1431
+ dark: "rgb(255 255 255 / 0.1)"
1432
+ },
1433
+ codeBackground: {
1434
+ light: "#f6fbf8",
1435
+ dark: "#18181b"
1436
+ }
1437
+ },
1438
+ radius: {
1439
+ sm: "6px",
1440
+ md: "10px",
1441
+ lg: "14px",
1442
+ xl: "18px"
1443
+ }
1444
+ },
1445
+ layout: { maxWidth: "82rem" },
1446
+ editor: false
1447
+ },
1448
+ base: {
1449
+ preset: "base",
1450
+ tokens: {
1451
+ colors: {
1452
+ primary: "#18181b",
1453
+ accent: "#52525b",
1454
+ background: {
1455
+ light: "#ffffff",
1456
+ dark: "#09090b"
1457
+ },
1458
+ foreground: {
1459
+ light: "#18181b",
1460
+ dark: "#ffffff"
1461
+ },
1462
+ surface: {
1463
+ light: "#ffffff",
1464
+ dark: "#18181b"
1465
+ },
1466
+ muted: {
1467
+ light: "#71717a",
1468
+ dark: "#a1a1aa"
1469
+ },
1470
+ border: {
1471
+ light: "rgb(24 24 27 / 0.12)",
1472
+ dark: "rgb(255 255 255 / 0.1)"
1473
+ },
1474
+ codeBackground: {
1475
+ light: "#f4f4f5",
1476
+ dark: "#18181b"
1477
+ }
1478
+ },
1479
+ radius: {
1480
+ sm: "6px",
1481
+ md: "8px",
1482
+ lg: "12px",
1483
+ xl: "16px"
1484
+ }
1485
+ },
1486
+ layout: { maxWidth: "80rem" },
1487
+ editor: false
1488
+ }
1489
+ };
1490
+ function cloneThemeColorValue(value) {
1491
+ return typeof value === "string" ? value : { ...value };
1492
+ }
1493
+ function cloneTheme(theme) {
1494
+ return {
1495
+ preset: theme.preset,
1496
+ tokens: {
1497
+ colors: {
1498
+ primary: cloneThemeColorValue(theme.tokens.colors.primary),
1499
+ accent: cloneThemeColorValue(theme.tokens.colors.accent),
1500
+ background: cloneThemeColorValue(theme.tokens.colors.background),
1501
+ foreground: cloneThemeColorValue(theme.tokens.colors.foreground),
1502
+ surface: cloneThemeColorValue(theme.tokens.colors.surface),
1503
+ muted: cloneThemeColorValue(theme.tokens.colors.muted),
1504
+ border: cloneThemeColorValue(theme.tokens.colors.border),
1505
+ codeBackground: cloneThemeColorValue(theme.tokens.colors.codeBackground)
1506
+ },
1507
+ radius: { ...theme.tokens.radius }
1508
+ },
1509
+ layout: { ...theme.layout },
1510
+ editor: theme.editor
1511
+ };
1512
+ }
1513
+ function isModeColorValue(value) {
1514
+ return typeof value === "object" && value !== null;
1515
+ }
1516
+ function resolveThemeColorValue(value, resolvedTheme = "light") {
1517
+ if (!isModeColorValue(value)) return value;
1518
+ return value[resolvedTheme] ?? value.light ?? value.dark ?? "";
1519
+ }
1520
+ function resolveThemeColors(colors, resolvedTheme = "light") {
1521
+ return {
1522
+ primary: resolveThemeColorValue(colors.primary, resolvedTheme),
1523
+ accent: resolveThemeColorValue(colors.accent, resolvedTheme),
1524
+ background: resolveThemeColorValue(colors.background, resolvedTheme),
1525
+ foreground: resolveThemeColorValue(colors.foreground, resolvedTheme),
1526
+ surface: resolveThemeColorValue(colors.surface, resolvedTheme),
1527
+ muted: resolveThemeColorValue(colors.muted, resolvedTheme),
1528
+ border: resolveThemeColorValue(colors.border, resolvedTheme),
1529
+ codeBackground: resolveThemeColorValue(colors.codeBackground, resolvedTheme)
1530
+ };
1531
+ }
1532
+ function themeToCssVariables(theme, resolvedTheme) {
1533
+ const colors = resolveThemeColors(theme.tokens.colors, resolvedTheme);
1534
+ const { radius } = theme.tokens;
1535
+ return {
1536
+ "--clarify-theme-tokens-colors-primary": colors.primary,
1537
+ "--clarify-theme-tokens-colors-accent": colors.accent,
1538
+ "--clarify-theme-tokens-colors-background": colors.background,
1539
+ "--clarify-theme-tokens-colors-foreground": colors.foreground,
1540
+ "--clarify-theme-tokens-colors-surface": colors.surface,
1541
+ "--clarify-theme-tokens-colors-muted": colors.muted,
1542
+ "--clarify-theme-tokens-colors-border": colors.border,
1543
+ "--clarify-theme-tokens-colors-code-background": colors.codeBackground,
1544
+ "--clarify-theme-tokens-radius-sm": radius.sm,
1545
+ "--clarify-theme-tokens-radius-md": radius.md,
1546
+ "--clarify-theme-tokens-radius-lg": radius.lg,
1547
+ "--clarify-theme-tokens-radius-xl": radius.xl,
1548
+ "--clarify-theme-layout-max-width": theme.layout.maxWidth
1549
+ };
1550
+ }
1551
+ function themeBootstrapScript(theme = themePresets.default) {
1552
+ const darkVariables = themeToCssVariables(theme, "dark");
1553
+ const lightVariables = themeToCssVariables(theme, "light");
1554
+ return `(function(){try{var c=${JSON.stringify(themeCookieName)};var m=document.cookie?document.cookie.split('; '):[];var e=null;for(var i=0;i<m.length;i++){var p=m[i].indexOf('=');var n=p===-1?m[i]:m[i].slice(0,p);if(decodeURIComponent(n)===c){e=p===-1?'':decodeURIComponent(m[i].slice(p+1));break}}var t=e==='dark'||e==='light'||e==='system'?e:'system';var r=t==='system'?window.matchMedia('(prefers-color-scheme: dark)').matches:t==='dark';var v=r?${JSON.stringify(darkVariables)}:${JSON.stringify(lightVariables)};var s=document.documentElement.style;for(var k in v)s.setProperty(k,v[k]);document.documentElement.classList.toggle('dark',r);document.documentElement.style.colorScheme=r?'dark':'light'}catch(e){}})();`;
1555
+ }
1556
+ function uniqueElements(elements) {
1557
+ return Array.from(new Set(elements));
1558
+ }
1559
+ function resolveThemeVariableTargets(target) {
1560
+ if (typeof document === "undefined") return [];
1561
+ if (target instanceof HTMLElement) return [target];
1562
+ if (typeof target === "string") return Array.from(document.querySelectorAll(target));
1563
+ return uniqueElements([document.documentElement, ...Array.from(document.querySelectorAll(".clarify-app"))]);
1564
+ }
1565
+ function applyThemeCssVariables(variables, targets) {
1566
+ const previousValues = /* @__PURE__ */ new Map();
1567
+ for (const element of targets) {
1568
+ const elementPreviousValues = /* @__PURE__ */ new Map();
1569
+ for (const [property, value] of Object.entries(variables)) {
1570
+ elementPreviousValues.set(property, element.style.getPropertyValue(property));
1571
+ element.style.setProperty(property, value);
1572
+ }
1573
+ previousValues.set(element, elementPreviousValues);
1574
+ }
1575
+ return () => {
1576
+ for (const [element, elementPreviousValues] of previousValues) for (const [property, previousValue] of elementPreviousValues) if (previousValue) element.style.setProperty(property, previousValue);
1577
+ else element.style.removeProperty(property);
1578
+ };
1579
+ }
1580
+ //#endregion
1287
1581
  //#region source/theme/ThemeEditor.tsx
1288
1582
  var colorTokenFields = [
1289
1583
  {
@@ -1341,18 +1635,24 @@ var layoutFields = [{
1341
1635
  key: "maxWidth",
1342
1636
  label: "Max width"
1343
1637
  }];
1344
- var clarifyThemeEditorPresets = clarifyThemePresets;
1345
- function applyClarifyThemeVariables(theme, target) {
1638
+ var themeEditorPresets = themePresets;
1639
+ function applyThemeVariables(theme, target) {
1346
1640
  return applyThemeCssVariables(themeToCssVariables(theme), resolveThemeVariableTargets(target));
1347
1641
  }
1348
1642
  function isHexColor(value) {
1349
1643
  return /^#[0-9a-f]{6}$/i.test(value);
1350
1644
  }
1351
- function updateThemeModeColorValue(value, resolvedTheme, nextValue) {
1352
- if (typeof value === "string") return nextValue;
1645
+ function updateThemeModeColorValue(value, mode, nextValue) {
1646
+ if (typeof value === "string") return mode === "light" ? {
1647
+ light: nextValue,
1648
+ dark: value
1649
+ } : {
1650
+ light: value,
1651
+ dark: nextValue
1652
+ };
1353
1653
  return {
1354
1654
  ...value,
1355
- [resolvedTheme]: nextValue
1655
+ [mode]: nextValue
1356
1656
  };
1357
1657
  }
1358
1658
  function TextField(props) {
@@ -1385,6 +1685,61 @@ function TextField(props) {
1385
1685
  })]
1386
1686
  });
1387
1687
  }
1688
+ function ColorField(props) {
1689
+ const { id, label, value, onChange } = props;
1690
+ const lightValue = resolveThemeColorValue(value, "light");
1691
+ const darkValue = resolveThemeColorValue(value, "dark");
1692
+ return /* @__PURE__ */ jsxs("div", {
1693
+ className: "grid min-w-0 gap-1.5",
1694
+ children: [/* @__PURE__ */ jsx("span", {
1695
+ className: "text-xs/5 font-medium text-(--clarify-ui-text)",
1696
+ children: label
1697
+ }), /* @__PURE__ */ jsxs("div", {
1698
+ className: "grid grid-cols-2 gap-2",
1699
+ children: [/* @__PURE__ */ jsx(ColorModeInput, {
1700
+ id: `${id}-light`,
1701
+ mode: "light",
1702
+ value: lightValue,
1703
+ onChange: (v) => onChange("light", v)
1704
+ }), /* @__PURE__ */ jsx(ColorModeInput, {
1705
+ id: `${id}-dark`,
1706
+ mode: "dark",
1707
+ value: darkValue,
1708
+ onChange: (v) => onChange("dark", v)
1709
+ })]
1710
+ })]
1711
+ });
1712
+ }
1713
+ function ColorModeInput(props) {
1714
+ const { id, mode, value, onChange } = props;
1715
+ const canUseColorInput = isHexColor(value);
1716
+ function handleTextChange(event) {
1717
+ onChange(event.target.value);
1718
+ }
1719
+ return /* @__PURE__ */ jsxs("label", {
1720
+ htmlFor: id,
1721
+ className: "grid min-w-0 gap-1 text-[11px]/4 font-medium text-(--clarify-ui-text-faint)",
1722
+ children: [/* @__PURE__ */ jsxs("span", {
1723
+ className: "flex min-w-0 items-center justify-between gap-2",
1724
+ children: [/* @__PURE__ */ jsx("span", {
1725
+ className: "uppercase tracking-wide",
1726
+ children: mode
1727
+ }), canUseColorInput ? /* @__PURE__ */ jsx("input", {
1728
+ type: "color",
1729
+ value,
1730
+ "aria-label": `${id} color`,
1731
+ className: "h-4 w-6 shrink-0 cursor-pointer rounded border border-(--clarify-theme-tokens-colors-border) bg-transparent p-0",
1732
+ onChange: handleTextChange
1733
+ }) : null]
1734
+ }), /* @__PURE__ */ jsx("input", {
1735
+ id,
1736
+ value,
1737
+ spellCheck: false,
1738
+ className: "h-8 w-full min-w-0 rounded-(--clarify-theme-tokens-radius-sm) border border-(--clarify-theme-tokens-colors-border) bg-(--clarify-theme-tokens-colors-background) px-2 font-mono text-xs text-(--clarify-theme-tokens-colors-foreground) shadow-xs outline-none transition focus:border-(--clarify-theme-tokens-colors-primary) focus:ring-2 focus:ring-(--clarify-ui-accent-border)",
1739
+ onChange: handleTextChange
1740
+ })]
1741
+ });
1742
+ }
1388
1743
  function themeToConfigSource(theme) {
1389
1744
  return JSON.stringify({ theme: {
1390
1745
  preset: theme.preset,
@@ -1396,7 +1751,7 @@ function ThemeEditor(props) {
1396
1751
  const { initialTheme, onChange, target, defaultOpen = false, className } = props;
1397
1752
  const { resolvedTheme } = useTheme();
1398
1753
  const [isOpen, setIsOpen] = useState(defaultOpen);
1399
- const [theme, setTheme] = useState(() => cloneTheme(initialTheme ?? clarifyThemeEditorPresets.default));
1754
+ const [theme, setTheme] = useState(() => cloneTheme(initialTheme ?? themeEditorPresets.default));
1400
1755
  const [copyState, setCopyState] = useState("idle");
1401
1756
  const configSource = useMemo(() => themeToConfigSource(theme), [theme]);
1402
1757
  useEffect(() => applyThemeCssVariables(themeToCssVariables(theme, resolvedTheme), resolveThemeVariableTargets(target)), [
@@ -1409,16 +1764,16 @@ function ThemeEditor(props) {
1409
1764
  onChange?.(nextTheme);
1410
1765
  }
1411
1766
  function updatePreset(nextPreset) {
1412
- commit(cloneTheme(clarifyThemeEditorPresets[nextPreset]));
1767
+ commit(cloneTheme(themeEditorPresets[nextPreset]));
1413
1768
  }
1414
- function updateColorToken(key, value) {
1769
+ function updateColorToken(key, mode, value) {
1415
1770
  commit({
1416
1771
  ...theme,
1417
1772
  tokens: {
1418
1773
  ...theme.tokens,
1419
1774
  colors: {
1420
1775
  ...theme.tokens.colors,
1421
- [key]: updateThemeModeColorValue(theme.tokens.colors[key], resolvedTheme, value)
1776
+ [key]: updateThemeModeColorValue(theme.tokens.colors[key], mode, value)
1422
1777
  }
1423
1778
  }
1424
1779
  });
@@ -1508,12 +1863,11 @@ function ThemeEditor(props) {
1508
1863
  children: "Colors"
1509
1864
  }), /* @__PURE__ */ jsx("div", {
1510
1865
  className: "grid grid-cols-1 gap-3",
1511
- children: colorTokenFields.map((field) => /* @__PURE__ */ jsx(TextField, {
1866
+ children: colorTokenFields.map((field) => /* @__PURE__ */ jsx(ColorField, {
1512
1867
  id: `clarify-theme-editor-color-${field.key}`,
1513
1868
  label: field.label,
1514
- value: resolveThemeColorValue(theme.tokens.colors[field.key], resolvedTheme),
1515
- withColorInput: true,
1516
- onChange: (value) => updateColorToken(field.key, value)
1869
+ value: theme.tokens.colors[field.key],
1870
+ onChange: (mode, value) => updateColorToken(field.key, mode, value)
1517
1871
  }, field.key))
1518
1872
  })]
1519
1873
  }),
@@ -1590,11 +1944,10 @@ function ThemeRoot(props) {
1590
1944
  return /* @__PURE__ */ jsxs("div", {
1591
1945
  className: "clarify-app h-full min-h-screen bg-(--clarify-theme-tokens-colors-background) text-(--clarify-theme-tokens-colors-foreground)",
1592
1946
  "data-theme-preset": theme.preset,
1593
- style: themeVariables,
1594
1947
  children: [children, themeEditor ? /* @__PURE__ */ jsx(ThemeEditor, { initialTheme: theme }) : null]
1595
1948
  });
1596
1949
  }
1597
1950
  //#endregion
1598
- export { AppShell as a, clarifyThemeEditorPresets as i, ThemeEditor as n, PageFooter as o, applyClarifyThemeVariables as r, BuiltWithClarify as s, ThemeRoot as t };
1951
+ export { themeBootstrapScript as a, AppShell as c, PageBanner as d, themeEditorPresets as i, PageFooter as l, ThemeEditor as n, themePresets as o, applyThemeVariables as r, themeStorageKey as s, ThemeRoot as t, BuiltWithClarify as u };
1599
1952
 
1600
- //# sourceMappingURL=ThemeRoot-C_ZdzSMu.js.map
1953
+ //# sourceMappingURL=ThemeRoot-CLa0yvRQ.js.map