@sybilion/uilib 1.2.5 → 1.2.8

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 (37) hide show
  1. package/assets/standalone-global.css +12 -11
  2. package/dist/esm/components/ui/AppHeader/AppHeader.styl.js +1 -1
  3. package/dist/esm/components/ui/Logo/Logo.js +7 -2
  4. package/dist/esm/components/ui/Logo/Logo.styl.js +1 -1
  5. package/dist/esm/components/ui/NavUserHeader/NavUserHeader.js +4 -2
  6. package/dist/esm/components/ui/Sidebar/Sidebar.styl.js +1 -1
  7. package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.js +4 -2
  8. package/dist/esm/components/widgets/SybilionAppHeader/SybilionAppHeader.styl.js +2 -2
  9. package/dist/esm/docs/contexts/theme-context.js +14 -0
  10. package/dist/esm/docs/lib/theme.js +23 -0
  11. package/dist/esm/types/src/components/ui/Logo/Logo.d.ts +5 -0
  12. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.d.ts +1 -1
  13. package/dist/esm/types/src/components/ui/NavUserHeader/NavUserHeader.types.d.ts +0 -4
  14. package/dist/esm/types/src/components/widgets/SybilionAppHeader/SybilionAppHeader.d.ts +7 -1
  15. package/dist/esm/types/src/docs/contexts/theme-context.d.ts +1 -0
  16. package/dist/esm/types/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.d.ts +7 -0
  17. package/docs/standalone-apps.md +111 -12
  18. package/package.json +3 -2
  19. package/src/assets/logo.svg +3 -0
  20. package/src/components/ui/AppHeader/AppHeader.styl +5 -0
  21. package/src/components/ui/Logo/Logo.styl +2 -0
  22. package/src/components/ui/Logo/Logo.tsx +12 -1
  23. package/src/components/ui/NavUserHeader/NavUserHeader.tsx +15 -17
  24. package/src/components/ui/NavUserHeader/NavUserHeader.types.ts +0 -4
  25. package/src/components/ui/Sidebar/Sidebar.styl +1 -1
  26. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.styl +46 -0
  27. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.styl.d.ts +3 -0
  28. package/src/components/widgets/SybilionAppHeader/SybilionAppHeader.tsx +23 -0
  29. package/src/docs/config/webpack.config.js +4 -3
  30. package/src/docs/contexts/theme-context.tsx +14 -1
  31. package/src/docs/pages/NavUserHeaderPage.tsx +1 -20
  32. package/src/docs/pages/StandaloneAppLayoutPage/StandaloneAppLayoutPage.constants.ts +444 -0
  33. package/src/docs/pages/{StandaloneAppLayoutPage.styl → StandaloneAppLayoutPage/StandaloneAppLayoutPage.styl} +11 -21
  34. package/src/docs/pages/{StandaloneAppLayoutPage.styl.d.ts → StandaloneAppLayoutPage/StandaloneAppLayoutPage.styl.d.ts} +1 -0
  35. package/src/docs/pages/{StandaloneAppLayoutPage.tsx → StandaloneAppLayoutPage/StandaloneAppLayoutPage.tsx} +18 -116
  36. package/src/docs/registry.ts +2 -1
  37. /package/dist/esm/types/src/docs/pages/{StandaloneAppLayoutPage.d.ts → StandaloneAppLayoutPage/StandaloneAppLayoutPage.d.ts} +0 -0
@@ -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;
@@ -64,7 +64,7 @@
64
64
  @media (min-width MOBILE)
65
65
  &[data-state="expanded"]
66
66
  display flex
67
- height calc(100vh - var(--gap-top))
67
+ height calc(100% - var(--gap-top))
68
68
  min-height 0
69
69
 
70
70
  &[data-collapsible="offcanvas"]
@@ -5,3 +5,49 @@
5
5
  align-items center
6
6
  gap var(--p-4)
7
7
  flex-shrink 0
