diff --git a/.github/workflows/CI.yaml b/.github/workflows/CI.yaml index f40fd98db..ea35e732e 100644 --- a/.github/workflows/CI.yaml +++ b/.github/workflows/CI.yaml @@ -5,6 +5,7 @@ name: CI on: pull_request: branches: [main] + workflow_dispatch: jobs: CI: diff --git a/.github/workflows/deploy.yaml b/.github/workflows/deploy.yaml index 72a148ca6..7468c4acd 100644 --- a/.github/workflows/deploy.yaml +++ b/.github/workflows/deploy.yaml @@ -1,7 +1,10 @@ +name: Deploy + on: push: branches: [main] -name: Deploy + workflow_dispatch: + jobs: flatpak: name: "Flatpak" diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index e5c428cf6..7883f3db7 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -32,7 +32,7 @@ We provide a couple of tools to make the development process pleasant. # sudo dnf install flatpak flatpak-builder nodejs make gcc gcc-c++ cd Workbench -make setup +make ``` Before submitting a PR, we recommend running tests locally with diff --git a/Makefile b/Makefile index 87224e76b..90fa3fde0 100644 --- a/Makefile +++ b/Makefile @@ -1,19 +1,27 @@ SHELL:=/bin/bash -O globstar .PHONY: setup build lint unit test ci sandbox flatpak -.DEFAULT_GOAL := test +.DEFAULT_GOAL := setup setup: flatpak remote-add --user --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo flatpak install --or-update --user --noninteractive flathub org.gnome.Sdk//46 org.flatpak.Builder org.freedesktop.Sdk.Extension.rust-stable//23.08 org.freedesktop.Sdk.Extension.vala//23.08 org.freedesktop.Sdk.Extension.llvm16//23.08 org.freedesktop.Sdk.Extension.node18//23.08 org.freedesktop.Sdk.Extension.typescript//23.08 -# flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo + flatpak remote-add --user --if-not-exists flathub-beta https://flathub.org/beta-repo/flathub-beta.flatpakrepo + flatpak install --or-update --user --noninteractive flathub-beta org.freedesktop.Sdk.Extension.rust-stable//24.08beta org.freedesktop.Sdk.Extension.vala//24.08beta org.freedesktop.Sdk.Extension.llvm18//24.08beta +# org.freedesktop.Sdk.Extension.node18//24.08beta org.freedesktop.Sdk.Extension.typescript//24.08beta flatpak remote-add --user --if-not-exists gnome-nightly https://nightly.gnome.org/gnome-nightly.flatpakrepo flatpak install --or-update --user --noninteractive gnome-nightly org.gnome.Sdk//master - npm install - make build + git submodule update --init + npm install --no-fund + @echo " ✅ You can use make stable or make devel to build Workbench" -build: +stable: + flatpak-builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.json + +devel: flatpak-builder --delete-build-dirs --disable-updates --build-only --ccache --force-clean flatpak build-aux/re.sonny.Workbench.Devel.json +build: devel + cli: ./troll/gjspack/bin/gjspack src/cli/main.js --appid=re.sonny.Workbench.cli --prefix=/re/sonny/Workbench --resource-root=src/ --no-executable flatpak/files/share/re.sonny.Workbench.cli/ cp src/cli/bin.js flatpak/files/bin/workbench-cli diff --git a/README.md b/README.md index 0c89cb47a..50c496e79 100644 --- a/README.md +++ b/README.md @@ -30,14 +30,14 @@ Among other things, Workbench comes with | | Formatter | Linter | Library demos[1] | | ---------- | --------- | ------ | ---------------- | -| JavaScript | ✅ | ✅ | 100 | +| JavaScript | ✅ | ✅ | 99 | | Python | ✅ | ✅ | 92 | -| Vala | ✅ | ✅ | 67 | +| Vala | ✅ | ✅ | 92 | | Rust | ✅ | ✅ | 45 | | Blueprint | ✅ | ✅ | | | CSS | ✅ | ✅ | | -[1] As of 2024-04-28 +[1] As of 2024-06-16 ## Tips and tricks diff --git a/demos b/demos index bb5df9b69..0db011334 160000 --- a/demos +++ b/demos @@ -1 +1 @@ -Subproject commit bb5df9b69152334e67dc79a31db4e7f0ba884141 +Subproject commit 0db011334ad15bfc60ef4aaca6c90a1dec7d705c diff --git a/src/Library/EntryRow.blp b/src/Library/EntryRow.blp index 84e37b83e..35c9488ce 100644 --- a/src/Library/EntryRow.blp +++ b/src/Library/EntryRow.blp @@ -1,20 +1,20 @@ using Gtk 4.0; using Adw 1; -template $EntryRow: Adw.PreferencesRow { +template $EntryRow: Adw.ActionRow { + activatable: true; + accessibility { labelled-by: title_label; described-by: description_label; } - title: bind title_label.label; - + [prefix] Box contents { orientation: horizontal; Box labels_box { margin-top: 6; - margin-start: 12; margin-bottom: 6; spacing: 3; orientation: vertical; @@ -43,13 +43,13 @@ template $EntryRow: Adw.PreferencesRow { margin-top: 3; } } + } - Image { - icon-name: "go-next-symbolic"; - margin-end: 12; - margin-start: 6; - hexpand: true; - halign: end; - } + [suffix] + Image { + icon-name: "go-next-symbolic"; + margin-start: 6; + hexpand: true; + halign: end; } } diff --git a/src/Library/EntryRow.js b/src/Library/EntryRow.js index 9eb9d9827..e40e6963a 100644 --- a/src/Library/EntryRow.js +++ b/src/Library/EntryRow.js @@ -6,7 +6,7 @@ import GObject from "gi://GObject"; import { getLanguage } from "../util.js"; import Template from "./EntryRow.blp" with { type: "uri" }; -class EntryRow extends Adw.PreferencesRow { +class EntryRow extends Adw.ActionRow { constructor({ demo, ...params } = {}) { super(params); @@ -22,7 +22,7 @@ class EntryRow extends Adw.PreferencesRow { }); activate_action.connect("activate", () => { - this.emit("activated", null); + this.emit("triggered", null); }); action_group.add_action(activate_action); @@ -47,7 +47,7 @@ class EntryRow extends Adw.PreferencesRow { }); button.connect("clicked", () => { - this.emit("activated", language); + this.emit("triggered", language); }); return button; @@ -68,7 +68,7 @@ export default GObject.registerClass( ), }, Signals: { - activated: { + triggered: { param_types: [GObject.TYPE_JSOBJECT], }, }, diff --git a/src/Library/Library.blp b/src/Library/Library.blp index 240898c9a..a218402bf 100644 --- a/src/Library/Library.blp +++ b/src/Library/Library.blp @@ -1,75 +1,97 @@ using Gtk 4.0; using Adw 1; -Adw.PreferencesWindow window { +Adw.Window window { hide-on-close: true; modal: false; title: _("Workbench — Library"); default-height: 700; default-width: 700; - Adw.PreferencesPage { - Adw.PreferencesGroup { - Picture picture_illustration { - can-shrink: false; - margin-bottom: 32; - } - - Label { - label: _("Learn, Test, Remix"); + Adw.ToolbarView toolbar_view { + [top] + Adw.HeaderBar header_bar { + title-widget: Adw.WindowTitle { + title: _("Workbench — Library"); + }; + } - styles [ - "title-1" - ] + content: Adw.PreferencesPage { + Adw.PreferencesGroup { + Box { + halign: center; + vexpand: false; + + Picture picture_illustration { + can-shrink: false; + margin-bottom: 32; + } + } + + Label { + label: _("Learn, Test, Remix"); + + styles [ + "title-1" + ] + } + + SearchEntry search_entry { + search-delay: 100; + placeholder-text: _("Search demos"); + activates-default: true; + width-request: 400; + margin-top: 32; + } } - } - Adw.PreferencesGroup library_uncategorized {} + Adw.PreferencesGroup library_uncategorized {} - Adw.PreferencesGroup library_tools { - title: _("Tools"); - } + Adw.PreferencesGroup library_tools { + title: _("Tools"); + } - Adw.PreferencesGroup library_network { - title: _("Network"); - } + Adw.PreferencesGroup library_network { + title: _("Network"); + } - Adw.PreferencesGroup library_controls { - title: _("Controls"); - } + Adw.PreferencesGroup library_controls { + title: _("Controls"); + } - Adw.PreferencesGroup library_layout { - title: _("Layout"); - } + Adw.PreferencesGroup library_layout { + title: _("Layout"); + } - Adw.PreferencesGroup library_feedback { - title: _("Feedback"); - } + Adw.PreferencesGroup library_feedback { + title: _("Feedback"); + } - Adw.PreferencesGroup library_navigation { - title: _("Navigation"); - } + Adw.PreferencesGroup library_navigation { + title: _("Navigation"); + } - Adw.PreferencesGroup library_user_interface { - title: _("User Interface"); - } + Adw.PreferencesGroup library_user_interface { + title: _("User Interface"); + } - Adw.PreferencesGroup library_platform { - title: _("Platform APIs"); - } + Adw.PreferencesGroup library_platform { + title: _("Platform APIs"); + } - Adw.PreferencesGroup { - vexpand: true; - valign: end; + Adw.PreferencesGroup { + vexpand: true; + valign: end; - Label { - label: _('All examples are dedicated to the public domain\nand can be used freely under the terms of CC0 1.0'); - use-markup: true; + Label { + label: _("All examples are dedicated to the public domain\nand can be used freely under the terms of CC0 1.0"); + use-markup: true; - styles [ - "caption" - ] + styles [ + "caption" + ] + } } - } + }; } } diff --git a/src/Library/Library.js b/src/Library/Library.js index 7267f36e4..ed0973d03 100644 --- a/src/Library/Library.js +++ b/src/Library/Library.js @@ -19,7 +19,7 @@ import { build } from "../../troll/src/builder.js"; export default function Library({ application }) { const objects = build(resource); - const { window, picture_illustration } = objects; + const { window, picture_illustration, search_entry } = objects; window.application = application; picture_illustration.set_resource(illustration); @@ -27,17 +27,19 @@ export default function Library({ application }) { window.add_css_class("devel"); } - let last_selected; + let last_triggered; window.connect("close-request", quitOnLastWindowClose); const demos = getDemos(); + const widgets_map = new Map(); + const category_map = new Map(); demos.forEach((demo) => { - const widget = new EntryRow({ demo: demo }); - if (demo.name === "Welcome") last_selected = widget; + const entry_row = new EntryRow({ demo: demo }); + if (demo.name === "Welcome") last_triggered = entry_row; - widget.connect("activated", (_self, language) => { - last_selected = widget; + entry_row.connect("triggered", (_self, language) => { + last_triggered = entry_row; openDemo({ application, @@ -45,17 +47,34 @@ export default function Library({ application }) { language, }).catch(console.error); }); - - objects[`library_${demo.category}`].add(widget); + if (!category_map.has(demo.category)) { + category_map.set(demo.category, objects[`library_${demo.category}`]); + } + objects[`library_${demo.category}`].add(entry_row); + widgets_map.set(demo.name, { entry_row, category: demo.category }); }); + search_entry.connect("search-changed", () => { + const search_term = search_entry.get_text().toLowerCase(); + const visible_categories = new Set(); + + widgets_map.forEach(({ entry_row, category }, demo_name) => { + const is_match = demo_name.toLowerCase().includes(search_term); + entry_row.visible = is_match; + if (is_match) visible_categories.add(category); + }); + + category_map.forEach((category_widget, category_name) => { + category_widget.visible = visible_categories.has(category_name); + }); + }); const action_library = new Gio.SimpleAction({ name: "library", parameter_type: null, }); action_library.connect("activate", () => { window.present(); - last_selected?.grab_focus(); + last_triggered?.grab_focus(); }); application.add_action(action_library); application.set_accels_for_action("app.library", ["O"]); @@ -86,9 +105,9 @@ async function openDemo({ application, demo_name, language }) { session.settings.set_int("code-language", language.index); global_settings.set_int("recent-code-language", language.index); - // If the user explictely requested to open the demo + // If the user explicitly requested to open the demo // in a specific language then that's probably what they are interested in - // therefor override the demo default and force show the code panel + // therefore override the demo default and force show the code panel session.settings.set_boolean("show-code", true); }