@sybilion/uilib 1.2.6 → 1.2.9

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 (54) hide show
  1. package/assets/standalone-global.css +12 -11
  2. package/dist/esm/components/ui/Logo/Logo.js +7 -2
  3. package/dist/esm/components/ui/Logo/Logo.styl.js +1 -1
  4. package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +4 -2
  5. package/dist/esm/components/widgets/SignInPage/SignInPage.js +25 -0
  6. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js +8 -0
  7. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.js +7 -0
  8. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.js +16 -0
  9. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.js +7 -0
  10. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.js +11 -0
  11. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.js +7 -0
  12. package/dist/esm/docs/contexts/theme-context.js +14 -0
  13. package/dist/esm/docs/lib/theme.js +23 -0
  14. package/dist/esm/index.js +4 -0
  15. package/dist/esm/types/src/components/ui/Logo/Logo.d.ts +5 -0
  16. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +1 -1
  17. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +0 -4
  18. package/dist/esm/types/src/components/widgets/SignInPage/SignInPage.d.ts +10 -0
  19. package/dist/esm/types/src/components/widgets/SignInPage/index.d.ts +1 -0
  20. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.d.ts +1 -0
  21. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.d.ts +14 -0
  22. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/index.d.ts +2 -0
  23. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.d.ts +11 -0
  24. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/index.d.ts +1 -0
  25. package/dist/esm/types/src/docs/contexts/theme-context.d.ts +1 -0
  26. package/dist/esm/types/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.d.ts +7 -0
  27. package/dist/esm/types/src/index.d.ts +3 -0
  28. package/docs/standalone-apps.md +38 -0
  29. package/package.json +4 -2
  30. package/src/assets/logo.svg +3 -0
  31. package/src/assets/sybilion_bg.svg +8 -0
  32. package/src/components/ui/Logo/Logo.styl +2 -0
  33. package/src/components/ui/Logo/Logo.tsx +12 -1
  34. package/src/components/ui/NavUserHeader/NavUserHeader.tsx +15 -17
  35. package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +0 -4
  36. package/src/components/widgets/SignInPage/SignInPage.tsx +84 -0
  37. package/src/components/widgets/SignInPage/index.ts +1 -0
  38. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl +26 -0
  39. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.d.ts +2 -0
  40. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.tsx +18 -0
  41. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl +79 -0
  42. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.d.ts +2 -0
  43. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.tsx +64 -0
  44. package/src/components/widgets/SybilionAuthLayout/index.ts +6 -0
  45. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl +48 -0
  46. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.d.ts +2 -0
  47. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.tsx +59 -0
  48. package/src/components/widgets/SybilionSignInPanel/index.ts +4 -0
  49. package/src/docs/config/webpack.config.js +4 -3
  50. package/src/docs/contexts/theme-context.tsx +14 -1
  51. package/src/docs/pages/NavUserHeaderPage.tsx +1 -20
  52. package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.ts +444 -0
  53. package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.tsx +9 -456
  54. package/src/index.ts +3 -0
@@ -125,17 +125,18 @@
125
125
  --font-family-heading: 'KMR Apparat', sans-serif;
126
126
  --font-family-body: 'Manrope', sans-serif;
127
127
 
128
- --brand-color: var(--sb-purple-400);
129
- --brand-color-50: var(--sb-purple-50);
130
- --brand-color-100: var(--sb-purple-100);
131
- --brand-color-200: var(--sb-purple-200);
132
- --brand-color-300: var(--sb-purple-300);
133
- --brand-color-400: var(--sb-purple-400);
134
- --brand-color-500: var(--sb-purple-500);
135
- --brand-color-600: var(--sb-purple-600);
136
- --brand-color-700: var(--sb-purple-700);
137
- --brand-color-800: var(--sb-purple-800);
138
- --brand-color-900: var(--sb-purple-900);
128
+ /* Same mapping as sybilion-client/assets/globals.css (app variables) */
129
+ --brand-color: var(--sb-cyan-400);
130
+ --brand-color-50: var(--sb-cyan-50);
131
+ --brand-color-100: var(--sb-cyan-100);
132
+ --brand-color-200: var(--sb-cyan-200);
133
+ --brand-color-300: var(--sb-cyan-300);
134
+ --brand-color-400: var(--sb-cyan-400);
135
+ --brand-color-500: var(--sb-cyan-500);
136
+ --brand-color-600: var(--sb-cyan-600);
137
+ --brand-color-700: var(--sb-cyan-700);
138
+ --brand-color-800: var(--sb-cyan-800);
139
+ --brand-color-900: var(--sb-cyan-900);
139
140
  --header-height: 94px;
