Per-node primary language; home-country flags; grouped lang grid

- Node.language sets an article's primary language, inherited down the
  hierarchy, configured per row in the structure tab; English is now a
  regular language in the lang tab, still the root fallback
- Flags map a base tag to the language's home country (en → GB,
  pt → PT); explicit variant tags resolve their own region
- Lang tab flag grid: geographic group rows, shading-only selection
This commit is contained in:
2026-09-03 03:01:13 +00:00
parent 652f1f82ac
commit fb159f0cb0
14 changed files with 310 additions and 127 deletions
+31 -2
View File
@@ -1,7 +1,10 @@
<script setup>
// Recursive site-structure tree with drag-and-drop ordering (vue-draggable).
// Nodes come from the server (GET /_api/pages via StructureEditor.vue) as
// {slug, path, title, translated, order, published, has_content, children}.
// {slug, path, title, translated, order, published, has_content, language,
// primary, children}. The row's flag (LangSelect) sets the node's primary
// language (language; '' = inherit — dimmed, showing the resolved flag);
// the setting covers the whole subtree.
// With a `lang` prop (StructureEditor's language strip) the titles shown
// are that language's; `translated` marks rows with an actual translation
// (untranslated rows show the original title, dimmed).
@@ -27,6 +30,7 @@
import { inject } from 'vue'
import draggable from 'vuedraggable'
import { slugify } from './slugify'
import LangSelect from './LangSelect.vue'
defineOptions({ name: 'StructureTree' })
const props = defineProps({
@@ -150,6 +154,17 @@ function onEnd() {
@change="handlers.commitSlug(element, $event)"
/>
<span class="acts">
<span
class="row-lang"
:class="{ inherited: !element.language }"
><LangSelect
:model-value="element.language"
:options="handlers.langOptions(element)"
:title="element.language
? `primary language: set on this page (subtree inherits)`
: `primary language: inherited — set it here (subtree inherits)`"
@update:model-value="handlers.setLanguage(element, $event)"
/></span>
<span v-if="!element.published" class="draft">draft</span>
<button
v-if="element.has_content || !element.children.length"
@@ -234,7 +249,7 @@ body.tree-dragging .treelist {
level, not across levels). */
.row {
display: grid;
grid-template-columns: 1.2em minmax(3rem, 1fr) 7rem 5rem;
grid-template-columns: 1.2em minmax(3rem, 1fr) 7rem auto;
align-items: baseline;
gap: 0.35rem;
/* Vertical spacing widens the drop zones: the exposed top strip is the
@@ -303,6 +318,20 @@ body.tree-dragging .treelist {
justify-content: end;
}
/* Row language selector (LangSelect): the effective primary language's
flag; dimmed while the setting is inherited rather than set on the row. */
.row-lang {
display: inline-flex;
}
.row-lang.inherited :deep(.lang-current) {
opacity: 0.45;
}
.row-lang.inherited:hover :deep(.lang-current) {
opacity: 0.85;
}
.draft {
color: var(--muted);
font-size: 0.75rem;