@sybilion/uilib 1.0.25 → 1.0.27

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.
@@ -139,12 +139,12 @@
139
139
  --header-height: 94px;
140
140
  --page-x-padding: var(--p-16);
141
141
  --page-y-padding: var(--p-12);
142
- --page-color: oklch(1 0 0);
143
- --page-color-alpha-800: oklch(from var(--page-color) l c h / 0.8);
144
- --background: var(--sb-slate-100);
145
- --background-alpha-800: oklch(from var(--background) l c h / 0.8);
146
- --background-alpha-700: oklch(from var(--background) l c h / 0.7);
147
- --background-alpha-500: oklch(from var(--background) l c h / 0.5);
142
+ --page-color: var(--sb-slate-100);
143
+ --page-color-alpha-800: var(--sb-slate-100);
144
+ --background: oklch(1 0 0);
145
+ --background-alpha-800: oklch(0.99 0 0 / 0.8);
146
+ --background-alpha-700: oklch(0.99 0 0 / 0.7);
147
+ --background-alpha-500: oklch(0.99 0 0 / 0.5);
148
148
  --foreground: oklch(0.15 0 0);
149
149
  --card: oklch(1 0 0);
150
150
  --card-foreground: oklch(0.15 0 0);
@@ -196,12 +196,12 @@
196
196
  }
197
197
 
