@sybilion/uilib 1.2.8 → 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 (33) hide show
  1. package/dist/esm/components/widgets/SignInPage/SignInPage.js +25 -0
  2. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js +8 -0
  3. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.js +7 -0
  4. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.js +16 -0
  5. package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.js +7 -0
  6. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.js +11 -0
  7. package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.js +7 -0
  8. package/dist/esm/index.js +4 -0
  9. package/dist/esm/types/src/components/widgets/SignInPage/SignInPage.d.ts +10 -0
  10. package/dist/esm/types/src/components/widgets/SignInPage/index.d.ts +1 -0
  11. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.d.ts +1 -0
  12. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.d.ts +14 -0
  13. package/dist/esm/types/src/components/widgets/SybilionAuthLayout/index.d.ts +2 -0
  14. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.d.ts +11 -0
  15. package/dist/esm/types/src/components/widgets/SybilionSignInPanel/index.d.ts +1 -0
  16. package/dist/esm/types/src/index.d.ts +3 -0
  17. package/docs/standalone-apps.md +36 -16
  18. package/package.json +3 -2
  19. package/src/assets/sybilion_bg.svg +8 -0
  20. package/src/components/widgets/SignInPage/SignInPage.tsx +84 -0
  21. package/src/components/widgets/SignInPage/index.ts +1 -0
  22. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl +26 -0
  23. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.d.ts +2 -0
  24. package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.tsx +18 -0
  25. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl +79 -0
  26. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.d.ts +2 -0
  27. package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.tsx +64 -0
  28. package/src/components/widgets/SybilionAuthLayout/index.ts +6 -0
  29. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl +48 -0
  30. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.d.ts +2 -0
  31. package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.tsx +59 -0
  32. package/src/components/widgets/SybilionSignInPanel/index.ts +4 -0
  33. package/src/index.ts +3 -0
@@ -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 };
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';
@@ -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';
@@ -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,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.
@@ -488,18 +504,19 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
488
504
 
489
505
  ### Greenfield checklist (agents)
490
506
 
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. |
507
+ | Step | Deliverable |
508
+ | ------------------ | ---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- |
509
+ | 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_. |
510
+ | Env files | **`.env.example`** (committed) + **`.env`** locally; **`PORT=3000`** recommended for Auth0 test tenant; **`VITE_*`** as in §1 table. |
511
+ | Scripts | **`package.json`** includes mandatory **`dev`** (e.g. `"vite"`); optional **`build`**, **`preview`**. |
512
+ | Vite proxy | **`vite.config.ts`** spreads **`sybilionStandaloneViteDev({ mode })`**; SDK **`baseUrl`** empty in dev (§2). |
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. |
516
+ | Pages + UI | **§4 Route page body** (mandatory stack) + **Discovering** (barrel-first; bespoke markup only when no export fits). |
517
+ | Auth0 | SPA callback / logout URLs + allowed web origins **`http://localhost:<PORT>`** for local dev and deploy URLs (and previews). |
518
+ | API | **Dev:** proxy handles API traffic (no browser CORS to API). **Prod:** Sybilion backend **CORS** your deploy `Origin`, unless API is same-origin. |
519
+ | Go (if applicable) | Server proxies **`/api`** to Sybilion; SPA dev **`baseUrl`** stays `''` when same-origin. |
503
520
 
504
521
  ### Glossary (high-use pieces)
505
522
 