8
+
9
+ .logoArea
10
+ position absolute
11
+ top 22px
12
+ left 40px
13
+ z-index 10
14
+
15
+ display flex
16
+ align-items center
17
+ gap var(--p-2)
18
+
19
+ @media (max-width MOBILE)
20
+ left 32px
21
+ @media (min-width MOBILE)
22
+ :global([data-slot='sidebar-wrapper'][data-state='expanded']) &
23
+ position fixed
24
+
25
+ .logoAreaWithBanner
26
+ top calc(22px + var(--welcome-banner-height, 0px))
27
+
28
+ @media (min-width MOBILE)
29
+ :global([data-slot='sidebar-wrapper'][data-state='collapsed']) &
30
+ top 22px
31
+
32
+ .logoLink
33
+ display flex
34
+ align-items center
35
+ gap 0.5rem
36
+ width fit-content
37
+
38
+ font-weight 400
39
+ font-size 1.5rem
40
+ color var(--color-foreground)
41
+ text-decoration none
42
+ white-space nowrap
43
+
44
+ svg
45
+ display inline-flex
46
+ height 32px
47
+ width auto
48
+ flex-shrink 0
49
+ transition transform 0.1s ease-in-out
50
+
51
+ &:hover svg
52
+ transform scale(1.05)
53
+
@@ -2,6 +2,9 @@
2
2
  // Please do not change this file!
3
3
  interface CssExports {
4
4
  'actionsAnchor': string;
5
+ 'logoArea': string;
6
+ 'logoAreaWithBanner': string;
7
+ 'logoLink': string;
5
8
  }
6
9
  export const cssExports: CssExports;
7
10
  export default cssExports;
@@ -1,8 +1,11 @@
1
1
  import cn from 'classnames';
2
+ import type { ReactNode } from 'react';
3
+ import { Link } from 'react-router-dom';
2
4
 
3
5
  import { AppHeaderPortal } from '#uilib/components/ui/AppHeader/AppHeader';
4
6
  import { PAGE_HEADER_ACTIONS_ID } from '#uilib/components/ui/AppHeader/appChromeAnchors';
5
7
  import { Gap } from '#uilib/components/ui/Gap/Gap';
8
+ import { Logo } from '#uilib/components/ui/Logo/Logo';
6
9
  import { NavUserHeader } from '#uilib/components/ui/NavUserHeader';
7
10
  import type { NavUserHeaderProps } from '#uilib/components/ui/NavUserHeader';
8
11
  import {
@@ -17,6 +20,11 @@ export type SybilionAppHeaderProps = WorkspaceAppSwitcherProps &
17
20
  pageHeaderId?: string;
18
21
  actionsAnchorId?: string;
19
22
  actionsAnchorClassName?: string;
23
+ /** Branded markup; omit for default lucide tile + «Sybilion». */
24
+ logo?: ReactNode;
25
+ logoAreaClassName?: string;
26
+ /** Applies vertical offset when a welcome banner consumes top space (CSS `--welcome-banner-height` on shell). */
27
+ welcomeBannerOffset?: boolean;
20
28
  };
21
29
 
22
30
  export function SybilionAppHeader({
@@ -28,10 +36,25 @@ export function SybilionAppHeader({
28
36
  authenticated,
29
37
  defaultApps,
30
38
  appsStorageKey,
39
+ logo,
40
+ logoAreaClassName,
41
+ welcomeBannerOffset,
31
42
  ...navUserHeaderProps
32
43
  }: SybilionAppHeaderProps) {
33
44
  return (
34
45
  <AppHeaderPortal pageHeaderId={pageHeaderId}>
46
+ <div
47
+ className={cn(
48
+ S.logoArea,
49
+ welcomeBannerOffset && S.logoAreaWithBanner,
50
+ logoAreaClassName,
51
+ )}
52
+ >
53
+ <Link to="/" className={S.logoLink}>
54
+ {logo ?? <Logo size="md" aria-hidden />}
55
+ </Link>
56
+ </div>
57
+
35
58
  <WorkspaceAppSwitcher
36
59
  pathname={pathname}
37
60
  onNavigate={onNavigate}
@@ -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: `${paths.assets}/logo.svg`,
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(`${paths.assets}/logo.svg`) &&
179
+ existsSync(logoSvgPath) &&
179
180
  new FaviconWebpackPlugin({
180
- logo: `${paths.assets}/logo.svg`,
181
+ logo: logoSvgPath,
181
182
  mode: 'webapp',
182
183
  devMode: 'webapp',
183
184
  favicons: {
@@ -1,4 +1,10 @@
1
- import { createContext, useContext, useEffect, useState } from 'react';
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
  }}