198
198
  .dark {
199
- --page-color: oklch(0.14 0 0);
200
- --page-color-alpha-800: oklch(from var(--page-color) l c h / 0.95);
201
- --background: oklch(0.22 0 0);
202
- --background-alpha-800: oklch(from var(--background) l c h / 0.95);
203
- --background-alpha-700: oklch(from var(--background) l c h / 0.7);
204
- --background-alpha-500: oklch(from var(--background) l c h / 0.5);
199
+ --page-color: oklch(0.22 0 0);
200
+ --page-color-alpha-800: oklch(0.2242 0 0 / 0.8);
201
+ --background: oklch(0.14 0 0);
202
+ --background-alpha-800: oklch(0.14 0 0 / 0.95);
203
+ --background-alpha-700: oklch(0.14 0 0 / 0.7);
204
+ --background-alpha-500: oklch(0.14 0 0 / 0.5);
205
205
  --foreground: oklch(0.95 0 0);
206
206
  --card: oklch(0.1 0 0);
207
207
  --card-foreground: oklch(0.95 0 0);
package/dist/esm/index.js CHANGED
@@ -1,4 +1,5 @@
1
1
  export { MINIAPP_CHANNEL, MINIAPP_VERSION, applyThemeToDocument, buildReadyMessage, parseThemeSyncMessage, resolveParentOriginFromReferrer } from './mini-app/miniAppProtocol.js';
2
+ export { getDefaultMiniAppThemeConfig } from './mini-app/miniAppThemeConfig.js';
2
3
  export { MiniAppRoot, useMiniAppShellTheme } from './mini-app/MiniAppRoot.js';
3
4
  export { ChatContext, ChatProvider, useChat, useChats, useChatsForDataset, useChatsForScopeId, useCurrentChat } from './contexts/chat-context.js';
4
5
  export { AnalysesSelector } from './components/ui/AnalysesSelector/AnalysesSelector.js';
@@ -1,13 +1,27 @@
1
- import { jsx } from 'react/jsx-runtime';
2
- import { createContext, useContext, useState, useRef, useCallback, useEffect, useMemo } from 'react';
3
- import { Scroll } from '@homecode/ui';
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { createContext, useContext, useState, useRef, useMemo, useCallback, useEffect } from 'react';
4
+ import { Theme, Scroll } from '@homecode/ui';
4
5
  import S from './MiniAppRoot.styl.js';
5
6
  import { resolveParentOriginFromReferrer, applyThemeToDocument, buildReadyMessage, parseThemeSyncMessage } from './miniAppProtocol.js';
7
+ import { getDefaultMiniAppThemeConfig } from './miniAppThemeConfig.js';
6
8
 
7
9
  const defaultTheme = {
8
10
  mode: 'light',
9
11
  isDarkMode: false,
10
12
  };
13
+ function isEmbeddedMiniApp() {
14
+ return typeof window !== 'undefined' && window.parent !== window;
15
+ }
16
+ function themeFromDocument() {
17
+ if (typeof document === 'undefined')
18
+ return defaultTheme;
19
+ const isDark = document.documentElement.classList.contains('dark');
20
+ return {
21
+ mode: isDark ? 'dark' : 'light',
22
+ isDarkMode: isDark,
23
+ };
24
+ }
11
25
  const MiniAppShellContext = createContext(null);
12
26
  function useMiniAppShellTheme() {
13
27
  const v = useContext(MiniAppShellContext);
@@ -32,10 +46,13 @@ function isTrustedParentMessage(event) {
32
46
  return false;
33
47
  return true;
34
48
  }
35
- function MiniAppRoot({ children, appId, onThemeChange, }) {
36
- const [theme, setTheme] = useState(defaultTheme);
49
+ function MiniAppRoot({ children, className, appId, onThemeChange, getThemeConfig, }) {
50
+ const [theme, setTheme] = useState(() => isEmbeddedMiniApp() ? defaultTheme : themeFromDocument());
37
51
  const onThemeChangeRef = useRef(onThemeChange);
38
52
  onThemeChangeRef.current = onThemeChange;
53
+ const getThemeConfigRef = useRef(getThemeConfig ?? getDefaultMiniAppThemeConfig);
54
+ getThemeConfigRef.current = getThemeConfig ?? getDefaultMiniAppThemeConfig;
55
+ const currThemeConfig = useMemo(() => getThemeConfigRef.current(theme.isDarkMode), [theme.isDarkMode]);
39
56
  const sendReady = useCallback(() => {
40
57
  if (!window.parent || window.parent === window)
41
58
  return;
@@ -50,6 +67,8 @@ function MiniAppRoot({ children, appId, onThemeChange, }) {
50
67
  }
51
68
  }, [appId]);
52
69
  useEffect(() => {
70
+ if (!isEmbeddedMiniApp())
71
+ return;
53
72
  applyThemeToDocument(theme.mode);
54
73
  }, [theme.mode]);
55
74
  useEffect(() => {
@@ -73,7 +92,7 @@ function MiniAppRoot({ children, appId, onThemeChange, }) {
73
92
  return () => window.removeEventListener('load', sendReady);
74
93
  }, [sendReady]);
75
94
  const ctx = useMemo(() => ({ theme }), [theme]);
76
- return (jsx(MiniAppShellContext.Provider, { value: ctx, children: jsx(Scroll, { y: true, fadeSize: "l", className: S.root, children: children }) }));
95
+ return (jsxs(MiniAppShellContext.Provider, { value: ctx, children: [jsx(Theme, { config: currThemeConfig }), jsx(Scroll, { y: true, fadeSize: "l", className: cn(S.root, className), innerClassName: S.inner, offset: { y: { before: 50, after: 50 } }, autoHide: true, children: children })] }));
77
96
  }
78
97
 
79
98
  export { MiniAppRoot, useMiniAppShellTheme };
@@ -1,7 +1,7 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.MiniAppRoot_root__UVklz{display:flex;flex-direction:column;height:100vh;overflow:hidden;position:relative;width:100%}@media (max-width:768px){.MiniAppRoot_root__UVklz{flex:1;height:auto;min-height:0}}";
4
- var S = {"root":"MiniAppRoot_root__UVklz"};
3
+ var css_248z = "@media (max-width:768px){:root{--page-x-padding:var(--p-6);--page-y-padding:var(--p-6)}}.MiniAppRoot_root__UVklz{height:100vh;min-height:0;overflow:hidden;position:relative;width:100%}@media (max-width:768px){.MiniAppRoot_root__UVklz{flex:1;height:auto;min-height:0}}.MiniAppRoot_inner__1ZFfl{box-sizing:border-box;max-height:100%;padding:var(--page-y-padding) var(--page-x-padding);width:100%}";
4
+ var S = {"root":"MiniAppRoot_root__UVklz","inner":"MiniAppRoot_inner__1ZFfl"};
5
5
  styleInject(css_248z);
6
6
 
7
7
  export { S as default };
@@ -0,0 +1,40 @@
1
+ import { ThemeHelpers, ThemeDefaults } from '@homecode/ui';
2
+
3
+ const { colors, getColors, getConfig } = ThemeDefaults;
4
+ const defaultPalette = getColors();
5
+ const colorsConfig = {
6
+ light: {
7
+ ...ThemeHelpers.colorsConfigToVars({
8
+ ...getColors({
9
+ accent: colors.dark,
10
+ decent: colors.light,
11
+ }),
12
+ }),
13
+ },
14
+ dark: {
15
+ ...ThemeHelpers.colorsConfigToVars({
16
+ ...getColors({
17
+ accent: colors.light,
18
+ decent: colors.dark,
19
+ }),
20
+ }),
21
+ },
22
+ };
23
+ /** Homecode `<Theme config={...}>` shape for workspace mini-apps (generic palette). */
24
+ function getDefaultMiniAppThemeConfig(isDarkMode) {
25
+ return {
26
+ ...getConfig(),
27
+ ...colorsConfig[isDarkMode ? 'dark' : 'light'],
28
+ ...ThemeHelpers.colorsConfigToVars({
29
+ active: {
30
+ color: '#00a9c7',
31
+ mods: {
32
+ // @ts-ignore — extend defaults so --active-color-alpha-* variants match Homecode
33
+ alpha: [0, 50, 100, 200, ...defaultPalette.active.mods.alpha],
34
+ },
35
+ },
36
+ }),
37
+ };
38
+ }
39
+
40
+ export { getDefaultMiniAppThemeConfig };
@@ -0,0 +1 @@
1
+ export default function MiniAppRootPage(): import("react/jsx-runtime").JSX.Element;
@@ -1,14 +1,18 @@
1
1
  import type { ReactNode } from 'react';
2
2
  import React from 'react';
3
3
  import { type ThemeSyncPayload } from './miniAppProtocol';
4
+ import { type MiniAppThemeConfig } from './miniAppThemeConfig';
4
5
  export type MiniAppShellContextValue = {
5
6
  theme: ThemeSyncPayload;
6
7
  };
7
8
  export declare function useMiniAppShellTheme(): MiniAppShellContextValue;
8
9
  export type MiniAppRootProps = {
9
10
  children: ReactNode;
11
+ className?: string;
10
12
  /** Included in READY payload when set. */
11
13
  appId?: string;
12
14
  onThemeChange?: (theme: ThemeSyncPayload) => void;
15
+ /** Overrides `@homecode/ui` `<Theme config>` builder (defaults to generic mini-app palette). */
16
+ getThemeConfig?: (isDarkMode: boolean) => MiniAppThemeConfig;
13
17
  };
14
- export declare function MiniAppRoot({ children, appId, onThemeChange, }: MiniAppRootProps): React.ReactElement;
18
+ export declare function MiniAppRoot({ children, className, appId, onThemeChange, getThemeConfig, }: MiniAppRootProps): React.ReactElement;
@@ -1,4 +1,6 @@
1
1
  export { applyThemeToDocument, buildReadyMessage, MINIAPP_CHANNEL, MINIAPP_VERSION, parseThemeSyncMessage, resolveParentOriginFromReferrer, } from './miniAppProtocol';
2
2
  export type { MiniAppMessageReady, MiniAppMessageThemeSync, ThemeSyncPayload, } from './miniAppProtocol';
3
- export { MiniAppRoot, useMiniAppShellTheme, } from './MiniAppRoot';
4
- export type { MiniAppRootProps, MiniAppShellContextValue, } from './MiniAppRoot';
3
+ export { getDefaultMiniAppThemeConfig } from './miniAppThemeConfig';
4
+ export type { MiniAppThemeConfig } from './miniAppThemeConfig';
5
+ export { MiniAppRoot, useMiniAppShellTheme } from './MiniAppRoot';
6
+ export type { MiniAppRootProps, MiniAppShellContextValue } from './MiniAppRoot';
@@ -0,0 +1,3 @@
1
+ /** Homecode `<Theme config={...}>` shape for workspace mini-apps (generic palette). */
2
+ export declare function getDefaultMiniAppThemeConfig(isDarkMode: boolean): any;
3
+ export type MiniAppThemeConfig = ReturnType<typeof getDefaultMiniAppThemeConfig>;
@@ -1,6 +1,6 @@
1
1
  # Workspace mini-apps (Sybilion iframe)
2
2
 
3
- The Sybilion client embeds mini-apps in an **iframe** and syncs theme with `postMessage`. Use **`MiniAppRoot`** so this document’s `<html>` gets **`light` / `dark`** (uilib uses `.dark { … }` for tokens).
3
+ The Sybilion client embeds mini-apps in an **iframe** and syncs theme with `postMessage`. Use **`MiniAppRoot`** so this document’s `<html>` gets **`light` / `dark`** (uilib uses `.dark { … }` for tokens), and so **`@homecode/ui`’s `<Theme />`** runs with vars matching that mode (`getDefaultMiniAppThemeConfig`; override via props if needed).
4
4
 
5
5
  1. Import **`@sybilion/uilib/mini-app-global.css`** (slim tokens + font imports; ships in this package).
6
6
  2. Wrap the React root:
@@ -18,4 +18,6 @@ createRoot(document.getElementById('root')!).render(
18
18
 
19
19
  3. Optional: **`useMiniAppShellTheme()`** for **`{ theme: { mode, isDarkMode } }`** under the provider (object leaves room for more shell fields later).
20
20
 
21
+ 4. Optional: **`getThemeConfig`** on **`MiniAppRoot`** — passed **`(isDarkMode) => config`** like the Sybilion app’s **`getThemeConfig`** from **`src/lib/theme.ts`**, so iframe UI matches host accent/danger tokens.
22
+
21
23
  **Bridge:** `MiniAppRoot` handles `THEME_SYNC`, sends `READY` on mount/load, and checks `event.source === window.parent` plus `document.referrer` origin when present. If the referrer is missing (strict `Referrer-Policy`), `READY` may use `targetOrigin` `*` — document that for your host.
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.0.25",
3
+ "version": "1.0.27",
4
4
  "description": "Sybilion Design System — React UI components (Webpack + Stylus)",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -0,0 +1,58 @@
1
+ import { PageContentSection } from '#uilib/components/ui/Page';
2
+ import { getThemeConfig } from '#uilib/docs/lib/theme';
3
+ import { MiniAppRoot, useMiniAppShellTheme } from '#uilib/mini-app';
4
+
5
+ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
6
+ import { DocsHeaderActions } from '../docsHeaderActions';
7
+
8
+ function MiniAppThemeDemo() {
9
+ const { theme } = useMiniAppShellTheme();
10
+
11
+ return (
12
+ <>
13
+ <p style={{ margin: 0 }}>
14
+ Context theme: <code>{theme.mode}</code>, isDarkMode:{' '}
15
+ <code>{String(theme.isDarkMode)}</code>
16
+ </p>
17
+ <p style={{ margin: 0, color: 'var(--muted-foreground)' }}>
18
+ Long content below — scroll should stay inside the mini-app shell (not
19
+ only the docs page), matching iframe workspace apps.
20
+ </p>
21
+ {Array.from({ length: 36 }, (_, i) => (
22
+ <p key={i} style={{ margin: 0, lineHeight: 1.6 }}>
23
+ Block {i + 1}: Lorem ipsum dolor sit amet, consectetur adipiscing
24
+ elit. Sed do eiusmod tempor incididunt ut labore et dolore magna
25
+ aliqua.
26
+ </p>
27
+ ))}
28
+ </>
29
+ );
30
+ }
31
+
32
+ export default function MiniAppRootPage() {
33
+ return (
34
+ <>
35
+ <AppPageHeader
36
+ breadcrumbs={[{ label: 'MiniAppRoot' }]}
37
+ title="MiniAppRoot"
38
+ subheader="Workspace mini-app shell: syncs document light/dark from parent THEME_SYNC postMessage, exposes theme via useMiniAppShellTheme. When embedded in Sybilion, child posts READY to parent; on this top-level docs page READY is skipped (no iframe parent)."
39
+ actions={<DocsHeaderActions />}
40
+ />
41
+ <style>{`
42
+ .mini-app-root-page {
43
+ box-shadow: 0 0 0 2px rgba(0, 0, 0, 0.1);
44
+ border-radius: var(--p-4);
45
+ }
46
+ `}</style>
47
+ <PageContentSection style={{ maxHeight: '500px' }}>
48
+ <MiniAppRoot
49
+ appId="uilib-docs"
50
+ className="mini-app-root-page"
51
+ getThemeConfig={isDarkMode => getThemeConfig(isDarkMode)}
52
+ >
53
+ <MiniAppThemeDemo />
54
+ </MiniAppRoot>
55
+ </PageContentSection>
56
+ </>
57
+ );
58
+ }
@@ -156,6 +156,12 @@ export const DOC_REGISTRY: DocEntry[] = [
156
156
  section: 'Layout',
157
157
  load: () => import('./pages/InteractiveContentPage'),
158
158
  },
159
+ {
160
+ slug: 'mini-app-root',
161
+ title: 'MiniAppRoot',
162
+ section: 'Layout',
163
+ load: () => import('./pages/MiniAppRootPage'),
164
+ },
159
165
  {
160
166
  slug: 'label',
161
167
  title: 'Label',
@@ -1,15 +1,24 @@
1
1
  @import 'lib/theme.styl'
2
2
 
3
+ // Scroll root must stay flex row: [scrollable inner | y-bar]. column stacks inner
4
+ // + scrollbar → inner grows with content → overflow-y never engages (clips via overflow:hidden).
3
5
  .root
4
6
  overflow hidden
5
7
 
6
8
  position relative
7
- display flex
8
9
  width 100%
9
10
  height 100vh
10
- flex-direction column
11
+ min-height 0
11
12
 
12
13
  @media (max-width MOBILE)
13
14
  height auto
14
15
  flex 1
15
16
  min-height 0
17
+
18
+ // Match PageScroll: constrain inner so homecode Scroll max-height:100% + overflow-y work
19
+ .inner
20
+ width 100%
21
+ // min-height 0
22
+ max-height 100%
23
+ box-sizing border-box
24
+ padding var(--page-y-padding) var(--page-x-padding)
@@ -1,2 +1,8 @@
1
- const mod: { [cls: string]: string }
2
- export default mod
1
+ // This file is automatically generated.
2
+ // Please do not change this file!
3
+ interface CssExports {
4
+ 'inner': string;
5
+ 'root': string;
6
+ }
7
+ export const cssExports: CssExports;
8
+ export default cssExports;
@@ -1,3 +1,4 @@
1
+ import cn from 'classnames';
1
2
  import type { ReactNode } from 'react';
2
3
  import React, {
3
4
  createContext,
@@ -9,7 +10,7 @@ import React, {
9
10
  useState,
10
11
  } from 'react';
11
12
 
12
- import { Scroll } from '@homecode/ui';
13
+ import { Scroll, Theme } from '@homecode/ui';
13
14
 
14
15
  import S from './MiniAppRoot.styl';
15
16
  import {
@@ -19,12 +20,29 @@ import {
19
20
  parseThemeSyncMessage,
20
21
  resolveParentOriginFromReferrer,
21
22
  } from './miniAppProtocol';
23
+ import {
24
+ type MiniAppThemeConfig,
25
+ getDefaultMiniAppThemeConfig,
26
+ } from './miniAppThemeConfig';
22
27
 
23
28
  const defaultTheme: ThemeSyncPayload = {
24
29
  mode: 'light',
25
30
  isDarkMode: false,
26
31
  };
27
32
 
33
+ function isEmbeddedMiniApp(): boolean {
34
+ return typeof window !== 'undefined' && window.parent !== window;
35
+ }
36
+
37
+ function themeFromDocument(): ThemeSyncPayload {
38
+ if (typeof document === 'undefined') return defaultTheme;
39
+ const isDark = document.documentElement.classList.contains('dark');
40
+ return {
41
+ mode: isDark ? 'dark' : 'light',
42
+ isDarkMode: isDark,
43
+ };
44
+ }
45
+
28
46
  export type MiniAppShellContextValue = {
29
47
  theme: ThemeSyncPayload;
30
48
  };
@@ -58,20 +76,37 @@ function isTrustedParentMessage(event: MessageEvent): boolean {
58
76
 
59
77
  export type MiniAppRootProps = {
60
78
  children: ReactNode;
79
+ className?: string;
61
80
  /** Included in READY payload when set. */
62
81
  appId?: string;
63
82
  onThemeChange?: (theme: ThemeSyncPayload) => void;
83
+ /** Overrides `@homecode/ui` `<Theme config>` builder (defaults to generic mini-app palette). */
84
+ getThemeConfig?: (isDarkMode: boolean) => MiniAppThemeConfig;
64
85
  };
65
86
 
66
87
  export function MiniAppRoot({
67
88
  children,
89
+ className,
68
90
  appId,
69
91
  onThemeChange,
92
+ getThemeConfig,
70
93
  }: MiniAppRootProps): React.ReactElement {
71
- const [theme, setTheme] = useState<ThemeSyncPayload>(defaultTheme);
94
+ const [theme, setTheme] = useState<ThemeSyncPayload>(() =>
95
+ isEmbeddedMiniApp() ? defaultTheme : themeFromDocument(),
96
+ );
72
97
  const onThemeChangeRef = useRef(onThemeChange);
73
98
  onThemeChangeRef.current = onThemeChange;
74
99
 
100
+ const getThemeConfigRef = useRef(
101
+ getThemeConfig ?? getDefaultMiniAppThemeConfig,
102
+ );
103
+ getThemeConfigRef.current = getThemeConfig ?? getDefaultMiniAppThemeConfig;
104
+
105
+ const currThemeConfig = useMemo(
106
+ () => getThemeConfigRef.current(theme.isDarkMode),
107
+ [theme.isDarkMode],
108
+ );
109
+
75
110
  const sendReady = useCallback(() => {
76
111
  if (!window.parent || window.parent === window) return;
77
112
  const payload = appId ? { appId } : {};
@@ -86,6 +121,7 @@ export function MiniAppRoot({
86
121
  }, [appId]);
87
122
 
88
123
  useEffect(() => {
124
+ if (!isEmbeddedMiniApp()) return;
89
125
  applyThemeToDocument(theme.mode);
90
126
  }, [theme.mode]);
91
127
 
@@ -112,7 +148,15 @@ export function MiniAppRoot({
112
148
 
113
149
  return (
114
150
  <MiniAppShellContext.Provider value={ctx}>
115
- <Scroll y fadeSize="l" className={S.root}>
151
+ <Theme config={currThemeConfig} />
152
+ <Scroll
153
+ y
154
+ fadeSize="l"
155
+ className={cn(S.root, className)}
156
+ innerClassName={S.inner}
157
+ offset={{ y: { before: 50, after: 50 } }}
158
+ autoHide
159
+ >
116
160
  {children}
117
161
  </Scroll>
118
162
  </MiniAppShellContext.Provider>
@@ -11,11 +11,7 @@ export type {
11
11
  MiniAppMessageThemeSync,
12
12
  ThemeSyncPayload,
13
13
  } from './miniAppProtocol';
14
- export {
15
- MiniAppRoot,
16
- useMiniAppShellTheme,
17
- } from './MiniAppRoot';
18
- export type {
19
- MiniAppRootProps,
20
- MiniAppShellContextValue,
21
- } from './MiniAppRoot';
14
+ export { getDefaultMiniAppThemeConfig } from './miniAppThemeConfig';
15
+ export type { MiniAppThemeConfig } from './miniAppThemeConfig';
16
+ export { MiniAppRoot, useMiniAppShellTheme } from './MiniAppRoot';
17
+ export type { MiniAppRootProps, MiniAppShellContextValue } from './MiniAppRoot';
@@ -0,0 +1,45 @@
1
+ import { ThemeDefaults, ThemeHelpers } from '@homecode/ui';
2
+
3
+ const { colors, getColors, getConfig } = ThemeDefaults;
4
+
5
+ const defaultPalette = getColors();
6
+
7
+ const colorsConfig = {
8
+ light: {
9
+ ...ThemeHelpers.colorsConfigToVars({
10
+ ...getColors({
11
+ accent: colors.dark,
12
+ decent: colors.light,
13
+ }),
14
+ }),
15
+ },
16
+ dark: {
17
+ ...ThemeHelpers.colorsConfigToVars({
18
+ ...getColors({
19
+ accent: colors.light,
20
+ decent: colors.dark,
21
+ }),
22
+ }),
23
+ },
24
+ };
25
+
26
+ /** Homecode `<Theme config={...}>` shape for workspace mini-apps (generic palette). */
27
+ export function getDefaultMiniAppThemeConfig(isDarkMode: boolean) {
28
+ return {
29
+ ...getConfig(),
30
+ ...colorsConfig[isDarkMode ? 'dark' : 'light'],
31
+ ...ThemeHelpers.colorsConfigToVars({
32
+ active: {
33
+ color: '#00a9c7',
34
+ mods: {
35
+ // @ts-ignore — extend defaults so --active-color-alpha-* variants match Homecode
36
+ alpha: [0, 50, 100, 200, ...defaultPalette.active.mods.alpha],
37
+ },
38
+ },
39
+ }),
40
+ };
41
+ }
42
+
43
+ export type MiniAppThemeConfig = ReturnType<
44
+ typeof getDefaultMiniAppThemeConfig
45
+ >;