@gjsify/example-gtk-adwaita-storybook 0.38.1 → 0.40.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.
@@ -33,6 +33,54 @@ export const OVERVIEW_ADVANCED_ROWS: ReadonlyArray<OverviewExpanderRow> = [
33
33
  /** The accent names the gallery's combo row offers — a plain widget demo, not the real setting. */
34
34
  export const OVERVIEW_ACCENT_OPTIONS: readonly string[] = ['Blue', 'Teal', 'Green', 'Orange'];
35
35
 
36
+ /**
37
+ * The gallery's preference-group headings.
38
+ *
39
+ * Shared for the same reason the rows are: they were literals repeated in all
40
+ * three renderings, and the NativeScript copy had drifted to UPPERCASE
41
+ * (`APPEARANCE`) while GTK and the browser used title case. It was the only file
42
+ * in that showcase spelling group titles that way, so it read as a house style
43
+ * without being one — `Adw.PreferencesGroup:title` is rendered as given on every
44
+ * target, and libadwaita does not upper-case it.
45
+ */
46
+ export const OVERVIEW_GROUP_TITLES = {
47
+ appearance: 'Appearance',
48
+ account: 'Account',
49
+ shortcuts: 'Shortcuts',
50
+ actions: 'Actions',
51
+ } as const;
52
+
53
+ /**
54
+ * Every remaining string the gallery puts on screen.
55
+ *
56
+ * The rows, shortcuts and accent names were already shared; the labels around
57
+ * them were not, and that is where the uppercase drift got in. Sharing only the
58
+ * headings would fix the one instance and leave the class — a literal repeated in
59
+ * three renderings, with nothing comparing them — so the whole content of the
60
+ * gallery lives here and each target only decides how to BUILD it.
61
+ */
62
+ export const OVERVIEW_TEXT = {
63
+ bannerTitle: 'You have unsaved changes',
64
+ bannerButton: 'Save',
65
+ darkMode: 'Dark mode',
66
+ darkModeSubtitle: 'Use the dark Adwaita palette',
67
+ notifications: 'Notifications',
68
+ notificationsSubtitle: 'Show toasts for events',
69
+ accentColor: 'Accent color',
70
+ name: 'Name',
71
+ nameValue: 'Ada Lovelace',
72
+ email: 'Email',
73
+ emailValue: 'ada@example.com',
74
+ devices: 'Devices',
75
+ advanced: 'Advanced',
76
+ advancedSubtitle: 'More options',
77
+ save: 'Save changes',
78
+ delete: 'Delete account',
79
+ } as const;
80
+
81
+ /** The spin row's range and starting value, shared so the three agree on it too. */
82
+ export const OVERVIEW_DEVICES = { value: 3, lower: 1, upper: 10, step: 1 } as const;
83
+
36
84
  /** The shortcut rows, so the newest widget appears in context and not only alone. */
37
85
  export const OVERVIEW_SHORTCUTS: ReadonlyArray<{ title: string; accelerator: string }> = [
38
86
  { title: 'Copy', accelerator: '<Control>C' },
@@ -8,7 +8,10 @@ import { type StoryArgs, type StoryMeta, type StoryModule, StoryWidget } from '@
8
8
  import {
9
9
  OVERVIEW_ACCENT_OPTIONS,
10
10
  OVERVIEW_ADVANCED_ROWS,
11
+ OVERVIEW_DEVICES,
12
+ OVERVIEW_GROUP_TITLES,
11
13
  OVERVIEW_SHORTCUTS,
14
+ OVERVIEW_TEXT,
12
15
  overviewWidgetsMeta,
13
16
  } from './widgets.meta.js';
14
17
 
@@ -32,8 +35,8 @@ export class OverviewWidgetsStory extends StoryWidget {
32
35
  const box = new Gtk.Box({ orientation: Gtk.Orientation.VERTICAL, hexpand: true });
33
36
 
34
37
  this._banner = new Adw.Banner({
35
- title: 'You have unsaved changes',
36
- button_label: 'Save',
38
+ title: OVERVIEW_TEXT.bannerTitle,
39
+ button_label: OVERVIEW_TEXT.bannerButton,
37
40
  revealed: this.args.revealed as boolean,
38
41
  });
39
42
  box.append(this._banner);
@@ -43,14 +46,24 @@ export class OverviewWidgetsStory extends StoryWidget {
43
46
  // --- Appearance: switches and a combo. A widget demo only — the
44
47
  // storybook's OWN appearance lives in the header bar's dialog, and wiring
45
48
  // these to it would give one setting two controls that disagree.
46
- const appearance = new Adw.PreferencesGroup({ title: 'Appearance' });
49
+ const appearance = new Adw.PreferencesGroup({ title: OVERVIEW_GROUP_TITLES.appearance });
47
50
  appearance.add(
48
- new Adw.SwitchRow({ title: 'Dark mode', subtitle: 'Use the dark Adwaita palette', active: false }),
51
+ new Adw.SwitchRow({
52
+ title: OVERVIEW_TEXT.darkMode,
53
+ subtitle: OVERVIEW_TEXT.darkModeSubtitle,
54
+ active: false,
55
+ }),
56
+ );
57
+ appearance.add(
58
+ new Adw.SwitchRow({
59
+ title: OVERVIEW_TEXT.notifications,
60
+ subtitle: OVERVIEW_TEXT.notificationsSubtitle,
61
+ active: true,
62
+ }),
49
63
  );
50
- appearance.add(new Adw.SwitchRow({ title: 'Notifications', subtitle: 'Show toasts for events', active: true }));
51
64
  appearance.add(
52
65
  new Adw.ComboRow({
53
- title: 'Accent color',
66
+ title: OVERVIEW_TEXT.accentColor,
54
67
  model: Gtk.StringList.new([...OVERVIEW_ACCENT_OPTIONS]),
55
68
  selected: 0,
56
69
  }),
@@ -58,26 +71,36 @@ export class OverviewWidgetsStory extends StoryWidget {
58
71
  page.add(appearance);
59
72
 
60
73
  // --- Account: entries, a spin row, and a nested expander ---
61
- const account = new Adw.PreferencesGroup({ title: 'Account' });
74
+ const account = new Adw.PreferencesGroup({ title: OVERVIEW_GROUP_TITLES.account });
62
75
 
63
- const name = new Adw.EntryRow({ title: 'Name' });
64
- name.set_text('Ada Lovelace');
76
+ const name = new Adw.EntryRow({ title: OVERVIEW_TEXT.name });
77
+ name.set_text(OVERVIEW_TEXT.nameValue);
65
78
  account.add(name);
66
79
 
67
- const email = new Adw.EntryRow({ title: 'Email' });
68
- email.set_text('ada@example.com');
80
+ const email = new Adw.EntryRow({ title: OVERVIEW_TEXT.email });
81
+ email.set_text(OVERVIEW_TEXT.emailValue);
69
82
  account.add(email);
70
83
 
71
84
  const devices = new Adw.SpinRow({
72
- title: 'Devices',
73
- adjustment: new Gtk.Adjustment({ value: 3, lower: 1, upper: 10, step_increment: 1, page_increment: 1 }),
85
+ title: OVERVIEW_TEXT.devices,
86
+ adjustment: new Gtk.Adjustment({
87
+ value: OVERVIEW_DEVICES.value,
88
+ lower: OVERVIEW_DEVICES.lower,
89
+ upper: OVERVIEW_DEVICES.upper,
90
+ step_increment: OVERVIEW_DEVICES.step,
91
+ page_increment: OVERVIEW_DEVICES.step,
92
+ }),
74
93
  });
75
94
  // The displayed value does not always follow the adjustment through
76
95
  // property-init ordering, so it is set explicitly.
77
- devices.set_value(3);
96
+ devices.set_value(OVERVIEW_DEVICES.value);
78
97
  account.add(devices);
79
98
 
80
- const advanced = new Adw.ExpanderRow({ title: 'Advanced', subtitle: 'More options', expanded: true });
99
+ const advanced = new Adw.ExpanderRow({
100
+ title: OVERVIEW_TEXT.advanced,
101
+ subtitle: OVERVIEW_TEXT.advancedSubtitle,
102
+ expanded: true,
103
+ });
81
104
  for (const row of OVERVIEW_ADVANCED_ROWS) {
82
105
  advanced.add_row(
83
106
  row.kind === 'switch'
@@ -89,7 +112,7 @@ export class OverviewWidgetsStory extends StoryWidget {
89
112
  page.add(account);
90
113
 
91
114
  // --- Shortcuts: the newest widget, in context ---
92
- const shortcuts = new Adw.PreferencesGroup({ title: 'Shortcuts' });
115
+ const shortcuts = new Adw.PreferencesGroup({ title: OVERVIEW_GROUP_TITLES.shortcuts });
93
116
  for (const shortcut of OVERVIEW_SHORTCUTS) {
94
117
  const row = new Adw.ActionRow({ title: shortcut.title });
95
118
  row.add_suffix(new Adw.ShortcutLabel({ accelerator: shortcut.accelerator, valign: Gtk.Align.CENTER }));
@@ -98,7 +121,7 @@ export class OverviewWidgetsStory extends StoryWidget {
98
121
  page.add(shortcuts);
99
122
 
100
123
  // --- Actions: the two button styles side by side ---
101
- const actions = new Adw.PreferencesGroup({ title: 'Actions' });
124
+ const actions = new Adw.PreferencesGroup({ title: OVERVIEW_GROUP_TITLES.actions });
102
125
  const buttons = new Gtk.Box({
103
126
  orientation: Gtk.Orientation.HORIZONTAL,
104
127
  spacing: 12,
@@ -106,10 +129,10 @@ export class OverviewWidgetsStory extends StoryWidget {
106
129
  margin_top: 6,
107
130
  margin_bottom: 6,
108
131
  });
109
- const save = new Gtk.Button({ label: 'Save changes' });
132
+ const save = new Gtk.Button({ label: OVERVIEW_TEXT.save });
110
133
  save.add_css_class('suggested-action');
111
134
  buttons.append(save);
112
- const remove = new Gtk.Button({ label: 'Delete account' });
135
+ const remove = new Gtk.Button({ label: OVERVIEW_TEXT.delete });
113
136
  remove.add_css_class('destructive-action');
114
137
  buttons.append(remove);
115
138
  actions.add(buttons);
@@ -0,0 +1,20 @@
1
+ // Shared, renderer-agnostic metadata for the View Switcher Bar story. Imported by the
2
+ // GTK renderer (view-switcher-bar.story.ts), the browser renderer
3
+ // (browser/view-switching/view-switcher-bar.web.ts) and the NativeScript one.
4
+
5
+ import { ControlType, type StoryMeta } from '@gjsify/stories';
6
+
7
+ /** The three pages every rendering puts in its stack, so the bar has the same buttons. */
8
+ export const VIEW_SWITCHER_BAR_PAGES: ReadonlyArray<{ name: string; title: string; icon: string }> = [
9
+ { name: 'inbox', title: 'Inbox', icon: 'mail-unread-symbolic' },
10
+ { name: 'starred', title: 'Starred', icon: 'starred-symbolic' },
11
+ { name: 'archive', title: 'Archive', icon: 'folder-symbolic' },
12
+ ];
13
+
14
+ export const viewSwitcherBarMeta: StoryMeta = {
15
+ title: 'View Switching/View Switcher Bar',
16
+ description:
17
+ 'Adw.ViewSwitcherBar — the narrow-window switcher, pinned to the bottom of a toolbar view. `reveal` ' +
18
+ 'is a REQUEST, not a state: a stack with fewer than two pages stays collapsed however loudly it is asked.',
19
+ controls: [{ name: 'reveal', label: 'Reveal', type: ControlType.BOOLEAN, defaultValue: true }],
20
+ };
@@ -0,0 +1,61 @@
1
+ // Adw.ViewSwitcherBar — the narrow-window switcher, pinned to the bottom.
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 { VIEW_SWITCHER_BAR_PAGES, viewSwitcherBarMeta } from './view-switcher-bar.meta.js';
8
+
9
+ /** Story: an Adw.ViewSwitcherBar at the bottom of a toolbar view, driving its stack. */
10
+ export class ViewSwitcherBarStory extends StoryWidget {
11
+ private _bar: Adw.ViewSwitcherBar | null = null;
12
+
13
+ static {
14
+ GObject.registerClass({ GTypeName: 'AdwStorybookViewSwitcherBar' }, ViewSwitcherBarStory);
15
+ }
16
+
17
+ constructor() {
18
+ super(StoryWidget.fromMeta(ViewSwitcherBarStory.getMetadata(), 'Default'));
19
+ }
20
+
21
+ static getMetadata(): StoryMeta {
22
+ return { ...viewSwitcherBarMeta, component: Adw.ViewSwitcherBar.$gtype };
23
+ }
24
+
25
+ initialize(): void {
26
+ const stack = new Adw.ViewStack({ vexpand: true });
27
+ for (const page of VIEW_SWITCHER_BAR_PAGES) {
28
+ const status = new Adw.StatusPage({
29
+ iconName: page.icon,
30
+ title: page.title,
31
+ description: `The ${page.title.toLowerCase()} page.`,
32
+ vexpand: true,
33
+ });
34
+ stack.add_titled_with_icon(status, page.name, page.title, page.icon);
35
+ }
36
+
37
+ this._bar = new Adw.ViewSwitcherBar({ stack });
38
+ this._apply();
39
+
40
+ // The bar belongs at an edge — a toolbar view is where libadwaita puts it,
41
+ // and it is what makes the story show the bar's real position rather than a
42
+ // widget floating in the middle of the preview.
43
+ const view = new Adw.ToolbarView({ content: stack, widthRequest: 360, heightRequest: 360 });
44
+ view.add_bottom_bar(this._bar);
45
+
46
+ this.addContent(view);
47
+ }
48
+
49
+ updateArgs(_args: StoryArgs): void {
50
+ this._apply();
51
+ }
52
+
53
+ private _apply(): void {
54
+ if (!this._bar) return;
55
+ this._bar.reveal = this.args.reveal as boolean;
56
+ }
57
+ }
58
+
59
+ GObject.type_ensure(ViewSwitcherBarStory.$gtype);
60
+
61
+ export const ViewSwitcherBarStories: StoryModule = { stories: [ViewSwitcherBarStory] };