@@ -519,6 +536,9 @@ Composition: `PageScroll` → `AppShell` → `AppSidebar` → `AppShellMainConte
519
536
  | `Gap` | Spacing primitive between flex children. |
520
537
  | `PageHeader`, `PageContent`, `PageContentSection`, … | **§4 Route page body** (roles, `breadcrumbSidebarTrigger`, example). Same barrel also has `PageTabs`, `PageColumns`, `SectionHeader`, `PageEmptyCanvas`, … |
521
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. |
522
542
  | `useSybilionAuth` | User session + login/logout under provider. |
523
543
  | `useSybilionApiFetch` | Authenticated `fetch` using stored JWT. |
524
544
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sybilion/uilib",
3
- "version": "1.2.8",
3
+ "version": "1.2.9",
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>
@@ -0,0 +1,84 @@
1
+ import type { RedirectLoginOptions } from '@auth0/auth0-react';
2
+
3
+ import {
4
+ SybilionAuthLayout,
5
+ type SybilionAuthLayoutProps,
6
+ } from '#uilib/components/widgets/SybilionAuthLayout';
7
+ import { useSybilionAuth } from '#uilib/sybilion-auth/SybilionAuthProvider';
8
+
9
+ import {
10
+ SybilionSignInPanel,
11
+ type SybilionSignInPanelProps,
12
+ } from '../SybilionSignInPanel';
13
+
14
+ export type SignInPageProps = Pick<
15
+ SybilionAuthLayoutProps,
16
+ 'heroBackgroundUrl' | 'logoSize' | 'containerClassName'
17
+ > &
18
+ Pick<
19
+ SybilionSignInPanelProps,
20
+ | 'forgotPasswordTo'
21
+ | 'releasesTo'
22
+ | 'versionLabel'
23
+ | 'primaryButtonLabel'
24
+ | 'connectingLabel'
25
+ > & {
26
+ title?: string;
27
+ subtitle?: string;
28
+ /** Extra Auth0 `loginWithRedirect` options; merged with default sign-in params. */
29
+ loginRedirectOptions?: RedirectLoginOptions;
30
+ };
31
+
32
+ const DEFAULT_TITLE = 'Sign In';
33
+ const DEFAULT_SUBTITLE =
34
+ 'To get access authenticate through google or your email.';
35
+
36
+ export function SignInPage({
37
+ title = DEFAULT_TITLE,
38
+ subtitle = DEFAULT_SUBTITLE,
39
+ forgotPasswordTo = '/forgot-password',
40
+ releasesTo = '/releases',
41
+ versionLabel,
42
+ primaryButtonLabel,
43
+ connectingLabel,
44
+ loginRedirectOptions,
45
+ heroBackgroundUrl,
46
+ logoSize,
47
+ containerClassName,
48
+ }: SignInPageProps) {
49
+ const { error, loginWithRedirect, isLoading } = useSybilionAuth();
50
+
51
+ const handleSignIn = () =>
52
+ loginWithRedirect({
53
+ ...loginRedirectOptions,
54
+ authorizationParams: {
55
+ prompt: 'login',
56
+ screen_hint: 'login',
57
+ ...(typeof window !== 'undefined'
58
+ ? { origin: window.location.origin }
59
+ : {}),
60
+ ...loginRedirectOptions?.authorizationParams,
61
+ },
62
+ });
63
+
64
+ return (
65
+ <SybilionAuthLayout
66
+ title={title}
67
+ subtitle={subtitle}
68
+ heroBackgroundUrl={heroBackgroundUrl}
69
+ logoSize={logoSize}
70
+ containerClassName={containerClassName}
71
+ >
72
+ <SybilionSignInPanel
73
+ onSignIn={handleSignIn}
74
+ isSigningIn={isLoading}
75
+ error={error}
76
+ forgotPasswordTo={forgotPasswordTo}
77
+ releasesTo={releasesTo}
78
+ versionLabel={versionLabel}
79
+ primaryButtonLabel={primaryButtonLabel}
80
+ connectingLabel={connectingLabel}
81
+ />
82
+ </SybilionAuthLayout>
83
+ );
84
+ }
@@ -0,0 +1 @@
1
+ export { SignInPage, type SignInPageProps } from './SignInPage';
@@ -0,0 +1,26 @@
1
+ .root
2
+ display flex
3
+ flex-direction column
4
+ justify-content center
5
+ align-items center
6
+ width 100%
7
+ padding 64px 48px
8
+ position relative
9
+ z-index 10
10
+ height 100%
11
+ font-family var(--font-family-heading)
12
+ font-weight 300
13
+ text-shadow 0 0 2px var(--background)
14
+
15
+ .headline
16
+ font-size 40px
17
+ line-height 48px
18
+ text-align left
19
+ width 100%
20
+ max-width 480px
21
+
22
+ .headlineParagraph
23
+ margin 0
24
+
25
+ .headlineCyan
26
+ color #27d1ef
@@ -0,0 +1,2 @@
1
+ const mod: { [cls: string]: string };
2
+ export default mod;
@@ -0,0 +1,18 @@
1
+ import S from './SybilionAuthHeadline.styl';
2
+
3
+ export function SybilionAuthHeadline() {
4
+ return (
5
+ <div className={S.root}>
6
+ <div className={S.headline}>
7
+ <p className={S.headlineParagraph}>
8
+ <span>External volatility</span>
9
+ <span></span>
10
+ </p>
11
+ <p className={S.headlineParagraph}>turned into</p>
12
+ <p className={S.headlineParagraph}>
13
+ <span className={S.headlineCyan}>confident decisions</span>
14
+ </p>
15
+ </div>
16
+ </div>
17
+ );
18
+ }
@@ -0,0 +1,79 @@
1
+ .root
2
+ height 100vh
3
+ display flex
4
+ width 100%
5
+
6
+ .leftPanel
7
+ display none
8
+
9
+ @media (min-width: 768px)
10
+ display flex
11
+ width 50%
12
+ position relative
13
+ overflow hidden
14
+ background-color var(--secondary)
15
+ border-top-left-radius var(--p-6)
16
+ border-bottom-left-radius var(--p-6)
17
+ border-top-right-radius var(--p-1)
18
+ border-bottom-right-radius var(--p-1)
19
+
20
+ :global(.dark) &
21
+ background-color var(--page-color-alpha-800)
22
+
23
+ .bgImage
24
+ position absolute
25
+ bottom 0
26
+ left 0
27
+ width 300px
28
+ height 300px
29
+ background-size contain
30
+ background-repeat no-repeat
31
+ background-position left bottom
32
+
33
+ .logoContainer
34
+ z-index 10
35
+ position absolute
36
+ top 0
37
+ left 0
38
+ display flex
39
+ align-items center
40
+ min-height 94px
41
+ padding 16px 48px
42
+
43
+ .logo
44
+ width 24px
45
+ height 24px
46
+
47
+ .rightPanel
48
+ flex 1
49
+ background-color var(--background)
50
+ display flex
51
+ flex-direction column
52
+ justify-content center
53
+ align-items center
54
+ padding 48px 64px
55
+
56
+ .formContainer
57
+ // position relative
58
+ max-width 480px
59
+ width 100%
60
+
61
+ .header
62
+ margin-bottom 36px
63
+
64
+ .title
65
+ font-family var(--font-family-heading)
66
+ font-weight normal
67
+ font-size 30px
68
+ line-height 42px
69
+ margin 0
70
+ margin-bottom 6px
71
+ color var(--foreground)
72
+
73
+ .subtitle
74
+ font-size 14px
75
+ color var(--muted-foreground)
76
+ line-height 16px
77
+ margin 0
78
+ font-family 'Manrope', sans-serif
79
+ font-weight 500
@@ -0,0 +1,2 @@
1
+ const mod: { [cls: string]: string };
2
+ export default mod;
@@ -0,0 +1,64 @@
1
+ import cn from 'classnames';
2
+ import type { ReactNode } from 'react';
3
+
4
+ import { Logo } from '#uilib/components/ui/Logo/Logo';
5
+ import type { LogoSize } from '#uilib/components/ui/Logo/Logo.types';
6
+
7
+ import { SybilionAuthHeadline } from './SybilionAuthHeadline';
8
+ import S from './SybilionAuthLayout.styl';
9
+
10
+ /** Same convention as {@link SYBILION_STANDALONE_LOGO_PUBLIC_URL}: copy `sybilion-bg.svg` from the package into `public/`. */
11
+ export const SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL =
12
+ '/sybilion_bg.svg' as const;
13
+
14
+ export type SybilionAuthLayoutProps = {
15
+ title: string;
16
+ subtitle?: string;
17
+ children: ReactNode;
18
+ logoSize?: LogoSize;
19
+ containerClassName?: string;
20
+ /** Public URL for the hero watermark SVG (default {@link SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL}). */
21
+ heroBackgroundUrl?: string;
22
+ };
23
+
24
+ export function SybilionAuthLayout({
25
+ title,
26
+ subtitle,
27
+ children,
28
+ logoSize,
29
+ containerClassName,
30
+ heroBackgroundUrl = SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL,
31
+ }: SybilionAuthLayoutProps) {
32
+ const bg = heroBackgroundUrl
33
+ ? `url(${JSON.stringify(heroBackgroundUrl)})`
34
+ : 'none';
35
+
36
+ return (
37
+ <div className={S.root}>
38
+ <div className={S.leftPanel}>
39
+ <div
40
+ className={S.bgImage}
41
+ style={{ backgroundImage: bg }}
42
+ aria-hidden
43
+ />
44
+
45
+ <div className={S.logoContainer}>
46
+ <Logo className={S.logo} size={logoSize} />
47
+ </div>
48
+
49
+ <SybilionAuthHeadline />
50
+ </div>
51
+
52
+ <div className={S.rightPanel}>
53
+ <div className={cn(S.formContainer, containerClassName)}>
54
+ <div className={S.header}>
55
+ <h1 className={S.title}>{title}</h1>
56
+ {subtitle && <p className={S.subtitle}>{subtitle}</p>}
57
+ </div>
58
+
59
+ {children}
60
+ </div>
61
+ </div>
62
+ </div>
63
+ );
64
+ }
@@ -0,0 +1,6 @@
1
+ export {
2
+ SybilionAuthLayout,
3
+ SYBILION_STANDALONE_AUTH_HERO_BG_PUBLIC_URL,
4
+ type SybilionAuthLayoutProps,
5
+ } from './SybilionAuthLayout';
6
+ export { SybilionAuthHeadline } from './SybilionAuthHeadline';
@@ -0,0 +1,48 @@
1
+ .socialButtonContainer
2
+ display flex
3
+ width 100%
4
+ gap 10px
5
+ margin-bottom 10px
6
+
7
+ .socialButton
8
+ flex 1
9
+ height 48px
10
+ padding 14px 16px
11
+ font-size 14px
12
+ font-weight 600
13
+ border-radius 14px
14
+ border 1px solid var(--border)
15
+
16
+ .errorMessage
17
+ color red
18
+ padding 10px
19
+ font-size 14px
20
+ margin-bottom 10px
21
+
22
+ .forgotPassword
23
+ text-align right
24
+ margin-bottom 24px
25
+
26
+ .forgotPasswordLink
27
+ color var(--primary)
28
+ text-decoration none
29
+ font-size 14px
30
+ font-family 'Manrope', sans-serif
31
+ font-weight 500
32
+ transition opacity 0.2s
33
+
34
+ &:hover
35
+ opacity 0.8
36
+
37
+ .version
38
+ display block
39
+ margin-top var(--p-8)
40
+ padding-bottom var(--p-2)
41
+ width 100%
42
+ box-sizing border-box
43
+ text-align center
44
+ font-size 14px
45
+ color var(--muted-foreground)
46
+ opacity 0.5
47
+ transition opacity 0.3s ease-out
48
+ white-space nowrap
@@ -0,0 +1,2 @@
1
+ const mod: { [cls: string]: string };
2
+ export default mod;
@@ -0,0 +1,59 @@
1
+ import { Link } from 'react-router-dom';
2
+
3
+ import { Button } from '#uilib/components/ui/Button';
4
+
5
+ import S from './SybilionSignInPanel.styl';
6
+
7
+ export type SybilionSignInPanelProps = {
8
+ onSignIn: () => void | Promise<void>;
9
+ isSigningIn?: boolean;
10
+ error?: string | null;
11
+ forgotPasswordTo: string;
12
+ releasesTo?: string;
13
+ versionLabel?: string;
14
+ primaryButtonLabel?: string;
15
+ connectingLabel?: string;
16
+ };
17
+
18
+ export function SybilionSignInPanel({
19
+ onSignIn,
20
+ isSigningIn = false,
21
+ error,
22
+ forgotPasswordTo,
23
+ releasesTo,
24
+ versionLabel,
25
+ primaryButtonLabel = 'Sign-in',
26
+ connectingLabel = 'Connecting...',
27
+ }: SybilionSignInPanelProps) {
28
+ const signingIn = Boolean(isSigningIn);
29
+
30
+ return (
31
+ <>
32
+ <div className={S.socialButtonContainer}>
33
+ <Button
34
+ variant="outline"
35
+ type="button"
36
+ className={S.socialButton}
37
+ onClick={() => void onSignIn()}
38
+ disabled={signingIn}
39
+ >
40
+ {signingIn ? connectingLabel : primaryButtonLabel}
41
+ </Button>
42
+ </div>
43
+
44
+ {error ? <div className={S.errorMessage}>{error}</div> : null}
45
+
46
+ <div className={S.forgotPassword}>
47
+ <Link to={forgotPasswordTo} className={S.forgotPasswordLink}>
48
+ Forgot password?
49
+ </Link>
50
+ </div>
51
+
52
+ {releasesTo && versionLabel ? (
53
+ <Link className={S.version} to={releasesTo}>
54
+ v{versionLabel}
55
+ </Link>
56
+ ) : null}
57
+ </>
58
+ );
59
+ }
@@ -0,0 +1,4 @@
1
+ export {
2
+ SybilionSignInPanel,
3
+ type SybilionSignInPanelProps,
4
+ } from './SybilionSignInPanel';
package/src/index.ts CHANGED
@@ -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';