@sybilion/uilib 1.2.8 → 1.2.10

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 (53) hide show
  1. package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +8 -3
  2. package/dist/esm/components/widgets/SignInPage/SignInPage.js +25 -0
  3. package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.js +2 -2
  4. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js +8 -0
  5. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.js +7 -0
  6. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.js +16 -0
  7. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.js +7 -0
  8. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.js +11 -0
  9. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.js +7 -0
  10. package/dist/esm/contexts/theme-context.js +44 -0
  11. package/dist/esm/docs/lib/theme.js +35 -3
  12. package/dist/esm/index.js +6 -0
  13. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +1 -1
  14. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +3 -0
  15. package/dist/esm/types/src/components/widgets/SignInPage/SignInPage.d.ts +10 -0
  16. package/dist/esm/types/src/components/widgets/SignInPage/index.d.ts +1 -0
  17. package/dist/esm/types/src/components/widgets/SybilionAppHeader/SybilionAppHeader.d.ts +5 -1
  18. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.d.ts +1 -0
  19. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.d.ts +14 -0
  20. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/index.d.ts +2 -0
  21. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.d.ts +11 -0
  22. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/index.d.ts +1 -0
  23. package/dist/esm/types/src/contexts/theme-context.d.ts +20 -0
  24. package/dist/esm/types/src/docs/contexts/theme-context.d.ts +1 -10
  25. package/dist/esm/types/src/docs/lib/theme.d.ts +5 -1
  26. package/dist/esm/types/src/index.d.ts +5 -0
  27. package/docs/standalone-apps.md +58 -37
  28. package/package.json +3 -2
  29. package/src/assets/sybilion_bg.svg +8 -0
  30. package/src/components/ui/NavUserHeader/NavUserHeader.tsx +10 -2
  31. package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +3 -0
  32. package/src/components/widgets/SignInPage/SignInPage.tsx +84 -0
  33. package/src/components/widgets/SignInPage/index.ts +1 -0
  34. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.tsx +8 -0
  35. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl +26 -0
  36. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.d.ts +2 -0
  37. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.tsx +18 -0
  38. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl +79 -0
  39. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.d.ts +2 -0
  40. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.tsx +64 -0
  41. package/src/components/widgets/SybilionAuthLayout/index.ts +6 -0
  42. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl +51 -0
  43. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.d.ts +2 -0
  44. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.tsx +59 -0
  45. package/src/components/widgets/SybilionSignInPanel/index.ts +4 -0
  46. package/src/contexts/theme-context.tsx +106 -0
  47. package/src/docs/App/ThemeToggle.tsx +1 -1
  48. package/src/docs/contexts/theme-context.tsx +8 -68
  49. package/src/docs/index.tsx +1 -1
  50. package/src/docs/lib/theme.ts +13 -2
  51. package/src/docs/pages/ChartAreaInteractivePage.tsx +1 -1
  52. package/src/index.ts +5 -0
  53. package/dist/esm/docs/contexts/theme-context.js +0 -14
@@ -1,6 +1,6 @@
1
1
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
2
2
  import cn from 'classnames';
3
- import { useTheme } from '../../../docs/contexts/theme-context.js';
3
+ import { useTheme } from '../../../contexts/theme-context.js';
4
4
  import { UserCircleIcon, SunIcon, MoonIcon, SignOutIcon } from '@phosphor-icons/react';
5
5
  import { ChevronDownIcon } from 'lucide-react';
6
6
  import { Avatar } from '../Avatar/Avatar.js';
@@ -9,8 +9,13 @@ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLab
9
9
  import { Image } from '../Image/Image.js';
10
10
  import S from './NavUserHeader.styl.js';
11
11
 
