@gjsify/example-gtk-adwaita-storybook 0.19.0

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 (119) hide show
  1. package/README.md +120 -0
  2. package/dist/adw-runasync.mjs +1 -0
  3. package/dist/gjs.js +91 -0
  4. package/dist/interact-probe.node.mjs +87 -0
  5. package/dist/probe.node.mjs +87 -0
  6. package/dist/render-probe.node.mjs +87 -0
  7. package/dist/runasync-probe.mjs +1 -0
  8. package/dist/storybook.node.mjs +87 -0
  9. package/package.json +64 -0
  10. package/src/browser/buttons/button-content.web.ts +55 -0
  11. package/src/browser/buttons/button-styles.web.ts +79 -0
  12. package/src/browser/buttons/split-button.web.ts +86 -0
  13. package/src/browser/buttons/toggle-group.web.ts +56 -0
  14. package/src/browser/embed.ts +46 -0
  15. package/src/browser/feedback/about-dialog.web.ts +82 -0
  16. package/src/browser/feedback/alert-dialog.web.ts +72 -0
  17. package/src/browser/feedback/preferences-dialog.web.ts +106 -0
  18. package/src/browser/feedback/toast.web.ts +62 -0
  19. package/src/browser/index.html +23 -0
  20. package/src/browser/layout/clamp.web.ts +45 -0
  21. package/src/browser/layout/header-bar.web.ts +56 -0
  22. package/src/browser/layout/toolbar-view.web.ts +95 -0
  23. package/src/browser/layout/wrap-box.web.ts +45 -0
  24. package/src/browser/main.ts +14 -0
  25. package/src/browser/navigation/bottom-sheet.web.ts +119 -0
  26. package/src/browser/navigation/navigation-split-view.web.ts +99 -0
  27. package/src/browser/navigation/navigation-view.web.ts +104 -0
  28. package/src/browser/navigation/overlay-split-view.web.ts +106 -0
  29. package/src/browser/navigation/sidebar.web.ts +84 -0
  30. package/src/browser/presentation/avatar.web.ts +36 -0
  31. package/src/browser/presentation/banner.web.ts +41 -0
  32. package/src/browser/presentation/spinner.web.ts +28 -0
  33. package/src/browser/presentation/status-page.web.ts +43 -0
  34. package/src/browser/presentation/window-title.web.ts +34 -0
  35. package/src/browser/rows/action-row.web.ts +61 -0
  36. package/src/browser/rows/button-row.web.ts +64 -0
  37. package/src/browser/rows/combo-row.web.ts +44 -0
  38. package/src/browser/rows/entry-row.web.ts +42 -0
  39. package/src/browser/rows/expander-row.web.ts +53 -0
  40. package/src/browser/rows/password-entry-row.web.ts +43 -0
  41. package/src/browser/rows/preferences-group.web.ts +68 -0
  42. package/src/browser/rows/spin-row.web.ts +47 -0
  43. package/src/browser/rows/switch-row.web.ts +43 -0
  44. package/src/browser/stories.ts +82 -0
  45. package/src/browser/view-switching/carousel.web.ts +106 -0
  46. package/src/browser/view-switching/inline-view-switcher.web.ts +55 -0
  47. package/src/browser/view-switching/tab-view.web.ts +64 -0
  48. package/src/browser/view-switching/view-switcher.web.ts +55 -0
  49. package/src/buttons/button-content.meta.ts +26 -0
  50. package/src/buttons/button-content.story.ts +49 -0
  51. package/src/buttons/button-styles.meta.ts +26 -0
  52. package/src/buttons/button-styles.story.ts +77 -0
  53. package/src/buttons/split-button.meta.ts +45 -0
  54. package/src/buttons/split-button.story.ts +102 -0
  55. package/src/buttons/toggle-group.meta.ts +34 -0
  56. package/src/buttons/toggle-group.story.ts +56 -0
  57. package/src/feedback/about-dialog.meta.ts +13 -0
  58. package/src/feedback/about-dialog.story.ts +64 -0
  59. package/src/feedback/alert-dialog.meta.ts +19 -0
  60. package/src/feedback/alert-dialog.story.ts +61 -0
  61. package/src/feedback/preferences-dialog.meta.ts +13 -0
  62. package/src/feedback/preferences-dialog.story.ts +92 -0
  63. package/src/feedback/toast.meta.ts +23 -0
  64. package/src/feedback/toast.story.ts +66 -0
  65. package/src/layout/clamp.meta.ts +29 -0
  66. package/src/layout/clamp.story.ts +59 -0
  67. package/src/layout/header-bar.meta.ts +14 -0
  68. package/src/layout/header-bar.story.ts +66 -0
  69. package/src/layout/toolbar-view.meta.ts +18 -0
  70. package/src/layout/toolbar-view.story.ts +71 -0
  71. package/src/layout/wrap-box.meta.ts +29 -0
  72. package/src/layout/wrap-box.story.ts +52 -0
  73. package/src/metas.ts +41 -0
  74. package/src/navigation/bottom-sheet.meta.ts +13 -0
  75. package/src/navigation/bottom-sheet.story.ts +90 -0
  76. package/src/navigation/navigation-split-view.meta.ts +13 -0
  77. package/src/navigation/navigation-split-view.story.ts +83 -0
  78. package/src/navigation/navigation-view.meta.ts +19 -0
  79. package/src/navigation/navigation-view.story.ts +77 -0
  80. package/src/navigation/overlay-split-view.meta.ts +13 -0
  81. package/src/navigation/overlay-split-view.story.ts +82 -0
  82. package/src/navigation/sidebar.meta.ts +30 -0
  83. package/src/navigation/sidebar.story.ts +85 -0
  84. package/src/presentation/avatar.meta.ts +24 -0
  85. package/src/presentation/avatar.story.ts +46 -0
  86. package/src/presentation/banner.meta.ts +19 -0
  87. package/src/presentation/banner.story.ts +53 -0
  88. package/src/presentation/spinner.meta.ts +9 -0
  89. package/src/presentation/spinner.story.ts +47 -0
  90. package/src/presentation/status-page.meta.ts +29 -0
  91. package/src/presentation/status-page.story.ts +55 -0
  92. package/src/presentation/window-title.meta.ts +12 -0
  93. package/src/presentation/window-title.story.ts +42 -0
  94. package/src/rows/action-row.meta.ts +30 -0
  95. package/src/rows/action-row.story.ts +62 -0
  96. package/src/rows/button-row.meta.ts +34 -0
  97. package/src/rows/button-row.story.ts +61 -0
  98. package/src/rows/combo-row.meta.ts +29 -0
  99. package/src/rows/combo-row.story.ts +51 -0
  100. package/src/rows/entry-row.meta.ts +13 -0
  101. package/src/rows/entry-row.story.ts +49 -0
  102. package/src/rows/expander-row.meta.ts +25 -0
  103. package/src/rows/expander-row.story.ts +54 -0
  104. package/src/rows/password-entry-row.meta.ts +12 -0
  105. package/src/rows/password-entry-row.story.ts +47 -0
  106. package/src/rows/preferences-group.meta.ts +18 -0
  107. package/src/rows/preferences-group.story.ts +67 -0
  108. package/src/rows/spin-row.meta.ts +29 -0
  109. package/src/rows/spin-row.story.ts +56 -0
  110. package/src/rows/switch-row.meta.ts +18 -0
  111. package/src/rows/switch-row.story.ts +49 -0
  112. package/src/view-switching/carousel.meta.ts +35 -0
  113. package/src/view-switching/carousel.story.ts +131 -0
  114. package/src/view-switching/inline-view-switcher.meta.ts +25 -0
  115. package/src/view-switching/inline-view-switcher.story.ts +88 -0
  116. package/src/view-switching/tab-view.meta.ts +12 -0
  117. package/src/view-switching/tab-view.story.ts +72 -0
  118. package/src/view-switching/view-switcher.meta.ts +23 -0
  119. package/src/view-switching/view-switcher.story.ts +87 -0
