From 83e3ee14aca07266202704f39705ba8b691a8456 Mon Sep 17 00:00:00 2001 From: Marc Foley Date: Tue, 10 Nov 2026 15:37:49 +0000 Subject: [PATCH 1/4] Open three category panels from Start script tagging The dialog now takes one script and one category, both single selects. OK adds the placeholders and replaces the panels with three views of the category: the new placeholders for the script sorted by score, every tagging for the script sorted by family, and every tagging sorted by score. Category panels can be opened with a preset sort, script filter and placeholders-only state. --- src/App.vue | 15 +++++++++-- src/components/Panel.vue | 6 ++++- src/components/ScriptStarter.vue | 39 ++++++++++++++++------------- src/components/TagsByCategories.vue | 19 +++++++++++--- 4 files changed, 55 insertions(+), 24 deletions(-) diff --git a/src/App.vue b/src/App.vue index 7fe9ce5..7aecd74 100644 --- a/src/App.vue +++ b/src/App.vue @@ -1,6 +1,6 @@ @@ -125,17 +127,18 @@ function submit() {

Start script tagging

- Adds a 0-score placeholder for every family that supports the script and every - category below. Families with a wght axis get a variable placeholder at the wght - extremes, and at the wdth extremes too when they have wdth. Families that already - have any tagging for a category, for all scripts or for this script, are skipped. + Adds a 0-score placeholder for the category to every family that supports the script. + Families with a wght axis get a variable placeholder at the wght extremes, and at the + wdth extremes too when they have wdth. Families that already have any tagging for the + category, for all scripts or for this script, are skipped. OK then opens three panels + for the category: the new placeholders, every tagging for the script, and every tagging.

Script

-

Categories

- +

Category

+
{{ families.length }} families support {{ script }}: @@ -145,7 +148,7 @@ function submit() {

- +
diff --git a/src/components/TagsByCategories.vue b/src/components/TagsByCategories.vue index d1a7551..aac04e9 100644 --- a/src/components/TagsByCategories.vue +++ b/src/components/TagsByCategories.vue @@ -20,18 +20,31 @@ const props = defineProps({ vfDisplayMode: { type: String as () => 'animated' | 'list', default: 'animated' + }, + // Initial state of the controls, for panels opened with a preset + initialSortBy: { + type: String, + default: 'family' + }, + initialScriptFilter: { + type: Array as () => string[], + default: () => [] + }, + initialPlaceholdersOnly: { + type: Boolean, + default: false } }); const selectedCategories = ref(props.categories); -const sortBy = ref('family'); // Default sorting option +const sortBy = ref(props.initialSortBy); const tagFilter = ref(''); const axisFilter = ref(''); const reverseTags = ref(false); const variableOnly = ref(false); const staticOnly = ref(false); -const scriptFilter = ref([]); -const placeholdersOnly = ref(false); +const scriptFilter = ref([...props.initialScriptFilter]); +const placeholdersOnly = ref(props.initialPlaceholdersOnly); const sampleText = ref(''); // Every script any font supports, from the family metadata subsets From 888d9ba5e4523d95d299e3753f122eccf73534aa Mon Sep 17 00:00:00 2001 From: Marc Foley Date: Tue, 10 Nov 2026 15:43:11 +0000 Subject: [PATCH 2/4] Set Latin and script sample text on the panels from Start script tagging New src/pangrams.ts holds a sample per script, keyed by the subset names in the family metadata: a pangram where a known one exists, else the first line of the Universal Declaration of Human Rights. OK in the dialog puts the Latin pangram and the chosen script's sample into the sample text of all three panels, so every preview shows both. Category panels can be opened with a preset sample text. --- src/App.vue | 9 +++-- src/components/Panel.vue | 2 ++ src/components/TagsByCategories.vue | 6 +++- src/pangrams.ts | 55 +++++++++++++++++++++++++++++ 4 files changed, 68 insertions(+), 4 deletions(-) create mode 100644 src/pangrams.ts diff --git a/src/App.vue b/src/App.vue index 7aecd74..dc9e0ee 100644 --- a/src/App.vue +++ b/src/App.vue @@ -7,6 +7,7 @@ import type { Panel } from './components/Panel.vue'; import type { FilterSet } from './components/AddTags.vue'; import { EventBus } from './eventbus'; import { SCRIPT_TAGGING, LINT_RULES } from './config'; +import { sampleTextFor } from './pangrams'; let appLoaded = ref(false); let showUndefined = ref(false); @@ -56,10 +57,12 @@ function removePanel(idx: number) { panels.value.splice(idx, 1); } async function startScriptTagging({ script, category }: { script: string; category: string }) { panels.value = []; await nextTick(); + // Every preview shows Latin and the script side by side + const sampleText = sampleTextFor([script]); panels.value = [ - { type: 'categories', categories: [category], sortBy: 'score', scriptFilter: [script], placeholdersOnly: true }, - { type: 'categories', categories: [category], sortBy: 'family', scriptFilter: [script] }, - { type: 'categories', categories: [category], sortBy: 'score' }, + { type: 'categories', categories: [category], sortBy: 'score', scriptFilter: [script], placeholdersOnly: true, sampleText }, + { type: 'categories', categories: [category], sortBy: 'family', scriptFilter: [script], sampleText }, + { type: 'categories', categories: [category], sortBy: 'score', sampleText }, ]; } function shiftLeft(idx: number) { diff --git a/src/components/Panel.vue b/src/components/Panel.vue index 6ac2645..b0c852b 100644 --- a/src/components/Panel.vue +++ b/src/components/Panel.vue @@ -10,6 +10,7 @@ type CategoriesPanel = { sortBy?: string; scriptFilter?: string[]; placeholdersOnly?: boolean; + sampleText?: string; }; type TodoPanel = { type: "todo"; // Type of panel @@ -65,6 +66,7 @@ onMounted(() => { :showUndefined="props.showUndefined" :vfDisplayMode="props.vfDisplayMode"> diff --git a/src/components/TagsByCategories.vue b/src/components/TagsByCategories.vue index aac04e9..d0edae8 100644 --- a/src/components/TagsByCategories.vue +++ b/src/components/TagsByCategories.vue @@ -33,6 +33,10 @@ const props = defineProps({ initialPlaceholdersOnly: { type: Boolean, default: false + }, + initialSampleText: { + type: String, + default: '' } }); @@ -45,7 +49,7 @@ const variableOnly = ref(false); const staticOnly = ref(false); const scriptFilter = ref([...props.initialScriptFilter]); const placeholdersOnly = ref(props.initialPlaceholdersOnly); -const sampleText = ref(''); +const sampleText = ref(props.initialSampleText); // Every script any font supports, from the family metadata subsets const scriptOptions = computed(() => { diff --git a/src/pangrams.ts b/src/pangrams.ts new file mode 100644 index 0000000..0e3a653 --- /dev/null +++ b/src/pangrams.ts @@ -0,0 +1,55 @@ +// Sample text per script, keyed by the subset names in the family metadata. +// Pangrams where a well-known one exists, else the first line of the Universal +// Declaration of Human Rights in a language of that script. + +export const LATIN_PANGRAM = "The quick brown fox jumps over the lazy dog."; + +export const PANGRAMS: Record = { + latin: LATIN_PANGRAM, + vietnamese: "Tôi có thể ăn thủy tinh mà không hại gì.", + cyrillic: "Съешь же ещё этих мягких французских булок, да выпей чаю.", + greek: "Ξεσκεπάζω την ψυχοφθόρα βδελυγμία.", + armenian: "Բել դղյակի ձախ ժամն օֆ ազգությանը ցպահանջ չճշտած վնաս էր և փառք։", + georgian: "ყველა ადამიანი იბადება თავისუფალი და თანასწორი თავისი ღირსებითა და უფლებებით.", + hebrew: "דג סקרן שט בים מאוכזב ולפתע מצא חברה.", + arabic: "نص حكيم له سر قاطع وذو شأن عظيم مكتوب على ثوب أخضر ومغلف بجلد أزرق.", + syriac: "ܟܠ ܒܪܢܫܐ ܒܪܝܠܗ ܚܐܪܐ ܘܒܪܒܪ ܓܘ ܐܝܩܪܐ ܘܙܕܩ̈ܐ.", + thaana: "ހުރިހާ އިންސާނުން ވެސް އުފަންވަނީ މިނިވަންކަމާއި ހަމަހަމަކަން ލިބިގެންވާ ބައެއްގެ ގޮތުގައެވެ.", + ethiopic: "የሰው ልጅ ሁሉ ሲወለድ ነጻና በክብርና በመብትም እኩልነት ያለው ነው።", + devanagari: "सभी मनुष्यों को गौरव और अधिकारों के मामले में जन्मजात स्वतन्त्रता और समानता प्राप्त है।", + bengali: "সমস্ত মানুষ স্বাধীনভাবে সমান মর্যাদা এবং অধিকার নিয়ে জন্মগ্রহণ করে।", + gurmukhi: "ਸਾਰਾ ਮਨੁੱਖੀ ਪਰਿਵਾਰ ਆਪਣੀ ਮਹਿਮਾ, ਸ਼ਾਨ ਅਤੇ ਹੱਕਾਂ ਦੇ ਪੱਖੋਂ ਜਨਮ ਤੋਂ ਹੀ ਆਜ਼ਾਦ ਹੈ।", + gujarati: "પ્રતિષ્ઠા અને અધિકારોની દૃષ્ટિએ સર્વ માનવો જન્મથી સ્વતંત્ર અને સમાન હોય છે.", + oriya: "ସବୁ ମଣିଷ ଜନ୍ମରୁ ସ୍ୱାଧୀନ ଓ ସମ୍ମାନ ଏବଂ ଅଧିକାରରେ ସମାନ।", + tamil: "மனிதப் பிறவியினர் சகலரும் சுதந்திரமாகவே பிறக்கின்றனர்.", + telugu: "ప్రతిపత్తిస్వత్వముల విషయమున మానవులెల్లరును జన్మతః స్వతంత్రులును సమానులును నగుదురు.", + kannada: "ಎಲ್ಲಾ ಮಾನವರೂ ಸ್ವತಂತ್ರರಾಗಿಯೇ ಜನಿಸಿದ್ದಾರೆ, ಹಾಗೂ ಘನತೆ ಮತ್ತು ಹಕ್ಕುಗಳಲ್ಲಿ ಸಮಾನರಾಗಿದ್ದಾರೆ.", + malayalam: "മനുഷ്യരെല്ലാവരും തുല്യാവകാശങ്ങളോടും അന്തസ്സോടും സ്വാതന്ത്ര്യത്തോടുംകൂടി ജനിച്ചവരാണ്.", + sinhala: "සියලු මනුෂ්‍යයෝ නිදහස්ව උපත ලබා ඇත. ගරුත්වයෙන් හා අයිතිවාසිකම්වලින් සමාන වෙති.", + thai: "มนุษย์ทั้งหลายเกิดมามีอิสระและเสมอภาคกันในเกียรติศักดิ์และสิทธิ", + lao: "ມະນຸດທຸກຄົນເກີດມາມີສິດເສລີພາບ ແລະ ສະເໝີໜ້າກັນໃນທາງກຽດຕິສັກ ແລະ ທາງສິດດ້ວຍ", + khmer: "មនុស្សទាំងអស់ កើតមកមានសេរីភាព និងសមភាព ក្នុងផ្នែកសេចក្ដីថ្លៃថ្នូរនិងសិទ្ធិ។", + myanmar: "လူတိုင်းသည် တူညီ လွတ်လပ်သော ဂုဏ်သိက္ခာဖြင့် လည်းကောင်း၊ တူညီလွတ်လပ်သော အခွင့်အရေးများဖြင့် လည်းကောင်း မွေးဖွားလာသူများ ဖြစ်သည်။", + tibetan: "འགྲོ་བ་མིའི་རིགས་རྒྱུད་ཡོངས་ལ་སྐྱེས་ཙམ་ཉིད་ནས་ཆེ་མཐོངས་དང་ཐོབ་ཐང་གི་རང་དབང་འདྲ་མཉམ་དུ་ཡོད།", + japanese: "いろはにほへと ちりぬるを わかよたれそ つねならむ", + korean: "키스의 고유조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다.", + "chinese-simplified": "视野无限广,窗外有蓝天。", + "chinese-traditional": "視野無限廣,窗外有藍天。", + "chinese-hongkong": "視野無限廣,窗外有藍天。", + cherokee: "ᏂᎦᏓ ᎠᏂᏴᏫ ᏂᎨᎫᏓᎸᎾ ᎠᎴ ᎤᏂᎶᏓ ᎤᏂᎸᏅᏓ.", + "canadian-aboriginal": "ᐃᓄᒃᑎᑐᑦ ᑎᑎᕋᐅᓯᖅ", +}; + +export function hasPangram(script: string): boolean { + return script in PANGRAMS; +} + +// Latin first, then one sample per other script that has one. Scripts without a +// sample add nothing, so the result is never empty. +export function sampleTextFor(scripts: string[]): string { + const parts = [LATIN_PANGRAM]; + for (const script of scripts) { + if (script !== "latin" && hasPangram(script)) parts.push(PANGRAMS[script]); + } + return parts.join(" "); +} From 69a2bf15bdb6a74fb79c70d537c13f4a4209f1bc Mon Sep 17 00:00:00 2001 From: Marc Foley Date: Tue, 10 Nov 2026 15:45:22 +0000 Subject: [PATCH 3/4] Shorten the script samples to two words Latin plus one script is now four words at most, so previews stay short. --- src/pangrams.ts | 84 ++++++++++++++++++++++++------------------------- 1 file changed, 41 insertions(+), 43 deletions(-) diff --git a/src/pangrams.ts b/src/pangrams.ts index 0e3a653..8400ad9 100644 --- a/src/pangrams.ts +++ b/src/pangrams.ts @@ -1,55 +1,53 @@ // Sample text per script, keyed by the subset names in the family metadata. -// Pangrams where a well-known one exists, else the first line of the Universal -// Declaration of Human Rights in a language of that script. +// Two words at most per script, so Latin plus one script is four words at most. -export const LATIN_PANGRAM = "The quick brown fox jumps over the lazy dog."; +export const LATIN_SAMPLE = "Hello world"; -export const PANGRAMS: Record = { - latin: LATIN_PANGRAM, - vietnamese: "Tôi có thể ăn thủy tinh mà không hại gì.", - cyrillic: "Съешь же ещё этих мягких французских булок, да выпей чаю.", - greek: "Ξεσκεπάζω την ψυχοφθόρα βδελυγμία.", - armenian: "Բել դղյակի ձախ ժամն օֆ ազգությանը ցպահանջ չճշտած վնաս էր և փառք։", - georgian: "ყველა ადამიანი იბადება თავისუფალი და თანასწორი თავისი ღირსებითა და უფლებებით.", - hebrew: "דג סקרן שט בים מאוכזב ולפתע מצא חברה.", - arabic: "نص حكيم له سر قاطع وذو شأن عظيم مكتوب على ثوب أخضر ومغلف بجلد أزرق.", - syriac: "ܟܠ ܒܪܢܫܐ ܒܪܝܠܗ ܚܐܪܐ ܘܒܪܒܪ ܓܘ ܐܝܩܪܐ ܘܙܕܩ̈ܐ.", - thaana: "ހުރިހާ އިންސާނުން ވެސް އުފަންވަނީ މިނިވަންކަމާއި ހަމަހަމަކަން ލިބިގެންވާ ބައެއްގެ ގޮތުގައެވެ.", - ethiopic: "የሰው ልጅ ሁሉ ሲወለድ ነጻና በክብርና በመብትም እኩልነት ያለው ነው።", - devanagari: "सभी मनुष्यों को गौरव और अधिकारों के मामले में जन्मजात स्वतन्त्रता और समानता प्राप्त है।", - bengali: "সমস্ত মানুষ স্বাধীনভাবে সমান মর্যাদা এবং অধিকার নিয়ে জন্মগ্রহণ করে।", - gurmukhi: "ਸਾਰਾ ਮਨੁੱਖੀ ਪਰਿਵਾਰ ਆਪਣੀ ਮਹਿਮਾ, ਸ਼ਾਨ ਅਤੇ ਹੱਕਾਂ ਦੇ ਪੱਖੋਂ ਜਨਮ ਤੋਂ ਹੀ ਆਜ਼ਾਦ ਹੈ।", - gujarati: "પ્રતિષ્ઠા અને અધિકારોની દૃષ્ટિએ સર્વ માનવો જન્મથી સ્વતંત્ર અને સમાન હોય છે.", - oriya: "ସବୁ ମଣିଷ ଜନ୍ମରୁ ସ୍ୱାଧୀନ ଓ ସମ୍ମାନ ଏବଂ ଅଧିକାରରେ ସମାନ।", - tamil: "மனிதப் பிறவியினர் சகலரும் சுதந்திரமாகவே பிறக்கின்றனர்.", - telugu: "ప్రతిపత్తిస్వత్వముల విషయమున మానవులెల్లరును జన్మతః స్వతంత్రులును సమానులును నగుదురు.", - kannada: "ಎಲ್ಲಾ ಮಾನವರೂ ಸ್ವತಂತ್ರರಾಗಿಯೇ ಜನಿಸಿದ್ದಾರೆ, ಹಾಗೂ ಘನತೆ ಮತ್ತು ಹಕ್ಕುಗಳಲ್ಲಿ ಸಮಾನರಾಗಿದ್ದಾರೆ.", - malayalam: "മനുഷ്യരെല്ലാവരും തുല്യാവകാശങ്ങളോടും അന്തസ്സോടും സ്വാതന്ത്ര്യത്തോടുംകൂടി ജനിച്ചവരാണ്.", - sinhala: "සියලු මනුෂ්‍යයෝ නිදහස්ව උපත ලබා ඇත. ගරුත්වයෙන් හා අයිතිවාසිකම්වලින් සමාන වෙති.", - thai: "มนุษย์ทั้งหลายเกิดมามีอิสระและเสมอภาคกันในเกียรติศักดิ์และสิทธิ", - lao: "ມະນຸດທຸກຄົນເກີດມາມີສິດເສລີພາບ ແລະ ສະເໝີໜ້າກັນໃນທາງກຽດຕິສັກ ແລະ ທາງສິດດ້ວຍ", - khmer: "មនុស្សទាំងអស់ កើតមកមានសេរីភាព និងសមភាព ក្នុងផ្នែកសេចក្ដីថ្លៃថ្នូរនិងសិទ្ធិ។", - myanmar: "လူတိုင်းသည် တူညီ လွတ်လပ်သော ဂုဏ်သိက္ခာဖြင့် လည်းကောင်း၊ တူညီလွတ်လပ်သော အခွင့်အရေးများဖြင့် လည်းကောင်း မွေးဖွားလာသူများ ဖြစ်သည်။", - tibetan: "འགྲོ་བ་མིའི་རིགས་རྒྱུད་ཡོངས་ལ་སྐྱེས་ཙམ་ཉིད་ནས་ཆེ་མཐོངས་དང་ཐོབ་ཐང་གི་རང་དབང་འདྲ་མཉམ་དུ་ཡོད།", - japanese: "いろはにほへと ちりぬるを わかよたれそ つねならむ", - korean: "키스의 고유조건은 입술끼리 만나야 하고 특별한 기술은 필요치 않다.", - "chinese-simplified": "视野无限广,窗外有蓝天。", - "chinese-traditional": "視野無限廣,窗外有藍天。", - "chinese-hongkong": "視野無限廣,窗外有藍天。", - cherokee: "ᏂᎦᏓ ᎠᏂᏴᏫ ᏂᎨᎫᏓᎸᎾ ᎠᎴ ᎤᏂᎶᏓ ᎤᏂᎸᏅᏓ.", - "canadian-aboriginal": "ᐃᓄᒃᑎᑐᑦ ᑎᑎᕋᐅᓯᖅ", +export const SAMPLES: Record = { + latin: LATIN_SAMPLE, + vietnamese: "Xin chào", + cyrillic: "Привет мир", + greek: "Καλημέρα κόσμε", + armenian: "Բարև աշխարհ", + georgian: "გამარჯობა მსოფლიო", + hebrew: "שלום עולם", + arabic: "مرحبا بالعالم", + syriac: "ܫܠܡܐ ܥܠܡܐ", + ethiopic: "ሰላም ዓለም", + devanagari: "नमस्ते दुनिया", + bengali: "নমস্কার বিশ্ব", + gurmukhi: "ਨਮਸਤੇ ਦੁਨੀਆ", + gujarati: "નમસ્તે દુનિયા", + oriya: "ନମସ୍କାର ଦୁନିଆ", + tamil: "வணக்கம் உலகம்", + telugu: "నమస్కారం ప్రపంచం", + kannada: "ನಮಸ್ಕಾರ ಜಗತ್ತು", + malayalam: "നമസ്കാരം ലോകം", + sinhala: "ආයුබෝවන් ලෝකය", + thai: "สวัสดี ชาวโลก", + lao: "ສະບາຍດີ ໂລກ", + khmer: "សួស្តី ពិភពលោក", + myanmar: "မင်္ဂလာပါ ကမ္ဘာ", + tibetan: "བཀྲ་ཤིས་བདེ་ལེགས།", + japanese: "こんにちは 世界", + korean: "안녕 세상", + "chinese-simplified": "你好 世界", + "chinese-traditional": "你好 世界", + "chinese-hongkong": "你好 世界", + cherokee: "ᎣᏏᏲ ᎡᎶᎯ", + "canadian-aboriginal": "ᐊᐃ ᓄᓇ", }; -export function hasPangram(script: string): boolean { - return script in PANGRAMS; +export function hasSample(script: string): boolean { + return script in SAMPLES; } -// Latin first, then one sample per other script that has one. Scripts without a -// sample add nothing, so the result is never empty. +// Latin first, then the sample for each other script that has one. Scripts +// without a sample add nothing, so the result is never empty. export function sampleTextFor(scripts: string[]): string { - const parts = [LATIN_PANGRAM]; + const parts = [LATIN_SAMPLE]; for (const script of scripts) { - if (script !== "latin" && hasPangram(script)) parts.push(PANGRAMS[script]); + if (script !== "latin" && hasSample(script)) parts.push(SAMPLES[script]); } return parts.join(" "); } From 41dc32bbefe4f3eb39d9b919df34e1120566a720 Mon Sep 17 00:00:00 2001 From: Marc Foley Date: Tue, 10 Nov 2026 15:50:34 +0000 Subject: [PATCH 4/4] Keep the default sample text in the third panel from Start script tagging That panel lists every family for the category, most without the script. --- src/App.vue | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/App.vue b/src/App.vue index dc9e0ee..99f4e9b 100644 --- a/src/App.vue +++ b/src/App.vue @@ -57,12 +57,13 @@ function removePanel(idx: number) { panels.value.splice(idx, 1); } async function startScriptTagging({ script, category }: { script: string; category: string }) { panels.value = []; await nextTick(); - // Every preview shows Latin and the script side by side + // The two script panels show Latin and the script side by side. The third + // panel lists every family, most without the script, so it keeps the default. const sampleText = sampleTextFor([script]); panels.value = [ { type: 'categories', categories: [category], sortBy: 'score', scriptFilter: [script], placeholdersOnly: true, sampleText }, { type: 'categories', categories: [category], sortBy: 'family', scriptFilter: [script], sampleText }, - { type: 'categories', categories: [category], sortBy: 'score', sampleText }, + { type: 'categories', categories: [category], sortBy: 'score' }, ]; } function shiftLeft(idx: number) {