12
- function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated, user = null, menuItems, onLogout, signInSlot, onSignInClick, }) {
13
- const { toggleTheme, theme } = useTheme();
12
+ function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated, user = null, menuItems, onLogout, signInSlot, onSignInClick, theme: themeFromHost, onThemeToggle: onThemeToggleFromHost, }) {
13
+ const docsTheme = useTheme();
14
+ const hostControlsTheme = themeFromHost !== undefined && onThemeToggleFromHost !== undefined;
15
+ const theme = hostControlsTheme ? themeFromHost : docsTheme.theme;
16
+ const toggleTheme = hostControlsTheme
17
+ ? onThemeToggleFromHost
18
+ : docsTheme.toggleTheme;
14
19
  const authenticated = isAuthenticated ?? true;
15
20
  const avatarUrl = user?.avatar ?? '';
16
21
  const userName = user?.name ?? '';
@@ -0,0 +1,25 @@
1
+ import { jsx } from 'react/jsx-runtime';
2
+ import { SybilionAuthLayout } from '../SybilionAuthLayout/SybilionAuthLayout.js';
3
+ import '../SybilionAuthLayout/SybilionAuthHeadline.styl.js';
4
+ import { useSybilionAuth } from '../../../sybilion-auth/SybilionAuthProvider.js';
5
+ import { SybilionSignInPanel } from '../SybilionSignInPanel/SybilionSignInPanel.js';
6
+
7
+ const DEFAULT_TITLE = 'Sign In';
8
+ const DEFAULT_SUBTITLE = 'To get access authenticate through google or your email.';
9
+ function SignInPage({ title = DEFAULT_TITLE, subtitle = DEFAULT_SUBTITLE, forgotPasswordTo = '/forgot-password', releasesTo = '/releases', versionLabel, primaryButtonLabel, connectingLabel, loginRedirectOptions, heroBackgroundUrl, logoSize, containerClassName, }) {
10
+ const { error, loginWithRedirect, isLoading } = useSybilionAuth();
11
+ const handleSignIn = () => loginWithRedirect({
12
+ ...loginRedirectOptions,
13
+ authorizationParams: {
14
+ prompt: 'login',
15
+ screen_hint: 'login',
16
+ ...(typeof window !== 'undefined'
17
+ ? { origin: window.location.origin }
18
+ : {}),
19
+ ...loginRedirectOptions?.authorizationParams,
20
+ },
21
+ });
22
+ return (jsx(SybilionAuthLayout, { title: title, subtitle: subtitle, heroBackgroundUrl: heroBackgroundUrl, logoSize: logoSize, containerClassName: containerClassName, children: jsx(SybilionSignInPanel, { onSignIn: handleSignIn, isSigningIn: isLoading, error: error, forgotPasswordTo: forgotPasswordTo, releasesTo: releasesTo, versionLabel: versionLabel, primaryButtonLabel: primaryButtonLabel, connectingLabel: connectingLabel }) }));
23
+ }
24
+
25
+ export { SignInPage };
@@ -11,8 +11,8 @@ import '@phosphor-icons/react';
11
11
  import 'lucide-react';
12
12
  import S from './SybilionAppHeader.styl.js';
13
13
 
14
- function SybilionAppHeader({ pageHeaderId, actionsAnchorId = PAGE_HEADER_ACTIONS_ID, actionsAnchorClassName, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, logo, logoAreaClassName, welcomeBannerOffset, ...navUserHeaderProps }) {
15
- return (jsxs(AppHeaderPortal, { pageHeaderId: pageHeaderId, children: [jsx("div", { className: cn(S.logoArea, welcomeBannerOffset && S.logoAreaWithBanner, logoAreaClassName), children: jsx(Link, { to: "/", className: S.logoLink, children: logo ?? jsx(Logo, { size: "md", "aria-hidden": true }) }) }), jsx(WorkspaceAppSwitcher, { pathname: pathname, onNavigate: onNavigate, authenticated: authenticated, defaultApps: defaultApps, appsStorageKey: appsStorageKey }), jsx(Gap, {}), jsx("div", { id: actionsAnchorId, className: cn(S.actionsAnchor, actionsAnchorClassName), children: jsx(NavUserHeader, { ...navUserHeaderProps }) })] }));
14
+ function SybilionAppHeader({ pageHeaderId, actionsAnchorId = PAGE_HEADER_ACTIONS_ID, actionsAnchorClassName, actionsStart, actionsEnd, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, logo, logoAreaClassName, welcomeBannerOffset, ...navUserHeaderProps }) {
15
+ return (jsxs(AppHeaderPortal, { pageHeaderId: pageHeaderId, children: [jsx("div", { className: cn(S.logoArea, welcomeBannerOffset && S.logoAreaWithBanner, logoAreaClassName), children: jsx(Link, { to: "/", className: S.logoLink, children: logo ?? jsx(Logo, { size: "md", "aria-hidden": true }) }) }), jsx(WorkspaceAppSwitcher, { pathname: pathname, onNavigate: onNavigate, authenticated: authenticated, defaultApps: defaultApps, appsStorageKey: appsStorageKey }), jsx(Gap, {}), jsxs("div", { id: actionsAnchorId, className: cn(S.actionsAnchor, actionsAnchorClassName), children: [actionsStart, jsx(NavUserHeader, { ...navUserHeaderProps }), actionsEnd] })] }));
16
16
  }
17
17
 
18
18
  export { SybilionAppHeader };
@@ -0,0 +1,8 @@
1
+ import { jsx, jsxs } from 'react/jsx-runtime';
2
+ import S from './SybilionAuthHeadline.styl.js';
3
+
4
+ function SybilionAuthHeadline() {
5
+ return (jsx("div", { className: S.root, children: jsxs("div", { className: S.headline, children: [jsxs("p", { className: S.headlineParagraph, children: [jsx("span", { children: "External volatility" }), jsx("span", {})] }), jsx("p", { className: S.headlineParagraph, children: "turned into" }), jsx("p", { className: S.headlineParagraph, children: jsx("span", { className: S.headlineCyan, children: "confident decisions" }) })] }) }));
6
+ }
7
+
8
+ export { SybilionAuthHeadline };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = ".SybilionAuthHeadline_root__iExEN{align-items:center;display:flex;flex-direction:column;font-family:var(--font-family-heading);font-weight:300;height:100%;justify-content:center;padding:64px 48px;position:relative;text-shadow:0 0 2px var(--background);width:100%;z-index:10}.SybilionAuthHeadline_headline__pkjEh{font-size:40px;line-height:48px;max-width:480px;text-align:left;width:100%}.SybilionAuthHeadline_headlineParagraph__jeOTl{margin:0}.SybilionAuthHeadline_headlineCyan__26sg2{color:#27d1ef}";
4
+ var S = {"root":"SybilionAuthHeadline_root__iExEN","headline":"SybilionAuthHeadline_headline__pkjEh","headlineParagraph":"SybilionAuthHeadline_headlineParagraph__jeOTl","headlineCyan":"SybilionAuthHeadline_headlineCyan__26sg2"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,16 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import cn from 'classnames';
3
+ import { Logo } from '../../ui/Logo/Logo.js';
4
+ import { SybilionAuthHeadline } from './SybilionAuthHeadline.js';
5
+ import S from './SybilionAuthLayout.styl.js';
6
+
7
+ /** Same convention as {@link SYBILION_STANDALONE_LOGO_PUBLIC_URL}: copy `sybilion-bg.svg` from the package into `public/`. */
8
+ const SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL = '/sybilion_bg.svg';
9
+ function SybilionAuthLayout({ title, subtitle, children, logoSize, containerClassName, heroBackgroundUrl = SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL, }) {
10
+ const bg = heroBackgroundUrl
11
+ ? `url(${JSON.stringify(heroBackgroundUrl)})`
12
+ : 'none';
13
+ return (jsxs("div", { className: S.root, children: [jsxs("div", { className: S.leftPanel, children: [jsx("div", { className: S.bgImage, style: { backgroundImage: bg }, "aria-hidden": true }), jsx("div", { className: S.logoContainer, children: jsx(Logo, { className: S.logo, size: logoSize }) }), jsx(SybilionAuthHeadline, {})] }), jsx("div", { className: S.rightPanel, children: jsxs("div", { className: cn(S.formContainer, containerClassName), children: [jsxs("div", { className: S.header, children: [jsx("h1", { className: S.title, children: title }), subtitle && jsx("p", { className: S.subtitle, children: subtitle })] }), children] }) })] }));
14
+ }
15
+
16
+ export { SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL, SybilionAuthLayout };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = ".SybilionAuthLayout_root__jM5q5{display:flex;height:100vh;width:100%}.SybilionAuthLayout_leftPanel__MoyRZ{display:none}@media (min-width:768px){.SybilionAuthLayout_leftPanel__MoyRZ{background-color:var(--secondary);border-bottom-left-radius:var(--p-6);border-bottom-right-radius:var(--p-1);border-top-left-radius:var(--p-6);border-top-right-radius:var(--p-1);display:flex;overflow:hidden;position:relative;width:50%}.dark .SybilionAuthLayout_leftPanel__MoyRZ{background-color:var(--page-color-alpha-800)}}.SybilionAuthLayout_bgImage__LvCav{background-position:0 100%;background-repeat:no-repeat;background-size:contain;bottom:0;height:300px;left:0;position:absolute;width:300px}.SybilionAuthLayout_logoContainer__jR7Dw{align-items:center;display:flex;left:0;min-height:94px;padding:16px 48px;position:absolute;top:0;z-index:10}.SybilionAuthLayout_logo__LxBpo{height:24px;width:24px}.SybilionAuthLayout_rightPanel__pKcYC{align-items:center;background-color:var(--background);display:flex;flex:1;flex-direction:column;justify-content:center;padding:48px 64px}.SybilionAuthLayout_formContainer__xMCFZ{max-width:480px;width:100%}.SybilionAuthLayout_header__OOsdf{margin-bottom:36px}.SybilionAuthLayout_title__iYcZD{color:var(--foreground);font-family:var(--font-family-heading);font-size:30px;font-weight:400;line-height:42px;margin:0 0 6px}.SybilionAuthLayout_subtitle__sWv5p{color:var(--muted-foreground);font-family:Manrope,sans-serif;font-size:14px;font-weight:500;line-height:16px;margin:0}";
4
+ var S = {"root":"SybilionAuthLayout_root__jM5q5","leftPanel":"SybilionAuthLayout_leftPanel__MoyRZ","bgImage":"SybilionAuthLayout_bgImage__LvCav","logoContainer":"SybilionAuthLayout_logoContainer__jR7Dw","logo":"SybilionAuthLayout_logo__LxBpo","rightPanel":"SybilionAuthLayout_rightPanel__pKcYC","formContainer":"SybilionAuthLayout_formContainer__xMCFZ","header":"SybilionAuthLayout_header__OOsdf","title":"SybilionAuthLayout_title__iYcZD","subtitle":"SybilionAuthLayout_subtitle__sWv5p"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,11 @@
1
+ import { jsxs, Fragment, jsx } from 'react/jsx-runtime';
2
+ import { Link } from 'react-router-dom';
3
+ import { Button } from '../../ui/Button/Button.js';
4
+ import S from './SybilionSignInPanel.styl.js';
5
+
6
+ function SybilionSignInPanel({ onSignIn, isSigningIn = false, error, forgotPasswordTo, releasesTo, versionLabel, primaryButtonLabel = 'Sign-in', connectingLabel = 'Connecting...', }) {
7
+ const signingIn = Boolean(isSigningIn);
8
+ return (jsxs(Fragment, { children: [jsx("div", { className: S.socialButtonContainer, children: jsx(Button, { variant: "outline", type: "button", className: S.socialButton, onClick: () => void onSignIn(), disabled: signingIn, children: signingIn ? connectingLabel : primaryButtonLabel }) }), error ? jsx("div", { className: S.errorMessage, children: error }) : null, jsx("div", { className: S.forgotPassword, children: jsx(Link, { to: forgotPasswordTo, className: S.forgotPasswordLink, children: "Forgot password?" }) }), releasesTo && versionLabel ? (jsxs(Link, { className: S.version, to: releasesTo, children: ["v", versionLabel] })) : null] }));
9
+ }
10
+
11
+ export { SybilionSignInPanel };
@@ -0,0 +1,7 @@
1
+ import styleInject from 'style-inject';
2
+
3
+ var css_248z = ".SybilionSignInPanel_socialButtonContainer__lKNpp{display:flex;gap:10px;margin-bottom:10px;width:100%}.SybilionSignInPanel_socialButton__TqlKb{border:1px solid var(--border);border-radius:14px;flex:1;font-size:14px;font-weight:600;height:48px;padding:14px 16px}.SybilionSignInPanel_errorMessage__o8Q-m{color:red;font-size:14px;margin-bottom:10px;padding:10px}.SybilionSignInPanel_forgotPassword__47q20{margin-bottom:24px;text-align:right}.SybilionSignInPanel_forgotPasswordLink__lOJCv{color:var(--primary);font-family:Manrope,sans-serif;font-size:14px;font-weight:500;text-decoration:none;transition:opacity .2s}.SybilionSignInPanel_forgotPasswordLink__lOJCv:hover{opacity:.8}.SybilionSignInPanel_version__d5KAz{bottom:0;box-sizing:border-box;color:var(--muted-foreground);display:block;font-size:14px;margin-top:var(--p-8);opacity:.5;padding-bottom:var(--p-2);position:absolute;right:0;text-align:center;transition:opacity .3s ease-out;white-space:nowrap;width:50%}";
4
+ var S = {"socialButtonContainer":"SybilionSignInPanel_socialButtonContainer__lKNpp","socialButton":"SybilionSignInPanel_socialButton__TqlKb","errorMessage":"SybilionSignInPanel_errorMessage__o8Q-m","forgotPassword":"SybilionSignInPanel_forgotPassword__47q20","forgotPasswordLink":"SybilionSignInPanel_forgotPasswordLink__lOJCv","version":"SybilionSignInPanel_version__d5KAz"};
5
+ styleInject(css_248z);
6
+
7
+ export { S as default };
@@ -0,0 +1,44 @@
1
+ import { jsxs, jsx } from 'react/jsx-runtime';
2
+ import { createContext, useMemo, useState, useCallback, useEffect, useContext } from 'react';
3
+ import { Theme } from '@homecode/ui';
4
+ import { getThemeConfig } from '../docs/lib/theme.js';
5
+
6
+ const ThemeContext = createContext({
7
+ theme: 'light',
8
+ isDarkMode: false,
9
+ setTheme: () => { },
10
+ toggleTheme: () => { },
11
+ });
12
+ function ThemeProvider({ children, allowLocalStorage = true, activeColor, getThemeConfig: getThemeConfigProp, }) {
13
+ const getThemeConfig$1 = getThemeConfigProp ?? getThemeConfig;
14
+ const themeConfigOptions = useMemo(() => ({ activeColor }), [activeColor]);
15
+ const [theme, setTheme] = useState(() => {
16
+ return localStorage.getItem('theme') || 'light';
17
+ });
18
+ const [currThemeConfig, setCurrThemeConfig] = useState(() => getThemeConfig$1(theme === 'dark', themeConfigOptions));
19
+ const toggleTheme = useCallback(() => {
20
+ setTheme(t => (t === 'dark' ? 'light' : 'dark'));
21
+ }, []);
22
+ useEffect(() => {
23
+ setCurrThemeConfig(getThemeConfig$1(theme === 'dark', themeConfigOptions));
24
+ }, [theme, getThemeConfig$1, themeConfigOptions]);
25
+ useEffect(() => {
26
+ const root = document.documentElement;
27
+ const effectiveTheme = theme;
28
+ root.classList.remove('light', 'dark');
29
+ root.classList.add(effectiveTheme);
30
+ if (allowLocalStorage) {
31
+ localStorage.setItem('theme', theme);
32
+ }
33
+ }, [theme, allowLocalStorage]);
34
+ const value = useMemo(() => ({
35
+ theme,
36
+ isDarkMode: theme === 'dark',
37
+ setTheme,
38
+ toggleTheme,
39
+ }), [theme, toggleTheme]);
40
+ return (jsxs(ThemeContext.Provider, { value: value, children: [jsx(Theme, { config: currThemeConfig }), children] }));
41
+ }
42
+ const useTheme = () => useContext(ThemeContext);
43
+
44
+ export { ThemeProvider, useTheme };
@@ -2,8 +2,10 @@ import { ThemeHelpers, ThemeDefaults } from '@homecode/ui';
2
2
 
3
3
  const { colors, getColors, getConfig } = ThemeDefaults;
4
4
  getColors();
5
- getConfig();
6
- ({
5
+ const defaultConfig = getConfig();
6
+ const alphaMods = [0, 50, 100, 200, 300, 400, 500, 600, 700, 800, 900];
7
+ const DEFAULT_THEME_ACTIVE_COLOR = '#9c59ff';
8
+ const colorsConfig = {
7
9
  light: {
8
10
  ...ThemeHelpers.colorsConfigToVars({
9
11
  ...getColors({
@@ -20,4 +22,34 @@ getConfig();
20
22
  }),
21
23
  }),
22
24
  },
23
- });
25
+ };
26
+ function getThemeConfig(isDarkTheme, options) {
27
+ const activeColor = options?.activeColor ?? DEFAULT_THEME_ACTIVE_COLOR;
28
+ return {
29
+ ...defaultConfig,
30
+ ...colorsConfig[isDarkTheme ? 'dark' : 'light'],
31
+ ...ThemeHelpers.colorsConfigToVars({
32
+ active: {
33
+ color: activeColor,
34
+ mods: {
35
+ // @ts-ignore
36
+ alpha: alphaMods,
37
+ },
38
+ },
39
+ danger: {
40
+ color: '#ee0000',
41
+ mods: {
42
+ alpha: alphaMods,
43
+ },
44
+ },
45
+ warning: {
46
+ color: '#ffa500',
47
+ mods: {
48
+ alpha: alphaMods,
49
+ },
50
+ },
51
+ }),
52
+ };
53
+ }
54
+
55
+ export { DEFAULT_THEME_ACTIVE_COLOR, colorsConfig, getThemeConfig };
package/dist/esm/index.js CHANGED
@@ -1,3 +1,5 @@
1
+ export { ThemeProvider, useTheme } from './contexts/theme-context.js';
2
+ export { DEFAULT_THEME_ACTIVE_COLOR } from './docs/lib/theme.js';
1
3
  export { SybilionAuthProvider, createSybilionApiFetch, getSybilionApiOriginFromSdk, sybilionApiFetch, useSybilionApiFetch, useSybilionAuth } from './sybilion-auth/SybilionAuthProvider.js';
2
4
  export { SYBILION_AUTH_LOGIN_PATH, normalizeApiBaseUrl } from './sybilion-auth/authPaths.js';
3
5
  export { exchangeAuth0AccessTokenForSybilionJwt } from './sybilion-auth/exchangeSybilionToken.js';
@@ -86,6 +88,10 @@ export { findWorkspaceAppByPathname, workspaceAppSlugPath } from './components/u
86
88
  export { SidebarDatasetsItemsGrouped } from './components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js';
87
89
  export { groupSidebarDatasets } from './components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js';
88
90
  export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
91
+ export { SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL, SybilionAuthLayout } from './components/widgets/SybilionAuthLayout/SybilionAuthLayout.js';
92
+ export { SybilionAuthHeadline } from './components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js';
93
+ export { SybilionSignInPanel } from './components/widgets/SybilionSignInPanel/SybilionSignInPanel.js';
94
+ export { SignInPage } from './components/widgets/SignInPage/SignInPage.js';
89
95
  export { ChartTooltipItem } from './components/ui/Chart/components/ChartTooltipItem.js';
90
96
  export { ChartLegendItem } from './components/ui/Chart/components/ChartLegendItem.js';
91
97
  export { CustomChartLegend } from './components/ui/Chart/components/CustomChartLegend/CustomChartLegend.js';
@@ -1,2 +1,2 @@
1
1
  import type { NavUserHeaderProps } from './NavUserHeader.types';
2
- export declare function NavUserHeader({ variant, isLoading, isAuthenticated, user, menuItems, onLogout, signInSlot, onSignInClick, }: NavUserHeaderProps): string | number | bigint | true | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode>> | import("react/jsx-runtime").JSX.Element;
2
+ export declare function NavUserHeader({ variant, isLoading, isAuthenticated, user, menuItems, onLogout, signInSlot, onSignInClick, theme: themeFromHost, onThemeToggle: onThemeToggleFromHost, }: NavUserHeaderProps): string | number | bigint | true | Iterable<import("react").ReactNode> | Promise<string | number | bigint | boolean | import("react").ReactPortal | import("react").ReactElement<unknown, string | import("react").JSXElementConstructor<any>> | Iterable<import("react").ReactNode>> | import("react/jsx-runtime").JSX.Element;
@@ -18,4 +18,7 @@ export type NavUserHeaderProps = {
18
18
  /** Replaces default “Log in” control when signed out. */
19
19
  signInSlot?: ReactNode;
20
20
  onSignInClick?: () => void;
21
+ /** When both are set, theme row uses these instead of uilib `ThemeProvider` context. */
22
+ theme?: 'light' | 'dark';
23
+ onThemeToggle?: () => void;
21
24
  };
@@ -0,0 +1,10 @@
1
+ import type { RedirectLoginOptions } from '@auth0/auth0-react';
2
+ import { type SybilionAuthLayoutProps } from '#uilib/components/widgets/SybilionAuthLayout';
3
+ import { type SybilionSignInPanelProps } from '../SybilionSignInPanel';
4
+ export type SignInPageProps = Pick<SybilionAuthLayoutProps, 'heroBackgroundUrl' | 'logoSize' | 'containerClassName'> & Pick<SybilionSignInPanelProps, 'forgotPasswordTo' | 'releasesTo' | 'versionLabel' | 'primaryButtonLabel' | 'connectingLabel'> & {
5
+ title?: string;
6
+ subtitle?: string;
7
+ /** Extra Auth0 `loginWithRedirect` options; merged with default sign-in params. */
8
+ loginRedirectOptions?: RedirectLoginOptions;
9
+ };
10
+ export declare function SignInPage({ title, subtitle, forgotPasswordTo, releasesTo, versionLabel, primaryButtonLabel, connectingLabel, loginRedirectOptions, heroBackgroundUrl, logoSize, containerClassName, }: SignInPageProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export { SignInPage, type SignInPageProps } from './SignInPage';
@@ -5,10 +5,14 @@ export type SybilionAppHeaderProps = WorkspaceAppSwitcherProps & NavUserHeaderPr
5
5
  pageHeaderId?: string;
6
6
  actionsAnchorId?: string;
7
7
  actionsAnchorClassName?: string;
8
+ /** Renders before `NavUserHeader` inside the page actions anchor (e.g. impersonation). */
9
+ actionsStart?: ReactNode;
10
+ /** Renders after `NavUserHeader` inside the page actions anchor (e.g. notifications). */
11
+ actionsEnd?: ReactNode;
8
12
  /** Branded markup; omit for default lucide tile + «Sybilion». */
9
13
  logo?: ReactNode;
10
14
  logoAreaClassName?: string;
11
15
  /** Applies vertical offset when a welcome banner consumes top space (CSS `--welcome-banner-height` on shell). */
12
16
  welcomeBannerOffset?: boolean;
13
17
  };
14
- export declare function SybilionAppHeader({ pageHeaderId, actionsAnchorId, actionsAnchorClassName, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, logo, logoAreaClassName, welcomeBannerOffset, ...navUserHeaderProps }: SybilionAppHeaderProps): import("react/jsx-runtime").JSX.Element;
18
+ export declare function SybilionAppHeader({ pageHeaderId, actionsAnchorId, actionsAnchorClassName, actionsStart, actionsEnd, pathname, onNavigate, authenticated, defaultApps, appsStorageKey, logo, logoAreaClassName, welcomeBannerOffset, ...navUserHeaderProps }: SybilionAppHeaderProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export declare function SybilionAuthHeadline(): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,14 @@
1
+ import type { ReactNode } from 'react';
2
+ import type { LogoSize } from '#uilib/components/ui/Logo/Logo.types';
3
+ /** Same convention as {@link SYBILION_STANDALONE_LOGO_PUBLIC_URL}: copy `sybilion-bg.svg` from the package into `public/`. */
4
+ export declare const SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL: "/sybilion_bg.svg";
5
+ export type SybilionAuthLayoutProps = {
6
+ title: string;
7
+ subtitle?: string;
8
+ children: ReactNode;
9
+ logoSize?: LogoSize;
10
+ containerClassName?: string;
11
+ /** Public URL for the hero watermark SVG (default {@link SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL}). */
12
+ heroBackgroundUrl?: string;
13
+ };
14
+ export declare function SybilionAuthLayout({ title, subtitle, children, logoSize, containerClassName, heroBackgroundUrl, }: SybilionAuthLayoutProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,2 @@
1
+ export { SybilionAuthLayout, SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL, type SybilionAuthLayoutProps, } from './SybilionAuthLayout';
2
+ export { SybilionAuthHeadline } from './SybilionAuthHeadline';
@@ -0,0 +1,11 @@
1
+ export type SybilionSignInPanelProps = {
2
+ onSignIn: () => void | Promise<void>;
3
+ isSigningIn?: boolean;
4
+ error?: string | null;
5
+ forgotPasswordTo: string;
6
+ releasesTo?: string;
7
+ versionLabel?: string;
8
+ primaryButtonLabel?: string;
9
+ connectingLabel?: string;
10
+ };
11
+ export declare function SybilionSignInPanel({ onSignIn, isSigningIn, error, forgotPasswordTo, releasesTo, versionLabel, primaryButtonLabel, connectingLabel, }: SybilionSignInPanelProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1 @@
1
+ export { SybilionSignInPanel, type SybilionSignInPanelProps, } from './SybilionSignInPanel';
@@ -0,0 +1,20 @@
1
+ import { getThemeConfig as defaultGetThemeConfig, type GetThemeConfigOptions } from '#uilib/docs/lib/theme';
2
+ export type ThemeMode = 'light' | 'dark';
3
+ export type GetThemeConfigFn = (isDarkTheme: boolean, options?: GetThemeConfigOptions) => ReturnType<typeof defaultGetThemeConfig>;
4
+ export type { GetThemeConfigOptions };
5
+ export type ThemeProviderProps = {
6
+ children: React.ReactNode;
7
+ /** When false, DOM classes still update but theme is not persisted to `localStorage`. */
8
+ allowLocalStorage?: boolean;
9
+ /** Override docs default active/accent token (`DEFAULT_THEME_ACTIVE_COLOR`). Passed into `getThemeConfig`. */
10
+ activeColor?: string;
11
+ /** Homecode theme config; defaults to uilib docs palette. */
12
+ getThemeConfig?: GetThemeConfigFn;
13
+ };
14
+ export declare function ThemeProvider({ children, allowLocalStorage, activeColor, getThemeConfig: getThemeConfigProp, }: ThemeProviderProps): import("react/jsx-runtime").JSX.Element;
15
+ export declare const useTheme: () => {
16
+ theme: ThemeMode;
17
+ isDarkMode: boolean;
18
+ setTheme: (theme: ThemeMode) => void;
19
+ toggleTheme: () => void;
20
+ };
@@ -1,10 +1 @@
1
- export type ThemeMode = 'light' | 'dark';
2
- export declare function ThemeProvider({ children }: {
3
- children: React.ReactNode;
4
- }): import("react/jsx-runtime").JSX.Element;
5
- export declare const useTheme: () => {
6
- theme: ThemeMode;
7
- isDarkMode: boolean;
8
- setTheme: (theme: ThemeMode) => void;
9
- toggleTheme: () => void;
10
- };
1
+ export { ThemeProvider, useTheme, type GetThemeConfigFn, type GetThemeConfigOptions, type ThemeMode, type ThemeProviderProps, } from '#uilib/contexts/theme-context';
@@ -1,5 +1,9 @@
1
+ export declare const DEFAULT_THEME_ACTIVE_COLOR = "#9c59ff";
2
+ export type GetThemeConfigOptions = {
3
+ activeColor?: string;
4
+ };
1
5
  export declare const colorsConfig: {
2
6
  light: {};
3
7
  dark: {};
4
8
  };
5
- export declare function getThemeConfig(isDarkTheme: boolean): any;
9
+ export declare function getThemeConfig(isDarkTheme: boolean, options?: GetThemeConfigOptions): any;
@@ -1,3 +1,5 @@
1
+ export * from './contexts/theme-context';
2
+ export { DEFAULT_THEME_ACTIVE_COLOR } from './docs/lib/theme';
1
3
  export * from './sybilion-auth';
2
4
  export * from './types/sybilionDatasetSnapshots';
3
5
  export * from './contexts/chat-context';
@@ -58,3 +60,6 @@ export * from './components/ui/VimeoEmbed';
58
60
  export * from './components/ui/WorkspaceAppSwitcher';
59
61
  export * from './components/widgets/SidebarDatasetsItemsGrouped';
60
62
  export * from './components/widgets/SybilionAppHeader';
63
+ export * from './components/widgets/SybilionAuthLayout';
64
+ export * from './components/widgets/SybilionSignInPanel';
65
+ export * from './components/widgets/SignInPage';
@@ -40,15 +40,17 @@ Import tokens/fonts once (typically `src/main.tsx`):
40
40
  import '@sybilion/uilib/standalone-global.css';
41
41
  ```
42
42
 
43
- ### Branding (header logo + optional tab icon)
43
+ ### Branding (static SVGs + optional tab icon)
44
44
 
45
- **Header:** **`SybilionAppHeader`** includes **`Logo`** from **`@sybilion/uilib`**. **`Logo`** uses **`SYBILION_STANDALONE_LOGO_PUBLIC_URL`** (**`'/logo.svg'`**). Vite serves that from **`public/logo.svg`**. Copy the published file once:
45
+ **Header + auth hero:** Copy packaged SVGs into **`public/`** so **`Logo`** (**`SYBILION_STANDALONE_LOGO_PUBLIC_URL`** **`/logo.svg`**) and **`SybilionAuthLayout`** (**`SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL`** → **`/sybilion_bg.svg`**) resolve at runtime. Package paths: **`@sybilion/uilib/logo.svg`**, **`@sybilion/uilib/sybilion-bg.svg`**.
46
46
 
47
47
  ```bash
48
- mkdir -p public && cp node_modules/@sybilion/uilib/logo.svg public/logo.svg
48
+ mkdir -p public \
49
+ && cp node_modules/@sybilion/uilib/logo.svg public/logo.svg \
50
+ && cp node_modules/@sybilion/uilib/sybilion-bg.svg public/sybilion_bg.svg
49
51
  ```
50
52
 
51
- That asset is **`src/assets/logo.svg`** in the package (**cyan** glyph). The **uilib docs** repo uses **`assets/logo.svg`** (**purple**) for its own site only—not what **`./logo.svg`** publishes.
53
+ Logo source in the package: **`src/assets/logo.svg`** (**cyan** glyph).
52
54
 
53
55
  **Browser tab (optional):** The favicon (tiny icon next to the tab title) and the document title come from **`index.html`**, not from React. **`Logo`** does not set them. To replace Vite’s default tab icon with the package logo, add **`href="/logo.svg"`** — same as **`SYBILION_STANDALONE_LOGO_PUBLIC_URL`** from **`@sybilion/uilib`** — plus **`<title>`** in **`index.html`** `<head>`:
54
56
 
@@ -266,6 +268,20 @@ useEffect(() => {
266
268
 
267
269
  Pass `user` (or `null` while loading with `isLoading` on `NavUserHeader`) and `isAuthenticated` to `SybilionAppHeader`.
268
270
 
271
+ ### Sign-in page (unauthenticated)
272
+
273
+ Agents building the Auth0 entry route:
274
+
275
+ 1. **Public assets:** Same **`public/`** SVG setup as §1 _Branding (static SVGs + optional tab icon)_ (**`/sybilion_bg.svg`** for **`SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL`** / **`SybilionAuthLayout`**).
276
+
277
+ 2. **Routing:** Register **`/sign-in`** (and your Auth0 **`/callback`** route if applicable) **outside** **`AppLayout`** — full viewport auth chrome must not sit under **`AppShell`** / sidebar / **`SybilionAppHeader`**. Pattern: top-level `<Routes>` with `<Route path="/sign-in" … />` as a sibling of the branch that renders **`AppLayout`**, both wrapped by **`SybilionAuthProvider`** (§3).
278
+
279
+ 3. **Composition:**
280
+ - **`SignInPage`** (`@sybilion/uilib`) — drop-in when **`SybilionAuthProvider`** wraps the tree. Calls **`useSybilionAuth`**. **`loginWithRedirect`** merges defaults (`prompt`, `screen_hint`, `origin`) with optional **`loginRedirectOptions`** / **`authorizationParams`** for tenant-specific **`connection`** or audiences.
281
+ - **Custom:** compose **`SybilionAuthLayout`** + **`SybilionSignInPanel`** and wire **`loginWithRedirect`** yourself from **`useSybilionAuth`**.
282
+
283
+ 4. **Footer chip:** Pass **`versionLabel`** into **`SignInPage`** (or **`SybilionSignInPanel`**) when you want **`v…`** linked to **`releasesTo`** (default **`/releases`**).
284
+
269
285
  ## 4. Layout (AppShell)
270
286
 
271
287
  With §2 `sybilionSdk` and §3 `AppProviders` / `SybilionAuthProvider` defined, compose routing + shell so Auth0 callbacks and JWT-backed hooks wrap the whole UI.
@@ -376,7 +392,11 @@ Wire **`authenticated`**, **`user`** / **`isAuthenticated`**, **`theme`** / **`o
376
392
 
377
393
  #### Sidebar (`AppSidebar.tsx`)
378
394
 
379
- App-specific sidebar component — keeps the navigation surface out of `AppLayout` so the shell stays generic. Compose your nav from `@sybilion/uilib` primitives (`Sidebar` + `SidebarContent` + `SidebarGroup` + `SidebarMenu*`) and product widgets like `SidebarDatasetsItemsGrouped` (collapsible groups + nested rows for datasets — see demo `src/docs/pages/SidebarDatasetsItemsGroupedPage.tsx`, slug `sidebar-datasets-items-grouped`).
395
+ App-specific sidebar component — keeps the navigation surface out of `AppLayout` so the shell stays generic.
396
+
397
+ **One sidebar group (default):** Standalone apps use **a single `SidebarGroup`** for the whole sidebar menu unless the **product owner explicitly asks** for another section separated into its own group. **`SidebarDatasetsItemsGrouped`** ([`src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx`](../../src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx)) already renders **one** outer `SidebarGroup` — put primary routes (Home, Datasets, …) in **`preItems`** or **`postItems`** so nav and dataset rows share that group instead of wrapping routes in a separate **`SidebarGroup`** above/below the widget. Apps without datasets: one **`SidebarGroup`** + **`SidebarMenu`** / **`SidebarMenuItem`** only.
398
+
399
+ Collapsible dataset clusters + nested rows: demo **`src/docs/pages/SidebarDatasetsItemsGroupedPage.tsx`** (slug **`sidebar-datasets-items-grouped`**). Other primitives: **`Sidebar`** + **`SidebarContent`** + **`SidebarMenu*`**.
380
400
 
381
401
  ```tsx
382
402
  import { useEffect, useState } from 'react';
@@ -387,8 +407,6 @@ import {
387
407
  SidebarContent,
388
408
  SidebarDatasetsItemsGrouped,
389
409
  type SidebarDatasetsItemsGroupedDataset,
390
- SidebarGroup,
391
- SidebarMenu,
392
410
  SidebarMenuButton,
393
411
  SidebarMenuItem,
394
412
  } from '@sybilion/uilib';
@@ -411,27 +429,26 @@ export function AppSidebar() {
411
429
  return (
412
430
  <Sidebar variant="inset" collapsible="offcanvas">
413
431
  <SidebarContent>
414
- <SidebarGroup>
415
- <SidebarMenu>
416
- <SidebarMenuItem>
417
- <SidebarMenuButton asChild>
418
- <NavLink to="/" end>
419
- Home
420
- </NavLink>
421
- </SidebarMenuButton>
422
- </SidebarMenuItem>
423
- <SidebarMenuItem>
424
- <SidebarMenuButton asChild>
425
- <NavLink to="/datasets">Datasets</NavLink>
426
- </SidebarMenuButton>
427
- </SidebarMenuItem>
428
- </SidebarMenu>
429
- </SidebarGroup>
430
-
431
432
  <SidebarDatasetsItemsGrouped
432
433
  groupBy="regions"
433
434
  datasets={datasets}
434
435
  selectedDatasetId={selectedDatasetId}
436
+ preItems={
437
+ <>
438
+ <SidebarMenuItem>
439
+ <SidebarMenuButton asChild>
440
+ <NavLink to="/" end>
441
+ Home
442
+ </NavLink>
443
+ </SidebarMenuButton>
444
+ </SidebarMenuItem>
445
+ <SidebarMenuItem>
446
+ <SidebarMenuButton asChild>
447
+ <NavLink to="/datasets">Datasets</NavLink>
448
+ </SidebarMenuButton>
449
+ </SidebarMenuItem>
450
+ </>
451
+ }
435
452
  onDatasetClick={id => {
436
453
  setSelectedDatasetId(id);
437
454
  navigate(`/datasets/${id}`);
@@ -488,18 +505,19 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
488
505
 
489
506
  ### Greenfield checklist (agents)
490
507
 
491
- | Step | Deliverable |
492
- | ------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
493
- | React / router | **`react`**, **`react-dom`**, **`react-router-dom`**, **`@auth0/auth0-react`** (and **`vite`** if applicable) aligned with **`@sybilion/uilib`** **`package.json`** — §1 _React ecosystem versions_. |
494
- | Env files | **`.env.example`** (committed) + **`.env`** locally; **`PORT=3000`** recommended for Auth0 test tenant; **`VITE_*`** as in §1 table. |
495
- | Scripts | **`package.json`** includes mandatory **`dev`** (e.g. `"vite"`); optional **`build`**, **`preview`**. |
496
- | Vite proxy | **`vite.config.ts`** spreads **`sybilionStandaloneViteDev({ mode })`**; SDK **`baseUrl`** empty in dev (§2). |
497
- | Files | `src/libs/sybilion-sdk.ts`, `AppProviders.tsx`, `AppLayout.tsx`, `AppSidebar.tsx`, `App.tsx`, `main.tsx`, route pages under e.g. `src/pages/`. |
498
- | Branding | **`public/logo.svg`** for **`Logo`** / **`SybilionAppHeader`**: `cp node_modules/@sybilion/uilib/logo.svg public/logo.svg`. **`index.html`**: `<title>`; optional **`<link rel="icon">`** for tab icon (§1 _Branding_). |
499
- | Pages + UI | **§4 Route page body** (mandatory stack) + **Discovering** (barrel-first; bespoke markup only when no export fits). |
500
- | Auth0 | SPA callback / logout URLs + allowed web origins **`http://localhost:<PORT>`** for local dev and deploy URLs (and previews). |
501
- | API | **Dev:** proxy handles API traffic (no browser CORS to API). **Prod:** Sybilion backend **CORS** your deploy `Origin`, unless API is same-origin. |
502
- | Go (if applicable) | Server proxies **`/api`** to Sybilion; SPA dev **`baseUrl`** stays `''` when same-origin. |
508
+ | Step | Deliverable |
509
+ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
510
+ | React / router | **`react`**, **`react-dom`**, **`react-router-dom`**, **`@auth0/auth0-react`** (and **`vite`** if applicable) aligned with **`@sybilion/uilib`** **`package.json`** — §1 _React ecosystem versions_. |
511
+ | Env files | **`.env.example`** (committed) + **`.env`** locally; **`PORT=3000`** recommended for Auth0 test tenant; **`VITE_*`** as in §1 table. |
512
+ | Scripts | **`package.json`** includes mandatory **`dev`** (e.g. `"vite"`); optional **`build`**, **`preview`**. |
513
+ | Vite proxy | **`vite.config.ts`** spreads **`sybilionStandaloneViteDev({ mode })`**; SDK **`baseUrl`** empty in dev (§2). |
514
+ | Files | `src/libs/sybilion-sdk.ts`, `AppProviders.tsx`, `AppLayout.tsx`, `AppSidebar.tsx`, `App.tsx`, `main.tsx`, route pages under e.g. `src/pages/`. |
515
+ | Branding | §1 _Branding_: **`public/logo.svg`** + **`public/sybilion_bg.svg`** (one **`mkdir` + two `cp`** block). **`index.html`**: `<title>`; optional **`<link rel="icon">`** for tab icon. |
516
+ | Sign-in | §3 _Sign-in page (unauthenticated)_: **`SignInPage`** or **`SybilionAuthLayout`** + **`SybilionSignInPanel`**; **`/sign-in`** not inside **`AppLayout`**; **`SybilionAuthProvider`** wraps router. |
517
+ | Pages + UI | **§4 Route page body** (mandatory stack) + **Discovering** (barrel-first; bespoke markup only when no export fits). |
518
+ | Auth0 | SPA callback / logout URLs + allowed web origins **`http://localhost:<PORT>`** for local dev and deploy URLs (and previews). |
519
+ | API | **Dev:** proxy handles API traffic (no browser CORS to API). **Prod:** Sybilion backend **CORS** your deploy `Origin`, unless API is same-origin. |
520
+ | Go (if applicable) | Server proxies **`/api`** to Sybilion; SPA dev **`baseUrl`** stays `''` when same-origin. |
503
521
 
504
522
  ### Glossary (high-use pieces)
505
523
 
@@ -513,12 +531,15 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
513
531
  | `NavUserHeader` | Header user menu (avatar, account, theme, logout). |
514
532
  | `Sidebar`, `SidebarProvider` | Collapsible rail + context (`@sybilion/uilib`). Wrap `SidebarProvider` above `AppLayout`; render `Sidebar` inside `AppShell` (usually via `AppSidebar`). |
515
533
  | `AppSidebar` | App-specific component (`src/AppSidebar.tsx`) composing `Sidebar` + nav links + product widgets. Keeps `AppLayout` generic. |
516
- | `SidebarDatasetsItemsGrouped` | Dataset list widget for the sidebar: collapsible groups (`regions` / `target_type` / `categories`) with nested rows + selection callback. |
534
+ | `SidebarDatasetsItemsGrouped` | Single-sidebar-group widget: **`preItems`** / **`postItems`** for main nav + collapsible dataset groups (`regions` / `target_type` / `categories`) + **`onDatasetClick`**. Prefer this over stacking multiple **`SidebarGroup`** blocks unless explicitly requested. Source: **`src/components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.tsx`**. |
517
535
  | `SidebarTrigger` | Toggle sidebar visibility (especially mobile / `offcanvas`). |
518
536
  | `PageFooter` | Standard footer; requires `versionLink` + `versionLabel`. |
519
537
  | `Gap` | Spacing primitive between flex children. |
520
538
  | `PageHeader`, `PageContent`, `PageContentSection`, … | **§4 Route page body** (roles, `breadcrumbSidebarTrigger`, example). Same barrel also has `PageTabs`, `PageColumns`, `SectionHeader`, `PageEmptyCanvas`, … |
521
539
  | `SybilionAuthProvider` | Auth0 + Sybilion JWT (§3). |
540
+ | `SignInPage` | Full sign-in route using **`SybilionAuthLayout`** + **`SybilionSignInPanel`** + **`useSybilionAuth`**; §3 sign-in subsection. |
541
+ | `SybilionAuthLayout` | Split-view auth chrome (hero + form column); optional **`heroBackgroundUrl`** (default **`/sybilion_bg.svg`**). |
542
+ | `SybilionSignInPanel` | Presentational primary button, error line, forgot-password link, optional version link; §3 sign-in subsection. |
522
543
  | `useSybilionAuth` | User session + login/logout under provider. |
523
544
  | `useSybilionApiFetch` | Authenticated `fetch` using stored JWT. |
524
545
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.2.8",
3
+ "version": "1.2.10",
4
4
  "description": "Sybilion Design System — React UI components (Webpack + Stylus)",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -36,7 +36,8 @@
36
36
  "import": "./dist/standalone/vite-sybilion-standalone-dev.js",
37
37
  "default": "./dist/standalone/vite-sybilion-standalone-dev.js"
38
38
  },
39
- "./logo.svg": "./src/assets/logo.svg"
39
+ "./logo.svg": "./src/assets/logo.svg",
40
+ "./sybilion-bg.svg": "./src/assets/sybilion_bg.svg"
40
41
  },
41
42
  "files": [
42
43
  "assets",
@@ -0,0 +1,8 @@
1
+ <svg width="312" height="309" viewBox="0 0 312 309" fill="none" xmlns="http://www.w3.org/2000/svg">
2
+ <rect x="268.707" y="206.636" width="43.2928" height="57.7237" fill="#8EE9F7"/>
3
+ <rect width="43.2928" height="57.7237" transform="matrix(4.37114e-08 -1 -1 -4.37114e-08 106.365 43.848)" fill="#8EE9F7"/>
4
+ <rect x="268.707" y="206.639" width="57.7237" height="104.624" transform="rotate(180 268.707 206.639)" fill="#8EE9F7"/>
5
+ <rect x="48.6343" y="43.848" width="57.7237" height="104.624" transform="rotate(90 48.6343 43.848)" fill="#8EE9F7"/>
6
+ <rect width="57.7237" height="104.624" transform="matrix(-4.37114e-08 1 1 4.37114e-08 106.365 43.848)" fill="#8EE9F7"/>
7
+ <rect width="57.7237" height="104.624" transform="matrix(-1 0 0 1 268.707 264.36)" fill="#8EE9F7"/>
8
+ </svg>