140
141
  --page-x-padding: var(--p-16);
141
142
  --page-y-padding: var(--p-12);
@@ -2,8 +2,13 @@ import { jsxs, jsx } from 'react/jsx-runtime';
2
2
  import cn from 'classnames';
3
3
  import S from './Logo.styl.js';
4
4
 
5
+ /**
6
+ * Public URL for the Sybilion logo in standalone apps. Copy `@sybilion/uilib/logo.svg`
7
+ * to `public/logo.svg` (see standalone-apps guide). Same path as the favicon `<link href>`.
8
+ */
9
+ const SYBILION_STANDALONE_LOGO_PUBLIC_URL = '/logo.svg';
5
10
  function Logo({ showText = true, size = 'md', className, ...props }) {
6
- return (jsxs("div", { className: cn(S.root, S[size], className), ...props, children: [jsx("img", { src: "/logo.svg", alt: "Sybilion", className: S.icon }), showText && jsx("span", { className: S.text, children: "Sybilion" })] }));
11
+ return (jsxs("div", { className: cn(S.root, S[size], className), ...props, children: [jsx("img", { src: SYBILION_STANDALONE_LOGO_PUBLIC_URL, alt: showText ? '' : 'Sybilion', className: S.icon, ...(showText ? { 'aria-hidden': true } : {}) }), showText && jsx("span", { className: S.text, children: "Sybilion" })] }));
7
12
  }
8
13
 
9
- export { Logo };
14
+ export { Logo, SYBILION_STANDALONE_LOGO_PUBLIC_URL };
@@ -1,6 +1,6 @@
1
1
  import styleInject from 'style-inject';
2
2
 
3
- var css_248z = ".Logo_root__-IFVw{align-items:center;color:var(--color-foreground);display:flex;gap:8px}.Logo_icon__cE1BI{height:24px;width:auto}.Logo_text__YpU3U{font-family:var(--font-family-heading);line-height:48px}.Logo_sm__p25D- .Logo_icon__cE1BI{height:18px}.Logo_sm__p25D- .Logo_text__YpU3U{font-size:var(--text-lg);line-height:36px}.Logo_md__1Y9mG .Logo_icon__cE1BI{height:24px}.Logo_md__1Y9mG .Logo_text__YpU3U{font-size:var(--text-2xl);line-height:48px}.Logo_lg__V9Yy2 .Logo_icon__cE1BI{height:32px}.Logo_lg__V9Yy2 .Logo_text__YpU3U{font-size:var(--text-3xl);line-height:56px}";
3
+ var css_248z = ".Logo_root__-IFVw{align-items:center;color:var(--color-foreground);display:flex;gap:8px}.Logo_icon__cE1BI{display:block;flex-shrink:0;height:24px;width:auto}.Logo_text__YpU3U{font-family:var(--font-family-heading);line-height:48px}.Logo_sm__p25D- .Logo_icon__cE1BI{height:18px}.Logo_sm__p25D- .Logo_text__YpU3U{font-size:var(--text-lg);line-height:36px}.Logo_md__1Y9mG .Logo_icon__cE1BI{height:24px}.Logo_md__1Y9mG .Logo_text__YpU3U{font-size:var(--text-2xl);line-height:48px}.Logo_lg__V9Yy2 .Logo_icon__cE1BI{height:32px}.Logo_lg__V9Yy2 .Logo_text__YpU3U{font-size:var(--text-3xl);line-height:56px}";
4
4
  var S = {"root":"Logo_root__-IFVw","icon":"Logo_icon__cE1BI","text":"Logo_text__YpU3U","sm":"Logo_sm__p25D-","md":"Logo_md__1Y9mG","lg":"Logo_lg__V9Yy2"};