@@ -0,0 +1,77 @@
1
+ // Adw.NavigationView — a stack of navigation pages with push/pop and an
2
+ // automatic back button. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { navigationViewMeta } from './navigation-view.meta.js';
9
+
10
+ /** Story: Adw.NavigationView with a root page that pushes a detail page. */
11
+ export class NavigationViewStory extends StoryWidget {
12
+ private _view: Adw.NavigationView | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookNavigationView' }, NavigationViewStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(NavigationViewStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...navigationViewMeta, component: Adw.NavigationView.$gtype };
24
+ }
25
+
26
+ private buildPage(title: string, body: Gtk.Widget): Adw.NavigationPage {
27
+ const toolbarView = new Adw.ToolbarView();
28
+ toolbarView.add_top_bar(new Adw.HeaderBar());
29
+ toolbarView.content = body;
30
+ return new Adw.NavigationPage({ title, child: toolbarView });
31
+ }
32
+
33
+ initialize(): void {
34
+ this._view = new Adw.NavigationView({
35
+ animateTransitions: this.args.animateTransitions as boolean,
36
+ widthRequest: 480,
37
+ heightRequest: 340,
38
+ });
39
+
40
+ const detail = this.buildPage(
41
+ this.args.detailTitle as string,
42
+ new Adw.StatusPage({
43
+ iconName: 'avatar-default-symbolic',
44
+ title: this.args.detailTitle as string,
45
+ description: 'Mathematician and writer, the first computer programmer.',
46
+ vexpand: true,
47
+ }),
48
+ );
49
+
50
+ const openButton = new Gtk.Button({
51
+ label: 'Open contact',
52
+ halign: Gtk.Align.CENTER,
53
+ valign: Gtk.Align.CENTER,
54
+ vexpand: true,
55
+ });
56
+ openButton.add_css_class('pill');
57
+ openButton.add_css_class('suggested-action');
58
+ openButton.connect('clicked', () => {
59
+ this._view?.push(detail);
60
+ });
61
+
62
+ const root = this.buildPage(this.args.rootTitle as string, openButton);
63
+
64
+ this._view.add(root);
65
+ this._view.add(detail);
66
+ this.addContent(this._view);
67
+ }
68
+
69
+ updateArgs(_args: StoryArgs): void {
70
+ if (!this._view) return;
71
+ this._view.animateTransitions = this.args.animateTransitions as boolean;
72
+ }
73
+ }
74
+
75
+ GObject.type_ensure(NavigationViewStory.$gtype);
76
+
77
+ export const NavigationViewStories: StoryModule = { stories: [NavigationViewStory] };
@@ -0,0 +1,13 @@
1
+ // Shared, renderer-agnostic metadata for the Overlay Split View story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const overlaySplitViewMeta: StoryMeta = {
6
+ title: 'Navigation/Overlay Split View',
7
+ description:
8
+ 'Adw.OverlaySplitView — a sidebar shown beside the content, or overlaid on top of it when collapsed.',
9
+ controls: [
10
+ { name: 'showSidebar', label: 'Show sidebar', type: ControlType.BOOLEAN, defaultValue: true },
11
+ { name: 'collapsed', label: 'Collapsed', type: ControlType.BOOLEAN, defaultValue: false },
12
+ ],
13
+ };
@@ -0,0 +1,82 @@
1
+ // Adw.OverlaySplitView — a sidebar that sits beside the content, or overlays it
2
+ // when collapsed. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { overlaySplitViewMeta } from './overlay-split-view.meta.js';
9
+
10
+ /** Story: Adw.OverlaySplitView with a boxed-list sidebar and a status-page content. */
11
+ export class OverlaySplitViewStory extends StoryWidget {
12
+ private _view: Adw.OverlaySplitView | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookOverlaySplitView' }, OverlaySplitViewStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(OverlaySplitViewStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...overlaySplitViewMeta, component: Adw.OverlaySplitView.$gtype };
24
+ }
25
+
26
+ private buildSidebar(): Gtk.Widget {
27
+ const group = new Adw.PreferencesGroup();
28
+ for (const [title, icon] of [
29
+ ['Home', 'go-home-symbolic'],
30
+ ['Discover', 'system-search-symbolic'],
31
+ ['Library', 'folder-music-symbolic'],
32
+ ['Settings', 'emblem-system-symbolic'],
33
+ ] as const) {
34
+ const row = new Adw.ActionRow({ title });
35
+ row.add_prefix(new Gtk.Image({ iconName: icon }));
36
+ row.activatable = true;
37
+ group.add(row);
38
+ }
39
+
40
+ const toolbarView = new Adw.ToolbarView();
41
+ toolbarView.add_top_bar(new Adw.HeaderBar({ showTitle: false }));
42
+ toolbarView.content = group;
43
+ toolbarView.add_css_class('sidebar');
44
+ return toolbarView;
45
+ }
46
+
47
+ private buildContent(): Gtk.Widget {
48
+ const status = new Adw.StatusPage({
49
+ iconName: 'folder-music-symbolic',
50
+ title: 'Your Library',
51
+ description: 'Toggle the sidebar to browse sections. Collapse it to overlay the content.',
52
+ vexpand: true,
53
+ });
54
+
55
+ const toolbarView = new Adw.ToolbarView();
56
+ toolbarView.add_top_bar(new Adw.HeaderBar());
57
+ toolbarView.content = status;
58
+ return toolbarView;
59
+ }
60
+
61
+ initialize(): void {
62
+ this._view = new Adw.OverlaySplitView({
63
+ sidebar: this.buildSidebar(),
64
+ content: this.buildContent(),
65
+ showSidebar: this.args.showSidebar as boolean,
66
+ collapsed: this.args.collapsed as boolean,
67
+ widthRequest: 480,
68
+ heightRequest: 340,
69
+ });
70
+ this.addContent(this._view);
71
+ }
72
+
73
+ updateArgs(_args: StoryArgs): void {
74
+ if (!this._view) return;
75
+ this._view.showSidebar = this.args.showSidebar as boolean;
76
+ this._view.collapsed = this.args.collapsed as boolean;
77
+ }
78
+ }
79
+
80
+ GObject.type_ensure(OverlaySplitViewStory.$gtype);
81
+
82
+ export const OverlaySplitViewStories: StoryModule = { stories: [OverlaySplitViewStory] };
@@ -0,0 +1,30 @@
1
+ // Shared, renderer-agnostic metadata for the Sidebar story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const sidebarMeta: StoryMeta = {
6
+ title: 'Navigation/Sidebar',
7
+ description:
8
+ 'Adw.Sidebar — a selectable list of Adw.SidebarItem grouped into sections. Selecting an item updates the content.',
9
+ controls: [
10
+ {
11
+ name: 'mode',
12
+ label: 'Mode',
13
+ type: ControlType.SELECT,
14
+ options: [
15
+ { label: 'Sidebar', value: 'sidebar' },
16
+ { label: 'Page', value: 'page' },
17
+ ],
18
+ defaultValue: 'sidebar',
19
+ },
20
+ {
21
+ name: 'selected',
22
+ label: 'Selected index',
23
+ type: ControlType.NUMBER,
24
+ min: 0,
25
+ max: 3,
26
+ step: 1,
27
+ defaultValue: 0,
28
+ },
29
+ ],
30
+ };
@@ -0,0 +1,85 @@
1
+ // Adw.Sidebar — a selectable navigation sidebar built from sections of items.
2
+ // original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { sidebarMeta } from './sidebar.meta.js';
9
+
10
+ /** Story: Adw.Sidebar with a titled Adw.SidebarSection driving a content pane. */
11
+ export class SidebarStory extends StoryWidget {
12
+ private _sidebar: Adw.Sidebar | null = null;
13
+ private _status: Adw.StatusPage | null = null;
14
+
15
+ static {
16
+ GObject.registerClass({ GTypeName: 'AdwStorybookSidebar' }, SidebarStory);
17
+ }
18
+
19
+ constructor() {
20
+ super(StoryWidget.fromMeta(SidebarStory.getMetadata(), 'Default'));
21
+ }
22
+
23
+ static getMetadata(): StoryMeta {
24
+ return { ...sidebarMeta, component: Adw.Sidebar.$gtype };
25
+ }
26
+
27
+ private readonly items: readonly { title: string; subtitle: string; icon: string }[] = [
28
+ { title: 'Inbox', subtitle: '3 unread', icon: 'mail-unread-symbolic' },
29
+ { title: 'Starred', subtitle: 'Favourites', icon: 'starred-symbolic' },
30
+ { title: 'Sent', subtitle: 'Outgoing mail', icon: 'mail-send-symbolic' },
31
+ { title: 'Archive', subtitle: 'Older mail', icon: 'folder-symbolic' },
32
+ ];
33
+
34
+ private modeFromArg(value: string): Adw.SidebarMode {
35
+ return value === 'page' ? Adw.SidebarMode.PAGE : Adw.SidebarMode.SIDEBAR;
36
+ }
37
+
38
+ private syncContent(): void {
39
+ if (!this._sidebar || !this._status) return;
40
+ const item = this.items[this._sidebar.selected] ?? this.items[0];
41
+ this._status.title = item.title;
42
+ this._status.iconName = item.icon;
43
+ this._status.description = item.subtitle;
44
+ }
45
+
46
+ initialize(): void {
47
+ const section = new Adw.SidebarSection({ title: 'Mailboxes' });
48
+ for (const entry of this.items) {
49
+ section.append(new Adw.SidebarItem({ title: entry.title, subtitle: entry.subtitle, iconName: entry.icon }));
50
+ }
51
+
52
+ this._sidebar = new Adw.Sidebar({
53
+ mode: this.modeFromArg(this.args.mode as string),
54
+ selected: this.args.selected as number,
55
+ widthRequest: 220,
56
+ });
57
+ this._sidebar.append(section);
58
+ this._sidebar.connect('notify::selected', () => this.syncContent());
59
+
60
+ this._status = new Adw.StatusPage({ hexpand: true, vexpand: true });
61
+
62
+ const box = new Gtk.Box({
63
+ orientation: Gtk.Orientation.HORIZONTAL,
64
+ widthRequest: 480,
65
+ heightRequest: 340,
66
+ });
67
+ box.append(this._sidebar);
68
+ box.append(new Gtk.Separator({ orientation: Gtk.Orientation.VERTICAL }));
69
+ box.append(this._status);
70
+
71
+ this.syncContent();
72
+ this.addContent(box);
73
+ }
74
+
75
+ updateArgs(_args: StoryArgs): void {
76
+ if (!this._sidebar) return;
77
+ this._sidebar.mode = this.modeFromArg(this.args.mode as string);
78
+ this._sidebar.selected = this.args.selected as number;
79
+ this.syncContent();
80
+ }
81
+ }
82
+
83
+ GObject.type_ensure(SidebarStory.$gtype);
84
+
85
+ export const SidebarStories: StoryModule = { stories: [SidebarStory] };
@@ -0,0 +1,24 @@
1
+ // Shared, renderer-agnostic metadata for the Avatar story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const avatarMeta: StoryMeta = {
6
+ title: 'Presentation/Avatar',
7
+ description: 'A circular avatar that derives initials (and a colour) from a name, or shows a symbolic icon.',
8
+ controls: [
9
+ { name: 'text', label: 'Name', type: ControlType.TEXT, defaultValue: 'Ada Lovelace' },
10
+ { name: 'size', label: 'Size', type: ControlType.RANGE, min: 24, max: 160, step: 8, defaultValue: 96 },
11
+ { name: 'showInitials', label: 'Show initials', type: ControlType.BOOLEAN, defaultValue: true },
12
+ {
13
+ name: 'iconName',
14
+ label: 'Fallback icon',
15
+ type: ControlType.SELECT,
16
+ options: [
17
+ { label: 'Person', value: 'avatar-default-symbolic' },
18
+ { label: 'Contact', value: 'contact-new-symbolic' },
19
+ { label: 'Camera', value: 'camera-photo-symbolic' },
20
+ ],
21
+ defaultValue: 'avatar-default-symbolic',
22
+ },
23
+ ],
24
+ };
@@ -0,0 +1,46 @@
1
+ // Adw.Avatar — a circular avatar that renders generated initials, a symbolic
2
+ // icon, or a custom image. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import GObject from '@girs/gobject-2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { avatarMeta } from './avatar.meta.js';
8
+
9
+ /** Story: Adw.Avatar with live text / size / icon controls. */
10
+ export class AvatarStory extends StoryWidget {
11
+ private _avatar: Adw.Avatar | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookAvatar' }, AvatarStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(AvatarStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...avatarMeta, component: Adw.Avatar.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ this._avatar = new Adw.Avatar({
27
+ size: this.args.size as number,
28
+ text: this.args.text as string,
29
+ showInitials: this.args.showInitials as boolean,
30
+ iconName: this.args.iconName as string,
31
+ });
32
+ this.addContent(this._avatar);
33
+ }
34
+
35
+ updateArgs(_args: StoryArgs): void {
36
+ if (!this._avatar) return;
37
+ this._avatar.size = this.args.size as number;
38
+ this._avatar.text = this.args.text as string;
39
+ this._avatar.showInitials = this.args.showInitials as boolean;
40
+ this._avatar.iconName = this.args.iconName as string;
41
+ }
42
+ }
43
+
44
+ GObject.type_ensure(AvatarStory.$gtype);
45
+
46
+ export const AvatarStories: StoryModule = { stories: [AvatarStory] };
@@ -0,0 +1,19 @@
1
+ // Shared, renderer-agnostic metadata for the Banner story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const bannerMeta: StoryMeta = {
6
+ title: 'Presentation/Banner',
7
+ description: 'Adw.Banner — a full-width strip carrying a status message and an optional action button.',
8
+ controls: [
9
+ {
10
+ name: 'title',
11
+ label: 'Title',
12
+ type: ControlType.TEXT,
13
+ defaultValue: 'Metered connection — updates paused',
14
+ },
15
+ { name: 'buttonLabel', label: 'Button label', type: ControlType.TEXT, defaultValue: 'Resume' },
16
+ { name: 'revealed', label: 'Revealed', type: ControlType.BOOLEAN, defaultValue: true },
17
+ { name: 'useMarkup', label: 'Use markup', type: ControlType.BOOLEAN, defaultValue: false },
18
+ ],
19
+ };
@@ -0,0 +1,53 @@
1
+ // Adw.Banner — a full-width bar for a single in-context message, with an
2
+ // optional action button. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { bannerMeta } from './banner.meta.js';
9
+
10
+ /** Story: Adw.Banner shown full-width inside a sized container. */
11
+ export class BannerStory extends StoryWidget {
12
+ private _banner: Adw.Banner | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookBanner' }, BannerStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(BannerStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...bannerMeta, component: Adw.Banner.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ this._banner = new Adw.Banner({
28
+ title: this.args.title as string,
29
+ buttonLabel: this.args.buttonLabel as string,
30
+ revealed: this.args.revealed as boolean,
31
+ useMarkup: this.args.useMarkup as boolean,
32
+ });
33
+
34
+ const container = new Gtk.Box({
35
+ orientation: Gtk.Orientation.VERTICAL,
36
+ widthRequest: 460,
37
+ });
38
+ container.append(this._banner);
39
+ this.addContent(container);
40
+ }
41
+
42
+ updateArgs(_args: StoryArgs): void {
43
+ if (!this._banner) return;
44
+ this._banner.title = this.args.title as string;
45
+ this._banner.buttonLabel = this.args.buttonLabel as string;
46
+ this._banner.revealed = this.args.revealed as boolean;
47
+ this._banner.useMarkup = this.args.useMarkup as boolean;
48
+ }
49
+ }
50
+
51
+ GObject.type_ensure(BannerStory.$gtype);
52
+
53
+ export const BannerStories: StoryModule = { stories: [BannerStory] };
@@ -0,0 +1,9 @@
1
+ // Shared, renderer-agnostic metadata for the Spinner story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const spinnerMeta: StoryMeta = {
6
+ title: 'Presentation/Spinner',
7
+ description: 'Adw.Spinner — a lightweight loading indicator that spins continuously while visible.',
8
+ controls: [{ name: 'size', label: 'Size', type: ControlType.RANGE, min: 16, max: 64, step: 4, defaultValue: 48 }],
9
+ };
@@ -0,0 +1,47 @@
1
+ // Adw.Spinner — a determinate-free loading indicator that animates while
2
+ // shown. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { spinnerMeta } from './spinner.meta.js';
9
+
10
+ /** Story: Adw.Spinner sized via width/height requests. */
11
+ export class SpinnerStory extends StoryWidget {
12
+ private _spinner: Adw.Spinner | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookSpinner' }, SpinnerStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(SpinnerStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...spinnerMeta, component: Adw.Spinner.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ const size = this.args.size as number;
28
+ this._spinner = new Adw.Spinner({
29
+ widthRequest: size,
30
+ heightRequest: size,
31
+ halign: Gtk.Align.CENTER,
32
+ valign: Gtk.Align.CENTER,
33
+ });
34
+ this.addContent(this._spinner);
35
+ }
36
+
37
+ updateArgs(_args: StoryArgs): void {
38
+ if (!this._spinner) return;
39
+ const size = this.args.size as number;
40
+ this._spinner.widthRequest = size;
41
+ this._spinner.heightRequest = size;
42
+ }
43
+ }
44
+
45
+ GObject.type_ensure(SpinnerStory.$gtype);
46
+
47
+ export const SpinnerStories: StoryModule = { stories: [SpinnerStory] };
@@ -0,0 +1,29 @@
1
+ // Shared, renderer-agnostic metadata for the Status Page story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const statusPageMeta: StoryMeta = {
6
+ title: 'Presentation/Status Page',
7
+ description: 'Adw.StatusPage — a full-page empty state with an icon, title, description and optional action.',
8
+ controls: [
9
+ {
10
+ name: 'iconName',
11
+ label: 'Icon',
12
+ type: ControlType.SELECT,
13
+ options: [
14
+ { label: 'Folder', value: 'folder-symbolic' },
15
+ { label: 'Mail', value: 'mail-unread-symbolic' },
16
+ { label: 'Search', value: 'system-search-symbolic' },
17
+ { label: 'Star', value: 'starred-symbolic' },
18
+ ],
19
+ defaultValue: 'folder-symbolic',
20
+ },
21
+ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'No Documents' },
22
+ {
23
+ name: 'description',
24
+ label: 'Description',
25
+ type: ControlType.TEXT,
26
+ defaultValue: 'Documents you create or open will appear here.',
27
+ },
28
+ ],
29
+ };
@@ -0,0 +1,55 @@
1
+ // Adw.StatusPage — a centred empty/placeholder state with an icon, title,
2
+ // description and an optional action. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import Gtk from '@girs/gtk-4.0';
6
+ import GObject from '@girs/gobject-2.0';
7
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
8
+ import { statusPageMeta } from './status-page.meta.js';
9
+
10
+ /** Story: Adw.StatusPage with a suggested-action pill button. */
11
+ export class StatusPageStory extends StoryWidget {
12
+ private _statusPage: Adw.StatusPage | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookStatusPage' }, StatusPageStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(StatusPageStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...statusPageMeta, component: Adw.StatusPage.$gtype };
24
+ }
25
+
26
+ initialize(): void {
27
+ const button = new Gtk.Button({
28
+ label: 'New Document',
29
+ halign: Gtk.Align.CENTER,
30
+ cssClasses: ['pill', 'suggested-action'],
31
+ });
32
+
33
+ this._statusPage = new Adw.StatusPage({
34
+ iconName: this.args.iconName as string,
35
+ title: this.args.title as string,
36
+ description: this.args.description as string,
37
+ child: button,
38
+ widthRequest: 460,
39
+ heightRequest: 320,
40
+ });
41
+
42
+ this.addContent(this._statusPage);
43
+ }
44
+
45
+ updateArgs(_args: StoryArgs): void {
46
+ if (!this._statusPage) return;
47
+ this._statusPage.iconName = this.args.iconName as string;
48
+ this._statusPage.title = this.args.title as string;
49
+ this._statusPage.description = this.args.description as string;
50
+ }
51
+ }
52
+
53
+ GObject.type_ensure(StatusPageStory.$gtype);
54
+
55
+ export const StatusPageStories: StoryModule = { stories: [StatusPageStory] };
@@ -0,0 +1,12 @@
1
+ // Shared, renderer-agnostic metadata for the Window Title story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const windowTitleMeta: StoryMeta = {
6
+ title: 'Presentation/Window Title',
7
+ description: 'Adw.WindowTitle — a compact title/subtitle widget intended for a window or header bar.',
8
+ controls: [
9
+ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'Inbox' },
10
+ { name: 'subtitle', label: 'Subtitle', type: ControlType.TEXT, defaultValue: '3 unread messages' },
11
+ ],
12
+ };
@@ -0,0 +1,42 @@
1
+ // Adw.WindowTitle — a header-bar title widget pairing a title with an
2
+ // optional subtitle. original implementation.
3
+
4
+ import Adw from '@girs/adw-1';
5
+ import GObject from '@girs/gobject-2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { windowTitleMeta } from './window-title.meta.js';
8
+
9
+ /** Story: Adw.WindowTitle with live title / subtitle controls. */
10
+ export class WindowTitleStory extends StoryWidget {
11
+ private _windowTitle: Adw.WindowTitle | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookWindowTitle' }, WindowTitleStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(WindowTitleStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...windowTitleMeta, component: Adw.WindowTitle.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ this._windowTitle = new Adw.WindowTitle({
27
+ title: this.args.title as string,
28
+ subtitle: this.args.subtitle as string,
29
+ });
30
+ this.addContent(this._windowTitle);
31
+ }
32
+
33
+ updateArgs(_args: StoryArgs): void {
34
+ if (!this._windowTitle) return;
35
+ this._windowTitle.title = this.args.title as string;
36
+ this._windowTitle.subtitle = this.args.subtitle as string;
37
+ }
38
+ }
39
+
40
+ GObject.type_ensure(WindowTitleStory.$gtype);
41
+
42
+ export const WindowTitleStories: StoryModule = { stories: [WindowTitleStory] };
@@ -0,0 +1,30 @@
1
+ // Shared, renderer-agnostic metadata for the Action Row story.
2
+
3
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
4
+
5
+ export const actionRowMeta: StoryMeta = {
6
+ title: 'Boxed Lists/Action Row',
7
+ description:
8
+ 'Adw.ActionRow — a preferences row with a title/subtitle, a prefix icon and a suffix button, shown inside a boxed list.',
9
+ controls: [
10
+ { name: 'title', label: 'Title', type: ControlType.TEXT, defaultValue: 'Wi-Fi' },
11
+ {
12
+ name: 'subtitle',
13
+ label: 'Subtitle',
14
+ type: ControlType.TEXT,
15
+ defaultValue: 'Connected to Highgarden 5GHz',
16
+ },
17
+ {
18
+ name: 'iconName',
19
+ label: 'Prefix icon',
20
+ type: ControlType.SELECT,
21
+ options: [
22
+ { label: 'Network', value: 'network-wireless-symbolic' },
23
+ { label: 'Folder', value: 'folder-symbolic' },
24
+ { label: 'Starred', value: 'starred-symbolic' },
25
+ ],
26
+ defaultValue: 'network-wireless-symbolic',
27
+ },
28
+ { name: 'activatable', label: 'Activatable', type: ControlType.BOOLEAN, defaultValue: true },
29
+ ],
30
+ };