@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.
- package/assets/standalone-global.css +12 -11
- package/dist/esm/components/ui/Logo/Logo.js +7 -2
- package/dist/esm/components/ui/Logo/Logo.styl.js +1 -1
- package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +4 -2
- package/dist/esm/components/widgets/SignInPage/SignInPage.js +25 -0
- package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.js +8 -0
- package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.js +7 -0
- package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.js +16 -0
- package/dist/esm/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.js +7 -0
- package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.js +11 -0
- package/dist/esm/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.js +7 -0
- package/dist/esm/docs/contexts/theme-context.js +14 -0
- package/dist/esm/docs/lib/theme.js +23 -0
- package/dist/esm/index.js +4 -0
- package/dist/esm/types/src/components/ui/Logo/Logo.d.ts +5 -0
- package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +1 -1
- package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +0 -4
- package/dist/esm/types/src/components/widgets/SignInPage/SignInPage.d.ts +10 -0
- package/dist/esm/types/src/components/widgets/SignInPage/index.d.ts +1 -0
- package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.d.ts +1 -0
- package/dist/esm/types/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.d.ts +14 -0
- package/dist/esm/types/src/components/widgets/SybilionAuthLayout/index.d.ts +2 -0
- package/dist/esm/types/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.d.ts +11 -0
- package/dist/esm/types/src/components/widgets/SybilionSignInPanel/index.d.ts +1 -0
- package/dist/esm/types/src/docs/contexts/theme-context.d.ts +1 -0
- package/dist/esm/types/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.d.ts +7 -0
- package/dist/esm/types/src/index.d.ts +3 -0
- package/docs/standalone-apps.md +38 -0
- package/package.json +4 -2
- package/src/assets/logo.svg +3 -0
- package/src/assets/sybilion_bg.svg +8 -0
- package/src/components/ui/Logo/Logo.styl +2 -0
- package/src/components/ui/Logo/Logo.tsx +12 -1
- package/src/components/ui/NavUserHeader/NavUserHeader.tsx +15 -17
- package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +0 -4
- package/src/components/widgets/SignInPage/SignInPage.tsx +84 -0
- package/src/components/widgets/SignInPage/index.ts +1 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl +26 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.styl.d.ts +2 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthHeadline.tsx +18 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl +79 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.styl.d.ts +2 -0
- package/src/components/widgets/SybilionAuthLayout/SybilionAuthLayout.tsx +64 -0
- package/src/components/widgets/SybilionAuthLayout/index.ts +6 -0
- package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl +48 -0
- package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.styl.d.ts +2 -0
- package/src/components/widgets/SybilionSignInPanel/SybilionSignInPanel.tsx +59 -0
- package/src/components/widgets/SybilionSignInPanel/index.ts +4 -0
- package/src/docs/config/webpack.config.js +4 -3
- package/src/docs/contexts/theme-context.tsx +14 -1
- package/src/docs/pages/NavUserHeaderPage.tsx +1 -20
- package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.ts +444 -0
- package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.tsx +9 -456
- package/src/index.ts +3 -0
|
@@ -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,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,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,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,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
|
+
}
|
|
@@ -20,6 +20,7 @@ const FaviconWebpackPlugin = require('favicons-webpack-plugin');
|
|
|
20
20
|
const pkg = require('../../../package.json');
|
|
21
21
|
|
|
22
22
|
const themeStyl = pathResolve(paths.src, 'theme.styl');
|
|
23
|
+
const logoSvgPath = pathResolve(paths.assets, 'logo.svg');
|
|
23
24
|
|
|
24
25
|
export default (env, argv) => {
|
|
25
26
|
const isDev = argv.mode === 'development';
|
|
@@ -148,7 +149,7 @@ export default (env, argv) => {
|
|
|
148
149
|
noErrorOnMissing: true,
|
|
149
150
|
},
|
|
150
151
|
{
|
|
151
|
-
from:
|
|
152
|
+
from: logoSvgPath,
|
|
152
153
|
to: paths.build,
|
|
153
154
|
noErrorOnMissing: true,
|
|
154
155
|
},
|
|
@@ -175,9 +176,9 @@ export default (env, argv) => {
|
|
|
175
176
|
minifyURLs: true,
|
|
176
177
|
},
|
|
177
178
|
}),
|
|
178
|
-
existsSync(
|
|
179
|
+
existsSync(logoSvgPath) &&
|
|
179
180
|
new FaviconWebpackPlugin({
|
|
180
|
-
logo:
|
|
181
|
+
logo: logoSvgPath,
|
|
181
182
|
mode: 'webapp',
|
|
182
183
|
devMode: 'webapp',
|
|
183
184
|
favicons: {
|
|
@@ -1,4 +1,10 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import {
|
|
2
|
+
createContext,
|
|
3
|
+
useCallback,
|
|
4
|
+
useContext,
|
|
5
|
+
useEffect,
|
|
6
|
+
useState,
|
|
7
|
+
} from 'react';
|
|
2
8
|
|
|
3
9
|
import { Theme as ThemeRoot } from '@homecode/ui';
|
|
4
10
|
|
|
@@ -10,10 +16,12 @@ const ThemeContext = createContext<{
|
|
|
10
16
|
theme: ThemeMode;
|
|
11
17
|
isDarkMode: boolean;
|
|
12
18
|
setTheme: (theme: ThemeMode) => void;
|
|
19
|
+
toggleTheme: () => void;
|
|
13
20
|
}>({
|
|
14
21
|
theme: 'light',
|
|
15
22
|
isDarkMode: false,
|
|
16
23
|
setTheme: () => {},
|
|
24
|
+
toggleTheme: () => {},
|
|
17
25
|
});
|
|
18
26
|
|
|
19
27
|
export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
@@ -25,6 +33,10 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
|
25
33
|
getThemeConfig(theme === 'dark'),
|
|
26
34
|
);
|
|
27
35
|
|
|
36
|
+
const toggleTheme = useCallback(() => {
|
|
37
|
+
setTheme(theme === 'dark' ? 'light' : 'dark');
|
|
38
|
+
}, [theme, setTheme]);
|
|
39
|
+
|
|
28
40
|
useEffect(() => {
|
|
29
41
|
setCurrThemeConfig(getThemeConfig(theme === 'dark'));
|
|
30
42
|
}, [theme]);
|
|
@@ -44,6 +56,7 @@ export function ThemeProvider({ children }: { children: React.ReactNode }) {
|
|
|
44
56
|
theme,
|
|
45
57
|
isDarkMode: theme === 'dark',
|
|
46
58
|
setTheme,
|
|
59
|
+
toggleTheme,
|
|
47
60
|
}}
|
|
48
61
|
>
|
|
49
62
|
<ThemeRoot config={currThemeConfig} />
|
|
@@ -1,5 +1,3 @@
|
|
|
1
|
-
import { useCallback, useEffect, useState } from 'react';
|
|
2
|
-
|
|
3
1
|
import { DropdownMenuItem } from '#uilib/components/ui/DropdownMenu';
|
|
4
2
|
import { NavUserHeader } from '#uilib/components/ui/NavUserHeader';
|
|
5
3
|
import { PageContentSection } from '#uilib/components/ui/Page';
|
|
@@ -9,19 +7,6 @@ import { AppPageHeader } from '../components/AppPageHeader/AppPageHeader';
|
|
|
9
7
|
import { DocsHeaderActions } from '../docsHeaderActions';
|
|
10
8
|
|
|
11
9
|
export default function NavUserHeaderPage() {
|
|
12
|
-
const [theme, setTheme] = useState<'light' | 'dark'>('light');
|
|
13
|
-
|
|
14
|
-
useEffect(() => {
|
|
15
|
-
document.documentElement.dataset.theme = theme;
|
|
16
|
-
return () => {
|
|
17
|
-
delete document.documentElement.dataset.theme;
|
|
18
|
-
};
|
|
19
|
-
}, [theme]);
|
|
20
|
-
|
|
21
|
-
const onThemeToggle = useCallback(() => {
|
|
22
|
-
setTheme(t => (t === 'dark' ? 'light' : 'dark'));
|
|
23
|
-
}, []);
|
|
24
|
-
|
|
25
10
|
const customMenuItems = (
|
|
26
11
|
<>
|
|
27
12
|
<DropdownMenuItem>
|
|
@@ -40,7 +25,7 @@ export default function NavUserHeaderPage() {
|
|
|
40
25
|
<AppPageHeader
|
|
41
26
|
breadcrumbs={[{ label: 'NavUserHeader' }]}
|
|
42
27
|
title="NavUserHeader"
|
|
43
|
-
subheader="User menu with label, custom rows, theme toggle, and logout."
|
|
28
|
+
subheader="User menu with label, custom rows, theme toggle (docs ThemeProvider), and logout."
|
|
44
29
|
actions={<DocsHeaderActions />}
|
|
45
30
|
/>
|
|
46
31
|
<PageContentSection
|
|
@@ -56,8 +41,6 @@ export default function NavUserHeaderPage() {
|
|
|
56
41
|
email: 'demo@sybilion.io',
|
|
57
42
|
avatar: '',
|
|
58
43
|
}}
|
|
59
|
-
theme={theme}
|
|
60
|
-
onThemeToggle={onThemeToggle}
|
|
61
44
|
onLogout={() => {
|
|
62
45
|
console.info('[docs] logout');
|
|
63
46
|
}}
|
|
@@ -75,8 +58,6 @@ export default function NavUserHeaderPage() {
|
|
|
75
58
|
email: 'compact@sybilion.io',
|
|
76
59
|
avatar: '',
|
|
77
60
|
}}
|
|
78
|
-
theme={theme}
|
|
79
|
-
onThemeToggle={onThemeToggle}
|
|
80
61
|
onLogout={() => {
|
|
81
62
|
console.info('[docs] logout compact');
|
|
82
63
|
}}
|