5
5
  styleInject(css_248z);
6
6
 
@@ -1,5 +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
4
  import { UserCircleIcon, SunIcon, MoonIcon, SignOutIcon } from '@phosphor-icons/react';
4
5
  import { ChevronDownIcon } from 'lucide-react';
5
6
  import { Avatar } from '../Avatar/Avatar.js';
@@ -8,7 +9,8 @@ import { DropdownMenu, DropdownMenuTrigger, DropdownMenuContent, DropdownMenuLab
8
9
  import { Image } from '../Image/Image.js';
9
10
  import S from './NavUserHeader.styl.js';
10
11
 
11
- function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated, user = null, menuItems, theme, onThemeToggle, onLogout, signInSlot, onSignInClick, }) {
12
+ function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated, user = null, menuItems, onLogout, signInSlot, onSignInClick, }) {
13
+ const { toggleTheme, theme } = useTheme();
12
14
  const authenticated = isAuthenticated ?? true;
13
15
  const avatarUrl = user?.avatar ?? '';
14
16
  const userName = user?.name ?? '';
@@ -22,7 +24,7 @@ function NavUserHeader({ variant = 'default', isLoading = false, isAuthenticated
22
24
  }
23
25
  return (jsxs(Button, { variant: "ghost", size: "sm", className: S.loginButton, type: "button", onClick: onSignInClick, children: [jsx(UserCircleIcon, { className: S.iconLg }), jsx("span", { children: "Log in" })] }));
24
26
  }
25
- return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button, { variant: "ghost", size: "sm", className: cn(S.userButton, variant === 'compact' && S.compact), children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), variant === 'default' && (jsxs(Fragment, { children: [jsxs("div", { className: S.userInfo, children: [jsx("span", { className: `${S.userName} ph-no-capture`, children: userName }), jsx("span", { className: S.userEmail, children: userEmail })] }), jsx(ChevronDownIcon, { className: S.iconSm })] }))] }) }), jsxs(DropdownMenuContent, { className: S.dropdownContent, align: "end", elevation: "md", children: [jsx(DropdownMenuLabel, { className: S.userLabel, children: jsxs("div", { className: S.userLabelContent, children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), jsxs("div", { className: S.userDetails, children: [jsx("span", { className: `${S.userDetailName} ph-no-capture`, children: userName }), jsx("span", { className: S.userDetailEmail, children: userEmail })] })] }) }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuGroup, { children: [menuItems, onThemeToggle ? (jsx(DropdownMenuItem, { onSelect: () => onThemeToggle(), children: theme === 'dark' ? (jsxs(Fragment, { children: [jsx(SunIcon, {}), "Light theme"] })) : (jsxs(Fragment, { children: [jsx(MoonIcon, {}), "Dark theme"] })) })) : null] }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, { variant: "destructive", onSelect: () => onLogout(), children: [jsx(SignOutIcon, {}), "Log out"] })] })] }));
27
+ return (jsxs(DropdownMenu, { children: [jsx(DropdownMenuTrigger, { asChild: true, children: jsxs(Button, { variant: "ghost", size: "sm", className: cn(S.userButton, variant === 'compact' && S.compact), children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), variant === 'default' && (jsxs(Fragment, { children: [jsxs("div", { className: S.userInfo, children: [jsx("span", { className: `${S.userName} ph-no-capture`, children: userName }), jsx("span", { className: S.userEmail, children: userEmail })] }), jsx(ChevronDownIcon, { className: S.iconSm })] }))] }) }), jsxs(DropdownMenuContent, { className: S.dropdownContent, align: "end", elevation: "md", children: [jsx(DropdownMenuLabel, { className: S.userLabel, children: jsxs("div", { className: S.userLabelContent, children: [jsx(Avatar, { className: S.avatar, children: jsx(Image, { url: avatarUrl, alt: userName, fallback: jsx("div", { className: S.avatarFallback }) }) }), jsxs("div", { className: S.userDetails, children: [jsx("span", { className: `${S.userDetailName} ph-no-capture`, children: userName }), jsx("span", { className: S.userDetailEmail, children: userEmail })] })] }) }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuGroup, { children: [menuItems, jsx(DropdownMenuItem, { onSelect: toggleTheme, children: theme === 'dark' ? (jsxs(Fragment, { children: [jsx(SunIcon, {}), "Light theme"] })) : (jsxs(Fragment, { children: [jsx(MoonIcon, {}), "Dark theme"] })) })] }), jsx(DropdownMenuSeparator, {}), jsxs(DropdownMenuItem, { variant: "destructive", onSelect: () => onLogout(), children: [jsx(SignOutIcon, {}), "Log out"] })] })] }));
26
28
  }
