diff --git a/build-aux/wip/run.js b/build-aux/wip/run.js index 26bbf440f..da4d6a5e6 100755 --- a/build-aux/wip/run.js +++ b/build-aux/wip/run.js @@ -66,28 +66,30 @@ if (!exists(`${path}/.flatpak/repo`)) { } if (!exists(`${path}/.flatpak/flatpak-builder`)) { - const module_name = app_module.name; - - const manifest_relative_path = - Gio.File.new_for_path(path).get_relative_path(manifest_file); - - const prefix = [ - "flatpak-builder", - "--ccache", - "--force-clean", - "--disable-updates", - ]; - - const suffix = [ - `--state-dir=${path}/.flatpak/flatpak-builder`, - `--stop-at=${module_name}`, - `${path}/.flatpak/repo`, - manifest_relative_path, - ]; + await downloadSources(); + await buildModules(); +} - // downloads sources (de-initializes) +const prefix = [ + "flatpak-builder", + "--ccache", + "--force-clean", + "--disable-updates", +]; +const suffix = [ + `--state-dir=${path}/.flatpak/flatpak-builder`, + `--stop-at=${app_module.name}`, + `${path}/.flatpak/repo`, + Gio.File.new_for_path(path).get_relative_path(manifest_file), +]; + +// de-initializes +async function downloadSources() { await run([...prefix, "--download-only", ...suffix]); - // builds modules (de-initializes) +} + +// de-initializes +async function buildModules() { await run([ ...prefix, "--disable-download", diff --git a/src/Library/Library.blp b/src/Library/Library.blp index c63bf450f..f4ccfc72d 100644 --- a/src/Library/Library.blp +++ b/src/Library/Library.blp @@ -50,12 +50,24 @@ Adw.Window window { ] } - SearchEntry search_entry { - search-delay: 100; - placeholder-text: _("Search demos"); - activates-default: true; - width-request: 400; - margin-top: 32; + Box { + spacing: 6; + + SearchEntry search_entry { + search-delay: 100; + placeholder-text: _("Search demos"); + activates-default: true; + hexpand: true; + margin-top: 32; + } + + DropDown dropdown_language { + valign: end; + } + + DropDown dropdown_category { + valign: end; + } } } @@ -215,6 +227,28 @@ Adw.Window window { halign: center; margin-bottom: 24; margin-top: 12; + orientation: vertical; + + Box results_empty { + orientation: vertical; + visible: false; + margin-top: 46; + margin-bottom: 70; + spacing: 6; + + Label { + label: _("No results"); + + styles [ + "title-4" + ] + } + + Button button_reset { + label: _("Reset filters"); + halign: center; + } + } Label { label: _("All examples are dedicated to the public domain\nand can be used freely under the terms of CC0 1.0"); diff --git a/src/Library/Library.js b/src/Library/Library.js index b70358c95..6f2f7c7ee 100644 --- a/src/Library/Library.js +++ b/src/Library/Library.js @@ -1,4 +1,5 @@ import Gio from "gi://Gio"; +import Gtk from "gi://Gtk"; import { decode, @@ -14,12 +15,21 @@ import { createSessionFromDemo } from "../sessions.js"; import EntryRow from "./EntryRow.js"; import illustration from "./library.svg"; +import { gettext as _ } from "gettext"; import { build } from "../../troll/src/builder.js"; export default function Library({ application }) { const objects = build(resource); - const { window, picture_illustration, search_entry } = objects; + const { + window, + picture_illustration, + search_entry, + dropdown_category, + dropdown_language, + results_empty, + button_reset, + } = objects; window.application = application; picture_illustration.set_resource(illustration); @@ -34,7 +44,48 @@ export default function Library({ application }) { const demos = getDemos(); const widgets_map = new Map(); const category_map = new Map(); + + const language_model = new Gtk.StringList(); + language_model.append(_("Any Language")); + dropdown_language.set_model(language_model); + const language_check = [_("Any Language")]; + const language_labels = { + javascript: _("JavaScript"), + python: _("Python"), + rust: _("Rust"), + vala: _("Vala"), + typescript: _("TypeScript"), + }; + Object.values(language_labels).forEach((str) => language_model.push(str)); + + const category_model = new Gtk.StringList(); + category_model.append(_("Any Category")); + dropdown_category.set_model(category_model); + const category_check = [_("Any Category")]; + const category_labels = { + uncategorized: _("Uncategorized"), + tools: _("Tools"), + network: _("Network"), + controls: _("Controls"), + layout: _("Layout"), + feedback: _("Feedback"), + navigation: _("Navigation"), + user_interface: _("User Interface"), + platform: _("Platform APIs"), + }; + Object.values(category_labels).forEach((str) => category_model.push(str)); + demos.forEach((demo) => { + demo.languages.forEach((lang) => { + if (!language_check.includes(lang)) { + language_check.push(lang); + } + }); + + if (!category_check.includes(demo.category)) { + category_check.push(demo.category); + } + const entry_row = new EntryRow({ demo: demo }); if (demo.name === "Welcome") last_triggered = entry_row; @@ -51,25 +102,63 @@ export default function Library({ application }) { category_map.set(demo.category, objects[`library_${demo.category}`]); } objects[`library_${demo.category}`].append(entry_row); - widgets_map.set(demo.name, { entry_row, category: demo.category }); + widgets_map.set(demo.name, { + entry_row, + category_index: category_check.indexOf(demo.category), + languages_index: demo.languages.map((lang) => + language_check.indexOf(lang), + ), + }); }); - search_entry.connect("search-changed", () => { + function updateList() { + const current_category = dropdown_category.get_selected(); + const current_language = dropdown_language.get_selected(); + 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); - }); + let results_found = false; + widgets_map.forEach( + ({ entry_row, category_index, languages_index }, demo_name) => { + const category_match = + current_category === 0 || category_index === current_category; + const language_match = + current_language === 0 || languages_index.includes(current_language); + const search_match = demo_name.toLowerCase().includes(search_term); + const is_match = + category_match && + language_match && + (search_term === "" || search_match); + entry_row.visible = is_match; + if (is_match) { + results_found = true; + visible_categories.add(category_check[category_index]); + } + }, + ); category_map.forEach((category_widget, category_name) => { const label = objects[`label_${category_name}`]; - if (label) label.visible = search_term === ""; + if (label) + label.visible = + current_category === 0 && + current_language === 0 && + search_term === ""; category_widget.visible = visible_categories.has(category_name); }); + results_empty.set_visible(!results_found); + } + + search_entry.connect("search-changed", updateList); + dropdown_category.connect("notify::selected", updateList); + dropdown_language.connect("notify::selected", updateList); + + button_reset.connect("clicked", () => { + search_entry.text = ""; + dropdown_category.selected = 0; + dropdown_language.selected = 0; }); + const action_library = new Gio.SimpleAction({ name: "library", parameter_type: null,