@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,49 @@
1
+ // Adw.SwitchRow — a boxed-list row pairing a title/subtitle with a switch.
2
+ // 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 { switchRowMeta } from './switch-row.meta.js';
8
+
9
+ /** Story: Adw.SwitchRow inside a boxed list (Adw.PreferencesGroup). */
10
+ export class SwitchRowStory extends StoryWidget {
11
+ private _row: Adw.SwitchRow | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookSwitchRow' }, SwitchRowStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(SwitchRowStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...switchRowMeta, component: Adw.SwitchRow.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ this._row = new Adw.SwitchRow({
27
+ title: this.args.title as string,
28
+ subtitle: this.args.subtitle as string,
29
+ active: this.args.active as boolean,
30
+ });
31
+
32
+ const group = new Adw.PreferencesGroup();
33
+ group.add(this._row);
34
+
35
+ const clamp = new Adw.Clamp({ maximumSize: 400, child: group });
36
+ this.addContent(clamp);
37
+ }
38
+
39
+ updateArgs(_args: StoryArgs): void {
40
+ if (!this._row) return;
41
+ this._row.title = this.args.title as string;
42
+ this._row.subtitle = this.args.subtitle as string;
43
+ this._row.active = this.args.active as boolean;
44
+ }
45
+ }
46
+
47
+ GObject.type_ensure(SwitchRowStory.$gtype);
48
+
49
+ export const SwitchRowStories: StoryModule = { stories: [SwitchRowStory] };
@@ -0,0 +1,35 @@
1
+ // Shared, renderer-agnostic metadata for the Carousel stories. Imported by both
2
+ // the GTK renderer (carousel.story.ts) and the browser renderer
3
+ // (browser/view-switching/carousel.web.ts) so the two expose identical controls.
4
+ // Adw.Carousel ships two indicator widgets, so there are two stories — one
5
+ // paired with dot indicators, one with line indicators.
6
+
7
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
8
+
9
+ const carouselControls: StoryMeta['controls'] = [
10
+ {
11
+ name: 'allowScrollWheel',
12
+ label: 'Allow scroll wheel',
13
+ type: ControlType.BOOLEAN,
14
+ defaultValue: true,
15
+ },
16
+ {
17
+ name: 'allowLongSwipes',
18
+ label: 'Allow long swipes',
19
+ type: ControlType.BOOLEAN,
20
+ defaultValue: false,
21
+ },
22
+ ];
23
+
24
+ export const carouselDotsMeta: StoryMeta = {
25
+ title: 'View Switching/Carousel (Dots)',
26
+ description:
27
+ 'Adw.Carousel — a horizontally swipeable pager with three pages, paired with Adw.CarouselIndicatorDots.',
28
+ controls: carouselControls,
29
+ };
30
+
31
+ export const carouselLinesMeta: StoryMeta = {
32
+ title: 'View Switching/Carousel (Lines)',
33
+ description: 'Adw.Carousel — the same swipeable pager paired with Adw.CarouselIndicatorLines instead of dots.',
34
+ controls: carouselControls,
35
+ };
@@ -0,0 +1,131 @@
1
+ // Adw.Carousel — a swipeable pager paired with page indicators. original implementation.
2
+
3
+ import Adw from '@girs/adw-1';
4
+ import Gtk from '@girs/gtk-4.0';
5
+ import GObject from '@girs/gobject-2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { carouselDotsMeta, carouselLinesMeta } from './carousel.meta.js';
8
+
9
+ const PAGES: ReadonlyArray<{ title: string; css: string }> = [
10
+ { title: 'Welcome', css: 'accent' },
11
+ { title: 'Discover', css: 'success' },
12
+ { title: 'Get started', css: 'warning' },
13
+ ];
14
+
15
+ function buildPage(title: string, cssClass: string): Gtk.Widget {
16
+ const box = new Gtk.Box({
17
+ orientation: Gtk.Orientation.VERTICAL,
18
+ halign: Gtk.Align.CENTER,
19
+ valign: Gtk.Align.CENTER,
20
+ widthRequest: 440,
21
+ heightRequest: 260,
22
+ });
23
+ box.add_css_class('card');
24
+ box.add_css_class(cssClass);
25
+
26
+ const label = new Gtk.Label({ label: title, vexpand: true, valign: Gtk.Align.CENTER });
27
+ label.add_css_class('title-1');
28
+ box.append(label);
29
+
30
+ return box;
31
+ }
32
+
33
+ /** Story: Adw.Carousel with dot indicators. */
34
+ export class CarouselDotsStory extends StoryWidget {
35
+ private _carousel: Adw.Carousel | null = null;
36
+
37
+ static {
38
+ GObject.registerClass({ GTypeName: 'AdwStorybookCarouselDots' }, CarouselDotsStory);
39
+ }
40
+
41
+ constructor() {
42
+ super(StoryWidget.fromMeta(CarouselDotsStory.getMetadata(), 'Default'));
43
+ }
44
+
45
+ static getMetadata(): StoryMeta {
46
+ return { ...carouselDotsMeta, component: Adw.Carousel.$gtype };
47
+ }
48
+
49
+ initialize(): void {
50
+ this._carousel = new Adw.Carousel({
51
+ allowScrollWheel: this.args.allowScrollWheel as boolean,
52
+ allowLongSwipes: this.args.allowLongSwipes as boolean,
53
+ vexpand: true,
54
+ });
55
+ for (const page of PAGES) {
56
+ this._carousel.append(buildPage(page.title, page.css));
57
+ }
58
+
59
+ const dots = new Adw.CarouselIndicatorDots({ carousel: this._carousel });
60
+
61
+ const box = new Gtk.Box({
62
+ orientation: Gtk.Orientation.VERTICAL,
63
+ spacing: 12,
64
+ widthRequest: 480,
65
+ heightRequest: 340,
66
+ });
67
+ box.append(this._carousel);
68
+ box.append(dots);
69
+
70
+ this.addContent(box);
71
+ }
72
+
73
+ updateArgs(_args: StoryArgs): void {
74
+ if (!this._carousel) return;
75
+ this._carousel.allowScrollWheel = this.args.allowScrollWheel as boolean;
76
+ this._carousel.allowLongSwipes = this.args.allowLongSwipes as boolean;
77
+ }
78
+ }
79
+
80
+ GObject.type_ensure(CarouselDotsStory.$gtype);
81
+
82
+ /** Story: Adw.Carousel with line indicators. */
83
+ export class CarouselLinesStory extends StoryWidget {
84
+ private _carousel: Adw.Carousel | null = null;
85
+
86
+ static {
87
+ GObject.registerClass({ GTypeName: 'AdwStorybookCarouselLines' }, CarouselLinesStory);
88
+ }
89
+
90
+ constructor() {
91
+ super(StoryWidget.fromMeta(CarouselLinesStory.getMetadata(), 'Default'));
92
+ }
93
+
94
+ static getMetadata(): StoryMeta {
95
+ return { ...carouselLinesMeta, component: Adw.Carousel.$gtype };
96
+ }
97
+
98
+ initialize(): void {
99
+ this._carousel = new Adw.Carousel({
100
+ allowScrollWheel: this.args.allowScrollWheel as boolean,
101
+ allowLongSwipes: this.args.allowLongSwipes as boolean,
102
+ vexpand: true,
103
+ });
104
+ for (const page of PAGES) {
105
+ this._carousel.append(buildPage(page.title, page.css));
106
+ }
107
+
108
+ const lines = new Adw.CarouselIndicatorLines({ carousel: this._carousel });
109
+
110
+ const box = new Gtk.Box({
111
+ orientation: Gtk.Orientation.VERTICAL,
112
+ spacing: 12,
113
+ widthRequest: 480,
114
+ heightRequest: 340,
115
+ });
116
+ box.append(this._carousel);
117
+ box.append(lines);
118
+
119
+ this.addContent(box);
120
+ }
121
+
122
+ updateArgs(_args: StoryArgs): void {
123
+ if (!this._carousel) return;
124
+ this._carousel.allowScrollWheel = this.args.allowScrollWheel as boolean;
125
+ this._carousel.allowLongSwipes = this.args.allowLongSwipes as boolean;
126
+ }
127
+ }
128
+
129
+ GObject.type_ensure(CarouselLinesStory.$gtype);
130
+
131
+ export const CarouselStories: StoryModule = { stories: [CarouselDotsStory, CarouselLinesStory] };
@@ -0,0 +1,25 @@
1
+ // Shared, renderer-agnostic metadata for the Inline View Switcher story.
2
+ // Imported by both the GTK renderer (inline-view-switcher.story.ts) and the
3
+ // browser renderer (browser/view-switching/inline-view-switcher.web.ts) so the
4
+ // two expose identical controls.
5
+
6
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
7
+
8
+ export const inlineViewSwitcherMeta: StoryMeta = {
9
+ title: 'View Switching/Inline View Switcher',
10
+ description:
11
+ 'Adw.InlineViewSwitcher — a compact inline switcher that can show labels, icons, or both for an Adw.ViewStack.',
12
+ controls: [
13
+ {
14
+ name: 'displayMode',
15
+ label: 'Display mode',
16
+ type: ControlType.SELECT,
17
+ options: [
18
+ { label: 'Labels', value: 'labels' },
19
+ { label: 'Icons', value: 'icons' },
20
+ { label: 'Both', value: 'both' },
21
+ ],
22
+ defaultValue: 'both',
23
+ },
24
+ ],
25
+ };
@@ -0,0 +1,88 @@
1
+ // Adw.InlineViewSwitcher — a compact, toolbar-friendly switcher for an Adw.ViewStack.
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 { inlineViewSwitcherMeta } from './inline-view-switcher.meta.js';
9
+
10
+ /** Story: Adw.InlineViewSwitcher driving an Adw.ViewStack of three pages. */
11
+ export class InlineViewSwitcherStory extends StoryWidget {
12
+ private _switcher: Adw.InlineViewSwitcher | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookInlineViewSwitcher' }, InlineViewSwitcherStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(InlineViewSwitcherStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...inlineViewSwitcherMeta, component: Adw.InlineViewSwitcher.$gtype };
24
+ }
25
+
26
+ private buildPage(title: string, icon: string, body: string): Gtk.Widget {
27
+ return new Adw.StatusPage({
28
+ iconName: icon,
29
+ title,
30
+ description: body,
31
+ vexpand: true,
32
+ });
33
+ }
34
+
35
+ initialize(): void {
36
+ const stack = new Adw.ViewStack({ vexpand: true });
37
+ stack.add_titled_with_icon(
38
+ this.buildPage('Overview', 'view-grid-symbolic', 'A quick summary of your project.'),
39
+ 'overview',
40
+ 'Overview',
41
+ 'view-grid-symbolic',
42
+ );
43
+ stack.add_titled_with_icon(
44
+ this.buildPage('Activity', 'document-edit-symbolic', 'Recent edits and changes.'),
45
+ 'activity',
46
+ 'Activity',
47
+ 'document-edit-symbolic',
48
+ );
49
+ stack.add_titled_with_icon(
50
+ this.buildPage('Settings', 'emblem-system-symbolic', 'Configure how things behave.'),
51
+ 'settings',
52
+ 'Settings',
53
+ 'emblem-system-symbolic',
54
+ );
55
+
56
+ this._switcher = new Adw.InlineViewSwitcher({
57
+ stack,
58
+ displayMode: this.modeFromArg(this.args.displayMode as string),
59
+ halign: Gtk.Align.CENTER,
60
+ });
61
+
62
+ const box = new Gtk.Box({
63
+ orientation: Gtk.Orientation.VERTICAL,
64
+ spacing: 12,
65
+ widthRequest: 480,
66
+ heightRequest: 340,
67
+ });
68
+ box.append(this._switcher);
69
+ box.append(stack);
70
+
71
+ this.addContent(box);
72
+ }
73
+
74
+ private modeFromArg(value: string): Adw.InlineViewSwitcherDisplayMode {
75
+ if (value === 'labels') return Adw.InlineViewSwitcherDisplayMode.LABELS;
76
+ if (value === 'icons') return Adw.InlineViewSwitcherDisplayMode.ICONS;
77
+ return Adw.InlineViewSwitcherDisplayMode.BOTH;
78
+ }
79
+
80
+ updateArgs(_args: StoryArgs): void {
81
+ if (!this._switcher) return;
82
+ this._switcher.displayMode = this.modeFromArg(this.args.displayMode as string);
83
+ }
84
+ }
85
+
86
+ GObject.type_ensure(InlineViewSwitcherStory.$gtype);
87
+
88
+ export const InlineViewSwitcherStories: StoryModule = { stories: [InlineViewSwitcherStory] };
@@ -0,0 +1,12 @@
1
+ // Shared, renderer-agnostic metadata for the Tab View story. Imported by both
2
+ // the GTK renderer (tab-view.story.ts) and the browser renderer
3
+ // (browser/view-switching/tab-view.web.ts) so the two expose identical controls.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ export const tabViewMeta: StoryMeta = {
8
+ title: 'View Switching/Tab View',
9
+ description:
10
+ 'Adw.TabView with an Adw.TabBar header — three tabbed pages; the tab bar can auto-hide when only one tab remains.',
11
+ controls: [{ name: 'autohide', label: 'Autohide tab bar', type: ControlType.BOOLEAN, defaultValue: false }],
12
+ };
@@ -0,0 +1,72 @@
1
+ // Adw.TabView — a tabbed container with an Adw.TabBar header. original implementation.
2
+
3
+ import Adw from '@girs/adw-1';
4
+ import Gtk from '@girs/gtk-4.0';
5
+ import GObject from '@girs/gobject-2.0';
6
+ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@gjsify/storybook';
7
+ import { tabViewMeta } from './tab-view.meta.js';
8
+
9
+ const TABS: ReadonlyArray<{ title: string; body: string }> = [
10
+ { title: 'Overview', body: 'A summary of everything at a glance.' },
11
+ { title: 'Details', body: 'The specifics, broken down line by line.' },
12
+ { title: 'History', body: 'A log of every change made so far.' },
13
+ ];
14
+
15
+ /** Story: Adw.TabView with an Adw.TabBar and three appended pages. */
16
+ export class TabViewStory extends StoryWidget {
17
+ private _tabBar: Adw.TabBar | null = null;
18
+
19
+ static {
20
+ GObject.registerClass({ GTypeName: 'AdwStorybookTabView' }, TabViewStory);
21
+ }
22
+
23
+ constructor() {
24
+ super(StoryWidget.fromMeta(TabViewStory.getMetadata(), 'Default'));
25
+ }
26
+
27
+ static getMetadata(): StoryMeta {
28
+ return { ...tabViewMeta, component: Adw.TabView.$gtype };
29
+ }
30
+
31
+ private buildPageBody(title: string, body: string): Gtk.Widget {
32
+ const status = new Adw.StatusPage({
33
+ iconName: 'view-paged-symbolic',
34
+ title,
35
+ description: body,
36
+ vexpand: true,
37
+ });
38
+ return status;
39
+ }
40
+
41
+ initialize(): void {
42
+ const tabView = new Adw.TabView({ vexpand: true });
43
+ for (const tab of TABS) {
44
+ const page = tabView.append(this.buildPageBody(tab.title, tab.body));
45
+ page.title = tab.title;
46
+ }
47
+
48
+ this._tabBar = new Adw.TabBar({
49
+ view: tabView,
50
+ autohide: this.args.autohide as boolean,
51
+ });
52
+
53
+ const box = new Gtk.Box({
54
+ orientation: Gtk.Orientation.VERTICAL,
55
+ widthRequest: 480,
56
+ heightRequest: 340,
57
+ });
58
+ box.append(this._tabBar);
59
+ box.append(tabView);
60
+
61
+ this.addContent(box);
62
+ }
63
+
64
+ updateArgs(_args: StoryArgs): void {
65
+ if (!this._tabBar) return;
66
+ this._tabBar.autohide = this.args.autohide as boolean;
67
+ }
68
+ }
69
+
70
+ GObject.type_ensure(TabViewStory.$gtype);
71
+
72
+ export const TabViewStories: StoryModule = { stories: [TabViewStory] };
@@ -0,0 +1,23 @@
1
+ // Shared, renderer-agnostic metadata for the View Switcher story. Imported by
2
+ // both the GTK renderer (view-switcher.story.ts) and the browser renderer
3
+ // (browser/view-switching/view-switcher.web.ts) so the two expose identical
4
+ // controls.
5
+
6
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
7
+
8
+ export const viewSwitcherMeta: StoryMeta = {
9
+ title: 'View Switching/View Switcher',
10
+ description: 'Adw.ViewSwitcher — a segmented switcher whose buttons select pages in a paired Adw.ViewStack.',
11
+ controls: [
12
+ {
13
+ name: 'policy',
14
+ label: 'Policy',
15
+ type: ControlType.SELECT,
16
+ options: [
17
+ { label: 'Wide', value: 'wide' },
18
+ { label: 'Narrow', value: 'narrow' },
19
+ ],
20
+ defaultValue: 'wide',
21
+ },
22
+ ],
23
+ };
@@ -0,0 +1,87 @@
1
+ // Adw.ViewSwitcher — a tab-style switcher driving an Adw.ViewStack of pages.
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 { viewSwitcherMeta } from './view-switcher.meta.js';
9
+
10
+ /** Story: Adw.ViewSwitcher mounted above an Adw.ViewStack with three pages. */
11
+ export class ViewSwitcherStory extends StoryWidget {
12
+ private _switcher: Adw.ViewSwitcher | null = null;
13
+
14
+ static {
15
+ GObject.registerClass({ GTypeName: 'AdwStorybookViewSwitcher' }, ViewSwitcherStory);
16
+ }
17
+
18
+ constructor() {
19
+ super(StoryWidget.fromMeta(ViewSwitcherStory.getMetadata(), 'Default'));
20
+ }
21
+
22
+ static getMetadata(): StoryMeta {
23
+ return { ...viewSwitcherMeta, component: Adw.ViewSwitcher.$gtype };
24
+ }
25
+
26
+ private buildPage(title: string, icon: string, body: string): Gtk.Widget {
27
+ const status = new Adw.StatusPage({
28
+ iconName: icon,
29
+ title,
30
+ description: body,
31
+ vexpand: true,
32
+ });
33
+ return status;
34
+ }
35
+
36
+ initialize(): void {
37
+ const stack = new Adw.ViewStack({ vexpand: true });
38
+ stack.add_titled_with_icon(
39
+ this.buildPage('Inbox', 'mail-unread-symbolic', 'You have three unread conversations.'),
40
+ 'inbox',
41
+ 'Inbox',
42
+ 'mail-unread-symbolic',
43
+ );
44
+ stack.add_titled_with_icon(
45
+ this.buildPage('Starred', 'starred-symbolic', 'Messages you have marked as important.'),
46
+ 'starred',
47
+ 'Starred',
48
+ 'starred-symbolic',
49
+ );
50
+ stack.add_titled_with_icon(
51
+ this.buildPage('Archive', 'folder-symbolic', 'Older conversations kept for reference.'),
52
+ 'archive',
53
+ 'Archive',
54
+ 'folder-symbolic',
55
+ );
56
+
57
+ this._switcher = new Adw.ViewSwitcher({
58
+ stack,
59
+ policy: this.policyFromArg(this.args.policy as string),
60
+ halign: Gtk.Align.CENTER,
61
+ });
62
+
63
+ const box = new Gtk.Box({
64
+ orientation: Gtk.Orientation.VERTICAL,
65
+ spacing: 12,
66
+ widthRequest: 480,
67
+ heightRequest: 340,
68
+ });
69
+ box.append(this._switcher);
70
+ box.append(stack);
71
+
72
+ this.addContent(box);
73
+ }
74
+
75
+ private policyFromArg(value: string): Adw.ViewSwitcherPolicy {
76
+ return value === 'narrow' ? Adw.ViewSwitcherPolicy.NARROW : Adw.ViewSwitcherPolicy.WIDE;
77
+ }
78
+
79
+ updateArgs(_args: StoryArgs): void {
80
+ if (!this._switcher) return;
81
+ this._switcher.policy = this.policyFromArg(this.args.policy as string);
82
+ }
83
+ }
84
+
85
+ GObject.type_ensure(ViewSwitcherStory.$gtype);
86
+
87
+ export const ViewSwitcherStories: StoryModule = { stories: [ViewSwitcherStory] };