27
29
 
28
30
  export { NavUserHeader };
@@ -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 };
@@ -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{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);text-align:center;transition:opacity .3s ease-out;white-space:nowrap;width:100%}";
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,14 @@
1
+ import 'react/jsx-runtime';
2
+ import { createContext, useContext } from 'react';
3
+ import '@homecode/ui';
4
+ import '../lib/theme.js';
5
+
6
+ const ThemeContext = createContext({
7
+ theme: 'light',
8
+ isDarkMode: false,
9
+ setTheme: () => { },
10
+ toggleTheme: () => { },
11
+ });
12
+ const useTheme = () => useContext(ThemeContext);
13
+
14
+ export { useTheme };
@@ -0,0 +1,23 @@
1
+ import { ThemeHelpers, ThemeDefaults } from '@homecode/ui';
2
+
3
+ const { colors, getColors, getConfig } = ThemeDefaults;
4
+ getColors();
5
+ getConfig();
6
+ ({
7
+ light: {
8
+ ...ThemeHelpers.colorsConfigToVars({
9
+ ...getColors({
10
+ accent: colors.dark,
11
+ decent: colors.light,
12
+ }),
13
+ }),
14
+ },
15
+ dark: {
16
+ ...ThemeHelpers.colorsConfigToVars({
17
+ ...getColors({
18
+ accent: colors.light,
19
+ decent: colors.dark,
20
+ }),
21
+ }),
22
+ },
23
+ });
package/dist/esm/index.js CHANGED
@@ -86,6 +86,10 @@ export { findWorkspaceAppByPathname, workspaceAppSlugPath } from './components/u
86
86
  export { SidebarDatasetsItemsGrouped } from './components/widgets/SidebarDatasetsItemsGrouped/SidebarDatasetsItemsGrouped.js';
87
87
  export { groupSidebarDatasets } from './components/widgets/SidebarDatasetsItemsGrouped/groupSidebarDatasets.js';
88
88
  export { SybilionAppHeader } from './components/widgets/SybilionAppHeader/SybilionAppHeader.js';
89
+ export { SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL, SybilionAuthLayout } from './components/widgets/SybilionAuthLayout/SybilionAuthLayout.js';
90
+ export { SybilionAuthHeadline } from './components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js';
91
+ export { SybilionSignInPanel } from './components/widgets/SybilionSignInPanel/SybilionSignInPanel.js';
92
+ export { SignInPage } from './components/widgets/SignInPage/SignInPage.js';
89
93
  export { ChartTooltipItem } from './components/ui/Chart/components/ChartTooltipItem.js';
90
94
  export { ChartLegendItem } from './components/ui/Chart/components/ChartLegendItem.js';
91
95
  export { CustomChartLegend } from './components/ui/Chart/components/CustomChartLegend/CustomChartLegend.js';
@@ -1,2 +1,7 @@
1
1
  import type { LogoProps } from './Logo.types';
