diff --git a/po/POTFILES b/po/POTFILES index 0fa76665d..e0ccaf03f 100644 --- a/po/POTFILES +++ b/po/POTFILES @@ -76,4 +76,6 @@ src/Extensions/Extensions.js src/Manuals/DocumentationViewer.blp src/Manuals/Shortcuts.blp src/Manuals/Shortcuts.js -src/Manuals/DocumentationViewer.js \ No newline at end of file +src/Manuals/DocumentationViewer.js +src/Library/EntryRow.blp +src/Library/EntryRow.js diff --git a/src/Library/EntryRow.blp b/src/Library/EntryRow.blp new file mode 100644 index 000000000..a7d88e10c --- /dev/null +++ b/src/Library/EntryRow.blp @@ -0,0 +1,49 @@ +using Gtk 4.0; +using Adw 1; + +template $EntryRow : Adw.PreferencesRow { + accessibility { + labelled-by: title_label; + described-by: description_label; + } + title: bind title_label.label; + + Box contents { + orientation: horizontal; + + Box labels_box { + margin-top: 6; + margin-start: 12; + margin-bottom: 6; + spacing: 3; + orientation: vertical; + + Label title_label { + xalign: 0; + wrap: true; + wrap-mode: word_char; + } + Label description_label { + styles ["dim-label", "caption"] + xalign: 0; + wrap: true; + wrap-mode: word_char; + natural-wrap-mode: none; + } + + Box languages_box { + orientation: horizontal; + spacing: 3; + margin-top: 3; + } + } + + Image { + icon-name: "go-next-symbolic"; + margin-end: 12; + margin-start: 6; + hexpand: true; + halign: end; + } + } +} diff --git a/src/Library/EntryRow.js b/src/Library/EntryRow.js new file mode 100644 index 000000000..0b8248efb --- /dev/null +++ b/src/Library/EntryRow.js @@ -0,0 +1,82 @@ +import Adw from "gi://Adw"; +import Gtk from "gi://Gtk"; +import Gio from "gi://Gio"; +import GObject from "gi://GObject"; + +import { demoSupportsLanguage, getLanguage } from "../util.js"; +import Template from "./EntryRow.blp" with { type: "uri" }; + +class EntryRow extends Adw.PreferencesRow { + constructor({ demo, ...params } = {}) { + super(params); + + this._title_label.label = demo.name; + this._description_label.label = demo.description; + + this.#createLanguageTags(demo); + + const action_group = new Gio.SimpleActionGroup(); + const activate_action = new Gio.SimpleAction({ + name: "activate", + parameter_type: null, + }); + + activate_action.connect("activate", () => { + this.emit("activated", null); + }); + action_group.add_action(activate_action); + + this.insert_action_group("demo-row", action_group); + this.action_name = "demo-row.activate"; + } + + #createLanguageTags(demo) { + const language = getLanguage("javascript"); + const language_tag = this.#createLanguageTag(language); + this._languages_box.append(language_tag); + + ["vala", "rust"].forEach((id) => { + const language = getLanguage(id); + if (!demoSupportsLanguage(demo, language.id)) return; + const language_tag = this.#createLanguageTag(language); + this._languages_box.append(language_tag); + }); + } + + #createLanguageTag(language) { + const button = new Gtk.Button({ + label: language.name, + valign: Gtk.Align.CENTER, + css_classes: ["pill", "small"], + }); + + button.connect("clicked", () => { + this.emit("activated", language.id); + }); + + return button; + } +} + +export default GObject.registerClass( + { + GTypeName: "EntryRow", + Template, + Properties: { + demo: GObject.ParamSpec.jsobject( + "demo", + "", + "", + GObject.ParamFlags.READWRITE | GObject.ParamFlags.CONSTRUCT_ONLY, + null, + ), + }, + Signals: { + activated: { + param_types: [GObject.TYPE_STRING], + }, + }, + InternalChildren: ["title_label", "description_label", "languages_box"], + }, + EntryRow, +); diff --git a/src/Library/Library.js b/src/Library/Library.js index 9a6e8ce3c..cee3e8d8d 100644 --- a/src/Library/Library.js +++ b/src/Library/Library.js @@ -1,12 +1,12 @@ import Gio from "gi://Gio"; -import Adw from "gi://Adw"; import Gtk from "gi://Gtk"; -import { demos_dir, getDemo } from "../util.js"; +import { demos_dir, getDemo, settings as global_settings } from "../util.js"; import Window from "../window.js"; import resource from "./Library.blp"; import { createSessionFromDemo } from "../sessions.js"; +import EntryRow from "./EntryRow.js"; import illustration from "./library.svg"; @@ -21,21 +21,17 @@ export default function Library({ application }) { const demos = getDemos(); demos.forEach((demo) => { - const widget = new Adw.ActionRow({ - title: demo.name, - subtitle: demo.description, - activatable: true, - }); + const widget = new EntryRow({ demo: demo }); if (demo.name === "Welcome") last_selected = widget; - widget.add_suffix( - new Gtk.Image({ - icon_name: "go-next-symbolic", - }), - ); - widget.connect("activated", () => { + + widget.connect("activated", (_self, language_name) => { last_selected = widget; - openDemo({ application, demo_name: demo.name }).catch(console.error); + openDemo({ + application, + demo_name: demo.name, + language_name, + }).catch(console.error); }); builder.get_object(`library_${demo.category}`).add(widget); @@ -77,10 +73,27 @@ function getDemos() { return demos; } -async function openDemo({ application, demo_name }) { +async function openDemo({ application, demo_name, language_name }) { const demo = getDemo(demo_name); const session = await createSessionFromDemo(demo); + if (language_name) { + switch (language_name.toLowerCase()) { + case "javascript": + session.settings.set_int("code-language", 0); + global_settings.set_int("recent-code-language", 0); + break; + case "vala": + session.settings.set_int("code-language", 1); + global_settings.set_int("recent-code-language", 1); + break; + case "rust": + session.settings.set_int("code-language", 2); + global_settings.set_int("recent-code-language", 2); + break; + } + } + const is_js = session.settings.get_int("code-language") === 0; const { load } = Window({ application, session }); diff --git a/src/style.css b/src/style.css index e76a470fa..e25c9e2bf 100644 --- a/src/style.css +++ b/src/style.css @@ -21,6 +21,18 @@ border: 1px solid @borders; } +/* + * From Builder's stylesheet: + * https://gitlab.gnome.org/GNOME/gnome-builder/-/blob/45d4ec9b6f1aa2236c9bb7dfb846b35f9b959618/src/libide/gui/style.css#L33 + * Used to style the language tags for the demo entries in the Library + */ +button.pill.small { + font-size: 0.83333em; + border-radius: 99px; + margin: 0; + padding: 1px 12px; +} + #panel_code, #panel_style, #panel_ui { diff --git a/src/util.js b/src/util.js index 4a3cd0c43..392b98acd 100644 --- a/src/util.js +++ b/src/util.js @@ -61,6 +61,7 @@ export const languages = [ extensions: [".js", ".mjs"], types: ["text/javascript", "application/javascript"], document: null, + default_file: "main.js", }, { id: "css", @@ -78,6 +79,7 @@ export const languages = [ types: ["text/x-vala"], document: null, placeholder: "// Sorry, this demo is not available in Vala yet.", + default_file: "main.vala", }, { id: "rust", @@ -87,6 +89,7 @@ export const languages = [ types: ["text/x-rust"], document: null, placeholder: "// Sorry, this demo is not available in Rust yet.", + default_file: "code.rs", }, ]; @@ -186,6 +189,12 @@ export function getDemo(name) { return demo; } +export function demoSupportsLanguage(demo, id) { + const language = getLanguage(id); + const demo_dir = demos_dir.get_child(demo.name); + return demo_dir.get_child(language.default_file).query_exists(null); +} + export function getNowForFilename() { return new GLib.DateTime().format("%Y-%m-%d %H-%M-%S"); }