From c5381bf6cf5e2456befd9dbc5d53fb3ea107ff2e Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 6 Jan 2025 17:08:35 +0100 Subject: [PATCH 001/106] Put non-search items in accordion -- we'll add more items --- src/fontra/views/fontoverview/panel-navigation.js | 15 ++++++++++++--- 1 file changed, 12 insertions(+), 3 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index e016f1b44..97251bb28 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -4,6 +4,7 @@ import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; import { labeledCheckbox } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; +import { Accordion } from "/web-components/ui-accordion.js"; export class FontOverviewNavigation extends HTMLElement { constructor(fontOverviewController) { @@ -84,7 +85,6 @@ export class FontOverviewNavigation extends HTMLElement { ); const groupByContainer = html.div({}, [ - html.span({}, ["Group by"]), ...groupByProperties.map(({ key, label }) => labeledCheckbox(label, groupByController, key) ), @@ -95,9 +95,18 @@ export class FontOverviewNavigation extends HTMLElement { searchStringKey: "searchString", }); + const accordion = new Accordion(); + accordion.items = [ + { + label: translate("sources.labels.location"), + content: this.fontSourceInput, + open: true, + }, + { label: "Group by", content: groupByContainer, open: true }, + ]; + this.appendChild(this.searchField); - this.appendChild(fontSourceSelector); - this.appendChild(groupByContainer); + this.appendChild(accordion); } _updateFontSourceInput() { From ce87f10fed57f9ba357d620248b24f2c10115b3c Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 6 Jan 2025 17:11:27 +0100 Subject: [PATCH 002/106] Add translate todo --- src/fontra/views/fontoverview/panel-navigation.js | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 97251bb28..a34cd40e0 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -102,7 +102,11 @@ export class FontOverviewNavigation extends HTMLElement { content: this.fontSourceInput, open: true, }, - { label: "Group by", content: groupByContainer, open: true }, + { + label: "Group by", // TODO: translate + content: groupByContainer, + open: true, + }, ]; this.appendChild(this.searchField); From 35989348ae48c783ec9a5fb5dda723cc60937545 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 6 Jan 2025 17:13:27 +0100 Subject: [PATCH 003/106] Delete unused element code --- src/fontra/views/fontoverview/panel-navigation.js | 13 ------------- 1 file changed, 13 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index a34cd40e0..c8b49a43c 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -43,19 +43,6 @@ export class FontOverviewNavigation extends HTMLElement { ); } - const fontSourceSelector = html.div( - { - class: "font-source-selector", - }, - [ - html.label( - { for: "font-source-select" }, - translate("sidebar.font-overview.font-source") - ), - this.fontSourceInput, - ] - ); - this._updateFontSourceInput(); const groupByController = new ObservableController( From 8cabe9aac90f37fac5dc0ab431087ff856a462f2 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 7 Jan 2025 10:44:51 +0100 Subject: [PATCH 004/106] Add stubs for glyph sets --- src/fontra/views/fontoverview/panel-navigation.js | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index c8b49a43c..678cf9759 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -83,6 +83,7 @@ export class FontOverviewNavigation extends HTMLElement { }); const accordion = new Accordion(); + accordion.items = [ { label: translate("sources.labels.location"), @@ -94,6 +95,16 @@ export class FontOverviewNavigation extends HTMLElement { content: groupByContainer, open: true, }, + { + label: "Project glyph sets", // TODO: translate + content: html.div({ class: "glyph-sets-container" }, []), + open: true, + }, + { + label: "My glyph sets", // TODO: translate + content: html.div({ class: "glyph-sets-container" }, []), + open: true, + }, ]; this.appendChild(this.searchField); From 3903ea4b2b39e6fa157aa317de3e210825f1ccfa Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:51:00 +0100 Subject: [PATCH 005/106] More stubs for glyph sets UI --- src/fontra/views/fontoverview/fontoverview.js | 4 +++ .../views/fontoverview/panel-navigation.js | 26 +++++++++++++++++-- 2 files changed, 28 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index c5e9fcd67..7752afb1d 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -25,6 +25,8 @@ const persistentSettings = [ { key: "glyphSelection", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, { key: "closedGlyphSections", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, { key: "groupByKeys" }, + { key: "projectGlyphSets" }, + { key: "myGlyphSets" }, ]; function getDefaultFontOverviewSettings() { @@ -35,6 +37,8 @@ function getDefaultFontOverviewSettings() { glyphSelection: new Set(), closedGlyphSections: new Set(), groupByKeys: [], + projectGlyphSets: ["__this_font__"], + myGlyphSets: [], }; } diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 678cf9759..ca88bf0ea 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -97,12 +97,18 @@ export class FontOverviewNavigation extends HTMLElement { }, { label: "Project glyph sets", // TODO: translate - content: html.div({ class: "glyph-sets-container" }, []), + content: html.div( + { class: "glyph-sets-container" }, + this._setupProjectGlyphSetsUI() + ), open: true, }, { label: "My glyph sets", // TODO: translate - content: html.div({ class: "glyph-sets-container" }, []), + content: html.div( + { class: "glyph-sets-container" }, + this._setupMyGlyphSetsUI() + ), open: true, }, ]; @@ -111,6 +117,22 @@ export class FontOverviewNavigation extends HTMLElement { this.appendChild(accordion); } + _setupProjectGlyphSetsUI() { + const projectGlyphSetsController = new ObservableController({}); + + return [ + labeledCheckbox( + "This font's glyph set", + projectGlyphSetsController, + "__this_font__" + ), + ]; + } + + _setupMyGlyphSetsUI() { + return []; + } + _updateFontSourceInput() { const fontSourceIdentifier = this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( From c6292dd4f7a1085c198e1919fbc2d5deab35f1f4 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:53:08 +0100 Subject: [PATCH 006/106] Factor group-by UI into separate method --- .../views/fontoverview/panel-navigation.js | 68 ++++++++++--------- 1 file changed, 35 insertions(+), 33 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index ca88bf0ea..2ed387834 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -45,38 +45,6 @@ export class FontOverviewNavigation extends HTMLElement { this._updateFontSourceInput(); - const groupByController = new ObservableController( - Object.fromEntries( - this.fontOverviewSettings.groupByKeys.map((key) => [key, true]) - ) - ); - - groupByController.addListener((event) => { - if (event.senderInfo?.senderID !== this) { - this.fontOverviewSettings.groupByKeys = groupByKeys.filter( - (key) => groupByController.model[key] - ); - } - }); - - this.fontOverviewSettingsController.addKeyListener("groupByKeys", (event) => { - groupByController.withSenderInfo({ senderID: this }, () => { - for (const key of groupByKeys) { - groupByController.model[key] = event.newValue.includes(key); - } - }); - }); - - this.fontOverviewSettingsController.addKeyListener("fontLocationSource", (event) => - this._updateFontSourceInput() - ); - - const groupByContainer = html.div({}, [ - ...groupByProperties.map(({ key, label }) => - labeledCheckbox(label, groupByController, key) - ), - ]); - this.searchField = new GlyphSearchField({ settingsController: this.fontOverviewSettingsController, searchStringKey: "searchString", @@ -92,7 +60,7 @@ export class FontOverviewNavigation extends HTMLElement { }, { label: "Group by", // TODO: translate - content: groupByContainer, + content: this._setupGroupByUI(), open: true, }, { @@ -117,6 +85,40 @@ export class FontOverviewNavigation extends HTMLElement { this.appendChild(accordion); } + _setupGroupByUI() { + const groupByController = new ObservableController( + Object.fromEntries( + this.fontOverviewSettings.groupByKeys.map((key) => [key, true]) + ) + ); + + groupByController.addListener((event) => { + if (event.senderInfo?.senderID !== this) { + this.fontOverviewSettings.groupByKeys = groupByKeys.filter( + (key) => groupByController.model[key] + ); + } + }); + + this.fontOverviewSettingsController.addKeyListener("groupByKeys", (event) => { + groupByController.withSenderInfo({ senderID: this }, () => { + for (const key of groupByKeys) { + groupByController.model[key] = event.newValue.includes(key); + } + }); + }); + + this.fontOverviewSettingsController.addKeyListener("fontLocationSource", (event) => + this._updateFontSourceInput() + ); + + return html.div({}, [ + ...groupByProperties.map(({ key, label }) => + labeledCheckbox(label, groupByController, key) + ), + ]); + } + _setupProjectGlyphSetsUI() { const projectGlyphSetsController = new ObservableController({}); From b201ebf99dde4cad131b88ab02bb1c8f2cac5ea1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:55:06 +0100 Subject: [PATCH 007/106] Make group-by and glyphset setup methods more similar --- .../views/fontoverview/panel-navigation.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 2ed387834..bc7cfa9ea 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -65,18 +65,12 @@ export class FontOverviewNavigation extends HTMLElement { }, { label: "Project glyph sets", // TODO: translate - content: html.div( - { class: "glyph-sets-container" }, - this._setupProjectGlyphSetsUI() - ), + content: this._setupProjectGlyphSetsUI(), open: true, }, { label: "My glyph sets", // TODO: translate - content: html.div( - { class: "glyph-sets-container" }, - this._setupMyGlyphSetsUI() - ), + content: this._setupMyGlyphSetsUI(), open: true, }, ]; @@ -122,17 +116,17 @@ export class FontOverviewNavigation extends HTMLElement { _setupProjectGlyphSetsUI() { const projectGlyphSetsController = new ObservableController({}); - return [ + return html.div({ class: "glyph-sets-container" }, [ labeledCheckbox( "This font's glyph set", projectGlyphSetsController, "__this_font__" ), - ]; + ]); } _setupMyGlyphSetsUI() { - return []; + return html.div({ class: "glyph-sets-container" }, []); } _updateFontSourceInput() { From b19b2bdc66d6b4dc832fca0e502ca2f9639a18e1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:56:10 +0100 Subject: [PATCH 008/106] Rename methods: they return something --- src/fontra/views/fontoverview/panel-navigation.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index bc7cfa9ea..ff8c04415 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -60,17 +60,17 @@ export class FontOverviewNavigation extends HTMLElement { }, { label: "Group by", // TODO: translate - content: this._setupGroupByUI(), + content: this._makeGroupByUI(), open: true, }, { label: "Project glyph sets", // TODO: translate - content: this._setupProjectGlyphSetsUI(), + content: this._makeProjectGlyphSetsUI(), open: true, }, { label: "My glyph sets", // TODO: translate - content: this._setupMyGlyphSetsUI(), + content: this._makeMyGlyphSetsUI(), open: true, }, ]; @@ -79,7 +79,7 @@ export class FontOverviewNavigation extends HTMLElement { this.appendChild(accordion); } - _setupGroupByUI() { + _makeGroupByUI() { const groupByController = new ObservableController( Object.fromEntries( this.fontOverviewSettings.groupByKeys.map((key) => [key, true]) @@ -113,7 +113,7 @@ export class FontOverviewNavigation extends HTMLElement { ]); } - _setupProjectGlyphSetsUI() { + _makeProjectGlyphSetsUI() { const projectGlyphSetsController = new ObservableController({}); return html.div({ class: "glyph-sets-container" }, [ @@ -125,7 +125,7 @@ export class FontOverviewNavigation extends HTMLElement { ]); } - _setupMyGlyphSetsUI() { + _makeMyGlyphSetsUI() { return html.div({ class: "glyph-sets-container" }, []); } From b7ccb6775e0b241a82de715fc39b774786d7d9dc Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:58:48 +0100 Subject: [PATCH 009/106] Fix copy/paste error --- src/fontra/views/fontoverview/panel-navigation.js | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index ff8c04415..075c4fb65 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -43,6 +43,9 @@ export class FontOverviewNavigation extends HTMLElement { ); } + this.fontOverviewSettingsController.addKeyListener("fontLocationSource", (event) => + this._updateFontSourceInput() + ); this._updateFontSourceInput(); this.searchField = new GlyphSearchField({ @@ -102,10 +105,6 @@ export class FontOverviewNavigation extends HTMLElement { }); }); - this.fontOverviewSettingsController.addKeyListener("fontLocationSource", (event) => - this._updateFontSourceInput() - ); - return html.div({}, [ ...groupByProperties.map(({ key, label }) => labeledCheckbox(label, groupByController, key) From 636ec816ff636dec70f4ddf6040e92d32359a0f6 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 10:59:42 +0100 Subject: [PATCH 010/106] Move related lines closer --- src/fontra/views/fontoverview/panel-navigation.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 075c4fb65..a63526e91 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -53,6 +53,8 @@ export class FontOverviewNavigation extends HTMLElement { searchStringKey: "searchString", }); + this.appendChild(this.searchField); + const accordion = new Accordion(); accordion.items = [ @@ -78,7 +80,6 @@ export class FontOverviewNavigation extends HTMLElement { }, ]; - this.appendChild(this.searchField); this.appendChild(accordion); } From f7b684e1e485b4ea5b6c3b1dfb0d02a765f859aa Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 11:10:04 +0100 Subject: [PATCH 011/106] Factor out checkbox <-> list-of-keys mapping for glyphset reuse --- .../views/fontoverview/panel-navigation.js | 49 +++++++++++-------- 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index a63526e91..1bb7a6d2b 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -84,28 +84,11 @@ export class FontOverviewNavigation extends HTMLElement { } _makeGroupByUI() { - const groupByController = new ObservableController( - Object.fromEntries( - this.fontOverviewSettings.groupByKeys.map((key) => [key, true]) - ) + const groupByController = makeCheckBoxController( + this.fontOverviewSettingsController, + "groupByKeys" ); - groupByController.addListener((event) => { - if (event.senderInfo?.senderID !== this) { - this.fontOverviewSettings.groupByKeys = groupByKeys.filter( - (key) => groupByController.model[key] - ); - } - }); - - this.fontOverviewSettingsController.addKeyListener("groupByKeys", (event) => { - groupByController.withSenderInfo({ senderID: this }, () => { - for (const key of groupByKeys) { - groupByController.model[key] = event.newValue.includes(key); - } - }); - }); - return html.div({}, [ ...groupByProperties.map(({ key, label }) => labeledCheckbox(label, groupByController, key) @@ -141,3 +124,29 @@ export class FontOverviewNavigation extends HTMLElement { } customElements.define("font-overview-navigation", FontOverviewNavigation); + +function makeCheckBoxController(settingsController, settingsKey) { + const settings = settingsController.model; + + const checkboxController = new ObservableController( + Object.fromEntries(settings[settingsKey].map((key) => [key, true])) + ); + + checkboxController.addListener((event) => { + if (!event.senderInfo?.sentFromSettings) { + settings[settingsKey] = Object.entries(checkboxController.model) + .filter(([key, value]) => value) + .map(([key, value]) => key); + } + }); + + settingsController.addKeyListener(settingsKey, (event) => { + checkboxController.withSenderInfo({ sentFromSettings: true }, () => { + Object.entries(checkboxController.model).forEach(([key, value]) => { + checkboxController.model[key] = event.newValue.includes(key); + }); + }); + }); + + return checkboxController; +} From 58b6043220b1dc3b7a03d41d7372f3de00e8235a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 11:12:07 +0100 Subject: [PATCH 012/106] rename var, and CheckBox -> Checkbox --- src/fontra/views/fontoverview/panel-navigation.js | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 1bb7a6d2b..192b49709 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -84,14 +84,14 @@ export class FontOverviewNavigation extends HTMLElement { } _makeGroupByUI() { - const groupByController = makeCheckBoxController( + const checkboxController = makeCheckboxController( this.fontOverviewSettingsController, "groupByKeys" ); return html.div({}, [ ...groupByProperties.map(({ key, label }) => - labeledCheckbox(label, groupByController, key) + labeledCheckbox(label, checkboxController, key) ), ]); } @@ -125,7 +125,7 @@ export class FontOverviewNavigation extends HTMLElement { customElements.define("font-overview-navigation", FontOverviewNavigation); -function makeCheckBoxController(settingsController, settingsKey) { +function makeCheckboxController(settingsController, settingsKey) { const settings = settingsController.model; const checkboxController = new ObservableController( From 906c448731accf3c5c2aa44608b1f59cceb62413 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 11:18:35 +0100 Subject: [PATCH 013/106] Refactor --- .../views/fontoverview/panel-navigation.js | 27 ++++++++++++------- 1 file changed, 17 insertions(+), 10 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 192b49709..718d00da4 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -97,19 +97,26 @@ export class FontOverviewNavigation extends HTMLElement { } _makeProjectGlyphSetsUI() { - const projectGlyphSetsController = new ObservableController({}); - - return html.div({ class: "glyph-sets-container" }, [ - labeledCheckbox( - "This font's glyph set", - projectGlyphSetsController, - "__this_font__" - ), - ]); + const projectGlyphSets = [{ key: "__this_font__", label: "This font's glyph set" }]; + return this._makeGlyphSetsUI("projectGlyphSets", projectGlyphSets); } _makeMyGlyphSetsUI() { - return html.div({ class: "glyph-sets-container" }, []); + const myGlyphSets = [{ key: "floof", label: "Gloof" }]; + return this._makeGlyphSetsUI("myGlyphSets", myGlyphSets); + } + + _makeGlyphSetsUI(settingsKey, glyphSets) { + const checkboxController = makeCheckboxController( + this.fontOverviewSettingsController, + settingsKey + ); + + return html.div({}, [ + ...glyphSets.map(({ key, label }) => + labeledCheckbox(label, checkboxController, key) + ), + ]); } _updateFontSourceInput() { From 1e7f000f6f645c381df18e95867edc8e3ddfb331 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 11:21:24 +0100 Subject: [PATCH 014/106] More refactoring --- .../views/fontoverview/panel-navigation.js | 19 +++++-------------- 1 file changed, 5 insertions(+), 14 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 718d00da4..953172a74 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -84,29 +84,20 @@ export class FontOverviewNavigation extends HTMLElement { } _makeGroupByUI() { - const checkboxController = makeCheckboxController( - this.fontOverviewSettingsController, - "groupByKeys" - ); - - return html.div({}, [ - ...groupByProperties.map(({ key, label }) => - labeledCheckbox(label, checkboxController, key) - ), - ]); + return this._makeCheckboxUI("groupByKeys", groupByProperties); } _makeProjectGlyphSetsUI() { const projectGlyphSets = [{ key: "__this_font__", label: "This font's glyph set" }]; - return this._makeGlyphSetsUI("projectGlyphSets", projectGlyphSets); + return this._makeCheckboxUI("projectGlyphSets", projectGlyphSets); } _makeMyGlyphSetsUI() { - const myGlyphSets = [{ key: "floof", label: "Gloof" }]; - return this._makeGlyphSetsUI("myGlyphSets", myGlyphSets); + const myGlyphSets = []; + return this._makeCheckboxUI("myGlyphSets", myGlyphSets); } - _makeGlyphSetsUI(settingsKey, glyphSets) { + _makeCheckboxUI(settingsKey, glyphSets) { const checkboxController = makeCheckboxController( this.fontOverviewSettingsController, settingsKey From 33cd00f3a52d3c11247d950fc4ab620027f887f0 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 15:43:36 +0100 Subject: [PATCH 015/106] Get glyph sets from settings controller, fiddle with names --- src/fontra/views/fontoverview/fontoverview.js | 10 +++++++--- src/fontra/views/fontoverview/panel-navigation.js | 11 ++++++++--- 2 files changed, 15 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 7752afb1d..e0a53b567 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -25,10 +25,12 @@ const persistentSettings = [ { key: "glyphSelection", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, { key: "closedGlyphSections", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, { key: "groupByKeys" }, - { key: "projectGlyphSets" }, - { key: "myGlyphSets" }, + { key: "projectGlyphSetSelection" }, + { key: "myGlyphSetSelection" }, ]; +const THIS_FONTS_GLYPHSET = ""; + function getDefaultFontOverviewSettings() { return { searchString: "", @@ -37,8 +39,10 @@ function getDefaultFontOverviewSettings() { glyphSelection: new Set(), closedGlyphSections: new Set(), groupByKeys: [], - projectGlyphSets: ["__this_font__"], + projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { label: "This font's glyphs" } }, myGlyphSets: [], + projectGlyphSetSelection: [THIS_FONTS_GLYPHSET], + myGlyphSetSelection: [], }; } diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 953172a74..93832a06b 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -88,13 +88,18 @@ export class FontOverviewNavigation extends HTMLElement { } _makeProjectGlyphSetsUI() { - const projectGlyphSets = [{ key: "__this_font__", label: "This font's glyph set" }]; - return this._makeCheckboxUI("projectGlyphSets", projectGlyphSets); + const projectGlyphSets = Object.entries( + this.fontOverviewSettings.projectGlyphSets + ).map(([key, value]) => ({ + key, + label: value.label, + })); + return this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets); } _makeMyGlyphSetsUI() { const myGlyphSets = []; - return this._makeCheckboxUI("myGlyphSets", myGlyphSets); + return this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets); } _makeCheckboxUI(settingsKey, glyphSets) { From 46738c6a323c9af64fbb2e5edf57d2b57a531ab8 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 9 Jan 2025 22:17:15 +0100 Subject: [PATCH 016/106] Implement update methods for glyphset sections; reuse checkbox controllers, so we don't have to add/remove listeners --- .../views/fontoverview/panel-navigation.js | 58 ++++++++++++++----- 1 file changed, 44 insertions(+), 14 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 93832a06b..35b4f6ccd 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -15,6 +15,8 @@ export class FontOverviewNavigation extends HTMLElement { fontOverviewController.fontOverviewSettingsController; this.fontOverviewSettings = this.fontOverviewSettingsController.model; + this._checkboxControllers = {}; + this._setupUI(); } @@ -57,6 +59,20 @@ export class FontOverviewNavigation extends HTMLElement { const accordion = new Accordion(); + this._projectGlyphSetsItem = { + label: "Project glyph sets", // TODO: translate + id: "project-glyph-sets", + content: html.div(), + open: true, + }; + + this._myGlyphSetsItem = { + label: "My glyph sets", // TODO: translate + id: "my-glyph-sets", + content: html.div(), + open: true, + }; + accordion.items = [ { label: translate("sources.labels.location"), @@ -68,25 +84,34 @@ export class FontOverviewNavigation extends HTMLElement { content: this._makeGroupByUI(), open: true, }, - { - label: "Project glyph sets", // TODO: translate - content: this._makeProjectGlyphSetsUI(), - open: true, - }, - { - label: "My glyph sets", // TODO: translate - content: this._makeMyGlyphSetsUI(), - open: true, - }, + this._projectGlyphSetsItem, + this._myGlyphSetsItem, ]; this.appendChild(accordion); + + this.fontOverviewSettingsController.addKeyListener("projectGlyphSets", (event) => + this._updateProjectGlyphSets() + ); + this.fontOverviewSettingsController.addKeyListener("myGlyphSets", (event) => + this._updateMyGlyphSets() + ); + this._updateProjectGlyphSets(); + this._updateMyGlyphSets(); } _makeGroupByUI() { return this._makeCheckboxUI("groupByKeys", groupByProperties); } + _updateProjectGlyphSets() { + this._projectGlyphSetsItem.content = this._makeProjectGlyphSetsUI(); + } + + _updateMyGlyphSets() { + this._myGlyphSetsItem.content = this._makeMyGlyphSetsUI(); + } + _makeProjectGlyphSetsUI() { const projectGlyphSets = Object.entries( this.fontOverviewSettings.projectGlyphSets @@ -94,6 +119,7 @@ export class FontOverviewNavigation extends HTMLElement { key, label: value.label, })); + return this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets); } @@ -103,10 +129,14 @@ export class FontOverviewNavigation extends HTMLElement { } _makeCheckboxUI(settingsKey, glyphSets) { - const checkboxController = makeCheckboxController( - this.fontOverviewSettingsController, - settingsKey - ); + let checkboxController = this._checkboxControllers[settingsKey]; + if (!checkboxController) { + checkboxController = makeCheckboxController( + this.fontOverviewSettingsController, + settingsKey + ); + this._checkboxControllers[settingsKey] = checkboxController; + } return html.div({}, [ ...glyphSets.map(({ key, label }) => From 31b79aaaab7a97774996c3704ffc3be9f418e92d Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 15:06:45 +0100 Subject: [PATCH 017/106] Switch to monthly dependabot --- .github/dependabot.yml | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/.github/dependabot.yml b/.github/dependabot.yml index ce9982f4b..2912ebd87 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -3,15 +3,13 @@ updates: - package-ecosystem: "github-actions" directory: "/" schedule: - interval: "weekly" - day: "friday" + interval: "monthly" open-pull-requests-limit: 10 - package-ecosystem: "npm" directory: "/" schedule: - interval: "weekly" - day: "friday" + interval: "monthly" open-pull-requests-limit: 10 groups: npm-packages: @@ -21,8 +19,7 @@ updates: - package-ecosystem: "pip" directory: "/" schedule: - interval: "weekly" - day: "friday" + interval: "monthly" open-pull-requests-limit: 10 groups: python-packages: From 1a2c488f0a3d66c42341342b5ecf06a0f9833948 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:07:47 +0000 Subject: [PATCH 018/106] Bump the npm-packages group with 2 updates Bumps the npm-packages group with 2 updates: [prettier-plugin-sort-json](https://github.com/Gudahtt/prettier-plugin-sort-json) and [rollup](https://github.com/rollup/rollup). Updates `prettier-plugin-sort-json` from 4.0.0 to 4.1.1 - [Release notes](https://github.com/Gudahtt/prettier-plugin-sort-json/releases) - [Changelog](https://github.com/Gudahtt/prettier-plugin-sort-json/blob/main/CHANGELOG.md) - [Commits](https://github.com/Gudahtt/prettier-plugin-sort-json/compare/v4.0.0...v4.1.1) Updates `rollup` from 4.29.1 to 4.30.1 - [Release notes](https://github.com/rollup/rollup/releases) - [Changelog](https://github.com/rollup/rollup/blob/master/CHANGELOG.md) - [Commits](https://github.com/rollup/rollup/compare/v4.29.1...v4.30.1) --- updated-dependencies: - dependency-name: prettier-plugin-sort-json dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-packages - dependency-name: rollup dependency-type: direct:development update-type: version-update:semver-minor dependency-group: npm-packages ... Signed-off-by: dependabot[bot] --- package-lock.json | 332 +++++++++++++++++++++++----------------------- package.json | 4 +- 2 files changed, 168 insertions(+), 168 deletions(-) diff --git a/package-lock.json b/package-lock.json index 6f5d8975a..087fa6344 100644 --- a/package-lock.json +++ b/package-lock.json @@ -16,8 +16,8 @@ "chai-almost": "^1.0.1", "mocha": "^11.0.1", "prettier-plugin-organize-imports": "^4.1.0", - "prettier-plugin-sort-json": "^4.0.0", - "rollup": "^4.29.1" + "prettier-plugin-sort-json": "^4.1.1", + "rollup": "^4.30.1" } }, "node_modules/@isaacs/cliui": { @@ -217,9 +217,9 @@ } }, "node_modules/@rollup/rollup-android-arm-eabi": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", - "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "cpu": [ "arm" ], @@ -230,9 +230,9 @@ ] }, "node_modules/@rollup/rollup-android-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz", - "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "cpu": [ "arm64" ], @@ -243,9 +243,9 @@ ] }, "node_modules/@rollup/rollup-darwin-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz", - "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "cpu": [ "arm64" ], @@ -256,9 +256,9 @@ ] }, "node_modules/@rollup/rollup-darwin-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz", - "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "cpu": [ "x64" ], @@ -269,9 +269,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz", - "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "cpu": [ "arm64" ], @@ -282,9 +282,9 @@ ] }, "node_modules/@rollup/rollup-freebsd-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz", - "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "cpu": [ "x64" ], @@ -295,9 +295,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz", - "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "cpu": [ "arm" ], @@ -308,9 +308,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm-musleabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz", - "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "cpu": [ "arm" ], @@ -321,9 +321,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz", - "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "cpu": [ "arm64" ], @@ -334,9 +334,9 @@ ] }, "node_modules/@rollup/rollup-linux-arm64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz", - "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "cpu": [ "arm64" ], @@ -347,9 +347,9 @@ ] }, "node_modules/@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz", - "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", "cpu": [ "loong64" ], @@ -360,9 +360,9 @@ ] }, "node_modules/@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz", - "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "cpu": [ "ppc64" ], @@ -373,9 +373,9 @@ ] }, "node_modules/@rollup/rollup-linux-riscv64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz", - "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "cpu": [ "riscv64" ], @@ -386,9 +386,9 @@ ] }, "node_modules/@rollup/rollup-linux-s390x-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz", - "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "cpu": [ "s390x" ], @@ -399,9 +399,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", - "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "cpu": [ "x64" ], @@ -412,9 +412,9 @@ ] }, "node_modules/@rollup/rollup-linux-x64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", - "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "cpu": [ "x64" ], @@ -425,9 +425,9 @@ ] }, "node_modules/@rollup/rollup-win32-arm64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz", - "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "cpu": [ "arm64" ], @@ -438,9 +438,9 @@ ] }, "node_modules/@rollup/rollup-win32-ia32-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz", - "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "cpu": [ "ia32" ], @@ -451,9 +451,9 @@ ] }, "node_modules/@rollup/rollup-win32-x64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz", - "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "cpu": [ "x64" ], @@ -1455,9 +1455,9 @@ } }, "node_modules/prettier-plugin-sort-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-sort-json/-/prettier-plugin-sort-json-4.0.0.tgz", - "integrity": "sha512-zV5g+bWFD2zAqyQ8gCkwUTC49o9FxslaUdirwivt5GZHcf57hCocavykuyYqbExoEsuBOg8IU36OY7zmVEMOWA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-sort-json/-/prettier-plugin-sort-json-4.1.1.tgz", + "integrity": "sha512-uJ49wCzwJ/foKKV4tIPxqi4jFFvwUzw4oACMRG2dcmDhBKrxBv0L2wSKkAqHCmxKCvj0xcCZS4jO2kSJO/tRJw==", "dev": true, "engines": { "node": ">=18.0.0" @@ -1526,9 +1526,9 @@ } }, "node_modules/rollup": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", - "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "dev": true, "dependencies": { "@types/estree": "1.0.6" @@ -1541,25 +1541,25 @@ "npm": ">=8.0.0" }, "optionalDependencies": { - "@rollup/rollup-android-arm-eabi": "4.29.1", - "@rollup/rollup-android-arm64": "4.29.1", - "@rollup/rollup-darwin-arm64": "4.29.1", - "@rollup/rollup-darwin-x64": "4.29.1", - "@rollup/rollup-freebsd-arm64": "4.29.1", - "@rollup/rollup-freebsd-x64": "4.29.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.29.1", - "@rollup/rollup-linux-arm-musleabihf": "4.29.1", - "@rollup/rollup-linux-arm64-gnu": "4.29.1", - "@rollup/rollup-linux-arm64-musl": "4.29.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.29.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.29.1", - "@rollup/rollup-linux-riscv64-gnu": "4.29.1", - "@rollup/rollup-linux-s390x-gnu": "4.29.1", - "@rollup/rollup-linux-x64-gnu": "4.29.1", - "@rollup/rollup-linux-x64-musl": "4.29.1", - "@rollup/rollup-win32-arm64-msvc": "4.29.1", - "@rollup/rollup-win32-ia32-msvc": "4.29.1", - "@rollup/rollup-win32-x64-msvc": "4.29.1", + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", "fsevents": "~2.3.2" } }, @@ -2000,135 +2000,135 @@ } }, "@rollup/rollup-android-arm-eabi": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.29.1.tgz", - "integrity": "sha512-ssKhA8RNltTZLpG6/QNkCSge+7mBQGUqJRisZ2MDQcEGaK93QESEgWK2iOpIDZ7k9zPVkG5AS3ksvD5ZWxmItw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.30.1.tgz", + "integrity": "sha512-pSWY+EVt3rJ9fQ3IqlrEUtXh3cGqGtPDH1FQlNZehO2yYxCHEX1SPsz1M//NXwYfbTlcKr9WObLnJX9FsS9K1Q==", "dev": true, "optional": true }, "@rollup/rollup-android-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.29.1.tgz", - "integrity": "sha512-CaRfrV0cd+NIIcVVN/jx+hVLN+VRqnuzLRmfmlzpOzB87ajixsN/+9L5xNmkaUUvEbI5BmIKS+XTwXsHEb65Ew==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm64/-/rollup-android-arm64-4.30.1.tgz", + "integrity": "sha512-/NA2qXxE3D/BRjOJM8wQblmArQq1YoBVJjrjoTSBS09jgUisq7bqxNHJ8kjCHeV21W/9WDGwJEWSN0KQ2mtD/w==", "dev": true, "optional": true }, "@rollup/rollup-darwin-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.29.1.tgz", - "integrity": "sha512-2ORr7T31Y0Mnk6qNuwtyNmy14MunTAMx06VAPI6/Ju52W10zk1i7i5U3vlDRWjhOI5quBcrvhkCHyF76bI7kEw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-arm64/-/rollup-darwin-arm64-4.30.1.tgz", + "integrity": "sha512-r7FQIXD7gB0WJ5mokTUgUWPl0eYIH0wnxqeSAhuIwvnnpjdVB8cRRClyKLQr7lgzjctkbp5KmswWszlwYln03Q==", "dev": true, "optional": true }, "@rollup/rollup-darwin-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.29.1.tgz", - "integrity": "sha512-j/Ej1oanzPjmN0tirRd5K2/nncAhS9W6ICzgxV+9Y5ZsP0hiGhHJXZ2JQ53iSSjj8m6cRY6oB1GMzNn2EUt6Ng==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-darwin-x64/-/rollup-darwin-x64-4.30.1.tgz", + "integrity": "sha512-x78BavIwSH6sqfP2xeI1hd1GpHL8J4W2BXcVM/5KYKoAD3nNsfitQhvWSw+TFtQTLZ9OmlF+FEInEHyubut2OA==", "dev": true, "optional": true }, "@rollup/rollup-freebsd-arm64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.29.1.tgz", - "integrity": "sha512-91C//G6Dm/cv724tpt7nTyP+JdN12iqeXGFM1SqnljCmi5yTXriH7B1r8AD9dAZByHpKAumqP1Qy2vVNIdLZqw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-arm64/-/rollup-freebsd-arm64-4.30.1.tgz", + "integrity": "sha512-HYTlUAjbO1z8ywxsDFWADfTRfTIIy/oUlfIDmlHYmjUP2QRDTzBuWXc9O4CXM+bo9qfiCclmHk1x4ogBjOUpUQ==", "dev": true, "optional": true }, "@rollup/rollup-freebsd-x64": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.29.1.tgz", - "integrity": "sha512-hEioiEQ9Dec2nIRoeHUP6hr1PSkXzQaCUyqBDQ9I9ik4gCXQZjJMIVzoNLBRGet+hIUb3CISMh9KXuCcWVW/8w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-freebsd-x64/-/rollup-freebsd-x64-4.30.1.tgz", + "integrity": "sha512-1MEdGqogQLccphhX5myCJqeGNYTNcmTyaic9S7CG3JhwuIByJ7J05vGbZxsizQthP1xpVx7kd3o31eOogfEirw==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm-gnueabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.29.1.tgz", - "integrity": "sha512-Py5vFd5HWYN9zxBv3WMrLAXY3yYJ6Q/aVERoeUFwiDGiMOWsMs7FokXihSOaT/PMWUty/Pj60XDQndK3eAfE6A==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-gnueabihf/-/rollup-linux-arm-gnueabihf-4.30.1.tgz", + "integrity": "sha512-PaMRNBSqCx7K3Wc9QZkFx5+CX27WFpAMxJNiYGAXfmMIKC7jstlr32UhTgK6T07OtqR+wYlWm9IxzennjnvdJg==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm-musleabihf": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.29.1.tgz", - "integrity": "sha512-RiWpGgbayf7LUcuSNIbahr0ys2YnEERD4gYdISA06wa0i8RALrnzflh9Wxii7zQJEB2/Eh74dX4y/sHKLWp5uQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm-musleabihf/-/rollup-linux-arm-musleabihf-4.30.1.tgz", + "integrity": "sha512-B8Rcyj9AV7ZlEFqvB5BubG5iO6ANDsRKlhIxySXcF1axXYUyqwBok+XZPgIYGBgs7LDXfWfifxhw0Ik57T0Yug==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.29.1.tgz", - "integrity": "sha512-Z80O+taYxTQITWMjm/YqNoe9d10OX6kDh8X5/rFCMuPqsKsSyDilvfg+vd3iXIqtfmp+cnfL1UrYirkaF8SBZA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-gnu/-/rollup-linux-arm64-gnu-4.30.1.tgz", + "integrity": "sha512-hqVyueGxAj3cBKrAI4aFHLV+h0Lv5VgWZs9CUGqr1z0fZtlADVV1YPOij6AhcK5An33EXaxnDLmJdQikcn5NEw==", "dev": true, "optional": true }, "@rollup/rollup-linux-arm64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.29.1.tgz", - "integrity": "sha512-fOHRtF9gahwJk3QVp01a/GqS4hBEZCV1oKglVVq13kcK3NeVlS4BwIFzOHDbmKzt3i0OuHG4zfRP0YoG5OF/rA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-arm64-musl/-/rollup-linux-arm64-musl-4.30.1.tgz", + "integrity": "sha512-i4Ab2vnvS1AE1PyOIGp2kXni69gU2DAUVt6FSXeIqUCPIR3ZlheMW3oP2JkukDfu3PsexYRbOiJrY+yVNSk9oA==", "dev": true, "optional": true }, "@rollup/rollup-linux-loongarch64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.29.1.tgz", - "integrity": "sha512-5a7q3tnlbcg0OodyxcAdrrCxFi0DgXJSoOuidFUzHZ2GixZXQs6Tc3CHmlvqKAmOs5eRde+JJxeIf9DonkmYkw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-loongarch64-gnu/-/rollup-linux-loongarch64-gnu-4.30.1.tgz", + "integrity": "sha512-fARcF5g296snX0oLGkVxPmysetwUk2zmHcca+e9ObOovBR++9ZPOhqFUM61UUZ2EYpXVPN1redgqVoBB34nTpQ==", "dev": true, "optional": true }, "@rollup/rollup-linux-powerpc64le-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.29.1.tgz", - "integrity": "sha512-9b4Mg5Yfz6mRnlSPIdROcfw1BU22FQxmfjlp/CShWwO3LilKQuMISMTtAu/bxmmrE6A902W2cZJuzx8+gJ8e9w==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-powerpc64le-gnu/-/rollup-linux-powerpc64le-gnu-4.30.1.tgz", + "integrity": "sha512-GLrZraoO3wVT4uFXh67ElpwQY0DIygxdv0BNW9Hkm3X34wu+BkqrDrkcsIapAY+N2ATEbvak0XQ9gxZtCIA5Rw==", "dev": true, "optional": true }, "@rollup/rollup-linux-riscv64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.29.1.tgz", - "integrity": "sha512-G5pn0NChlbRM8OJWpJFMX4/i8OEU538uiSv0P6roZcbpe/WfhEO+AT8SHVKfp8qhDQzaz7Q+1/ixMy7hBRidnQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-riscv64-gnu/-/rollup-linux-riscv64-gnu-4.30.1.tgz", + "integrity": "sha512-0WKLaAUUHKBtll0wvOmh6yh3S0wSU9+yas923JIChfxOaaBarmb/lBKPF0w/+jTVozFnOXJeRGZ8NvOxvk/jcw==", "dev": true, "optional": true }, "@rollup/rollup-linux-s390x-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.29.1.tgz", - "integrity": "sha512-WM9lIkNdkhVwiArmLxFXpWndFGuOka4oJOZh8EP3Vb8q5lzdSCBuhjavJsw68Q9AKDGeOOIHYzYm4ZFvmWez5g==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-s390x-gnu/-/rollup-linux-s390x-gnu-4.30.1.tgz", + "integrity": "sha512-GWFs97Ruxo5Bt+cvVTQkOJ6TIx0xJDD/bMAOXWJg8TCSTEK8RnFeOeiFTxKniTc4vMIaWvCplMAFBt9miGxgkA==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-gnu": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.29.1.tgz", - "integrity": "sha512-87xYCwb0cPGZFoGiErT1eDcssByaLX4fc0z2nRM6eMtV9njAfEE6OW3UniAoDhX4Iq5xQVpE6qO9aJbCFumKYQ==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-gnu/-/rollup-linux-x64-gnu-4.30.1.tgz", + "integrity": "sha512-UtgGb7QGgXDIO+tqqJ5oZRGHsDLO8SlpE4MhqpY9Llpzi5rJMvrK6ZGhsRCST2abZdBqIBeXW6WPD5fGK5SDwg==", "dev": true, "optional": true }, "@rollup/rollup-linux-x64-musl": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.29.1.tgz", - "integrity": "sha512-xufkSNppNOdVRCEC4WKvlR1FBDyqCSCpQeMMgv9ZyXqqtKBfkw1yfGMTUTs9Qsl6WQbJnsGboWCp7pJGkeMhKA==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-linux-x64-musl/-/rollup-linux-x64-musl-4.30.1.tgz", + "integrity": "sha512-V9U8Ey2UqmQsBT+xTOeMzPzwDzyXmnAoO4edZhL7INkwQcaW1Ckv3WJX3qrrp/VHaDkEWIBWhRwP47r8cdrOow==", "dev": true, "optional": true }, "@rollup/rollup-win32-arm64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.29.1.tgz", - "integrity": "sha512-F2OiJ42m77lSkizZQLuC+jiZ2cgueWQL5YC9tjo3AgaEw+KJmVxHGSyQfDUoYR9cci0lAywv2Clmckzulcq6ig==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-arm64-msvc/-/rollup-win32-arm64-msvc-4.30.1.tgz", + "integrity": "sha512-WabtHWiPaFF47W3PkHnjbmWawnX/aE57K47ZDT1BXTS5GgrBUEpvOzq0FI0V/UYzQJgdb8XlhVNH8/fwV8xDjw==", "dev": true, "optional": true }, "@rollup/rollup-win32-ia32-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.29.1.tgz", - "integrity": "sha512-rYRe5S0FcjlOBZQHgbTKNrqxCBUmgDJem/VQTCcTnA2KCabYSWQDrytOzX7avb79cAAweNmMUb/Zw18RNd4mng==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-ia32-msvc/-/rollup-win32-ia32-msvc-4.30.1.tgz", + "integrity": "sha512-pxHAU+Zv39hLUTdQQHUVHf4P+0C47y/ZloorHpzs2SXMRqeAWmGghzAhfOlzFHHwjvgokdFAhC4V+6kC1lRRfw==", "dev": true, "optional": true }, "@rollup/rollup-win32-x64-msvc": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.29.1.tgz", - "integrity": "sha512-+10CMg9vt1MoHj6x1pxyjPSMjHTIlqs8/tBztXvPAx24SKs9jwVnKqHJumlH/IzhaPUaj3T6T6wfZr8okdXaIg==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/@rollup/rollup-win32-x64-msvc/-/rollup-win32-x64-msvc-4.30.1.tgz", + "integrity": "sha512-D6qjsXGcvhTjv0kI4fU8tUuBDF/Ueee4SVX79VfNDXZa64TfCW1Slkb6Z7O1p7vflqZjcmOVdZlqf8gvJxc6og==", "dev": true, "optional": true }, @@ -2847,9 +2847,9 @@ "requires": {} }, "prettier-plugin-sort-json": { - "version": "4.0.0", - "resolved": "https://registry.npmjs.org/prettier-plugin-sort-json/-/prettier-plugin-sort-json-4.0.0.tgz", - "integrity": "sha512-zV5g+bWFD2zAqyQ8gCkwUTC49o9FxslaUdirwivt5GZHcf57hCocavykuyYqbExoEsuBOg8IU36OY7zmVEMOWA==", + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/prettier-plugin-sort-json/-/prettier-plugin-sort-json-4.1.1.tgz", + "integrity": "sha512-uJ49wCzwJ/foKKV4tIPxqi4jFFvwUzw4oACMRG2dcmDhBKrxBv0L2wSKkAqHCmxKCvj0xcCZS4jO2kSJO/tRJw==", "dev": true, "requires": {} }, @@ -2897,30 +2897,30 @@ } }, "rollup": { - "version": "4.29.1", - "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.29.1.tgz", - "integrity": "sha512-RaJ45M/kmJUzSWDs1Nnd5DdV4eerC98idtUOVr6FfKcgxqvjwHmxc5upLF9qZU9EpsVzzhleFahrT3shLuJzIw==", + "version": "4.30.1", + "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.30.1.tgz", + "integrity": "sha512-mlJ4glW020fPuLi7DkM/lN97mYEZGWeqBnrljzN0gs7GLctqX3lNWxKQ7Gl712UAX+6fog/L3jh4gb7R6aVi3w==", "dev": true, "requires": { - "@rollup/rollup-android-arm-eabi": "4.29.1", - "@rollup/rollup-android-arm64": "4.29.1", - "@rollup/rollup-darwin-arm64": "4.29.1", - "@rollup/rollup-darwin-x64": "4.29.1", - "@rollup/rollup-freebsd-arm64": "4.29.1", - "@rollup/rollup-freebsd-x64": "4.29.1", - "@rollup/rollup-linux-arm-gnueabihf": "4.29.1", - "@rollup/rollup-linux-arm-musleabihf": "4.29.1", - "@rollup/rollup-linux-arm64-gnu": "4.29.1", - "@rollup/rollup-linux-arm64-musl": "4.29.1", - "@rollup/rollup-linux-loongarch64-gnu": "4.29.1", - "@rollup/rollup-linux-powerpc64le-gnu": "4.29.1", - "@rollup/rollup-linux-riscv64-gnu": "4.29.1", - "@rollup/rollup-linux-s390x-gnu": "4.29.1", - "@rollup/rollup-linux-x64-gnu": "4.29.1", - "@rollup/rollup-linux-x64-musl": "4.29.1", - "@rollup/rollup-win32-arm64-msvc": "4.29.1", - "@rollup/rollup-win32-ia32-msvc": "4.29.1", - "@rollup/rollup-win32-x64-msvc": "4.29.1", + "@rollup/rollup-android-arm-eabi": "4.30.1", + "@rollup/rollup-android-arm64": "4.30.1", + "@rollup/rollup-darwin-arm64": "4.30.1", + "@rollup/rollup-darwin-x64": "4.30.1", + "@rollup/rollup-freebsd-arm64": "4.30.1", + "@rollup/rollup-freebsd-x64": "4.30.1", + "@rollup/rollup-linux-arm-gnueabihf": "4.30.1", + "@rollup/rollup-linux-arm-musleabihf": "4.30.1", + "@rollup/rollup-linux-arm64-gnu": "4.30.1", + "@rollup/rollup-linux-arm64-musl": "4.30.1", + "@rollup/rollup-linux-loongarch64-gnu": "4.30.1", + "@rollup/rollup-linux-powerpc64le-gnu": "4.30.1", + "@rollup/rollup-linux-riscv64-gnu": "4.30.1", + "@rollup/rollup-linux-s390x-gnu": "4.30.1", + "@rollup/rollup-linux-x64-gnu": "4.30.1", + "@rollup/rollup-linux-x64-musl": "4.30.1", + "@rollup/rollup-win32-arm64-msvc": "4.30.1", + "@rollup/rollup-win32-ia32-msvc": "4.30.1", + "@rollup/rollup-win32-x64-msvc": "4.30.1", "@types/estree": "1.0.6", "fsevents": "~2.3.2" } diff --git a/package.json b/package.json index 37b355026..f6fc6b7bb 100644 --- a/package.json +++ b/package.json @@ -11,8 +11,8 @@ "chai-almost": "^1.0.1", "mocha": "^11.0.1", "prettier-plugin-organize-imports": "^4.1.0", - "prettier-plugin-sort-json": "^4.0.0", - "rollup": "^4.29.1" + "prettier-plugin-sort-json": "^4.1.1", + "rollup": "^4.30.1" }, "dependencies": { "bezier-js": "^6.1.4", From 706ec8567ac413d7f85df2d0cc5e30d5a440a726 Mon Sep 17 00:00:00 2001 From: "dependabot[bot]" <49699333+dependabot[bot]@users.noreply.github.com> Date: Fri, 10 Jan 2025 14:08:33 +0000 Subject: [PATCH 019/106] Bump the python-packages group with 2 updates Bumps the python-packages group with 2 updates: [watchfiles](https://github.com/samuelcolvin/watchfiles) and [pytest-asyncio](https://github.com/pytest-dev/pytest-asyncio). Updates `watchfiles` from 1.0.3 to 1.0.4 - [Release notes](https://github.com/samuelcolvin/watchfiles/releases) - [Commits](https://github.com/samuelcolvin/watchfiles/compare/v1.0.3...v1.0.4) Updates `pytest-asyncio` from 0.25.1 to 0.25.2 - [Release notes](https://github.com/pytest-dev/pytest-asyncio/releases) - [Commits](https://github.com/pytest-dev/pytest-asyncio/compare/v0.25.1...v0.25.2) --- updated-dependencies: - dependency-name: watchfiles dependency-type: direct:production update-type: version-update:semver-patch dependency-group: python-packages - dependency-name: pytest-asyncio dependency-type: direct:development update-type: version-update:semver-patch dependency-group: python-packages ... Signed-off-by: dependabot[bot] --- requirements-dev.txt | 2 +- requirements.txt | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/requirements-dev.txt b/requirements-dev.txt index a86d9ecf1..24a5a289c 100644 --- a/requirements-dev.txt +++ b/requirements-dev.txt @@ -1,5 +1,5 @@ mypy==1.14.1 pre-commit==4.0.1 pytest==8.3.4 -pytest-asyncio==0.25.1 +pytest-asyncio==0.25.2 types-PyYAML==6.0.12.20241230 diff --git a/requirements.txt b/requirements.txt index f09235ede..512a060e1 100644 --- a/requirements.txt +++ b/requirements.txt @@ -6,5 +6,5 @@ pillow==11.1.0 pyyaml==6.0.2 ufomerge==1.8.2 unicodedata2==15.1.0 -watchfiles==1.0.3 +watchfiles==1.0.4 skia-pathops==0.8.0.post2 From a096d250a5b6560c1c6a618ce1d24aabe02ff7b1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 20:41:10 +0100 Subject: [PATCH 020/106] Add key for action.export-as.glyphs, this fixes #1934 --- src/fontra/client/lang/de.js | 1 + src/fontra/client/lang/en.js | 1 + src/fontra/client/lang/fr.js | 1 + src/fontra/client/lang/ja.js | 1 + src/fontra/client/lang/nl.js | 1 + src/fontra/client/lang/zh-CN.js | 1 + 6 files changed, 6 insertions(+) diff --git a/src/fontra/client/lang/de.js b/src/fontra/client/lang/de.js index 26f2d462c..ffe982baa 100644 --- a/src/fontra/client/lang/de.js +++ b/src/fontra/client/lang/de.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "Hilfslinie bearbeiten", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", diff --git a/src/fontra/client/lang/en.js b/src/fontra/client/lang/en.js index d0eb1bc6d..099afe589 100644 --- a/src/fontra/client/lang/en.js +++ b/src/fontra/client/lang/en.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "Edit Guideline", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", diff --git a/src/fontra/client/lang/fr.js b/src/fontra/client/lang/fr.js index 2912253f1..df68ca107 100644 --- a/src/fontra/client/lang/fr.js +++ b/src/fontra/client/lang/fr.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "Éditer le guide", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", diff --git a/src/fontra/client/lang/ja.js b/src/fontra/client/lang/ja.js index 7f2d687d4..c54c5f7c9 100644 --- a/src/fontra/client/lang/ja.js +++ b/src/fontra/client/lang/ja.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "ガイドラインを編集", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", diff --git a/src/fontra/client/lang/nl.js b/src/fontra/client/lang/nl.js index fcb3bbeda..dc97dcbc9 100644 --- a/src/fontra/client/lang/nl.js +++ b/src/fontra/client/lang/nl.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "Edit Guideline", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", diff --git a/src/fontra/client/lang/zh-CN.js b/src/fontra/client/lang/zh-CN.js index e23a39f6e..b357cc151 100644 --- a/src/fontra/client/lang/zh-CN.js +++ b/src/fontra/client/lang/zh-CN.js @@ -29,6 +29,7 @@ export const strings = { "action.edit-guideline": "编辑参考线", "action.export-as.designspace": "Designspace + UFO (*.designspace)", "action.export-as.fontra": "Fontra (*.fontra)", + "action.export-as.glyphs": "Glyphs (*.glyphs)", "action.export-as.otf": "OpenType (*.otf)", "action.export-as.rcjk": "RCJK (*.rcjk)", "action.export-as.ttf": "TrueType (*.ttf)", From 5f714e4264dcf51c1c2eed174a9eacdb2be06b8f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 21:03:53 +0100 Subject: [PATCH 021/106] Keep nav accordion sections open/closed state in URL --- src/fontra/views/fontoverview/fontoverview.js | 6 +++ .../views/fontoverview/panel-navigation.js | 38 ++++++++++++++++--- 2 files changed, 39 insertions(+), 5 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index db58fb1de..ca51c332e 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -30,6 +30,11 @@ const persistentSettings = [ { key: "fontLocationUser" }, { key: "glyphSelection", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, { key: "closedGlyphSections", toJSON: (v) => [...v], fromJSON: (v) => new Set(v) }, + { + key: "closedNavigationSections", + toJSON: (v) => [...v], + fromJSON: (v) => new Set(v), + }, { key: "groupByKeys" }, { key: "projectGlyphSetSelection" }, { key: "myGlyphSetSelection" }, @@ -45,6 +50,7 @@ function getDefaultFontOverviewSettings() { fontLocationSource: {}, glyphSelection: new Set(), closedGlyphSections: new Set(), + closedNavigationSections: new Set(), groupByKeys: [], projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { label: "This font's glyphs" } }, myGlyphSets: [], diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 35b4f6ccd..9f59ba355 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -2,6 +2,7 @@ import { groupByKeys, groupByProperties } from "/core/glyph-organizer.js"; import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; +import { difference, symmetricDifference, union } from "/core/set-ops.js"; import { labeledCheckbox } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { Accordion } from "/web-components/ui-accordion.js"; @@ -59,35 +60,62 @@ export class FontOverviewNavigation extends HTMLElement { const accordion = new Accordion(); + accordion.onItemOpenClose = (item, openClose) => { + const setOp = openClose ? difference : union; + this.fontOverviewSettingsController.setItem( + "closedNavigationSections", + setOp(this.fontOverviewSettings.closedNavigationSections, [item.id]), + { sentFromUserClick: true } + ); + }; + + this.fontOverviewSettingsController.addKeyListener( + "closedNavigationSections", + (event) => { + if (!event.senderInfo?.sentFromUserClick) { + const diff = symmetricDifference(event.newValue, event.oldValue); + for (const id of diff) { + const item = accordion.items.find((item) => item.id == id); + accordion.openCloseAccordionItem(item, !event.newValue.has(id)); + } + } + } + ); + this._projectGlyphSetsItem = { label: "Project glyph sets", // TODO: translate id: "project-glyph-sets", content: html.div(), - open: true, }; this._myGlyphSetsItem = { label: "My glyph sets", // TODO: translate id: "my-glyph-sets", content: html.div(), - open: true, }; - accordion.items = [ + const accordionItems = [ { label: translate("sources.labels.location"), + id: "location", content: this.fontSourceInput, - open: true, }, { label: "Group by", // TODO: translate + id: "group-by", content: this._makeGroupByUI(), - open: true, }, this._projectGlyphSetsItem, this._myGlyphSetsItem, ]; + accordionItems.forEach( + (item) => + (item.open = !this.fontOverviewSettings.closedNavigationSections.has(item.id)) + ); + + accordion.items = accordionItems; + this.appendChild(accordion); this.fontOverviewSettingsController.addKeyListener("projectGlyphSets", (event) => From cbc29401fea9c6d672606efca45f566d820a03f1 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 21:23:13 +0100 Subject: [PATCH 022/106] Move button CSS to shared.css, make work for 'button' --- src/fontra/client/css/core.css | 22 ---------------------- src/fontra/client/css/shared.css | 25 +++++++++++++++++++++++++ 2 files changed, 25 insertions(+), 22 deletions(-) diff --git a/src/fontra/client/css/core.css b/src/fontra/client/css/core.css index 91cf060fb..2f5fbe1ed 100644 --- a/src/fontra/client/css/core.css +++ b/src/fontra/client/css/core.css @@ -152,28 +152,6 @@ icon-button { width: 1.25em; } -input[type="button"] { - cursor: pointer; - background-color: #ddd; - - border-radius: 1em; - padding: 0.35em 2em 0.35em 2em; - - border: none; - font-family: fontra-ui-regular, sans-serif; - font-size: 1em; - text-align: center; - transition: 100ms; -} - -input[type="button"]:hover { - background-color: #ccc; -} - -input[type="button"]:active { - background-color: #bbb; -} - .top-bar-container { position: relative; /* for z-index */ z-index: 200; diff --git a/src/fontra/client/css/shared.css b/src/fontra/client/css/shared.css index 0e2948b08..fff9003ef 100644 --- a/src/fontra/client/css/shared.css +++ b/src/fontra/client/css/shared.css @@ -3,3 +3,28 @@ *::after { box-sizing: border-box; } + +button, +input[type="button"] { + cursor: pointer; + background-color: #ddd; + + border-radius: 1em; + padding: 0.35em 2em 0.35em 2em; + + border: none; + font-family: fontra-ui-regular, sans-serif; + font-size: 1em; + text-align: center; + transition: 100ms; +} + +button:hover, +input[type="button"]:hover { + background-color: #ccc; +} + +button:active, +input[type="button"]:active { + background-color: #bbb; +} From c2cd102a0c59421854587bd05d775d125dffe9b2 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 21:23:27 +0100 Subject: [PATCH 023/106] Beginnings of add glyph set UI --- .../views/fontoverview/panel-navigation.js | 43 ++++++++++++++++++- 1 file changed, 41 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 9f59ba355..58aad355a 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -60,6 +60,19 @@ export class FontOverviewNavigation extends HTMLElement { const accordion = new Accordion(); + accordion.appendStyle(` + .glyph-set-container { + display: grid; + justify-items: left; + gap: 0.5em; + } + + .add-glyph-set-button { + padding: 0.3em 1em 0.3em 1em; + font-size: 0.9em; + } + `); + accordion.onItemOpenClose = (item, openClose) => { const setOp = openClose ? difference : union; this.fontOverviewSettingsController.setItem( @@ -148,12 +161,30 @@ export class FontOverviewNavigation extends HTMLElement { label: value.label, })); - return this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets); + return html.div({ class: "glyph-set-container" }, [ + this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets), + html.button( + { + class: "add-glyph-set-button", + onclick: (event) => this._addProjectGlyphSet(event), + }, + ["Add glyph set"] + ), + ]); } _makeMyGlyphSetsUI() { const myGlyphSets = []; - return this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets); + return html.div({ class: "glyph-set-container" }, [ + this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), + html.button( + { + class: "add-glyph-set-button", + onclick: (event) => this._addMyGlyphSet(event), + }, + ["Add glyph set"] + ), + ]); } _makeCheckboxUI(settingsKey, glyphSets) { @@ -173,6 +204,14 @@ export class FontOverviewNavigation extends HTMLElement { ]); } + _addProjectGlyphSet(event) { + console.log("add project gs"); + } + + _addMyGlyphSet(event) { + console.log("add user gs"); + } + _updateFontSourceInput() { const fontSourceIdentifier = this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( From 69862ff2d1478efa8d94c94469305d64c72bc7d3 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Fri, 10 Jan 2025 21:25:04 +0100 Subject: [PATCH 024/106] Tweak button padding --- src/fontra/views/fontoverview/panel-navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 58aad355a..cdccb8232 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -68,7 +68,7 @@ export class FontOverviewNavigation extends HTMLElement { } .add-glyph-set-button { - padding: 0.3em 1em 0.3em 1em; + padding: 0.25em 1em 0.3em 1em; font-size: 0.9em; } `); From 0e62991d0177922071721960358a1918fb298c99 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 09:03:09 +0100 Subject: [PATCH 025/106] Work around wrong button focus (cosmetically) --- src/fontra/client/css/shared.css | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/src/fontra/client/css/shared.css b/src/fontra/client/css/shared.css index fff9003ef..1ccb172cb 100644 --- a/src/fontra/client/css/shared.css +++ b/src/fontra/client/css/shared.css @@ -28,3 +28,14 @@ button:active, input[type="button"]:active { background-color: #bbb; } + +/* +This is a workaround. We don't necessarily want to suppress the focus ring, +but we're running into a (Chrome) bug where a button gets focus when it +shouldn't: when a dialog gets dismissed with a key event, the button that +caused the dialog to *open* wrongly gets the focus. +*/ +button:focus, +input[type="button"]:active { + outline: none; +} From 7d68229581b8861bf4824e618fcc342d0e4f5f37 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:04:20 +0100 Subject: [PATCH 026/106] Increase the max width for dialogs --- src/fontra/client/web-components/modal-dialog.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/modal-dialog.js b/src/fontra/client/web-components/modal-dialog.js index af6fba7b7..aa40053ec 100644 --- a/src/fontra/client/web-components/modal-dialog.js +++ b/src/fontra/client/web-components/modal-dialog.js @@ -61,7 +61,7 @@ export class ModalDialog extends SimpleElement { gap: 1em; outline: none; /* to catch key events we need to focus, but we don't want a focus border */ - max-width: 32em; + max-width: 38em; max-height: 80vh; overflow-wrap: normal; font-size: 1.15em; From e25e6cb6fcff48da77991b23a4dab44f3fc6340f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:05:09 +0100 Subject: [PATCH 027/106] No need for a hard-coded container in the HTML, but we need to take special care of dialogs --- .../client/web-components/menu-panel.js | 43 ++++++++++++------- 1 file changed, 28 insertions(+), 15 deletions(-) diff --git a/src/fontra/client/web-components/menu-panel.js b/src/fontra/client/web-components/menu-panel.js index b3c782d63..e9bd2bf3a 100644 --- a/src/fontra/client/web-components/menu-panel.js +++ b/src/fontra/client/web-components/menu-panel.js @@ -12,12 +12,13 @@ import { InlineSVG } from "/web-components/inline-svg.js"; export const MenuItemDivider = { title: "-" }; -export function showMenu(menuItems, position, positionContainer, container) { - if (!container) { - container = document.querySelector("#menu-panel-container"); - } - const menu = new MenuPanel(menuItems, { position, positionContainer }); +export function showMenu(menuItems, position, options) { + const container = getMenuContainer(); + const { left, top } = container.getBoundingClientRect(); + position = { x: position.x - left, y: position.y - top }; + const menu = new MenuPanel(menuItems, { position, ...options }); container.appendChild(menu); + return menu; } export class MenuPanel extends SimpleElement { @@ -212,17 +213,18 @@ export class MenuPanel extends SimpleElement { this._savedActiveElement = document.activeElement; const position = { ...this.position }; this.style = `display: inherited; left: ${position.x}px; top: ${position.y}px;`; - if (this.positionContainer) { - const containerRect = this.positionContainer.getBoundingClientRect(); - const thisRect = this.getBoundingClientRect(); - if (thisRect.right > containerRect.right) { - position.x -= thisRect.width + 2; - } - if (thisRect.bottom > containerRect.bottom) { - position.y -= thisRect.bottom - containerRect.bottom + 2; - } - this.style = `display: inherited; left: ${position.x}px; top: ${position.y}px;`; + + // Ensure the whole menu is visible, and not cropped by the window + const containerRect = document.body.getBoundingClientRect(); + const thisRect = this.getBoundingClientRect(); + if (thisRect.right > containerRect.right) { + position.x -= thisRect.width + 2; + } + if (thisRect.bottom > containerRect.bottom) { + position.y -= thisRect.bottom - containerRect.bottom + 2; } + this.style = `display: inherited; left: ${position.x}px; top: ${position.y}px;`; + this.focus(); } @@ -381,3 +383,14 @@ customElements.define("menu-panel", MenuPanel); window.addEventListener("mousedown", (event) => MenuPanel.closeAllMenus(event)); window.addEventListener("blur", (event) => MenuPanel.closeAllMenus(event)); + +function getMenuContainer() { + // This is tightly coupled to modal-dialog.js + // We need to return a different container if the menu is opened from a dialog + const dialogContainer = + document.activeElement.tagName === "MODAL-DIALOG" + ? document.activeElement.shadowRoot.querySelector(".dialog-box") + : null; + + return dialogContainer || document.body; +} From b77cb3b6d4f8d6e90b5a1349526cdba8b009d3b7 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:05:32 +0100 Subject: [PATCH 028/106] The menu container is gone --- src/fontra/views/editor/editor.css | 7 ------- 1 file changed, 7 deletions(-) diff --git a/src/fontra/views/editor/editor.css b/src/fontra/views/editor/editor.css index 5343b65fc..5011d7d6e 100644 --- a/src/fontra/views/editor/editor.css +++ b/src/fontra/views/editor/editor.css @@ -302,13 +302,6 @@ body { /* sidebar content styling */ -#menu-panel-container { - position: absolute; - overflow: hidden; - width: 100%; - height: 100%; -} - .sidebar-resize-gutter { height: 100%; width: 4px; From 8ad18f6f72ca21eec9d61af34bf132b93c29b34f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:08:00 +0100 Subject: [PATCH 029/106] No more container stuff for menu --- src/fontra/views/editor/editor.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/editor/editor.js b/src/fontra/views/editor/editor.js index 7441fcb74..5a42ec058 100644 --- a/src/fontra/views/editor/editor.js +++ b/src/fontra/views/editor/editor.js @@ -3095,7 +3095,7 @@ export class EditorController extends ViewController { const { x, y } = event; this.contextMenuPosition = { x: x, y: y }; - showMenu(this.buildContextMenuItems(event), { x: x + 1, y: y - 1 }, event.target); + showMenu(this.buildContextMenuItems(event), { x: x + 1, y: y - 1 }); } async newGlyph(glyphName, codePoint, varGlyph, undoLabel = null) { From 440ed261992b88165126be75016cc45c80176264 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:08:20 +0100 Subject: [PATCH 030/106] No more container stuff for menu --- src/fontra/views/editor/panel-related-glyphs.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/editor/panel-related-glyphs.js b/src/fontra/views/editor/panel-related-glyphs.js index 9b0fabcbd..6bf5f40a5 100644 --- a/src/fontra/views/editor/panel-related-glyphs.js +++ b/src/fontra/views/editor/panel-related-glyphs.js @@ -222,7 +222,7 @@ export default class RelatedGlyphPanel extends Panel { }, ]; const { x, y } = event; - showMenu(items, { x: x + 1, y: y - 1 }, document.documentElement); + showMenu(items, { x: x + 1, y: y - 1 }); } async toggle(on, focus) { From efb6fafb24ce2afc805d1e6d110dd89ef9bcd3f2 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:09:41 +0100 Subject: [PATCH 031/106] I don't think this is needed --- src/fontra/views/fontoverview/fontoverview.css | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fontra/views/fontoverview/fontoverview.css b/src/fontra/views/fontoverview/fontoverview.css index 9443f7062..ce70f23e1 100644 --- a/src/fontra/views/fontoverview/fontoverview.css +++ b/src/fontra/views/fontoverview/fontoverview.css @@ -1,6 +1,5 @@ body { overflow: auto; - user-select: none; } .main-container { From d9538eb07639bfbb96b639eb29485761796dd1ef Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:11:46 +0100 Subject: [PATCH 032/106] The menu container is no more --- src/fontra/views/editor/editor.html | 2 -- 1 file changed, 2 deletions(-) diff --git a/src/fontra/views/editor/editor.html b/src/fontra/views/editor/editor.html index 81e6a9dfc..c4c353196 100644 --- a/src/fontra/views/editor/editor.html +++ b/src/fontra/views/editor/editor.html @@ -26,8 +26,6 @@ - -
From eefdea1f4ae98734f568219e87292b8eaad5cb48 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:33:34 +0100 Subject: [PATCH 033/106] Ensure onClose is called in all cases; fix dialog container logic --- src/fontra/client/web-components/menu-panel.js | 13 ++++++++----- 1 file changed, 8 insertions(+), 5 deletions(-) diff --git a/src/fontra/client/web-components/menu-panel.js b/src/fontra/client/web-components/menu-panel.js index e9bd2bf3a..040a75fc1 100644 --- a/src/fontra/client/web-components/menu-panel.js +++ b/src/fontra/client/web-components/menu-panel.js @@ -26,7 +26,7 @@ export class MenuPanel extends SimpleElement { static closeAllMenus(event) { for (const element of MenuPanel.openMenuPanels) { - element.parentElement?.removeChild(element); + element.dismiss(); } MenuPanel.openMenuPanels.splice(0, MenuPanel.openMenuPanels.length); } @@ -283,6 +283,8 @@ export class MenuPanel extends SimpleElement { } handleKeyDown(event) { + event.preventDefault(); + event.stopImmediatePropagation(); this.searchMenuItems(event.key); switch (event.key) { case "Escape": @@ -387,10 +389,11 @@ window.addEventListener("blur", (event) => MenuPanel.closeAllMenus(event)); function getMenuContainer() { // This is tightly coupled to modal-dialog.js // We need to return a different container if the menu is opened from a dialog - const dialogContainer = - document.activeElement.tagName === "MODAL-DIALOG" - ? document.activeElement.shadowRoot.querySelector(".dialog-box") - : null; + const dialog = document.querySelector("modal-dialog"); + + const dialogContainer = dialog?.isActive() + ? dialog.shadowRoot.querySelector(".dialog-box") + : null; return dialogContainer || document.body; } From 5d068f1157a5902083e644540a61150c2668c3a7 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 22:34:02 +0100 Subject: [PATCH 034/106] Add method so we can know the dialog is active or not --- src/fontra/client/web-components/modal-dialog.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fontra/client/web-components/modal-dialog.js b/src/fontra/client/web-components/modal-dialog.js index aa40053ec..3b83b6430 100644 --- a/src/fontra/client/web-components/modal-dialog.js +++ b/src/fontra/client/web-components/modal-dialog.js @@ -304,6 +304,10 @@ export class ModalDialog extends SimpleElement { this._resolveDialogResult(result); } + + isActive() { + return !!this.dialogContent; + } } customElements.define("modal-dialog", ModalDialog); From 54d8895502013b6688e6b1165985b00906b3343c Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 23:06:04 +0100 Subject: [PATCH 035/106] No text wrapping menu items; previously this depended on context --- src/fontra/client/web-components/menu-panel.js | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fontra/client/web-components/menu-panel.js b/src/fontra/client/web-components/menu-panel.js index 040a75fc1..d41fe218f 100644 --- a/src/fontra/client/web-components/menu-panel.js +++ b/src/fontra/client/web-components/menu-panel.js @@ -93,6 +93,7 @@ export class MenuPanel extends SimpleElement { display: flex; gap: 0.5em; justify-content: space-between; + text-wrap: nowrap; } .submenu-icon { From 35934e70973b1e95dac1d280eb0b012c53e2ca92 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 23:06:25 +0100 Subject: [PATCH 036/106] Beginnings of add glyph set dialog --- .../views/fontoverview/panel-navigation.js | 71 +++++++++++++++++-- 1 file changed, 66 insertions(+), 5 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index cdccb8232..5456ac0dd 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -3,8 +3,10 @@ import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; import { difference, symmetricDifference, union } from "/core/set-ops.js"; -import { labeledCheckbox } from "/core/ui-utils.js"; +import { labeledCheckbox, labeledTextInput } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; +import { dialogSetup } from "/web-components/modal-dialog.js"; +import { PopupMenu } from "/web-components/popup-menu.js"; import { Accordion } from "/web-components/ui-accordion.js"; export class FontOverviewNavigation extends HTMLElement { @@ -204,12 +206,14 @@ export class FontOverviewNavigation extends HTMLElement { ]); } - _addProjectGlyphSet(event) { - console.log("add project gs"); + async _addProjectGlyphSet(event) { + const glyphSet = await runGlyphSetDialog(); + // XXXX } - _addMyGlyphSet(event) { - console.log("add user gs"); + async _addMyGlyphSet(event) { + const glyphSet = await runGlyphSetDialog(); + // XXXX } _updateFontSourceInput() { @@ -250,3 +254,60 @@ function makeCheckboxController(settingsController, settingsKey) { return checkboxController; } + +const glyphSetPresets = [ + { + provider: "Google Fonts", + glyphSets: [ + { name: "Basic Latin", url: "https://xxxxx" }, + { name: "Greek", url: "https://yyyy" }, + ], + }, +]; + +async function runGlyphSetDialog() { + const dialog = await dialogSetup("Add glyph set", "", [ + { title: translate("dialog.cancel"), isCancelButton: true }, + { title: translate("dialog.add"), isDefaultButton: true }, + ]); + + const contentStyle = ` + .glyph-set-dialog-content { + display: grid; + gap: 0.5em; + grid-template-columns: max-content auto; + align-items: center; + width: 30em; + } + `; + + dialog.appendStyle(contentStyle); + + const dialogController = new ObservableController(); + + const presetMenuItems = glyphSetPresets.map((providerGroup) => ({ + title: providerGroup.provider, + getItems: () => + providerGroup.glyphSets.map((glyphSet) => ({ + title: glyphSet.name, + callback: () => { + dialogController.model.name = glyphSet.name; + dialogController.model.url = glyphSet.url; + dialogController.model.fileType = glyphSet.fileType || "auto-detect"; + }, + })), + })); + + dialog.setContent( + html.div({ class: "glyph-set-dialog-content" }, [ + html.div(), + new PopupMenu("Choose preset", () => presetMenuItems), + ...labeledTextInput("Name", dialogController, "name"), + ...labeledTextInput("URL", dialogController, "url"), + ...labeledTextInput("File type", dialogController, "fileType"), // XXXX should be popu + ...labeledTextInput("Note", dialogController, "note"), + ]) + ); + const result = await dialog.run(); + console.log(result); +} From a667d3b56023763434986fa6b7cce34fb6293901 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 23:16:52 +0100 Subject: [PATCH 037/106] For now, hard-code some GF glyph set URLs --- .../views/fontoverview/panel-navigation.js | 110 +++++++++++++++++- 1 file changed, 108 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 5456ac0dd..4e54328d7 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -259,8 +259,114 @@ const glyphSetPresets = [ { provider: "Google Fonts", glyphSets: [ - { name: "Basic Latin", url: "https://xxxxx" }, - { name: "Greek", url: "https://yyyy" }, + { + name: "GF Arabic Core", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Arabic_Core.txt", + }, + { + name: "GF Arabic Plus", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Arabic_Plus.txt", + }, + { + name: "GF Cyrillic Core", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Cyrillic_Core.txt", + }, + { + name: "GF Cyrillic Historical", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Cyrillic_Historical.txt", + }, + { + name: "GF Cyrillic Plus", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Cyrillic_Plus.txt", + }, + { + name: "GF Cyrillic Pro", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Cyrillic_Pro.txt", + }, + { + name: "GF Greek AncientMusicalSymbols", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_AncientMusicalSymbols.txt", + }, + { + name: "GF Greek Archaic", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Archaic.txt", + }, + { + name: "GF Greek Coptic", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Coptic.txt", + }, + { + name: "GF Greek Core", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Core.txt", + }, + { + name: "GF Greek Expert", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Expert.txt", + }, + { + name: "GF Greek Plus", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Plus.txt", + }, + { + name: "GF Greek Pro", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Greek_Pro.txt", + }, + { + name: "GF Latin African", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_African.txt", + }, + { + name: "GF Latin Beyond", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_Beyond.txt", + }, + { + name: "GF Latin Core", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_Core.txt", + }, + { + name: "GF Latin Kernel", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_Kernel.txt", + }, + { + name: "GF Latin Plus", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_Plus.txt", + }, + { + name: "GF Latin PriAfrican", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_PriAfrican.txt", + }, + { + name: "GF Latin Vietnamese", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Latin_Vietnamese.txt", + }, + { + name: "GF Phonetics APA", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Phonetics_APA.txt", + }, + { + name: "GF Phonetics DisorderedSpeech", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Phonetics_DisorderedSpeech.txt", + }, + { + name: "GF Phonetics IPAHistorical", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Phonetics_IPAHistorical.txt", + }, + { + name: "GF Phonetics IPAStandard", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Phonetics_IPAStandard.txt", + }, + { + name: "GF Phonetics SinoExt", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_Phonetics_SinoExt.txt", + }, + { + name: "GF TransLatin Arabic", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_TransLatin_Arabic.txt", + }, + { + name: "GF TransLatin Pinyin", + url: "https://raw.githubusercontent.com/googlefonts/glyphsets/main/data/results/txt/nice-names/GF_TransLatin_Pinyin.txt", + }, ], }, ]; From 08615f69afa0a5b98d8887a690a986702328714a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sat, 11 Jan 2025 23:18:43 +0100 Subject: [PATCH 038/106] provider -> curator --- src/fontra/views/fontoverview/panel-navigation.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 4e54328d7..00eb19e7d 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -257,7 +257,7 @@ function makeCheckboxController(settingsController, settingsKey) { const glyphSetPresets = [ { - provider: "Google Fonts", + curator: "Google Fonts", glyphSets: [ { name: "GF Arabic Core", @@ -391,10 +391,10 @@ async function runGlyphSetDialog() { const dialogController = new ObservableController(); - const presetMenuItems = glyphSetPresets.map((providerGroup) => ({ - title: providerGroup.provider, + const presetMenuItems = glyphSetPresets.map((curatorGroup) => ({ + title: curatorGroup.curator, getItems: () => - providerGroup.glyphSets.map((glyphSet) => ({ + curatorGroup.glyphSets.map((glyphSet) => ({ title: glyphSet.name, callback: () => { dialogController.model.name = glyphSet.name; From eb6c6f76f2f0599a0fea8d4c0f3351a60e93f381 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 09:18:54 +0100 Subject: [PATCH 039/106] Add popupSelect + labeledPopupSelect --- src/fontra/client/core/ui-utils.js | 29 +++++++++++++++++++++++++++++ 1 file changed, 29 insertions(+) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index e2b77861d..73bc01148 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -1,5 +1,6 @@ import * as html from "./html-utils.js"; import { uniqueID, zip } from "./utils.js"; +import { PopupMenu } from "/web-components/popup-menu.js"; const containerClassName = "fontra-ui-sortable-list-container"; const draggingClassName = "fontra-ui-sortable-list-dragging"; @@ -171,6 +172,34 @@ export function labeledTextInput(label, controller, key, options) { return items; } +export function popupSelect(controller, key, options) { + function findLabel() { + const option = options.find(({ value }) => value === controller.model[key]); + return option?.label || ""; + } + + controller.addKeyListener(key, (event) => { + menu.valueLabel = findLabel(); + }); + + const menu = new PopupMenu(findLabel(), () => + options.map(({ value, label }) => ({ + title: label, + checked: value === controller.model[key], + callback: () => { + controller.model[key] = value; + menu.valueLabel = label; + }, + })) + ); + return menu; +} + +export function labeledPopupSelect(label, controller, key, options) { + const inputElement = popupSelect(controller, key, options); + return [labelForElement(label, inputElement), inputElement]; +} + export const DefaultFormatter = { toString: (value) => (value !== undefined && value !== null ? value.toString() : ""), fromString: (value) => { From 5b9c6fbdb29933ff0dfd869fede3019123a7b226 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 09:19:12 +0100 Subject: [PATCH 040/106] Use new popupSelect for file type --- src/fontra/views/fontoverview/panel-navigation.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 00eb19e7d..936a63c3a 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -3,7 +3,11 @@ import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; import { difference, symmetricDifference, union } from "/core/set-ops.js"; -import { labeledCheckbox, labeledTextInput } from "/core/ui-utils.js"; +import { + labeledCheckbox, + labeledPopupSelect, + labeledTextInput, +} from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { dialogSetup } from "/web-components/modal-dialog.js"; import { PopupMenu } from "/web-components/popup-menu.js"; @@ -404,13 +408,20 @@ async function runGlyphSetDialog() { })), })); + const fileTypeOptions = [ + { value: "auto-detect", label: "auto-detect" }, + { value: "glyph-names", label: "Glyph names (whitespace-separated)" }, + { value: "csv", label: "CSV (comma- or semicolon-separated)" }, + { value: "tsv", label: "TSV (tab-separated)" }, + ]; + dialog.setContent( html.div({ class: "glyph-set-dialog-content" }, [ html.div(), new PopupMenu("Choose preset", () => presetMenuItems), ...labeledTextInput("Name", dialogController, "name"), ...labeledTextInput("URL", dialogController, "url"), - ...labeledTextInput("File type", dialogController, "fileType"), // XXXX should be popu + ...labeledPopupSelect("File type", dialogController, "fileType", fileTypeOptions), ...labeledTextInput("Note", dialogController, "note"), ]) ); From d37a300e4e41cbab138343fac5675ac3323b1a08 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 09:49:16 +0100 Subject: [PATCH 041/106] Use our own popupSelect for better styling --- .../views/fontoverview/panel-navigation.js | 85 ++++++++++--------- 1 file changed, 45 insertions(+), 40 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 936a63c3a..4a38d990e 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -7,6 +7,7 @@ import { labeledCheckbox, labeledPopupSelect, labeledTextInput, + popupSelect, } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { dialogSetup } from "/web-components/modal-dialog.js"; @@ -28,35 +29,6 @@ export class FontOverviewNavigation extends HTMLElement { } async _setupUI() { - this.fontSources = await this.fontController.getSources(); - - this.fontSourceInput = html.select( - { - id: "font-source-select", - style: "width: 100%;", - onchange: (event) => { - const fontSourceIdentifier = event.target.value; - const sourceLocation = { - ...this.fontSources[fontSourceIdentifier]?.location, - }; // A font may not have any font sources, therefore the ?-check - this.fontOverviewSettings.fontLocationSource = sourceLocation; - }, - }, - [] - ); - - for (const fontSourceIdentifier of this.fontController.getSortedSourceIdentifiers()) { - const sourceName = this.fontSources[fontSourceIdentifier].name; - this.fontSourceInput.appendChild( - html.option({ value: fontSourceIdentifier }, [sourceName]) - ); - } - - this.fontOverviewSettingsController.addKeyListener("fontLocationSource", (event) => - this._updateFontSourceInput() - ); - this._updateFontSourceInput(); - this.searchField = new GlyphSearchField({ settingsController: this.fontOverviewSettingsController, searchStringKey: "searchString", @@ -117,7 +89,7 @@ export class FontOverviewNavigation extends HTMLElement { { label: translate("sources.labels.location"), id: "location", - content: this.fontSourceInput, + content: await this._makeFontSourcePopup(), }, { label: "Group by", // TODO: translate @@ -147,6 +119,49 @@ export class FontOverviewNavigation extends HTMLElement { this._updateMyGlyphSets(); } + async _makeFontSourcePopup() { + const fontSources = await this.fontController.getSources(); + + const selectedSourceIdentifier = () => + this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( + this.fontOverviewSettings.fontLocationSource + ); + + const options = this.fontController + .getSortedSourceIdentifiers() + .map((fontSourceIdentifier) => ({ + value: fontSourceIdentifier, + label: fontSources[fontSourceIdentifier].name, + })); + + const controller = new ObservableController({ + value: selectedSourceIdentifier(), + }); + + this.fontOverviewSettingsController.addKeyListener( + "fontLocationSource", + (event) => { + if (!event.senderInfo?.sentFromInput) { + controller.model.value = selectedSourceIdentifier(); + } + } + ); + + controller.addKeyListener("value", (event) => { + const fontSourceIdentifier = event.newValue; + const sourceLocation = { + ...fontSources[fontSourceIdentifier]?.location, + }; // A font may not have any font sources, therefore the ?-check + this.fontOverviewSettingsController.setItem( + "fontLocationSource", + sourceLocation, + { sentFromInput: true } + ); + }); + + return popupSelect(controller, "value", options); + } + _makeGroupByUI() { return this._makeCheckboxUI("groupByKeys", groupByProperties); } @@ -219,16 +234,6 @@ export class FontOverviewNavigation extends HTMLElement { const glyphSet = await runGlyphSetDialog(); // XXXX } - - _updateFontSourceInput() { - const fontSourceIdentifier = - this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( - this.fontOverviewSettings.fontLocationSource - ); - for (const optionElement of this.fontSourceInput.children) { - optionElement.selected = optionElement.value === fontSourceIdentifier; - } - } } customElements.define("font-overview-navigation", FontOverviewNavigation); From bd3907e3ecc964e34463bf64d7ac2bb55b534c84 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 10:10:25 +0100 Subject: [PATCH 042/106] Fix glitch with focusing: somehow calling .focus() on the modal-dialog itself doesn't work --- src/fontra/client/web-components/modal-dialog.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fontra/client/web-components/modal-dialog.js b/src/fontra/client/web-components/modal-dialog.js index 3b83b6430..db37a8612 100644 --- a/src/fontra/client/web-components/modal-dialog.js +++ b/src/fontra/client/web-components/modal-dialog.js @@ -162,6 +162,10 @@ export class ModalDialog extends SimpleElement { this.shadowRoot.append(this.dialogElement); } + focus() { + this.dialogBox?.focus(); + } + setupDialog(headline, message, buttonDefs, autoDismissTimeout) { buttonDefs = buttonDefs.map((bd) => { return { ...bd }; From 833f6f3093783ca8d3ad3c05379753accc24e5dc Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 16:09:49 +0100 Subject: [PATCH 043/106] Flesh out add glyphset dialog --- src/fontra/views/fontoverview/fontoverview.js | 2 +- .../views/fontoverview/panel-navigation.js | 61 ++++++++++++++++--- 2 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index ca51c332e..32731a00f 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -52,7 +52,7 @@ function getDefaultFontOverviewSettings() { closedGlyphSections: new Set(), closedNavigationSections: new Set(), groupByKeys: [], - projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { label: "This font's glyphs" } }, + projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { name: "This font's glyphs" } }, myGlyphSets: [], projectGlyphSetSelection: [THIS_FONTS_GLYPHSET], myGlyphSetSelection: [], diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 4a38d990e..87aca8cf7 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -167,11 +167,13 @@ export class FontOverviewNavigation extends HTMLElement { } _updateProjectGlyphSets() { - this._projectGlyphSetsItem.content = this._makeProjectGlyphSetsUI(); + this._projectGlyphSetsItem.content.innerHTML = ""; + this._projectGlyphSetsItem.content.appendChild(this._makeProjectGlyphSetsUI()); } _updateMyGlyphSets() { - this._myGlyphSetsItem.content = this._makeMyGlyphSetsUI(); + this._myGlyphSetsItem.content.innerHTML = ""; + this._myGlyphSetsItem.content.appendChild(this._makeMyGlyphSetsUI()); } _makeProjectGlyphSetsUI() { @@ -179,7 +181,7 @@ export class FontOverviewNavigation extends HTMLElement { this.fontOverviewSettings.projectGlyphSets ).map(([key, value]) => ({ key, - label: value.label, + label: value.name, })); return html.div({ class: "glyph-set-container" }, [ @@ -195,7 +197,13 @@ export class FontOverviewNavigation extends HTMLElement { } _makeMyGlyphSetsUI() { - const myGlyphSets = []; + const myGlyphSets = Object.entries(this.fontOverviewSettings.myGlyphSets).map( + ([key, value]) => ({ + key, + label: value.name, + }) + ); + return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), html.button( @@ -227,12 +235,24 @@ export class FontOverviewNavigation extends HTMLElement { async _addProjectGlyphSet(event) { const glyphSet = await runGlyphSetDialog(); - // XXXX + if (!glyphSet) { + return; + } + this.fontOverviewSettings.projectGlyphSets = { + ...this.fontOverviewSettings.projectGlyphSets, + [glyphSet.url]: glyphSet, + }; } async _addMyGlyphSet(event) { const glyphSet = await runGlyphSetDialog(); - // XXXX + if (!glyphSet) { + return; + } + this.fontOverviewSettings.myGlyphSets = { + ...this.fontOverviewSettings.myGlyphSets, + [glyphSet.url]: glyphSet, + }; } } @@ -381,9 +401,32 @@ const glyphSetPresets = [ ]; async function runGlyphSetDialog() { + const glyphSetInfo = { fileType: "auto-detect" }; + const dialogController = new ObservableController(glyphSetInfo); + + const validateInput = () => { + let valid = true; + let url; + try { + url = new URL(dialogController.model.url); + } catch (e) { + valid = false; + } + if (url?.pathname.length <= 1 || !url?.hostname.includes(".")) { + valid = false; + } + if (!dialogController.model.name) { + valid; + } + // TODO: warningsElement: say what/why it's invalid + dialog.defaultButton.classList.toggle("disabled", !valid); + }; + + dialogController.addListener((event) => validateInput()); + const dialog = await dialogSetup("Add glyph set", "", [ { title: translate("dialog.cancel"), isCancelButton: true }, - { title: translate("dialog.add"), isDefaultButton: true }, + { title: translate("dialog.add"), isDefaultButton: true, disabled: true }, ]); const contentStyle = ` @@ -398,8 +441,6 @@ async function runGlyphSetDialog() { dialog.appendStyle(contentStyle); - const dialogController = new ObservableController(); - const presetMenuItems = glyphSetPresets.map((curatorGroup) => ({ title: curatorGroup.curator, getItems: () => @@ -431,5 +472,5 @@ async function runGlyphSetDialog() { ]) ); const result = await dialog.run(); - console.log(result); + return !!(result && glyphSetInfo.name && glyphSetInfo.url) ? glyphSetInfo : null; } From 436c0a4491c3d27a1c7b95aa4dafe91b6c47d0e3 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 16:19:00 +0100 Subject: [PATCH 044/106] Improve checkbox + label layout --- src/fontra/client/core/ui-utils.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index 73bc01148..708ec4e1f 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -102,6 +102,13 @@ export function labeledCheckbox(label, controller, key, options) { inputElement.checked = controller.model[key]; inputWrapper.appendChild(inputElement); if (label) { + inputWrapper.style = ` + display: grid; + grid-template-columns: auto max-content; + justify-content: left; + gap: 0.1em; + align-items: center; + `; inputWrapper.appendChild(html.label({ for: checkboxID }, [label])); } From f6414e5e0e6149fa960080f58109ccb7e2e22bee Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 20:46:04 +0100 Subject: [PATCH 045/106] Store my-glyph-sets info in localStorage --- src/fontra/views/fontoverview/fontoverview.js | 32 ++++++++++++++++--- 1 file changed, 28 insertions(+), 4 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 32731a00f..b4b70f2b5 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -53,7 +53,7 @@ function getDefaultFontOverviewSettings() { closedNavigationSections: new Set(), groupByKeys: [], projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { name: "This font's glyphs" } }, - myGlyphSets: [], + myGlyphSets: {}, projectGlyphSetSelection: [THIS_FONTS_GLYPHSET], myGlyphSetSelection: [], cellMagnification: 1, @@ -101,11 +101,16 @@ export class FontOverviewController extends ViewController { this._updateFromWindowLocation(); }); - this.fontOverviewSettingsController = new ObservableController( - getDefaultFontOverviewSettings() - ); + this.myGlyphSetsController = new ObservableController({ settings: {} }); + this.myGlyphSetsController.synchronizeWithLocalStorage("fontra-my-glyph-sets-"); + + this.fontOverviewSettingsController = new ObservableController({ + ...getDefaultFontOverviewSettings(), + myGlyphSets: this.myGlyphSetsController.model.settings, + }); this.fontOverviewSettings = this.fontOverviewSettingsController.model; + this._setupMyGlyphSetsDependencies(); this._setupLocationDependencies(); this._updateFromWindowLocation(); @@ -170,6 +175,25 @@ export class FontOverviewController extends ViewController { this._updateGlyphItemList(); } + _setupMyGlyphSetsDependencies() { + // This synchronizes the myGlyphSets object with local storage + this.fontOverviewSettingsController.addKeyListener("myGlyphSets", (event) => { + if (!event.senderInfo?.sentFromLocalStorage) { + this.myGlyphSetsController.setItem("settings", event.newValue, { + sentFromSettings: true, + }); + } + }); + + this.myGlyphSetsController.addKeyListener("settings", (event) => { + if (!event.senderInfo?.sentFromSettings) { + this.fontOverviewSettingsController.setItem("myGlyphSets", event.newValue, { + sentFromLocalStorage: true, + }); + } + }); + } + _setupLocationDependencies() { // TODO: This currently does *not* do avar-2 / cross-axis-mapping // - We need the "user location" to send to the editor From 1312ad1eb09dcae56748efc2ac8fab594d34a26b Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 20:55:11 +0100 Subject: [PATCH 046/106] Sort glyph sets, refactor into helper func --- .../views/fontoverview/panel-navigation.js | 33 ++++++++++++------- 1 file changed, 22 insertions(+), 11 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 87aca8cf7..d6b1eedbb 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -177,12 +177,9 @@ export class FontOverviewNavigation extends HTMLElement { } _makeProjectGlyphSetsUI() { - const projectGlyphSets = Object.entries( + const projectGlyphSets = sortedGlyphSets( this.fontOverviewSettings.projectGlyphSets - ).map(([key, value]) => ({ - key, - label: value.name, - })); + ); return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets), @@ -197,12 +194,7 @@ export class FontOverviewNavigation extends HTMLElement { } _makeMyGlyphSetsUI() { - const myGlyphSets = Object.entries(this.fontOverviewSettings.myGlyphSets).map( - ([key, value]) => ({ - key, - label: value.name, - }) - ); + const myGlyphSets = sortedGlyphSets(this.fontOverviewSettings.myGlyphSets); return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), @@ -474,3 +466,22 @@ async function runGlyphSetDialog() { const result = await dialog.run(); return !!(result && glyphSetInfo.name && glyphSetInfo.url) ? glyphSetInfo : null; } + +function sortedGlyphSets(glyphSets) { + return Object.entries(glyphSets) + .map(([key, value]) => ({ + key, + label: value.name, + })) + .sort((a, b) => { + if (a.label == b.label) { + return 0; + } + if (!a.key) { + return -1; + } else if (!b.key) { + return 1; + } + return a.label < b.label ? -1 : 1; + }); +} From c4b1fe0b79da55090118fcec8ffe9a29ff955154 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 21:44:59 +0100 Subject: [PATCH 047/106] Add convenience methods for editing non-glyph data --- src/fontra/client/core/font-controller.js | 17 ++++++++++++++++- 1 file changed, 16 insertions(+), 1 deletion(-) diff --git a/src/fontra/client/core/font-controller.js b/src/fontra/client/core/font-controller.js index a26e0ca76..3f1e9da54 100644 --- a/src/fontra/client/core/font-controller.js +++ b/src/fontra/client/core/font-controller.js @@ -1,4 +1,4 @@ -import { getClassSchema } from "../core/classes.js"; +import { recordChanges } from "./change-recorder.js"; import { applyChange, collectChangePaths, @@ -6,6 +6,7 @@ import { filterChangePattern, matchChangePattern, } from "./changes.js"; +import { getClassSchema } from "./classes.js"; import { getGlyphMapProxy, makeCharacterMapFromGlyphMap } from "./cmap.js"; import { CrossAxisMapping } from "./cross-axis-mapping.js"; import { FontSourcesInstancer } from "./font-sources-instancer.js"; @@ -681,6 +682,20 @@ export class FontController { return editContext; } + async performEdit(editLabel, rootKey, editFunc, senderID) { + // This is a convenience for non-continuous non-glyph changes + const root = { [rootKey]: await this.getData(rootKey) }; + const changes = recordChanges(root, editFunc); + await this.postChange(changes.change, changes.rollbackChange, editLabel, senderID); + return changes; + } + + async postChange(change, rollbackChange, editLabel, senderID) { + const error = await this.editFinal(change, rollbackChange, editLabel, true); + // TODO handle error + this.notifyEditListeners("editFinal", senderID); + } + async applyChange(change, isExternalChange) { if (!isExternalChange && this.readOnly) { console.log("can't edit font in read-only mode"); From 52cf6f50b0815875b941e225a8aff43d2d8391e3 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 21:45:15 +0100 Subject: [PATCH 048/106] Write project glyph sets to custom data --- src/fontra/views/fontoverview/fontoverview.js | 21 +++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index b4b70f2b5..760b7a0d4 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -110,6 +110,7 @@ export class FontOverviewController extends ViewController { }); this.fontOverviewSettings = this.fontOverviewSettingsController.model; + this._setupProjectGlyphSetsDependencies(); this._setupMyGlyphSetsDependencies(); this._setupLocationDependencies(); @@ -175,6 +176,26 @@ export class FontOverviewController extends ViewController { this._updateGlyphItemList(); } + _setupProjectGlyphSetsDependencies() { + this.fontOverviewSettingsController.addKeyListener( + "projectGlyphSets", + async (event) => { + const changes = await this.fontController.performEdit( + "edit glyph sets", + "customData", + (root) => { + const projectGlyphSets = Object.values(event.newValue).filter( + (glyphSet) => glyphSet.url + ); + root.customData["fontra.projectGlyphSets"] = projectGlyphSets; + }, + this + ); + console.log(changes); + } + ); + } + _setupMyGlyphSetsDependencies() { // This synchronizes the myGlyphSets object with local storage this.fontOverviewSettingsController.addKeyListener("myGlyphSets", (event) => { From 256a9840a7d245597c0087e60886ef7caacdb034 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 22:11:01 +0100 Subject: [PATCH 049/106] Read glyph sets from font --- src/fontra/views/fontoverview/fontoverview.js | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 760b7a0d4..508963194 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -42,6 +42,7 @@ const persistentSettings = [ ]; const THIS_FONTS_GLYPHSET = ""; +const PROJECT_GLYPH_SETS_CUSTOM_DATA_KEY = "fontra.projectGlyphSets"; function getDefaultFontOverviewSettings() { return { @@ -52,7 +53,7 @@ function getDefaultFontOverviewSettings() { closedGlyphSections: new Set(), closedNavigationSections: new Set(), groupByKeys: [], - projectGlyphSets: { [THIS_FONTS_GLYPHSET]: { name: "This font's glyphs" } }, + projectGlyphSets: {}, myGlyphSets: {}, projectGlyphSetSelection: [THIS_FONTS_GLYPHSET], myGlyphSetSelection: [], @@ -106,6 +107,7 @@ export class FontOverviewController extends ViewController { this.fontOverviewSettingsController = new ObservableController({ ...getDefaultFontOverviewSettings(), + projectGlyphSets: readProjectGlyphSets(this.fontController), myGlyphSets: this.myGlyphSetsController.model.settings, }); this.fontOverviewSettings = this.fontOverviewSettingsController.model; @@ -187,7 +189,7 @@ export class FontOverviewController extends ViewController { const projectGlyphSets = Object.values(event.newValue).filter( (glyphSet) => glyphSet.url ); - root.customData["fontra.projectGlyphSets"] = projectGlyphSets; + root.customData[PROJECT_GLYPH_SETS_CUSTOM_DATA_KEY] = projectGlyphSets; }, this ); @@ -402,3 +404,12 @@ function openGlyphsInEditor(glyphsInfo, userLocation, glyphMap) { url.hash = dumpURLFragment(viewInfo); window.open(url.toString()); } + +function readProjectGlyphSets(fontController) { + return Object.fromEntries( + [ + { name: "This font's glyphs", url: "" }, + ...(fontController.customData[PROJECT_GLYPH_SETS_CUSTOM_DATA_KEY] || []), + ].map((glyphSet) => [glyphSet.url, glyphSet]) + ); +} From 9ef771055127d42511ec99fd7257bc674894d4cd Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 22:14:49 +0100 Subject: [PATCH 050/106] Remove debug log --- src/fontra/views/fontoverview/fontoverview.js | 1 - 1 file changed, 1 deletion(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 508963194..7f6ac76ab 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -193,7 +193,6 @@ export class FontOverviewController extends ViewController { }, this ); - console.log(changes); } ); } From d8917b7737169947c643452aaf565ea09b26cb82 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 22:29:40 +0100 Subject: [PATCH 051/106] Listen to external glyph set changes --- src/fontra/views/fontoverview/fontoverview.js | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 7f6ac76ab..90e23f94e 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -173,6 +173,19 @@ export class FontOverviewController extends ViewController { this._updateGlyphItemList(); }); + this.fontController.addChangeListener( + { customData: { [PROJECT_GLYPH_SETS_CUSTOM_DATA_KEY]: null } }, + (change, isExternalChange) => { + if (isExternalChange) { + this.fontOverviewSettingsController.setItem( + "projectGlyphSets", + readProjectGlyphSets(this.fontController), + { sentFromExternalChange: true } + ); + } + } + ); + document.addEventListener("keydown", (event) => this.handleKeyDown(event)); this._updateGlyphItemList(); @@ -182,6 +195,9 @@ export class FontOverviewController extends ViewController { this.fontOverviewSettingsController.addKeyListener( "projectGlyphSets", async (event) => { + if (event.senderInfo?.sentFromExternalChange) { + return; + } const changes = await this.fontController.performEdit( "edit glyph sets", "customData", From 3d28b57aa534e9ff4e0a3da1730e072d2018ae14 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Sun, 12 Jan 2025 22:31:02 +0100 Subject: [PATCH 052/106] Move change listener to appropriate method --- src/fontra/views/fontoverview/fontoverview.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 90e23f94e..d4edc227e 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -173,6 +173,12 @@ export class FontOverviewController extends ViewController { this._updateGlyphItemList(); }); + document.addEventListener("keydown", (event) => this.handleKeyDown(event)); + + this._updateGlyphItemList(); + } + + _setupProjectGlyphSetsDependencies() { this.fontController.addChangeListener( { customData: { [PROJECT_GLYPH_SETS_CUSTOM_DATA_KEY]: null } }, (change, isExternalChange) => { @@ -186,12 +192,6 @@ export class FontOverviewController extends ViewController { } ); - document.addEventListener("keydown", (event) => this.handleKeyDown(event)); - - this._updateGlyphItemList(); - } - - _setupProjectGlyphSetsDependencies() { this.fontOverviewSettingsController.addKeyListener( "projectGlyphSets", async (event) => { From 102de053113a2a3fc32417e89895b07039b9f850 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 13:39:03 +0100 Subject: [PATCH 053/106] Fix method signature --- src/fontra/core/remote.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fontra/core/remote.py b/src/fontra/core/remote.py index 95c5d901a..7a1213111 100644 --- a/src/fontra/core/remote.py +++ b/src/fontra/core/remote.py @@ -137,8 +137,8 @@ class RemoteClientProxy: def __init__(self, connection): self._connection = connection - async def messageFromServer(self, text): - return await self._connection.callMethod("messageFromServer", text) + async def messageFromServer(self, headline, message): + return await self._connection.callMethod("messageFromServer", headline, message) async def externalChange(self, change, isLiveChange): return await self._connection.callMethod("externalChange", change, isLiveChange) From 3dfcbc5417fc522977f1c4845cdd5472d5d00d8b Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 15:18:10 +0100 Subject: [PATCH 054/106] Add helper func to read an arbitrary json file in the repo --- test-js/test-support.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/test-js/test-support.js b/test-js/test-support.js index b3e24a2a6..eefef9dba 100644 --- a/test-js/test-support.js +++ b/test-js/test-support.js @@ -17,3 +17,8 @@ export function getTestData(fileName) { const path = join(dirname(__dirname), "test-common", fileName); return JSON.parse(fs.readFileSync(path, "utf8")); } + +export function readRepoPathAsJSON(...pathComponents) { + const path = join(dirname(__dirname), ...pathComponents); + return JSON.parse(fs.readFileSync(path, "utf8")); +} From 374371789c69822057525798150edc8bdbc0184c Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 15:19:16 +0100 Subject: [PATCH 055/106] Explicitly read file instead of relying on too old (import/assert) or too new (import/with) syntax --- test-js/test-classes.js | 11 +++++++++-- 1 file changed, 9 insertions(+), 2 deletions(-) diff --git a/test-js/test-classes.js b/test-js/test-classes.js index 6740d0d3a..baf7d3f97 100644 --- a/test-js/test-classes.js +++ b/test-js/test-classes.js @@ -1,8 +1,6 @@ import { expect } from "chai"; import { getClassSchema } from "../src/fontra/client/core/classes.js"; -// prettier-ignore -import classesSchema from "../src/fontra/client/core/classes.json" assert { type: "json" }; import { enumerate, range } from "../src/fontra/client/core/utils.js"; import { Layer, @@ -10,6 +8,15 @@ import { VariableGlyph, } from "../src/fontra/client/core/var-glyph.js"; import { VarPackedPath } from "../src/fontra/client/core/var-path.js"; +import { readRepoPathAsJSON } from "./test-support.js"; + +const classesSchema = readRepoPathAsJSON( + "src", + "fontra", + "client", + "core", + "classes.json" +); describe("schema tests", () => { const testPaths = [ From 926b3fa40ad9cf27d3f21ceb253d3d6194356740 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 15:23:45 +0100 Subject: [PATCH 056/106] Simplify, good enough --- test-js/test-classes.js | 8 +------- test-js/test-support.js | 4 ++-- 2 files changed, 3 insertions(+), 9 deletions(-) diff --git a/test-js/test-classes.js b/test-js/test-classes.js index baf7d3f97..3f32bdde8 100644 --- a/test-js/test-classes.js +++ b/test-js/test-classes.js @@ -10,13 +10,7 @@ import { import { VarPackedPath } from "../src/fontra/client/core/var-path.js"; import { readRepoPathAsJSON } from "./test-support.js"; -const classesSchema = readRepoPathAsJSON( - "src", - "fontra", - "client", - "core", - "classes.json" -); +const classesSchema = readRepoPathAsJSON("src/fontra/client/core/classes.json"); describe("schema tests", () => { const testPaths = [ diff --git a/test-js/test-support.js b/test-js/test-support.js index eefef9dba..fc1d94905 100644 --- a/test-js/test-support.js +++ b/test-js/test-support.js @@ -18,7 +18,7 @@ export function getTestData(fileName) { return JSON.parse(fs.readFileSync(path, "utf8")); } -export function readRepoPathAsJSON(...pathComponents) { - const path = join(dirname(__dirname), ...pathComponents); +export function readRepoPathAsJSON(path) { + path = join(dirname(__dirname), path); return JSON.parse(fs.readFileSync(path, "utf8")); } From 30c36efdaf8e38ee31b9da4b57c3764c3fed4688 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 18:37:57 +0100 Subject: [PATCH 057/106] Ensure the selected list only contains sets we know --- src/fontra/views/fontoverview/fontoverview.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index d4edc227e..b30763a7a 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -209,6 +209,11 @@ export class FontOverviewController extends ViewController { }, this ); + + this.fontOverviewSettings.projectGlyphSetSelection = + this.fontOverviewSettings.projectGlyphSetSelection.filter( + (name) => !!event.newValue[name] + ); } ); } @@ -220,6 +225,11 @@ export class FontOverviewController extends ViewController { this.myGlyphSetsController.setItem("settings", event.newValue, { sentFromSettings: true, }); + + this.fontOverviewSettings.myGlyphSetSelection = + this.fontOverviewSettings.myGlyphSetSelection.filter( + (name) => !!event.newValue[name] + ); } }); From 66c06db924a7305033617e4e59fe69b7f70bb35a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:18:57 +0100 Subject: [PATCH 058/106] Removing button selectors, as these match our icon-buttons, messing up styling. Hmmm... --- src/fontra/client/css/shared.css | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/fontra/client/css/shared.css b/src/fontra/client/css/shared.css index 1ccb172cb..ef737d0c3 100644 --- a/src/fontra/client/css/shared.css +++ b/src/fontra/client/css/shared.css @@ -4,7 +4,6 @@ box-sizing: border-box; } -button, input[type="button"] { cursor: pointer; background-color: #ddd; @@ -19,12 +18,10 @@ input[type="button"] { transition: 100ms; } -button:hover, input[type="button"]:hover { background-color: #ccc; } -button:active, input[type="button"]:active { background-color: #bbb; } @@ -35,7 +32,6 @@ but we're running into a (Chrome) bug where a button gets focus when it shouldn't: when a dialog gets dismissed with a key event, the button that caused the dialog to *open* wrongly gets the focus. */ -button:focus, -input[type="button"]:active { +input[type="button"]:focus { outline: none; } From bb020b13638f1c56c8affeecd47c6c5c269b6bb8 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:19:23 +0100 Subject: [PATCH 059/106] Add icon button to glyph sets --- .../views/fontoverview/panel-navigation.js | 58 +++++++++++++------ 1 file changed, 40 insertions(+), 18 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index d6b1eedbb..7b86aea1c 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -10,6 +10,7 @@ import { popupSelect, } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; +import { IconButton } from "/web-components/icon-button.js"; // required for the icon buttons import { dialogSetup } from "/web-components/modal-dialog.js"; import { PopupMenu } from "/web-components/popup-menu.js"; import { Accordion } from "/web-components/ui-accordion.js"; @@ -49,6 +50,18 @@ export class FontOverviewNavigation extends HTMLElement { padding: 0.25em 1em 0.3em 1em; font-size: 0.9em; } + + .checkbox-group { + width: 100%; + display: grid; + grid-template-columns: auto auto; + justify-content: space-between; + } + + icon-button { + width: 1.4em; + height: 1.4em; + } `); accordion.onItemOpenClose = (item, openClose) => { @@ -183,13 +196,12 @@ export class FontOverviewNavigation extends HTMLElement { return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets), - html.button( - { - class: "add-glyph-set-button", - onclick: (event) => this._addProjectGlyphSet(event), - }, - ["Add glyph set"] - ), + html.input({ + type: "button", + class: "add-glyph-set-button", + value: "Add glyph set", + onclick: (event) => this._addProjectGlyphSet(event), + }), ]); } @@ -198,13 +210,12 @@ export class FontOverviewNavigation extends HTMLElement { return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), - html.button( - { - class: "add-glyph-set-button", - onclick: (event) => this._addMyGlyphSet(event), - }, - ["Add glyph set"] - ), + html.input({ + type: "button", + class: "add-glyph-set-button", + value: "Add glyph set", + onclick: (event) => this._addMyGlyphSet(event), + }), ]); } @@ -218,10 +229,13 @@ export class FontOverviewNavigation extends HTMLElement { this._checkboxControllers[settingsKey] = checkboxController; } - return html.div({}, [ - ...glyphSets.map(({ key, label }) => - labeledCheckbox(label, checkboxController, key) - ), + return html.div({ class: "checkbox-group" }, [ + ...glyphSets + .map(({ key, label, extraItem }) => [ + labeledCheckbox(label, checkboxController, key), + extraItem ? extraItem : html.div(), + ]) + .flat(), ]); } @@ -472,6 +486,14 @@ function sortedGlyphSets(glyphSets) { .map(([key, value]) => ({ key, label: value.name, + extraItem: value.url + ? html.createDomElement("icon-button", { + src: "/tabler-icons/menu-2.svg", + onclick: (event) => console.log("---", value), + // "data-tooltip": "XXXXX", + // "data-tooltipposition": "left", + }) + : null, })) .sort((a, b) => { if (a.label == b.label) { From ecf6df1f46db4c24c47bae74c73aae5fb6eb7a45 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:33:05 +0100 Subject: [PATCH 060/106] Refactor, stubs for glyph set menu thing --- .../views/fontoverview/panel-navigation.js | 86 +++++++++---------- 1 file changed, 42 insertions(+), 44 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 7b86aea1c..31ae0defb 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -11,6 +11,7 @@ import { } from "/core/ui-utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { IconButton } from "/web-components/icon-button.js"; // required for the icon buttons +import { showMenu } from "/web-components/menu-panel.js"; import { dialogSetup } from "/web-components/modal-dialog.js"; import { PopupMenu } from "/web-components/popup-menu.js"; import { Accordion } from "/web-components/ui-accordion.js"; @@ -190,7 +191,7 @@ export class FontOverviewNavigation extends HTMLElement { } _makeProjectGlyphSetsUI() { - const projectGlyphSets = sortedGlyphSets( + const projectGlyphSets = this._prepareGlyphSets( this.fontOverviewSettings.projectGlyphSets ); @@ -200,13 +201,13 @@ export class FontOverviewNavigation extends HTMLElement { type: "button", class: "add-glyph-set-button", value: "Add glyph set", - onclick: (event) => this._addProjectGlyphSet(event), + onclick: (event) => this._addGlyphSet(event, true), }), ]); } _makeMyGlyphSetsUI() { - const myGlyphSets = sortedGlyphSets(this.fontOverviewSettings.myGlyphSets); + const myGlyphSets = this._prepareGlyphSets(this.fontOverviewSettings.myGlyphSets); return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), @@ -214,11 +215,44 @@ export class FontOverviewNavigation extends HTMLElement { type: "button", class: "add-glyph-set-button", value: "Add glyph set", - onclick: (event) => this._addMyGlyphSet(event), + onclick: (event) => this._addGlyphSet(event, false), }), ]); } + _prepareGlyphSets(glyphSets) { + return Object.entries(glyphSets) + .map(([key, value]) => ({ + key, + label: value.name, + extraItem: value.url + ? html.createDomElement("icon-button", { + src: "/tabler-icons/menu-2.svg", + onclick: (event) => { + const buttonRect = event.target.getBoundingClientRect(); + showMenu([{ title: "Edit" }, { title: "Delete" }], { + x: buttonRect.left, + y: buttonRect.bottom, + }); + }, + // "data-tooltip": "------", + // "data-tooltipposition": "left", + }) + : null, + })) + .sort((a, b) => { + if (a.label == b.label) { + return 0; + } + if (!a.key) { + return -1; + } else if (!b.key) { + return 1; + } + return a.label < b.label ? -1 : 1; + }); + } + _makeCheckboxUI(settingsKey, glyphSets) { let checkboxController = this._checkboxControllers[settingsKey]; if (!checkboxController) { @@ -239,24 +273,15 @@ export class FontOverviewNavigation extends HTMLElement { ]); } - async _addProjectGlyphSet(event) { + async _addGlyphSet(event, isProjectGlyphSet) { const glyphSet = await runGlyphSetDialog(); if (!glyphSet) { return; } - this.fontOverviewSettings.projectGlyphSets = { - ...this.fontOverviewSettings.projectGlyphSets, - [glyphSet.url]: glyphSet, - }; - } - async _addMyGlyphSet(event) { - const glyphSet = await runGlyphSetDialog(); - if (!glyphSet) { - return; - } - this.fontOverviewSettings.myGlyphSets = { - ...this.fontOverviewSettings.myGlyphSets, + const key = isProjectGlyphSet ? "projectGlyphSets" : "myGlyphSets"; + this.fontOverviewSettings[key] = { + ...this.fontOverviewSettings[key], [glyphSet.url]: glyphSet, }; } @@ -480,30 +505,3 @@ async function runGlyphSetDialog() { const result = await dialog.run(); return !!(result && glyphSetInfo.name && glyphSetInfo.url) ? glyphSetInfo : null; } - -function sortedGlyphSets(glyphSets) { - return Object.entries(glyphSets) - .map(([key, value]) => ({ - key, - label: value.name, - extraItem: value.url - ? html.createDomElement("icon-button", { - src: "/tabler-icons/menu-2.svg", - onclick: (event) => console.log("---", value), - // "data-tooltip": "XXXXX", - // "data-tooltipposition": "left", - }) - : null, - })) - .sort((a, b) => { - if (a.label == b.label) { - return 0; - } - if (!a.key) { - return -1; - } else if (!b.key) { - return 1; - } - return a.label < b.label ? -1 : 1; - }); -} From c8fa2a9bbb4280d23172198aca8c917ff8a3e09d Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:40:59 +0100 Subject: [PATCH 061/106] Hook up Edit and Delete buttons --- .../views/fontoverview/panel-navigation.js | 55 ++++++++++++++----- 1 file changed, 42 insertions(+), 13 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 31ae0defb..62ef65b9c 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -192,7 +192,8 @@ export class FontOverviewNavigation extends HTMLElement { _makeProjectGlyphSetsUI() { const projectGlyphSets = this._prepareGlyphSets( - this.fontOverviewSettings.projectGlyphSets + this.fontOverviewSettings.projectGlyphSets, + true ); return html.div({ class: "glyph-set-container" }, [ @@ -201,13 +202,16 @@ export class FontOverviewNavigation extends HTMLElement { type: "button", class: "add-glyph-set-button", value: "Add glyph set", - onclick: (event) => this._addGlyphSet(event, true), + onclick: (event) => this._editGlyphSet(event, true), }), ]); } _makeMyGlyphSetsUI() { - const myGlyphSets = this._prepareGlyphSets(this.fontOverviewSettings.myGlyphSets); + const myGlyphSets = this._prepareGlyphSets( + this.fontOverviewSettings.myGlyphSets, + false + ); return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), @@ -215,12 +219,12 @@ export class FontOverviewNavigation extends HTMLElement { type: "button", class: "add-glyph-set-button", value: "Add glyph set", - onclick: (event) => this._addGlyphSet(event, false), + onclick: (event) => this._editGlyphSet(event, false), }), ]); } - _prepareGlyphSets(glyphSets) { + _prepareGlyphSets(glyphSets, isProjectGlyphSet) { return Object.entries(glyphSets) .map(([key, value]) => ({ key, @@ -230,10 +234,26 @@ export class FontOverviewNavigation extends HTMLElement { src: "/tabler-icons/menu-2.svg", onclick: (event) => { const buttonRect = event.target.getBoundingClientRect(); - showMenu([{ title: "Edit" }, { title: "Delete" }], { - x: buttonRect.left, - y: buttonRect.bottom, - }); + showMenu( + [ + { + title: "Edit", + callback: (event) => { + this._editGlyphSet(event, isProjectGlyphSet, value); + }, + }, + { + title: "Delete", + callback: (event) => { + this._deleteGlyphSet(event, isProjectGlyphSet, value); + }, + }, + ], + { + x: buttonRect.left, + y: buttonRect.bottom, + } + ); }, // "data-tooltip": "------", // "data-tooltipposition": "left", @@ -273,8 +293,8 @@ export class FontOverviewNavigation extends HTMLElement { ]); } - async _addGlyphSet(event, isProjectGlyphSet) { - const glyphSet = await runGlyphSetDialog(); + async _editGlyphSet(event, isProjectGlyphSet, glyphSetInfo = null) { + const glyphSet = await runGlyphSetDialog(glyphSetInfo); if (!glyphSet) { return; } @@ -285,6 +305,15 @@ export class FontOverviewNavigation extends HTMLElement { [glyphSet.url]: glyphSet, }; } + + _deleteGlyphSet(event, isProjectGlyphSet, glyphSetInfo) { + const key = isProjectGlyphSet ? "projectGlyphSets" : "myGlyphSets"; + const glyphSets = { + ...this.fontOverviewSettings[key], + }; + delete glyphSets[glyphSetInfo.url]; + this.fontOverviewSettings[key] = glyphSets; + } } customElements.define("font-overview-navigation", FontOverviewNavigation); @@ -431,8 +460,8 @@ const glyphSetPresets = [ }, ]; -async function runGlyphSetDialog() { - const glyphSetInfo = { fileType: "auto-detect" }; +async function runGlyphSetDialog(glyphSetInfo) { + glyphSetInfo = { fileType: "auto-detect", ...glyphSetInfo }; const dialogController = new ObservableController(glyphSetInfo); const validateInput = () => { From 1977390f8ed3d3d4303480bd31b35c73691007b5 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:42:36 +0100 Subject: [PATCH 062/106] Rename variable --- src/fontra/views/fontoverview/panel-navigation.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 62ef65b9c..c697bdc42 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -226,10 +226,10 @@ export class FontOverviewNavigation extends HTMLElement { _prepareGlyphSets(glyphSets, isProjectGlyphSet) { return Object.entries(glyphSets) - .map(([key, value]) => ({ + .map(([key, glyphSet]) => ({ key, - label: value.name, - extraItem: value.url + label: glyphSet.name, + extraItem: glyphSet.url ? html.createDomElement("icon-button", { src: "/tabler-icons/menu-2.svg", onclick: (event) => { @@ -239,13 +239,13 @@ export class FontOverviewNavigation extends HTMLElement { { title: "Edit", callback: (event) => { - this._editGlyphSet(event, isProjectGlyphSet, value); + this._editGlyphSet(event, isProjectGlyphSet, glyphSet); }, }, { title: "Delete", callback: (event) => { - this._deleteGlyphSet(event, isProjectGlyphSet, value); + this._deleteGlyphSet(event, isProjectGlyphSet, glyphSet); }, }, ], From 545f67aef50f58f07a670bf0ee0d016a953dd143 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:44:57 +0100 Subject: [PATCH 063/106] Refactor glyphset button menu to new method --- .../views/fontoverview/panel-navigation.js | 60 ++++++++++--------- 1 file changed, 32 insertions(+), 28 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index c697bdc42..8be816b13 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -230,34 +230,7 @@ export class FontOverviewNavigation extends HTMLElement { key, label: glyphSet.name, extraItem: glyphSet.url - ? html.createDomElement("icon-button", { - src: "/tabler-icons/menu-2.svg", - onclick: (event) => { - const buttonRect = event.target.getBoundingClientRect(); - showMenu( - [ - { - title: "Edit", - callback: (event) => { - this._editGlyphSet(event, isProjectGlyphSet, glyphSet); - }, - }, - { - title: "Delete", - callback: (event) => { - this._deleteGlyphSet(event, isProjectGlyphSet, glyphSet); - }, - }, - ], - { - x: buttonRect.left, - y: buttonRect.bottom, - } - ); - }, - // "data-tooltip": "------", - // "data-tooltipposition": "left", - }) + ? this._makeGlyphSetMenuButton(glyphSet, isProjectGlyphSet) : null, })) .sort((a, b) => { @@ -273,6 +246,37 @@ export class FontOverviewNavigation extends HTMLElement { }); } + _makeGlyphSetMenuButton(glyphSet, isProjectGlyphSet) { + return html.createDomElement("icon-button", { + src: "/tabler-icons/menu-2.svg", + onclick: (event) => { + const buttonRect = event.target.getBoundingClientRect(); + showMenu( + [ + { + title: "Edit", + callback: (event) => { + this._editGlyphSet(event, isProjectGlyphSet, glyphSet); + }, + }, + { + title: "Delete", + callback: (event) => { + this._deleteGlyphSet(event, isProjectGlyphSet, glyphSet); + }, + }, + ], + { + x: buttonRect.left, + y: buttonRect.bottom, + } + ); + }, + // "data-tooltip": "------", + // "data-tooltipposition": "left", + }); + } + _makeCheckboxUI(settingsKey, glyphSets) { let checkboxController = this._checkboxControllers[settingsKey]; if (!checkboxController) { From 4b5db287caa586e94067908f87eb96ae9aa3cf77 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 19:50:10 +0100 Subject: [PATCH 064/106] Add 'copy to' menu item + impl --- .../views/fontoverview/panel-navigation.js | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 8be816b13..a9faa2bd4 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -265,6 +265,14 @@ export class FontOverviewNavigation extends HTMLElement { this._deleteGlyphSet(event, isProjectGlyphSet, glyphSet); }, }, + { + title: `Copy to ${ + isProjectGlyphSet ? "my glyph sets" : "project glyph sets" + }`, + callback: (event) => { + this._copyGlyphSet(event, isProjectGlyphSet, glyphSet); + }, + }, ], { x: buttonRect.left, @@ -318,6 +326,15 @@ export class FontOverviewNavigation extends HTMLElement { delete glyphSets[glyphSetInfo.url]; this.fontOverviewSettings[key] = glyphSets; } + + _copyGlyphSet(event, isProjectGlyphSet, glyphSet) { + const fromKey = isProjectGlyphSet ? "projectGlyphSets" : "myGlyphSets"; + const toKey = isProjectGlyphSet ? "myGlyphSets" : "projectGlyphSets"; + this.fontOverviewSettings[toKey] = { + ...this.fontOverviewSettings[toKey], + [glyphSet.url]: glyphSet, + }; + } } customElements.define("font-overview-navigation", FontOverviewNavigation); From a6734d6236600dbbdad55af365bf4d416328a880 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:05:08 +0100 Subject: [PATCH 065/106] Avoid focus ring (workaround) --- src/fontra/client/web-components/add-remove-buttons.js | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/fontra/client/web-components/add-remove-buttons.js b/src/fontra/client/web-components/add-remove-buttons.js index fb039d303..c8de47035 100644 --- a/src/fontra/client/web-components/add-remove-buttons.js +++ b/src/fontra/client/web-components/add-remove-buttons.js @@ -55,6 +55,10 @@ class AddRemoveButtons extends html.UnlitElement { background-color: var(--button-active-color); cursor: pointer; } + + button:focus { + outline: none; + } `; static properties = { From 38bd87fa7f1f67d5cf233a1844999079cf84272a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:05:59 +0100 Subject: [PATCH 066/106] Make button styling more specific --- src/fontra/client/css/shared.css | 6 +++--- src/fontra/views/applicationsettings/panel-shortcuts.js | 3 +++ src/fontra/views/fontinfo/panel-axes.js | 1 + src/fontra/views/fontinfo/panel-cross-axis-mapping.js | 1 + .../views/fontinfo/panel-development-status-definitions.js | 1 + src/fontra/views/fontinfo/panel-sources.js | 1 + src/fontra/views/fontoverview/panel-navigation.js | 6 ++++-- 7 files changed, 14 insertions(+), 5 deletions(-) diff --git a/src/fontra/client/css/shared.css b/src/fontra/client/css/shared.css index ef737d0c3..81e0449b6 100644 --- a/src/fontra/client/css/shared.css +++ b/src/fontra/client/css/shared.css @@ -4,7 +4,7 @@ box-sizing: border-box; } -input[type="button"] { +input[type="button"].fontra-button { cursor: pointer; background-color: #ddd; @@ -18,11 +18,11 @@ input[type="button"] { transition: 100ms; } -input[type="button"]:hover { +input[type="button"].fontra-button:hover { background-color: #ccc; } -input[type="button"]:active { +input[type="button"].fontra-button:active { background-color: #bbb; } diff --git a/src/fontra/views/applicationsettings/panel-shortcuts.js b/src/fontra/views/applicationsettings/panel-shortcuts.js index 3e1c1a530..0b3e96bb0 100644 --- a/src/fontra/views/applicationsettings/panel-shortcuts.js +++ b/src/fontra/views/applicationsettings/panel-shortcuts.js @@ -72,6 +72,7 @@ export class ShortCutsPanel extends BaseInfoPanel { containerButtons.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("shortcuts.reset-all"), onclick: (event) => this.resetToDefault(), @@ -81,6 +82,7 @@ export class ShortCutsPanel extends BaseInfoPanel { containerButtons.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("shortcuts.export"), onclick: (event) => this.exportShortCuts(), @@ -90,6 +92,7 @@ export class ShortCutsPanel extends BaseInfoPanel { containerButtons.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("shortcuts.import"), onclick: (event) => this.importShortCuts(), diff --git a/src/fontra/views/fontinfo/panel-axes.js b/src/fontra/views/fontinfo/panel-axes.js index ed4eaf1dc..9fdfc054b 100644 --- a/src/fontra/views/fontinfo/panel-axes.js +++ b/src/fontra/views/fontinfo/panel-axes.js @@ -106,6 +106,7 @@ export class AxesPanel extends BaseInfoPanel { this.panelElement.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("axes.new"), onclick: (event) => this.newAxis(), diff --git a/src/fontra/views/fontinfo/panel-cross-axis-mapping.js b/src/fontra/views/fontinfo/panel-cross-axis-mapping.js index 7a9e3408a..dc5364376 100644 --- a/src/fontra/views/fontinfo/panel-cross-axis-mapping.js +++ b/src/fontra/views/fontinfo/panel-cross-axis-mapping.js @@ -81,6 +81,7 @@ export class CrossAxisMappingPanel extends BaseInfoPanel { this.panelElement.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("cross-axis-mapping.new"), onclick: (event) => this.newCrossAxisMapping(), diff --git a/src/fontra/views/fontinfo/panel-development-status-definitions.js b/src/fontra/views/fontinfo/panel-development-status-definitions.js index b2d74684f..141300afe 100644 --- a/src/fontra/views/fontinfo/panel-development-status-definitions.js +++ b/src/fontra/views/fontinfo/panel-development-status-definitions.js @@ -74,6 +74,7 @@ export class DevelopmentStatusDefinitionsPanel extends BaseInfoPanel { this.panelElement.appendChild( html.input({ type: "button", + class: "fontra-button", style: "justify-self: start;", value: translate("development-status-definitions.button.new"), onclick: (event) => this.newStatusDefinition(), diff --git a/src/fontra/views/fontinfo/panel-sources.js b/src/fontra/views/fontinfo/panel-sources.js index 5daf3357f..a901fff50 100644 --- a/src/fontra/views/fontinfo/panel-sources.js +++ b/src/fontra/views/fontinfo/panel-sources.js @@ -72,6 +72,7 @@ export class SourcesPanel extends BaseInfoPanel { this.panelElement.appendChild( html.input({ type: "button", + class: "fontra-button", style: `justify-self: start;`, value: translate("sources.button.new-font-source"), onclick: (event) => this.newSource(), diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index a9faa2bd4..eebb414ba 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -200,7 +200,7 @@ export class FontOverviewNavigation extends HTMLElement { this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets), html.input({ type: "button", - class: "add-glyph-set-button", + class: "fontra-button add-glyph-set-button", value: "Add glyph set", onclick: (event) => this._editGlyphSet(event, true), }), @@ -217,7 +217,7 @@ export class FontOverviewNavigation extends HTMLElement { this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), html.input({ type: "button", - class: "add-glyph-set-button", + class: "fontra-button add-glyph-set-button", value: "Add glyph set", onclick: (event) => this._editGlyphSet(event, false), }), @@ -510,6 +510,8 @@ async function runGlyphSetDialog(glyphSetInfo) { { title: translate("dialog.add"), isDefaultButton: true, disabled: true }, ]); + validateInput(); + const contentStyle = ` .glyph-set-dialog-content { display: grid; From 37616d50d1a8564f488a3ce51de0a47d7080a1b9 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:08:28 +0100 Subject: [PATCH 067/106] Tweak icon size --- src/fontra/views/fontoverview/panel-navigation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index eebb414ba..37dd5a005 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -60,8 +60,8 @@ export class FontOverviewNavigation extends HTMLElement { } icon-button { - width: 1.4em; - height: 1.4em; + width: 1.3em; + height: 1.3em; } `); From 5e114c6aed614503b60eaa025a891fd5cf31b0e8 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:19:00 +0100 Subject: [PATCH 068/106] When editing an existing glyph set, make sure the old one gets deleted, in case the URL differs --- src/fontra/views/fontoverview/panel-navigation.js | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 37dd5a005..b799e3054 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -312,10 +312,14 @@ export class FontOverviewNavigation extends HTMLElement { } const key = isProjectGlyphSet ? "projectGlyphSets" : "myGlyphSets"; - this.fontOverviewSettings[key] = { + const glyphSets = { ...this.fontOverviewSettings[key], - [glyphSet.url]: glyphSet, }; + if (glyphSetInfo?.url) { + delete glyphSets[glyphSetInfo.url]; + } + glyphSets[glyphSet.url] = glyphSet; + this.fontOverviewSettings[key] = glyphSets; } _deleteGlyphSet(event, isProjectGlyphSet, glyphSetInfo) { From 44460dbe8e0e8ae0a95de8ccd6358d633417aa84 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:29:12 +0100 Subject: [PATCH 069/106] remove element tag, rely on class alone; add 'button' to general 'no focus ring on buttons' rule --- src/fontra/client/css/shared.css | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/src/fontra/client/css/shared.css b/src/fontra/client/css/shared.css index 81e0449b6..543d684d1 100644 --- a/src/fontra/client/css/shared.css +++ b/src/fontra/client/css/shared.css @@ -4,7 +4,7 @@ box-sizing: border-box; } -input[type="button"].fontra-button { +.fontra-button { cursor: pointer; background-color: #ddd; @@ -18,11 +18,11 @@ input[type="button"].fontra-button { transition: 100ms; } -input[type="button"].fontra-button:hover { +.fontra-button:hover { background-color: #ccc; } -input[type="button"].fontra-button:active { +.fontra-button:active { background-color: #bbb; } @@ -32,6 +32,7 @@ but we're running into a (Chrome) bug where a button gets focus when it shouldn't: when a dialog gets dismissed with a key event, the button that caused the dialog to *open* wrongly gets the focus. */ +button, input[type="button"]:focus { outline: none; } From d89546066fd4d27572b0ec274d2aa43e850dd230 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 20:29:24 +0100 Subject: [PATCH 070/106] Fiddle with button padding --- src/fontra/views/fontoverview/panel-navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index b799e3054..4cde4f4ab 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -48,7 +48,7 @@ export class FontOverviewNavigation extends HTMLElement { } .add-glyph-set-button { - padding: 0.25em 1em 0.3em 1em; + padding: 0.1em 1em 0.2em 1em; font-size: 0.9em; } From 512366a34ae04e64be5a9476a2dec2487483e3f6 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Mon, 13 Jan 2025 21:10:41 +0100 Subject: [PATCH 071/106] Stick with auto or else the element may stretch beyond its space --- src/fontra/client/core/ui-utils.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index 708ec4e1f..dd873fa7d 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -104,7 +104,7 @@ export function labeledCheckbox(label, controller, key, options) { if (label) { inputWrapper.style = ` display: grid; - grid-template-columns: auto max-content; + grid-template-columns: auto auto; justify-content: left; gap: 0.1em; align-items: center; From a2114ba08f4ca81b6f76908564b1e37e34c24be5 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 10:38:18 +0100 Subject: [PATCH 072/106] Forgot to add this new web component --- .../client/web-components/popup-menu.js | 106 ++++++++++++++++++ 1 file changed, 106 insertions(+) create mode 100644 src/fontra/client/web-components/popup-menu.js diff --git a/src/fontra/client/web-components/popup-menu.js b/src/fontra/client/web-components/popup-menu.js new file mode 100644 index 000000000..221457c9f --- /dev/null +++ b/src/fontra/client/web-components/popup-menu.js @@ -0,0 +1,106 @@ +import { InlineSVG } from "./inline-svg.js"; +import { showMenu } from "./menu-panel.js"; +import { themeColorCSS } from "./theme-support.js"; +import * as html from "/core/html-utils.js"; +import { UnlitElement } from "/core/html-utils.js"; + +const colors = { + "border-color": ["#0004", "#FFF4"], + "hover-color": ["#ccc", "#444"], +}; + +export class PopupMenu extends UnlitElement { + static styles = ` + ${themeColorCSS(colors)} + + #popup-menu { + background-color: var(--text-input-background-color); + border-radius: 0.25em; + padding: 0.1em 0.4em; + display: grid; + grid-template-columns: auto max-content; + gap: 0.4em; + border: 1px solid var(--border-color); + } + + #popup-menu:hover { + background-color: var(--hover-color); + } + + inline-svg { + display: inline-block; + height: 1.25em; + width: 1.25em; + transform: rotate(180deg); + } + `; + + static properties = { + valueLabel: { type: String }, + }; + + constructor(valueLabel, getMenuItemsFunc) { + super(); + this.valueLabel = valueLabel; + this._getMenuItems = getMenuItemsFunc; + } + + render() { + return html.div( + { id: "popup-menu", onmousedown: (event) => this._handleClickEvent(event) }, + [ + html.span({}, [this.valueLabel]), + html.createDomElement("inline-svg", { + src: "/tabler-icons/chevron-up.svg", + }), + ] + ); + } + + _handleClickEvent(event) { + event.preventDefault(); + event.stopImmediatePropagation(); + if (this._menu) { + this._menu.dismiss(); + delete this._menu; + return; + } + + const dialogParent = null; //this._findDialogParent(); + const thisRect = this.getBoundingClientRect(); + let pos; + + if (dialogParent) { + const dialogRect = dialogParent.getBoundingClientRect(); + pos = { + x: thisRect.left - dialogRect.left, + y: thisRect.bottom - dialogRect.y, + }; + } else { + pos = { x: thisRect.left, y: thisRect.bottom }; + } + + this._menu = showMenu( + this._getMenuItems?.() || [{ title: "Oops, menu items were not provided" }], + pos, + { + onClose: () => { + delete this._menu; + }, + } + ); + } + + _findDialogParent() { + let parent = this; + while (parent) { + if (parent.classList.contains("dialog-box")) { + return parent; + } + parent = parent.parentElement; + } + return null; + } +} + +customElements.define("popup-menu", PopupMenu); From b3b02a17da391456ac8973d3cb3a9175d6aa18d0 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 10:38:39 +0100 Subject: [PATCH 073/106] Stub for glyph set parsing --- src/fontra/client/core/parse-glyph-set.js | 11 +++++++++++ 1 file changed, 11 insertions(+) create mode 100644 src/fontra/client/core/parse-glyph-set.js diff --git a/src/fontra/client/core/parse-glyph-set.js b/src/fontra/client/core/parse-glyph-set.js new file mode 100644 index 000000000..598327d5a --- /dev/null +++ b/src/fontra/client/core/parse-glyph-set.js @@ -0,0 +1,11 @@ +export const glyphSetDataFormats = [ + { value: "auto-detect", label: "auto-detect" }, + { value: "glyph-names", label: "Glyph names (whitespace-separated)" }, + { value: "csv", label: "CSV (comma- or semicolon-separated)" }, + { value: "tsv", label: "TSV (tab-separated)" }, +]; + +export function parseGlyphSet(text, dataFormat) { + // TODO + return []; +} From cd636c3bb2eebad5b1d102b418b72335e5111667 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 10:39:36 +0100 Subject: [PATCH 074/106] Use definition from new module, different name --- .../views/fontoverview/panel-navigation.js | 19 +++++++++---------- 1 file changed, 9 insertions(+), 10 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 4cde4f4ab..4920980e0 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -2,6 +2,7 @@ import { groupByKeys, groupByProperties } from "/core/glyph-organizer.js"; import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; +import { glyphSetDataFormats } from "/core/parse-glyph-set.js"; import { difference, symmetricDifference, union } from "/core/set-ops.js"; import { labeledCheckbox, @@ -486,7 +487,7 @@ const glyphSetPresets = [ ]; async function runGlyphSetDialog(glyphSetInfo) { - glyphSetInfo = { fileType: "auto-detect", ...glyphSetInfo }; + glyphSetInfo = { dataFormat: "auto-detect", ...glyphSetInfo }; const dialogController = new ObservableController(glyphSetInfo); const validateInput = () => { @@ -536,25 +537,23 @@ async function runGlyphSetDialog(glyphSetInfo) { callback: () => { dialogController.model.name = glyphSet.name; dialogController.model.url = glyphSet.url; - dialogController.model.fileType = glyphSet.fileType || "auto-detect"; + dialogController.model.dataFormat = glyphSet.dataFormat || "auto-detect"; }, })), })); - const fileTypeOptions = [ - { value: "auto-detect", label: "auto-detect" }, - { value: "glyph-names", label: "Glyph names (whitespace-separated)" }, - { value: "csv", label: "CSV (comma- or semicolon-separated)" }, - { value: "tsv", label: "TSV (tab-separated)" }, - ]; - dialog.setContent( html.div({ class: "glyph-set-dialog-content" }, [ html.div(), new PopupMenu("Choose preset", () => presetMenuItems), ...labeledTextInput("Name", dialogController, "name"), ...labeledTextInput("URL", dialogController, "url"), - ...labeledPopupSelect("File type", dialogController, "fileType", fileTypeOptions), + ...labeledPopupSelect( + "Data format", + dialogController, + "dataFormat", + glyphSetDataFormats + ), ...labeledTextInput("Note", dialogController, "note"), ]) ); From 855470a42e4a40d52fadceab75d197e884bad96f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 10:40:04 +0100 Subject: [PATCH 075/106] Beginnings of loading/parsing glyph sets --- src/fontra/views/fontoverview/fontoverview.js | 80 ++++++++++++++++++- 1 file changed, 78 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index b30763a7a..2fe0073b8 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -4,13 +4,16 @@ import { registerActionCallbacks, } from "../core/actions.js"; import { FontOverviewNavigation } from "./panel-navigation.js"; +import { getGlyphMapProxy } from "/core/cmap.js"; import { makeFontraMenuBar } from "/core/fontra-menus.js"; import { GlyphOrganizer } from "/core/glyph-organizer.js"; import * as html from "/core/html-utils.js"; import { loaderSpinner } from "/core/loader-spinner.js"; import { translate } from "/core/localization.js"; import { ObservableController } from "/core/observable-object.js"; +import { parseGlyphSet } from "/core/parse-glyph-set.js"; import { + assert, dumpURLFragment, glyphMapToItemList, isActiveElementTypeable, @@ -69,6 +72,8 @@ export class FontOverviewController extends ViewController { constructor(font) { super(font); + this._loadedGlyphSets = {}; + this.initActions(); const myMenuBar = makeFontraMenuBar(["File", "Edit", "View", "Font"], this); @@ -137,6 +142,18 @@ export class FontOverviewController extends ViewController { this.updateGlyphSelection(); }); + this.fontOverviewSettingsController.addKeyListener( + [ + "projectGlyphSets", + "myGlyphSets", + "projectGlyphSetSelection", + "myGlyphSetSelection", + ], + (event) => { + this.updateGlyphSelection(); + } + ); + this.glyphOrganizer = new GlyphOrganizer(); this.glyphOrganizer.setSearchString(this.fontOverviewSettings.searchString); this.glyphOrganizer.setGroupByKeys(this.fontOverviewSettings.groupByKeys); @@ -314,15 +331,74 @@ export class FontOverviewController extends ViewController { this._updateGlyphSelection(); } - _updateGlyphSelection() { + async _updateGlyphSelection() { // We possibly need to be smarter about this: this.glyphCellView.parentElement.scrollTop = 0; - const glyphItemList = this.glyphOrganizer.filterGlyphs(this._glyphItemList); + const combinedGlyphItemList = await this._getCombineGlyphItemList(); + const glyphItemList = this.glyphOrganizer.filterGlyphs(combinedGlyphItemList); const glyphSections = this.glyphOrganizer.groupGlyphs(glyphItemList); this.glyphCellView.setGlyphSections(glyphSections); } + async _getCombineGlyphItemList() { + const combinedCharacterMap = {}; + const combinedGlyphMap = getGlyphMapProxy({}, combinedCharacterMap); + + const glyphSetKeys = [ + ...this.fontOverviewSettings.projectGlyphSetSelection, + ...this.fontOverviewSettings.myGlyphSetSelection, + ]; + glyphSetKeys.sort(); + + for (const glyphSetKey of glyphSetKeys) { + let glyphSet; + if (glyphSetKey === "") { + glyphSet = this._glyphItemList; + } else { + const glyphSetInfo = + this.fontOverviewSettings.projectGlyphSets[glyphSetKey] || + this.fontOverviewSettings.myGlyphSets[glyphSetKey]; + + if (!glyphSetInfo) { + console.log(`can't find glyph set info for ${glyphSetKey}`); + continue; + } + + glyphSet = await this._loadGlyphSet(glyphSetInfo); + } + + for (const { glyphName, codePoints } of glyphSet) { + if (!combinedGlyphMap[glyphName]) { + combinedGlyphMap[glyphName] = codePoints; + } + } + } + + return glyphMapToItemList(combinedGlyphMap); + } + + async _loadGlyphSet(glyphSetInfo) { + assert(glyphSetInfo.url); + let glyphSet = this._loadedGlyphSets[glyphSetInfo.url]; + if (!glyphSet) { + let glyphSetData; + try { + const response = await fetch(glyphSetInfo.url); + glyphSetData = await response.text(); + } catch (e) { + console.error(`can't load ${glyphSetInfo.url}`); + return []; + } + + glyphSet = parseGlyphSet(glyphSetData, glyphSetInfo.dataFormat); + + this._loadedGlyphSets[glyphSetInfo.url] = glyphSet; + } + + return glyphSet; + } + openSelectedGlyphs() { const selectedGlyphInfo = this.glyphCellView.getSelectedGlyphInfo(); if (!selectedGlyphInfo.length) { From 5158ebf212e0d8f770c127601cd30d1b5d68c7a2 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 10:59:59 +0100 Subject: [PATCH 076/106] Added missing parse step --- src/fontra/client/core/glyph-data.js | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/fontra/client/core/glyph-data.js b/src/fontra/client/core/glyph-data.js index bcea487a2..c5e680d2c 100644 --- a/src/fontra/client/core/glyph-data.js +++ b/src/fontra/client/core/glyph-data.js @@ -77,6 +77,8 @@ export function getSuggestedGlyphName(codePoint) { } export function getCodePointFromGlyphName(glyphName) { + parseGlyphDataCSV(); + const glyphInfo = glyphDataByName.get(glyphName); let codePoint = null; From be0fbf481827417a34aa5ce364602a342af4940b Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 11:00:37 +0100 Subject: [PATCH 077/106] Inital QnD glyph set parser, just enough for the GF sets --- src/fontra/client/core/parse-glyph-set.js | 28 ++++++++++++++++++++--- 1 file changed, 25 insertions(+), 3 deletions(-) diff --git a/src/fontra/client/core/parse-glyph-set.js b/src/fontra/client/core/parse-glyph-set.js index 598327d5a..0c69664fd 100644 --- a/src/fontra/client/core/parse-glyph-set.js +++ b/src/fontra/client/core/parse-glyph-set.js @@ -1,3 +1,5 @@ +import { getCodePointFromGlyphName } from "./glyph-data.js"; + export const glyphSetDataFormats = [ { value: "auto-detect", label: "auto-detect" }, { value: "glyph-names", label: "Glyph names (whitespace-separated)" }, @@ -5,7 +7,27 @@ export const glyphSetDataFormats = [ { value: "tsv", label: "TSV (tab-separated)" }, ]; -export function parseGlyphSet(text, dataFormat) { - // TODO - return []; +export function parseGlyphSet(sourceData, dataFormat) { + sourceData = sourceData.replaceAll("\r\n", "\n"); // normalize line endings + + // TODO: TSV/CSV, etc. + + const glyphSet = []; + for (let line of sourceData.split("\n")) { + const commentIndex = line.indexOf("#"); + if (commentIndex >= 0) { + line = line.slice(0, commentIndex); + } + line = line.trim(); + if (!line) { + continue; + } + + for (const glyphName of line.split(/\s+/)) { + const codePoint = getCodePointFromGlyphName(glyphName); + glyphSet.push({ glyphName, codePoints: codePoint ? [codePoint] : [] }); + } + } + + return glyphSet; } From 329c02d3a997ec0ba1765f564db4259ad3001883 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 14:33:35 +0100 Subject: [PATCH 078/106] Try pencil icon for edit menu --- src/fontra/views/fontoverview/panel-navigation.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 4920980e0..d6755c2c6 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -249,7 +249,7 @@ export class FontOverviewNavigation extends HTMLElement { _makeGlyphSetMenuButton(glyphSet, isProjectGlyphSet) { return html.createDomElement("icon-button", { - src: "/tabler-icons/menu-2.svg", + src: "/tabler-icons/pencil.svg", onclick: (event) => { const buttonRect = event.target.getBoundingClientRect(); showMenu( From 5775c45fac0af1d1f748a731e71bdab18c5c0d70 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 14:58:09 +0100 Subject: [PATCH 079/106] Fix oddball focus problem with menu --- src/fontra/client/web-components/menu-panel.js | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/fontra/client/web-components/menu-panel.js b/src/fontra/client/web-components/menu-panel.js index d41fe218f..1205a914d 100644 --- a/src/fontra/client/web-components/menu-panel.js +++ b/src/fontra/client/web-components/menu-panel.js @@ -59,6 +59,10 @@ export class MenuPanel extends SimpleElement { margin: 0.2em 0em 0.3em 0em; /* top, right, bottom, left */ } + .menu-container:focus { + outline: none; + } + .menu-item-divider { border: none; border-top: 1px solid #80808080; @@ -197,6 +201,7 @@ export class MenuPanel extends SimpleElement { this.shadowRoot.appendChild(this.menuElement); this.tabIndex = 0; this.addEventListener("keydown", (event) => this.handleKeyDown(event)); + setTimeout(() => this.menuElement.focus(), 0); MenuPanel.openMenuPanels.push(this); } From 604c6678e6f74eeae1a31894e721bf313f8d7d19 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 15:15:38 +0100 Subject: [PATCH 080/106] Twiddle user-select, and wow, this is behind a -webkit- prefix in Safari --- src/fontra/client/web-components/glyph-cell-view.js | 2 ++ src/fontra/client/web-components/glyph-cell.js | 1 + src/fontra/client/web-components/menu-bar.js | 1 + 3 files changed, 4 insertions(+) diff --git a/src/fontra/client/web-components/glyph-cell-view.js b/src/fontra/client/web-components/glyph-cell-view.js index 9dbf06acf..e3a3ebad6 100644 --- a/src/fontra/client/web-components/glyph-cell-view.js +++ b/src/fontra/client/web-components/glyph-cell-view.js @@ -96,6 +96,8 @@ export class GlyphCellView extends HTMLElement { this.accordion.appendStyle(` :host { display: ${this.displayMode}; + user-select: none; + -webkit-user-select: none; } .placeholder-label { diff --git a/src/fontra/client/web-components/glyph-cell.js b/src/fontra/client/web-components/glyph-cell.js index 41b29ea80..4da507b73 100644 --- a/src/fontra/client/web-components/glyph-cell.js +++ b/src/fontra/client/web-components/glyph-cell.js @@ -86,6 +86,7 @@ export class GlyphCell extends UnlitElement { justify-items: center; gap: 0; user-select: none; + -webkit-user-select: none; } .glyph-shape-placeholder { diff --git a/src/fontra/client/web-components/menu-bar.js b/src/fontra/client/web-components/menu-bar.js index f7969a796..2f337676d 100644 --- a/src/fontra/client/web-components/menu-bar.js +++ b/src/fontra/client/web-components/menu-bar.js @@ -24,6 +24,7 @@ export class MenuBar extends SimpleElement { padding: 0.4rem 0.6rem; cursor: default; user-select: none; + -webkit-user-select: none; } .menu-item.hovered, From 84a37c3717b3db6fa73109a09fdb38c0355bcd66 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 17:52:46 +0100 Subject: [PATCH 081/106] Make setting color work for icon-button, hmmm --- src/fontra/client/web-components/icon-button.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/client/web-components/icon-button.js b/src/fontra/client/web-components/icon-button.js index f5204527f..d32c934f3 100644 --- a/src/fontra/client/web-components/icon-button.js +++ b/src/fontra/client/web-components/icon-button.js @@ -10,7 +10,6 @@ export class IconButton extends UnlitElement { border: none; padding: 0; margin: 0; - color: var(--foreground-color); width: 100%; height: 100%; cursor: pointer; @@ -78,6 +77,7 @@ export class IconButton extends UnlitElement { focus.restore(); }, disabled: this._buttonDisabled, + style: `color: undefined var(--foreground-color);`, // TODO: huh. }, [html.createDomElement("inline-svg", { src: this.src })] ); From 8f291ed46410c90d3e9713c440bca290571c345e Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 19:15:21 +0100 Subject: [PATCH 082/106] Fix view URL redirection --- src/fontra/client/core/fontra-menus.js | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/src/fontra/client/core/fontra-menus.js b/src/fontra/client/core/fontra-menus.js index 167071851..b0b83cf83 100644 --- a/src/fontra/client/core/fontra-menus.js +++ b/src/fontra/client/core/fontra-menus.js @@ -1,6 +1,7 @@ import { registerActionInfo } from "./actions.js"; import * as html from "./html-utils.js"; import { translate } from "./localization.js"; +import { assert } from "./utils.js"; import { MenuBar } from "/web-components/menu-bar.js"; import { MenuItemDivider } from "/web-components/menu-panel.js"; @@ -166,7 +167,7 @@ function getFontMenuItems() { enabled: () => enabled, callback: () => { const url = new URL(window.location); - url.pathname = `/fontinfo/-/${url.pathname.split("/").slice(-1)[0]}`; + url.pathname = rerouteViewPath(url.pathname, "fontinfo"); url.hash = panelID; window.open(url.toString()); }, @@ -184,7 +185,7 @@ function getWindowMenuItems() { enabled: () => true, callback: () => { const url = new URL(window.location); - url.pathname = `/fontoverview/-/${url.pathname.split("/").slice(-1)[0]}`; + url.pathname = rerouteViewPath(url.pathname, "fontoverview"); url.hash = ""; // remove any hash window.open(url.toString()); }, @@ -194,7 +195,7 @@ function getWindowMenuItems() { enabled: () => true, callback: () => { const url = new URL(window.location); - url.pathname = `/editor/-/${url.pathname.split("/").slice(-1)[0]}`; + url.pathname = rerouteViewPath(url.pathname, "editor"); url.hash = ""; // remove any hash window.open(url.toString()); }, @@ -202,6 +203,15 @@ function getWindowMenuItems() { ]; } +function rerouteViewPath(path, targetView) { + assert(path[0] === "/"); + const parts = path.split("/"); + assert(parts.length >= 3); + assert(parts[1].length > 0); + parts[1] = targetView; + return parts.join("/"); +} + // Default action infos { From c87ed5230a30db210df39976440db112940deec9 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 19:21:34 +0100 Subject: [PATCH 083/106] Mention two bug fixes --- CHANGELOG.md | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/CHANGELOG.md b/CHANGELOG.md index 1588c546c..e5ae4cb26 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -1,5 +1,10 @@ # Changelog for Fontra +## 2025-01-14 + +- Fixed a regression with the Font menu [Issue 1941](https://github.com/googlefonts/fontra/issues/1941), [PR 1942](https://github.com/googlefonts/fontra/pull/1942) +- Fixed a regression with messages from server [PR 1939](https://github.com/googlefonts/fontra/pull/1939) + ## 2025-01-06 - Fixed bug related to deleting points [Issue 1910](https://github.com/googlefonts/fontra/issues/1910), [PR 1916](https://github.com/googlefonts/fontra/pull/1916) From 5edffdcf68629883a78017fcd9092e64c96cfda4 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 19:56:55 +0100 Subject: [PATCH 084/106] Implement error handling/reporting for loading/parsing glyph sets --- src/fontra/views/fontoverview/fontoverview.js | 27 ++++++++-- .../views/fontoverview/panel-navigation.js | 53 ++++++++++++++++++- 2 files changed, 73 insertions(+), 7 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 2fe0073b8..0cb7e9880 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -60,6 +60,7 @@ function getDefaultFontOverviewSettings() { myGlyphSets: {}, projectGlyphSetSelection: [THIS_FONTS_GLYPHSET], myGlyphSetSelection: [], + glyphSetErrors: {}, cellMagnification: 1, }; } @@ -380,23 +381,39 @@ export class FontOverviewController extends ViewController { async _loadGlyphSet(glyphSetInfo) { assert(glyphSetInfo.url); + const glyphSetErrors = { ...this.fontOverviewSettings.glyphSetErrors }; + let glyphSet = this._loadedGlyphSets[glyphSetInfo.url]; if (!glyphSet) { let glyphSetData; try { const response = await fetch(glyphSetInfo.url); glyphSetData = await response.text(); + delete glyphSetErrors[glyphSetInfo.url]; } catch (e) { - console.error(`can't load ${glyphSetInfo.url}`); - return []; + console.log(`can't load ${glyphSetInfo.url}`); + console.error(); + glyphSetErrors[glyphSetInfo.url] = `Could not load glyph set: ${e.toString()}`; } - glyphSet = parseGlyphSet(glyphSetData, glyphSetInfo.dataFormat); + if (glyphSetData) { + try { + glyphSet = parseGlyphSet(glyphSetData, glyphSetInfo.dataFormat); + } catch (e) { + glyphSetErrors[ + glyphSetInfo.url + ] = `Could not parse glyph set: ${e.toString()}`; + } + } - this._loadedGlyphSets[glyphSetInfo.url] = glyphSet; + this.fontOverviewSettings.glyphSetErrors = glyphSetErrors; + + if (glyphSet) { + this._loadedGlyphSets[glyphSetInfo.url] = glyphSet; + } } - return glyphSet; + return glyphSet || []; } openSelectedGlyphs() { diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index d6755c2c6..b127b68b2 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -13,7 +13,7 @@ import { import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { IconButton } from "/web-components/icon-button.js"; // required for the icon buttons import { showMenu } from "/web-components/menu-panel.js"; -import { dialogSetup } from "/web-components/modal-dialog.js"; +import { dialogSetup, message } from "/web-components/modal-dialog.js"; import { PopupMenu } from "/web-components/popup-menu.js"; import { Accordion } from "/web-components/ui-accordion.js"; @@ -27,6 +27,7 @@ export class FontOverviewNavigation extends HTMLElement { this.fontOverviewSettings = this.fontOverviewSettingsController.model; this._checkboxControllers = {}; + this._glyphSetErrorButtons = {}; this._setupUI(); } @@ -60,10 +61,27 @@ export class FontOverviewNavigation extends HTMLElement { justify-content: space-between; } + .glyphset-button-group { + justify-self: end; + display: grid; + grid-template-columns: auto auto; + gap: 0.2em; + } + icon-button { width: 1.3em; height: 1.3em; } + + .glyphset-error-button { + color: var(--fontra-light-red-color); + opacity: 0; + } + + .glyphset-error-button.glyphset-error { + opacity: 1; + } + `); accordion.onItemOpenClose = (item, openClose) => { @@ -132,6 +150,17 @@ export class FontOverviewNavigation extends HTMLElement { ); this._updateProjectGlyphSets(); this._updateMyGlyphSets(); + + this.fontOverviewSettingsController.addKeyListener("glyphSetErrors", (event) => { + const diffKeys = symmetricDifference( + new Set(Object.keys(event.oldValue)), + Object.keys(event.newValue) + ); + for (const key of diffKeys) { + const errorButton = this._glyphSetErrorButtons[key]; + errorButton.classList.toggle("glyphset-error", !!event.newValue[key]); + } + }); } async _makeFontSourcePopup() { @@ -231,7 +260,10 @@ export class FontOverviewNavigation extends HTMLElement { key, label: glyphSet.name, extraItem: glyphSet.url - ? this._makeGlyphSetMenuButton(glyphSet, isProjectGlyphSet) + ? html.div({ class: "glyphset-button-group" }, [ + this._makeGlyphSetErrorButton(glyphSet, isProjectGlyphSet), + this._makeGlyphSetMenuButton(glyphSet, isProjectGlyphSet), + ]) : null, })) .sort((a, b) => { @@ -286,6 +318,23 @@ export class FontOverviewNavigation extends HTMLElement { }); } + _makeGlyphSetErrorButton(glyphSet, isProjectGlyphSet) { + const errorButton = html.createDomElement("icon-button", { + class: "glyphset-error-button", + src: "/tabler-icons/alert-triangle.svg", + onclick: (event) => { + const errorMessage = this.fontOverviewSettings.glyphSetErrors[glyphSet.url]; + if (errorMessage) { + message(`The glyph set “${glyphSet.name}” could not be loaded`, errorMessage); + } + }, + }); + + this._glyphSetErrorButtons[glyphSet.url] = errorButton; + + return errorButton; + } + _makeCheckboxUI(settingsKey, glyphSets) { let checkboxController = this._checkboxControllers[settingsKey]; if (!checkboxController) { From 5c81c8cb4bcd9e0b00d846830c2eb2b24502ad73 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 21:25:03 +0100 Subject: [PATCH 085/106] Remove add glyph set button and replace with + icon button in accordion item header --- .../views/fontoverview/panel-navigation.js | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index b127b68b2..a28cafcd9 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -49,11 +49,6 @@ export class FontOverviewNavigation extends HTMLElement { gap: 0.5em; } - .add-glyph-set-button { - padding: 0.1em 1em 0.2em 1em; - font-size: 0.9em; - } - .checkbox-group { width: 100%; display: grid; @@ -110,12 +105,20 @@ export class FontOverviewNavigation extends HTMLElement { label: "Project glyph sets", // TODO: translate id: "project-glyph-sets", content: html.div(), + auxiliaryHeaderElement: this._makeAddGlyphSetButton( + true, + "Add a glyph set to the project" + ), }; this._myGlyphSetsItem = { label: "My glyph sets", // TODO: translate id: "my-glyph-sets", content: html.div(), + auxiliaryHeaderElement: this._makeAddGlyphSetButton( + false, + "Add a glyph set to my sets" + ), }; const accordionItems = [ @@ -210,6 +213,15 @@ export class FontOverviewNavigation extends HTMLElement { return this._makeCheckboxUI("groupByKeys", groupByProperties); } + _makeAddGlyphSetButton(isProjectGlyphSet, toolTip) { + return html.createDomElement("icon-button", { + "src": "/images/plus.svg", + "onclick": (event) => this._editGlyphSet(event, isProjectGlyphSet), + "data-tooltip": toolTip, + "data-tooltipposition": "bottom", + }); + } + _updateProjectGlyphSets() { this._projectGlyphSetsItem.content.innerHTML = ""; this._projectGlyphSetsItem.content.appendChild(this._makeProjectGlyphSetsUI()); @@ -228,12 +240,6 @@ export class FontOverviewNavigation extends HTMLElement { return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("projectGlyphSetSelection", projectGlyphSets), - html.input({ - type: "button", - class: "fontra-button add-glyph-set-button", - value: "Add glyph set", - onclick: (event) => this._editGlyphSet(event, true), - }), ]); } @@ -245,12 +251,6 @@ export class FontOverviewNavigation extends HTMLElement { return html.div({ class: "glyph-set-container" }, [ this._makeCheckboxUI("myGlyphSetSelection", myGlyphSets), - html.input({ - type: "button", - class: "fontra-button add-glyph-set-button", - value: "Add glyph set", - onclick: (event) => this._editGlyphSet(event, false), - }), ]); } From 85dd7fdcb297d8249833464d1c54cd555ef1866d Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Tue, 14 Jan 2025 21:31:40 +0100 Subject: [PATCH 086/106] Ensure the glyph set accordion item is open once we add a glyph set to it --- src/fontra/views/fontoverview/panel-navigation.js | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index a28cafcd9..7fc709e73 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -41,6 +41,7 @@ export class FontOverviewNavigation extends HTMLElement { this.appendChild(this.searchField); const accordion = new Accordion(); + this.accordion = accordion; accordion.appendStyle(` .glyph-set-container { @@ -361,6 +362,12 @@ export class FontOverviewNavigation extends HTMLElement { return; } + if (isProjectGlyphSet) { + this.accordion.openCloseAccordionItem(this._projectGlyphSetsItem, true); + } else { + this.accordion.openCloseAccordionItem(this._myGlyphSetsItem, true); + } + const key = isProjectGlyphSet ? "projectGlyphSets" : "myGlyphSets"; const glyphSets = { ...this.fontOverviewSettings[key], From 264d82430caa35fbdea94f9df83b6e5b3d0dd872 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 15 Jan 2025 12:49:06 +0100 Subject: [PATCH 087/106] Add menu item that links to glyphset discussion --- .../views/fontoverview/panel-navigation.js | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 7fc709e73..529171a18 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -598,6 +598,25 @@ async function runGlyphSetDialog(glyphSetInfo) { })), })); + presetMenuItems.push({ + title: html.span({}, [ + "Suggest glyph set collections", + html.createDomElement("inline-svg", { + style: ` + display: inline-block; + height: 1.2em; + width: 1.2em; + margin-left: 0.4em; + transform: translate(0, 0.25em); + `, + src: "/tabler-icons/external-link.svg", + }), + ]), + callback: () => { + window.open("https://github.com/googlefonts/fontra/discussions/1943"); + }, + }); + dialog.setContent( html.div({ class: "glyph-set-dialog-content" }, [ html.div(), From 3c40585da6da926c93291951cf75d66a0587ce64 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 15 Jan 2025 12:51:09 +0100 Subject: [PATCH 088/106] Tweak link icon --- src/fontra/views/fontoverview/panel-navigation.js | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 529171a18..ae26c65f3 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -604,10 +604,10 @@ async function runGlyphSetDialog(glyphSetInfo) { html.createDomElement("inline-svg", { style: ` display: inline-block; - height: 1.2em; - width: 1.2em; - margin-left: 0.4em; - transform: translate(0, 0.25em); + height: 1em; + width: 1em; + margin-left: 0.5em; + transform: translate(0, 0.15em); `, src: "/tabler-icons/external-link.svg", }), From 0d833f3d9380f6e1503ef1383b77a342bf6511ba Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 17:02:55 +0100 Subject: [PATCH 089/106] Add placeholder if no glyphs are found --- src/fontra/views/fontoverview/fontoverview.css | 6 ++++++ src/fontra/views/fontoverview/fontoverview.js | 17 +++++++++++++++-- 2 files changed, 21 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.css b/src/fontra/views/fontoverview/fontoverview.css index ce70f23e1..2f86132f6 100644 --- a/src/fontra/views/fontoverview/fontoverview.css +++ b/src/fontra/views/fontoverview/fontoverview.css @@ -44,3 +44,9 @@ font-overview-navigation { .font-overview-section-header { font-weight: bold; } + +.font-overview-no-glyphs { + color: #aaa; + display: grid; + place-items: center; +} diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 0cb7e9880..6a02bfae4 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -167,7 +167,7 @@ export class FontOverviewController extends ViewController { await this.fontController.subscribeChanges(rootSubscriptionPattern, false); const sidebarContainer = document.querySelector("#sidebar-container"); - const glyphCellViewContainer = document.querySelector("#glyph-cell-view-container"); + this.glyphCellViewContainer = document.querySelector("#glyph-cell-view-container"); this.navigation = new FontOverviewNavigation(this); @@ -185,7 +185,7 @@ export class FontOverviewController extends ViewController { this.glyphCellView.onOpenSelectedGlyphs = (event) => this.openSelectedGlyphs(); sidebarContainer.appendChild(this.navigation); - glyphCellViewContainer.appendChild(this.glyphCellView); + this.glyphCellViewContainer.appendChild(this.glyphCellView); this.fontController.addChangeListener({ glyphMap: null }, () => { this._updateGlyphItemList(); @@ -340,6 +340,19 @@ export class FontOverviewController extends ViewController { const glyphItemList = this.glyphOrganizer.filterGlyphs(combinedGlyphItemList); const glyphSections = this.glyphOrganizer.groupGlyphs(glyphItemList); this.glyphCellView.setGlyphSections(glyphSections); + + // Add placeholder if no glyphs are found + if (glyphSections.length === 0) { + if (!this.glyphCellViewContainer.querySelector(".font-overview-no-glyphs")) { + this.glyphCellViewContainer.appendChild( + html.div({ class: "font-overview-no-glyphs" }, [ + translate("(No glyphs found)"), // TODO: translation + ]) + ); + } + } else { + this.glyphCellViewContainer.querySelector(".font-overview-no-glyphs")?.remove(); + } } async _getCombineGlyphItemList() { From 99c2a8daf6b4c41572af943c3e5f29c5bb0e09f2 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 15 Jan 2025 18:56:52 +0100 Subject: [PATCH 090/106] Put more effort into merging glyph sets in the face of conflicting glyph names for a code point --- src/fontra/views/fontoverview/fontoverview.js | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 0cb7e9880..a613f5f88 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -343,6 +343,18 @@ export class FontOverviewController extends ViewController { } async _getCombineGlyphItemList() { + /* + Merge selected glyph sets. When multiple glyph sets define a character + but the glyph name does not match: + - If the font defines this character, take the font's glyph name for it + - Else take the glyph name from the first glyph set that defines the + character + The latter is arbitrary, but should still be deterministic, as glyph sets + should be sorted. + If the conflicting glyph name references multiple code points, we bail, + as it is not clear how to resolve. + */ + const fontCharacterMap = this.fontController.characterMap; const combinedCharacterMap = {}; const combinedGlyphMap = getGlyphMapProxy({}, combinedCharacterMap); @@ -370,7 +382,17 @@ export class FontOverviewController extends ViewController { } for (const { glyphName, codePoints } of glyphSet) { - if (!combinedGlyphMap[glyphName]) { + const singleCodePoint = codePoints.length === 1 ? codePoints[0] : null; + const foundGlyphName = + singleCodePoint !== null + ? combinedCharacterMap[singleCodePoint] || fontCharacterMap[singleCodePoint] + : null; + + if (foundGlyphName) { + if (!combinedGlyphMap[foundGlyphName]) { + combinedGlyphMap[foundGlyphName] = codePoints; + } + } else if (!combinedGlyphMap[glyphName]) { combinedGlyphMap[glyphName] = codePoints; } } From 6f9b958cd5d5b3054ec01ed943ed173af0742034 Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 22:31:46 +0100 Subject: [PATCH 091/106] Show/Hide placeholder via display: none --- .../views/fontoverview/fontoverview.css | 10 +++++--- src/fontra/views/fontoverview/fontoverview.js | 25 +++++++++++-------- 2 files changed, 21 insertions(+), 14 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.css b/src/fontra/views/fontoverview/fontoverview.css index 2f86132f6..000fc4e0d 100644 --- a/src/fontra/views/fontoverview/fontoverview.css +++ b/src/fontra/views/fontoverview/fontoverview.css @@ -45,8 +45,12 @@ font-overview-navigation { font-weight: bold; } -.font-overview-no-glyphs { +#font-overview-no-glyphs { color: #aaa; - display: grid; - place-items: center; + width: 100%; + text-align: center; +} + +.hidden { + display: none; } diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 6a02bfae4..3dbec23a8 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -167,7 +167,13 @@ export class FontOverviewController extends ViewController { await this.fontController.subscribeChanges(rootSubscriptionPattern, false); const sidebarContainer = document.querySelector("#sidebar-container"); - this.glyphCellViewContainer = document.querySelector("#glyph-cell-view-container"); + const glyphCellViewContainer = document.querySelector("#glyph-cell-view-container"); + + glyphCellViewContainer.appendChild( + html.div({ id: "font-overview-no-glyphs", class: "hidden" }, [ + translate("(No glyphs found)"), // TODO: translation + ]) + ); this.navigation = new FontOverviewNavigation(this); @@ -185,7 +191,7 @@ export class FontOverviewController extends ViewController { this.glyphCellView.onOpenSelectedGlyphs = (event) => this.openSelectedGlyphs(); sidebarContainer.appendChild(this.navigation); - this.glyphCellViewContainer.appendChild(this.glyphCellView); + glyphCellViewContainer.appendChild(this.glyphCellView); this.fontController.addChangeListener({ glyphMap: null }, () => { this._updateGlyphItemList(); @@ -341,17 +347,14 @@ export class FontOverviewController extends ViewController { const glyphSections = this.glyphOrganizer.groupGlyphs(glyphItemList); this.glyphCellView.setGlyphSections(glyphSections); - // Add placeholder if no glyphs are found + // Show placeholder if no glyphs are found + const fontOverviewNoGlyphsContainer = document.querySelector( + "#font-overview-no-glyphs" + ); if (glyphSections.length === 0) { - if (!this.glyphCellViewContainer.querySelector(".font-overview-no-glyphs")) { - this.glyphCellViewContainer.appendChild( - html.div({ class: "font-overview-no-glyphs" }, [ - translate("(No glyphs found)"), // TODO: translation - ]) - ); - } + fontOverviewNoGlyphsContainer.classList = ""; } else { - this.glyphCellViewContainer.querySelector(".font-overview-no-glyphs")?.remove(); + fontOverviewNoGlyphsContainer.classList = "hidden"; } } From 523afa93d4ae9f66e30f16b1263846b8264b47ba Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 22:41:21 +0100 Subject: [PATCH 092/106] Code improvement. simpler --- src/fontra/views/fontoverview/fontoverview.js | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 3dbec23a8..b7ad2beae 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -351,11 +351,7 @@ export class FontOverviewController extends ViewController { const fontOverviewNoGlyphsContainer = document.querySelector( "#font-overview-no-glyphs" ); - if (glyphSections.length === 0) { - fontOverviewNoGlyphsContainer.classList = ""; - } else { - fontOverviewNoGlyphsContainer.classList = "hidden"; - } + fontOverviewNoGlyphsContainer.classList.toggle("hidden", glyphSections.length); } async _getCombineGlyphItemList() { From 08eceb974a9cea5c2d332da2cef475f08ae1de41 Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 23:04:29 +0100 Subject: [PATCH 093/106] Remove unnecessary code --- src/fontra/views/fontoverview/fontoverview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index b7ad2beae..cc4a0251d 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -170,7 +170,7 @@ export class FontOverviewController extends ViewController { const glyphCellViewContainer = document.querySelector("#glyph-cell-view-container"); glyphCellViewContainer.appendChild( - html.div({ id: "font-overview-no-glyphs", class: "hidden" }, [ + html.div({ id: "font-overview-no-glyphs" }, [ translate("(No glyphs found)"), // TODO: translation ]) ); From 79c56c80c72b58a5dedc25d5263583603ae4de00 Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 23:17:48 +0100 Subject: [PATCH 094/106] Let's make the condition explicit by adding > 0. --- src/fontra/views/fontoverview/fontoverview.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index cc4a0251d..251c798fe 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -351,7 +351,7 @@ export class FontOverviewController extends ViewController { const fontOverviewNoGlyphsContainer = document.querySelector( "#font-overview-no-glyphs" ); - fontOverviewNoGlyphsContainer.classList.toggle("hidden", glyphSections.length); + fontOverviewNoGlyphsContainer.classList.toggle("hidden", glyphSections.length > 0); } async _getCombineGlyphItemList() { From 6bc0499d786c4966a6ca5b52f44d7e0d7adc4f9f Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Wed, 15 Jan 2025 23:39:30 +0100 Subject: [PATCH 095/106] Tweak color, variable name, class name. Reverse default --- src/fontra/views/editor/panel-related-glyphs.js | 2 +- src/fontra/views/fontoverview/fontoverview.css | 7 ++++--- src/fontra/views/fontoverview/fontoverview.js | 6 ++---- 3 files changed, 7 insertions(+), 8 deletions(-) diff --git a/src/fontra/views/editor/panel-related-glyphs.js b/src/fontra/views/editor/panel-related-glyphs.js index 6bf5f40a5..3c70a0bf9 100644 --- a/src/fontra/views/editor/panel-related-glyphs.js +++ b/src/fontra/views/editor/panel-related-glyphs.js @@ -32,7 +32,7 @@ export default class RelatedGlyphPanel extends Panel { } .no-related-glyphs { - color: #AAA; + color: #999; padding-top: 1em; } `; diff --git a/src/fontra/views/fontoverview/fontoverview.css b/src/fontra/views/fontoverview/fontoverview.css index 000fc4e0d..f19a191e6 100644 --- a/src/fontra/views/fontoverview/fontoverview.css +++ b/src/fontra/views/fontoverview/fontoverview.css @@ -46,11 +46,12 @@ font-overview-navigation { } #font-overview-no-glyphs { - color: #aaa; + display: none; + color: #999; width: 100%; text-align: center; } -.hidden { - display: none; +#font-overview-no-glyphs.shown { + display: block; } diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 74deb0ece..8159f888e 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -348,10 +348,8 @@ export class FontOverviewController extends ViewController { this.glyphCellView.setGlyphSections(glyphSections); // Show placeholder if no glyphs are found - const fontOverviewNoGlyphsContainer = document.querySelector( - "#font-overview-no-glyphs" - ); - fontOverviewNoGlyphsContainer.classList.toggle("hidden", glyphSections.length > 0); + const noGlyphsElement = document.querySelector("#font-overview-no-glyphs"); + noGlyphsElement.classList.toggle("shown", !glyphSections.length); } async _getCombineGlyphItemList() { From 438dc4f275ac12dc6a8e03f34d397c6dd793387e Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 20:59:50 +0100 Subject: [PATCH 096/106] First draft of adding font location sliders to font overview --- .../views/fontoverview/fontoverview.html | 1 + .../views/fontoverview/panel-navigation.js | 64 +++++++++++++++++-- 2 files changed, 59 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.html b/src/fontra/views/fontoverview/fontoverview.html index 26c85444a..98780da7e 100644 --- a/src/fontra/views/fontoverview/fontoverview.html +++ b/src/fontra/views/fontoverview/fontoverview.html @@ -8,6 +8,7 @@ Fontra Font Overview + diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index ae26c65f3..c43750cef 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -1,3 +1,7 @@ +import { + makeSparseLocation, + mapAxesFromUserSpaceToSourceSpace, +} from "../core/var-model.js"; import { groupByKeys, groupByProperties } from "/core/glyph-organizer.js"; import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; @@ -78,6 +82,11 @@ export class FontOverviewNavigation extends HTMLElement { opacity: 1; } + .font-source-location-container { + display: grid; + gap: 0.5em; + } + `); accordion.onItemOpenClose = (item, openClose) => { @@ -126,7 +135,10 @@ export class FontOverviewNavigation extends HTMLElement { { label: translate("sources.labels.location"), id: "location", - content: await this._makeFontSourcePopup(), + content: html.div({ class: "font-source-location-container" }, [ + await this._makeFontSourcePopup(), + await this._makeFontSourceSliders(), + ]), }, { label: "Group by", // TODO: translate @@ -182,7 +194,7 @@ export class FontOverviewNavigation extends HTMLElement { label: fontSources[fontSourceIdentifier].name, })); - const controller = new ObservableController({ + this.locationControllerPopup = new ObservableController({ value: selectedSourceIdentifier(), }); @@ -190,16 +202,56 @@ export class FontOverviewNavigation extends HTMLElement { "fontLocationSource", (event) => { if (!event.senderInfo?.sentFromInput) { - controller.model.value = selectedSourceIdentifier(); + this.locationControllerPopup.model.value = selectedSourceIdentifier(); } } ); - controller.addKeyListener("value", (event) => { + this.locationControllerPopup.addKeyListener("value", (event) => { const fontSourceIdentifier = event.newValue; - const sourceLocation = { + this.sourceLocation = { ...fontSources[fontSourceIdentifier]?.location, }; // A font may not have any font sources, therefore the ?-check + // TODO: set the sliders controller. The following does not work: + // this.locationControllerSilders.setItem(this.sourceLocation); + this.fontOverviewSettingsController.setItem( + "fontLocationSource", + this.sourceLocation, + { sentFromInput: true } + ); + }); + + return popupSelect(this.locationControllerPopup, "value", options); + } + + async _makeFontSourceSliders() { + const locationAxes = mapAxesFromUserSpaceToSourceSpace( + this.fontController.axes.axes + ); + + this.locationControllerSilders = new ObservableController({ + ...this.sourceLocation, + }); + + const locationElement = html.createDomElement("designspace-location", { + style: `grid-column: 1 / -1; + min-height: 0; + overflow: auto; + height: 100%; + `, + }); + locationElement.axes = locationAxes; + locationElement.controller = this.locationControllerSilders; + + this.locationControllerSilders.addListener((event) => { + const sourceLocation = { ...this.locationControllerSilders.model }; + const fontSourceIdentifier = + this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( + sourceLocation + ); + this.locationControllerPopup.setItem("value", fontSourceIdentifier, { + sentBySlider: true, + }); this.fontOverviewSettingsController.setItem( "fontLocationSource", sourceLocation, @@ -207,7 +259,7 @@ export class FontOverviewNavigation extends HTMLElement { ); }); - return popupSelect(controller, "value", options); + return locationElement; } _makeGroupByUI() { From df783ca03167093ce4c30929149e015940d7d8f7 Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Wed, 15 Jan 2025 22:56:18 +0100 Subject: [PATCH 097/106] Fix spelling mistakes --- src/fontra/views/fontoverview/panel-navigation.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index c43750cef..707c9daff 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -213,7 +213,7 @@ export class FontOverviewNavigation extends HTMLElement { ...fontSources[fontSourceIdentifier]?.location, }; // A font may not have any font sources, therefore the ?-check // TODO: set the sliders controller. The following does not work: - // this.locationControllerSilders.setItem(this.sourceLocation); + //this.locationControllerSliders.setItem(this.sourceLocation); this.fontOverviewSettingsController.setItem( "fontLocationSource", this.sourceLocation, @@ -229,7 +229,7 @@ export class FontOverviewNavigation extends HTMLElement { this.fontController.axes.axes ); - this.locationControllerSilders = new ObservableController({ + this.locationControllerSliders = new ObservableController({ ...this.sourceLocation, }); @@ -241,10 +241,10 @@ export class FontOverviewNavigation extends HTMLElement { `, }); locationElement.axes = locationAxes; - locationElement.controller = this.locationControllerSilders; + locationElement.controller = this.locationControllerSliders; - this.locationControllerSilders.addListener((event) => { - const sourceLocation = { ...this.locationControllerSilders.model }; + this.locationControllerSliders.addListener((event) => { + const sourceLocation = { ...this.locationControllerSliders.model }; const fontSourceIdentifier = this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( sourceLocation From 8e0077d81e2ec41917d16c541d55b7287c3a4d73 Mon Sep 17 00:00:00 2001 From: Olli Meier Date: Thu, 16 Jan 2025 01:26:24 +0100 Subject: [PATCH 098/106] Do not use this.sourceLocation --- src/fontra/views/fontoverview/panel-navigation.js | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 707c9daff..455ce8485 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -209,14 +209,14 @@ export class FontOverviewNavigation extends HTMLElement { this.locationControllerPopup.addKeyListener("value", (event) => { const fontSourceIdentifier = event.newValue; - this.sourceLocation = { + const sourceLocation = { ...fontSources[fontSourceIdentifier]?.location, }; // A font may not have any font sources, therefore the ?-check // TODO: set the sliders controller. The following does not work: - //this.locationControllerSliders.setItem(this.sourceLocation); + // this.locationControllerSliders.setItem(sourceLocation); this.fontOverviewSettingsController.setItem( "fontLocationSource", - this.sourceLocation, + sourceLocation, { sentFromInput: true } ); }); @@ -229,9 +229,7 @@ export class FontOverviewNavigation extends HTMLElement { this.fontController.axes.axes ); - this.locationControllerSliders = new ObservableController({ - ...this.sourceLocation, - }); + this.locationControllerSliders = new ObservableController({}); const locationElement = html.createDomElement("designspace-location", { style: `grid-column: 1 / -1; From c956e179022df361263292b38a89f202872c6b4a Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 09:26:20 +0100 Subject: [PATCH 099/106] Simplify a bit, no need with withSenderInfo, this is functionally the same --- src/fontra/views/fontoverview/fontoverview.js | 20 ++++++++----------- 1 file changed, 8 insertions(+), 12 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.js b/src/fontra/views/fontoverview/fontoverview.js index 8159f888e..2e66a391e 100644 --- a/src/fontra/views/fontoverview/fontoverview.js +++ b/src/fontra/views/fontoverview/fontoverview.js @@ -278,12 +278,10 @@ export class FontOverviewController extends ViewController { "fontLocationSource", (event) => { if (!event.senderInfo?.fromFontLocationUser) { - this.fontOverviewSettingsController.withSenderInfo( - { fromFontLocationSource: true }, - () => { - this.fontOverviewSettingsController.model.fontLocationUser = - this.fontController.mapSourceLocationToUserLocation(event.newValue); - } + this.fontOverviewSettingsController.setItem( + "fontLocationUser", + this.fontController.mapSourceLocationToUserLocation(event.newValue), + { fromFontLocationSource: true } ); } } @@ -291,12 +289,10 @@ export class FontOverviewController extends ViewController { this.fontOverviewSettingsController.addKeyListener("fontLocationUser", (event) => { if (!event.senderInfo?.fromFontLocationSource) { - this.fontOverviewSettingsController.withSenderInfo( - { fromFontLocationUser: true }, - () => { - this.fontOverviewSettingsController.model.fontLocationSource = - this.fontController.mapUserLocationToSourceLocation(event.newValue); - } + this.fontOverviewSettingsController.setItem( + "fontLocationSource", + this.fontController.mapUserLocationToSourceLocation(event.newValue), + { fromFontLocationUser: true } ); } }); From c1a35cac28897624bfaf13763e413fda224f91be Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 09:26:50 +0100 Subject: [PATCH 100/106] Hook up sliders to settings controller --- .../views/fontoverview/panel-navigation.js | 66 +++++++++---------- 1 file changed, 32 insertions(+), 34 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 455ce8485..d78270694 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -14,6 +14,7 @@ import { labeledTextInput, popupSelect, } from "/core/ui-utils.js"; +import { scheduleCalls } from "/core/utils.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { IconButton } from "/web-components/icon-button.js"; // required for the icon buttons import { showMenu } from "/web-components/menu-panel.js"; @@ -194,7 +195,7 @@ export class FontOverviewNavigation extends HTMLElement { label: fontSources[fontSourceIdentifier].name, })); - this.locationControllerPopup = new ObservableController({ + const controller = new ObservableController({ value: selectedSourceIdentifier(), }); @@ -202,35 +203,31 @@ export class FontOverviewNavigation extends HTMLElement { "fontLocationSource", (event) => { if (!event.senderInfo?.sentFromInput) { - this.locationControllerPopup.model.value = selectedSourceIdentifier(); + controller.setItem("value", selectedSourceIdentifier(), { + sentFromSourceLocationListener: true, + }); } } ); - this.locationControllerPopup.addKeyListener("value", (event) => { + controller.addKeyListener("value", (event) => { const fontSourceIdentifier = event.newValue; const sourceLocation = { ...fontSources[fontSourceIdentifier]?.location, }; // A font may not have any font sources, therefore the ?-check - // TODO: set the sliders controller. The following does not work: - // this.locationControllerSliders.setItem(sourceLocation); - this.fontOverviewSettingsController.setItem( - "fontLocationSource", - sourceLocation, - { sentFromInput: true } - ); + if (!event.senderInfo?.sentFromSourceLocationListener) { + this.fontOverviewSettingsController.setItem( + "fontLocationSource", + sourceLocation, + { sentFromInput: true } + ); + } }); - return popupSelect(this.locationControllerPopup, "value", options); + return popupSelect(controller, "value", options); } async _makeFontSourceSliders() { - const locationAxes = mapAxesFromUserSpaceToSourceSpace( - this.fontController.axes.axes - ); - - this.locationControllerSliders = new ObservableController({}); - const locationElement = html.createDomElement("designspace-location", { style: `grid-column: 1 / -1; min-height: 0; @@ -238,25 +235,26 @@ export class FontOverviewNavigation extends HTMLElement { height: 100%; `, }); - locationElement.axes = locationAxes; - locationElement.controller = this.locationControllerSliders; - - this.locationControllerSliders.addListener((event) => { - const sourceLocation = { ...this.locationControllerSliders.model }; - const fontSourceIdentifier = - this.fontController.fontSourcesInstancer.getLocationIdentifierForLocation( - sourceLocation - ); - this.locationControllerPopup.setItem("value", fontSourceIdentifier, { - sentBySlider: true, - }); - this.fontOverviewSettingsController.setItem( - "fontLocationSource", - sourceLocation, - { sentFromInput: true } - ); + locationElement.axes = this.fontController.axes.axes; + locationElement.values = { ...this.fontOverviewSettings.fontLocationUser }; + + this.fontOverviewSettingsController.addKeyListener("fontLocationUser", (event) => { + if (!event.senderInfo?.sentFromSliders) { + locationElement.values = { ...event.newValue }; + } }); + locationElement.addEventListener( + "locationChanged", + scheduleCalls((event) => { + this.fontOverviewSettingsController.setItem( + "fontLocationUser", + { ...locationElement.values }, + { sentFromSliders: true } + ); + }) + ); + return locationElement; } From cb765c6b45948a636ae876ef3edccc052ff98cf4 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:13:11 +0100 Subject: [PATCH 101/106] Clean up imports --- src/fontra/views/fontoverview/fontoverview.html | 2 -- src/fontra/views/fontoverview/panel-navigation.js | 9 ++------- 2 files changed, 2 insertions(+), 9 deletions(-) diff --git a/src/fontra/views/fontoverview/fontoverview.html b/src/fontra/views/fontoverview/fontoverview.html index 98780da7e..47ae5c328 100644 --- a/src/fontra/views/fontoverview/fontoverview.html +++ b/src/fontra/views/fontoverview/fontoverview.html @@ -8,8 +8,6 @@ Fontra Font Overview - - diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index d78270694..7877dbe33 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -15,6 +15,7 @@ import { popupSelect, } from "/core/ui-utils.js"; import { scheduleCalls } from "/core/utils.js"; +import { DesignspaceLocation } from "/web-components/designspace-location.js"; import { GlyphSearchField } from "/web-components/glyph-search-field.js"; import { IconButton } from "/web-components/icon-button.js"; // required for the icon buttons import { showMenu } from "/web-components/menu-panel.js"; @@ -228,13 +229,7 @@ export class FontOverviewNavigation extends HTMLElement { } async _makeFontSourceSliders() { - const locationElement = html.createDomElement("designspace-location", { - style: `grid-column: 1 / -1; - min-height: 0; - overflow: auto; - height: 100%; - `, - }); + const locationElement = new DesignspaceLocation(); locationElement.axes = this.fontController.axes.axes; locationElement.values = { ...this.fontOverviewSettings.fontLocationUser }; From 7343359e4a6b47ca124ac157e8fcc8972eb7b2bb Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:19:11 +0100 Subject: [PATCH 102/106] Sort of fix scrolling if the sidebar content doesn't fit --- src/fontra/views/fontoverview/fontoverview.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/fontra/views/fontoverview/fontoverview.css b/src/fontra/views/fontoverview/fontoverview.css index f19a191e6..3dd31cb8e 100644 --- a/src/fontra/views/fontoverview/fontoverview.css +++ b/src/fontra/views/fontoverview/fontoverview.css @@ -18,6 +18,7 @@ body { padding: 1em 1em 1em 1em; background-color: var(--ui-element-background-color); height: calc(100vh - var(--top-bar-height)); + overflow: auto; } .font-overview-sidebar-shadow-box { From fe97f77595451ebd133334711a41f4d6812ecf64 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:20:17 +0100 Subject: [PATCH 103/106] Remove unused imports --- src/fontra/views/fontoverview/panel-navigation.js | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index 7877dbe33..d9b72d3f1 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -1,7 +1,3 @@ -import { - makeSparseLocation, - mapAxesFromUserSpaceToSourceSpace, -} from "../core/var-model.js"; import { groupByKeys, groupByProperties } from "/core/glyph-organizer.js"; import * as html from "/core/html-utils.js"; import { translate } from "/core/localization.js"; From 2e8719b132732285300112e3ffe4e043b2e67c30 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:22:00 +0100 Subject: [PATCH 104/106] Function isn't async --- src/fontra/views/fontoverview/panel-navigation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index d9b72d3f1..fb250d5e6 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -135,7 +135,7 @@ export class FontOverviewNavigation extends HTMLElement { id: "location", content: html.div({ class: "font-source-location-container" }, [ await this._makeFontSourcePopup(), - await this._makeFontSourceSliders(), + this._makeFontSourceSliders(), ]), }, { @@ -224,7 +224,7 @@ export class FontOverviewNavigation extends HTMLElement { return popupSelect(controller, "value", options); } - async _makeFontSourceSliders() { + _makeFontSourceSliders() { const locationElement = new DesignspaceLocation(); locationElement.axes = this.fontController.axes.axes; locationElement.values = { ...this.fontOverviewSettings.fontLocationUser }; From 99df272b3fade6182c128e3ccd1ab691ac19b843 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:51:39 +0100 Subject: [PATCH 105/106] Rename variable --- src/fontra/views/fontoverview/panel-navigation.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/fontra/views/fontoverview/panel-navigation.js b/src/fontra/views/fontoverview/panel-navigation.js index fb250d5e6..e2f200f28 100644 --- a/src/fontra/views/fontoverview/panel-navigation.js +++ b/src/fontra/views/fontoverview/panel-navigation.js @@ -185,7 +185,7 @@ export class FontOverviewNavigation extends HTMLElement { this.fontOverviewSettings.fontLocationSource ); - const options = this.fontController + const popupItems = this.fontController .getSortedSourceIdentifiers() .map((fontSourceIdentifier) => ({ value: fontSourceIdentifier, @@ -221,7 +221,7 @@ export class FontOverviewNavigation extends HTMLElement { } }); - return popupSelect(controller, "value", options); + return popupSelect(controller, "value", popupItems); } _makeFontSourceSliders() { From 1a570f9002c3d4b9aca63ed10e175f21d75899b8 Mon Sep 17 00:00:00 2001 From: Just van Rossum Date: Thu, 16 Jan 2025 10:52:37 +0100 Subject: [PATCH 106/106] Rename argument to avoid confustion with other 'options' arguments --- src/fontra/client/core/ui-utils.js | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/src/fontra/client/core/ui-utils.js b/src/fontra/client/core/ui-utils.js index dd873fa7d..b4b559bbb 100644 --- a/src/fontra/client/core/ui-utils.js +++ b/src/fontra/client/core/ui-utils.js @@ -179,9 +179,9 @@ export function labeledTextInput(label, controller, key, options) { return items; } -export function popupSelect(controller, key, options) { +export function popupSelect(controller, key, popupItems) { function findLabel() { - const option = options.find(({ value }) => value === controller.model[key]); + const option = popupItems.find(({ value }) => value === controller.model[key]); return option?.label || ""; } @@ -190,7 +190,7 @@ export function popupSelect(controller, key, options) { }); const menu = new PopupMenu(findLabel(), () => - options.map(({ value, label }) => ({ + popupItems.map(({ value, label }) => ({ title: label, checked: value === controller.model[key], callback: () => { @@ -202,8 +202,8 @@ export function popupSelect(controller, key, options) { return menu; } -export function labeledPopupSelect(label, controller, key, options) { - const inputElement = popupSelect(controller, key, options); +export function labeledPopupSelect(label, controller, key, popupItems) { + const inputElement = popupSelect(controller, key, popupItems); return [labelForElement(label, inputElement), inputElement]; }