2
+ /**
3
+ * Public URL for the Sybilion logo in standalone apps. Copy `@sybilion/uilib/logo.svg`
4
+ * to `public/logo.svg` (see standalone-apps guide). Same path as the favicon `<link href>`.
5
+ */
6
+ export declare const SYBILION_STANDALONE_LOGO_PUBLIC_URL: "/logo.svg";
2
7
  export declare function Logo({ showText, size, className, ...props }: LogoProps): import("react/jsx-runtime").JSX.Element;
@@ -1,2 +1,2 @@
1
1
  import type { NavUserHeaderProps } from './NavUserHeader.types';
2
- export declare function NavUserHeader({ variant, isLoading, isAuthenticated, user, menuItems, theme, onThemeToggle, 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, }: 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;
@@ -14,10 +14,6 @@ export type NavUserHeaderProps = {
14
14
  user?: NavUserHeaderUser | null;
15
15
  /** Rows inside the menu above theme toggle and logout. Use `DropdownMenuItem` nodes. */
16
16
  menuItems?: ReactNode;
17
- /** Current theme drives the toggle row label/icons. */
18
- theme: 'light' | 'dark';
19
- /** When set, renders the light/dark theme menu row. */
20
- onThemeToggle?: () => void;
21
17
  onLogout: () => void;
22
18
  /** Replaces default “Log in” control when signed out. */
23
19
  signInSlot?: ReactNode;
@@ -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';
@@ -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';
@@ -6,4 +6,5 @@ export declare const useTheme: () => {
6
6
  theme: ThemeMode;
7
7
  isDarkMode: boolean;
8
8
  setTheme: (theme: ThemeMode) => void;
9
+ toggleTheme: () => void;
9
10
  };
@@ -0,0 +1,7 @@
1
+ import { WorkspaceAppEntry } from '#uilib/components/ui/WorkspaceAppSwitcher';
2
+ import { SidebarDatasetsItemsGroupedDataset } from '#uilib/components/widgets/SidebarDatasetsItemsGrouped';
3
+ export declare const MOCK_DATASETS: SidebarDatasetsItemsGroupedDataset[];
4
+ export type PreviewPanel = 'home' | 'datasets';
5
+ export declare const TEST_HEADER_ID = "test-header-id";
6
+ export declare const DOCS_WORKSPACE_APPS_LS_KEY = "uilib.docs.workspaceApps";
7
+ export declare const DOCS_PREVIEW_APPS: WorkspaceAppEntry[];
@@ -58,3 +58,6 @@ export * from './components/ui/VimeoEmbed';
58
58
  export * from './components/ui/WorkspaceAppSwitcher';
59
59
  export * from './components/widgets/SidebarDatasetsItemsGrouped';
60
60
  export * from './components/widgets/SybilionAppHeader';
61
+ export * from './components/widgets/SybilionAuthLayout';
62
+ export * from './components/widgets/SybilionSignInPanel';
63
+ export * from './components/widgets/SignInPage';
@@ -40,6 +40,25 @@ Import tokens/fonts once (typically `src/main.tsx`):
40
40
  import '@sybilion/uilib/standalone-global.css';
41
41
  ```
42
42
 
43
+ ### Branding (static SVGs + optional tab icon)
44
+
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
+
47
+ ```bash
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
51
+ ```
52
+
53
+ Logo source in the package: **`src/assets/logo.svg`** (**cyan** glyph).
54
+
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>`:
56
+
57
+ ```html
58
+ <link rel="icon" href="/logo.svg" type="image/svg+xml" />
59
+ <title>Your app name</title>
60
+ ```
61
+
43
62
  Mount the tree with `ReactDOM.createRoot` → `App` (wrap with `StrictMode` if you want).
44
63
 
45
64
  ### `package.json` scripts (required)
@@ -249,6 +268,20 @@ useEffect(() => {
249
268
 
250
269
  Pass `user` (or `null` while loading with `isLoading` on `NavUserHeader`) and `isAuthenticated` to `SybilionAppHeader`.
251
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
+
252
285
  ## 4. Layout (AppShell)
253
286
 
254
287
  With §2 `sybilionSdk` and §3 `AppProviders` / `SybilionAuthProvider` defined, compose routing + shell so Auth0 callbacks and JWT-backed hooks wrap the whole UI.
@@ -478,6 +511,8 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
478
511
  | Scripts | **`package.json`** includes mandatory **`dev`** (e.g. `"vite"`); optional **`build`**, **`preview`**. |
479
512
  | Vite proxy | **`vite.config.ts`** spreads **`sybilionStandaloneViteDev({ mode })`**; SDK **`baseUrl`** empty in dev (§2). |
480
513
  | Files | `src/libs/sybilion-sdk.ts`, `AppProviders.tsx`, `AppLayout.tsx`, `AppSidebar.tsx`, `App.tsx`, `main.tsx`, route pages under e.g. `src/pages/`. |
514
+ | 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. |
515
+ | Sign-in | §3 _Sign-in page (unauthenticated)_: **`SignInPage`** or **`SybilionAuthLayout`** + **`SybilionSignInPanel`**; **`/sign-in`** not inside **`AppLayout`**; **`SybilionAuthProvider`** wraps router. |
481
516
  | Pages + UI | **§4 Route page body** (mandatory stack) + **Discovering** (barrel-first; bespoke markup only when no export fits). |
482
517
  | Auth0 | SPA callback / logout URLs + allowed web origins → **`http://localhost:<PORT>`** for local dev and deploy URLs (and previews). |
483
518
  | API | **Dev:** proxy handles API traffic (no browser CORS to API). **Prod:** Sybilion backend **CORS** → your deploy `Origin`, unless API is same-origin. |
@@ -501,6 +536,9 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
501
536
  | `Gap` | Spacing primitive between flex children. |
502
537
  | `PageHeader`, `PageContent`, `PageContentSection`, … | **§4 Route page body** (roles, `breadcrumbSidebarTrigger`, example). Same barrel also has `PageTabs`, `PageColumns`, `SectionHeader`, `PageEmptyCanvas`, … |
503
538
  | `SybilionAuthProvider` | Auth0 + Sybilion JWT (§3). |
539
+ | `SignInPage` | Full sign-in route using **`SybilionAuthLayout`** + **`SybilionSignInPanel`** + **`useSybilionAuth`**; §3 sign-in subsection. |
540
+ | `SybilionAuthLayout` | Split-view auth chrome (hero + form column); optional **`heroBackgroundUrl`** (default **`/sybilion_bg.svg`**). |
541
+ | `SybilionSignInPanel` | Presentational primary button, error line, forgot-password link, optional version link; §3 sign-in subsection. |
504
542
  | `useSybilionAuth` | User session + login/logout under provider. |
505
543
  | `useSybilionApiFetch` | Authenticated `fetch` using stored JWT. |
506
544
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.2.6",
3
+ "version": "1.2.9",
4
4
  "description": "Sybilion Design System — React UI components (Webpack + Stylus)",
5
5
  "publishConfig": {
6
6
  "access": "public",
@@ -35,7 +35,9 @@
35
35
  "types": "./dist/standalone/vite-sybilion-standalone-dev.d.ts",
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",
40
+ "./sybilion-bg.svg": "./src/assets/sybilion_bg.svg"
39
41
  },
40
42
  "files": [
41
43
  "assets",
@@ -0,0 +1,3 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none">
2
+ <path fill="#59f0ff" d="M13.43 24.023h-2.836v-2.836h2.836zm-2.835-2.844H5.63v-2.74h4.965Zm10.527-2.74h-2.726v2.74h-4.965v-2.74h4.952v-4.965h2.74zm-15.5 0h-2.74v-4.965h2.74ZM2.87 13.462H.034v-2.836H2.87Zm21.096 0H21.13v-2.836h2.836zM5.617 10.635h-2.74V5.669h2.74zm15.505 0h-2.74V5.669h2.74zM10.588 2.927v2.74H5.623v-2.74Zm2.842 0h4.96v2.74h-4.966v-2.74h-2.83V.09h2.836z" style="stroke-width:.13252" />
3
+ </svg>
@@ -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>
@@ -5,6 +5,8 @@
5
5
  color var(--color-foreground)
6
6
 
7
7
  .icon
8
+ display block
9
+ flex-shrink 0
8
10
  height 24px
9
11
  width auto
10
12
 
@@ -3,6 +3,12 @@ import cn from 'classnames';
3
3
  import S from './Logo.styl';
4
4
  import type { LogoProps } from './Logo.types';
5
5
 
6
+ /**
7
+ * Public URL for the Sybilion logo in standalone apps. Copy `@sybilion/uilib/logo.svg`
8
+ * to `public/logo.svg` (see standalone-apps guide). Same path as the favicon `<link href>`.
9
+ */
10
+ export const SYBILION_STANDALONE_LOGO_PUBLIC_URL = '/logo.svg' as const;
11
+
6
12
  export function Logo({
7
13
  showText = true,
8
14
  size = 'md',
@@ -11,7 +17,12 @@ export function Logo({
11
17
  }: LogoProps) {
12
18
  return (
13
19
  <div className={cn(S.root, S[size], className)} {...props}>
14
- <img src="/logo.svg" alt="Sybilion" className={S.icon} />
20
+ <img
21
+ src={SYBILION_STANDALONE_LOGO_PUBLIC_URL}
22
+ alt={showText ? '' : 'Sybilion'}
23
+ className={S.icon}
24
+ {...(showText ? { 'aria-hidden': true } : {})}
25
+ />
15
26
  {showText && <span className={S.text}>Sybilion</span>}
16
27
  </div>
17
28
  );
@@ -1,5 +1,6 @@
1
1
  import cn from 'classnames';
2
2
 
3
+ import { useTheme } from '#uilib/docs/contexts/theme-context';
3
4
  import {
4
5
  MoonIcon,
5
6
  SignOutIcon,
@@ -29,12 +30,11 @@ export function NavUserHeader({
29
30
  isAuthenticated,
30
31
  user = null,
31
32
  menuItems,
32
- theme,
33
- onThemeToggle,
34
33
  onLogout,
35
34
  signInSlot,
36
35
  onSignInClick,
37
36
  }: NavUserHeaderProps) {
37
+ const { toggleTheme, theme } = useTheme();
38
38
  const authenticated = isAuthenticated ?? true;
39
39
 
40
40
  const avatarUrl = user?.avatar ?? '';
@@ -121,21 +121,19 @@ export function NavUserHeader({
121
121
  <DropdownMenuSeparator />
122
122
  <DropdownMenuGroup>
123
123
  {menuItems}
124
- {onThemeToggle ? (
125
- <DropdownMenuItem onSelect={() => onThemeToggle()}>
126
- {theme === 'dark' ? (
127
- <>
128
- <SunIcon />
129
- Light theme
130
- </>
131
- ) : (
132
- <>
133
- <MoonIcon />
134
- Dark theme
135
- </>
136
- )}
137
- </DropdownMenuItem>
138
- ) : null}
124
+ <DropdownMenuItem onSelect={toggleTheme}>
125
+ {theme === 'dark' ? (
126
+ <>
127
+ <SunIcon />
128
+ Light theme
129
+ </>
130
+ ) : (
131
+ <>
132
+ <MoonIcon />
133
+ Dark theme
134
+ </>
135
+ )}
136
+ </DropdownMenuItem>
139
137
  </DropdownMenuGroup>
140
138
  <DropdownMenuSeparator />
141
139
  <DropdownMenuItem variant="destructive" onSelect={() => onLogout()}>
@@ -16,10 +16,6 @@ export type NavUserHeaderProps = {
16
16
  user?: NavUserHeaderUser | null;
17
17
  /** Rows inside the menu above theme toggle and logout. Use `DropdownMenuItem` nodes. */
18
18
  menuItems?: ReactNode;
19
- /** Current theme drives the toggle row label/icons. */
20
- theme: 'light' | 'dark';
21
- /** When set, renders the light/dark theme menu row. */
22
- onThemeToggle?: () => void;
23
19
  onLogout: () => void;
24
20
  /** Replaces default “Log in” control when signed out. */
25
21
  signInSlot?: ReactNode;