From 59fe426e5e16d9d55332e9c9626cc64a35b0d2da Mon Sep 17 00:00:00 2001 From: Leo Vasanko Date: Mon, 28 Sep 2026 15:28:03 +0000 Subject: [PATCH] contact messages: messaging header = flag selector + fused enable toggle MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit The site settings' messaging block now opens with the article editor's LangSelect (the flag dropdown on the shared shell-wide editorLang, same option construction) instead of a plain select, and the enable checkbox is fused into the "messaging" section header — one line for the whole header. The separate enabled field row is gone. --- frontend/src/SiteEditor.vue | 93 ++++++++++++++++++++++--------------- 1 file changed, 55 insertions(+), 38 deletions(-) diff --git a/frontend/src/SiteEditor.vue b/frontend/src/SiteEditor.vue index b07da89..f3c38de 100644 --- a/frontend/src/SiteEditor.vue +++ b/frontend/src/SiteEditor.vue @@ -12,6 +12,9 @@ import { html } from '@codemirror/lang-html' import { cmHighlight, cmTheme } from './cmtheme' import { dropPageCache, loadPlain, runScripts } from './swapdoc' import { apiFetch, apiJson } from 'paskia' +import { editorLang } from './editorLang' +import LangSelect from './LangSelect.vue' +import { flagFor, langName, langSort } from './langs' const props = defineProps({ pagePath: { type: String, default: '' }, @@ -59,22 +62,38 @@ const brand = ref('') const theme = ref('') // --- Messaging (contact) --------------------------------------------------- -// Site-wide contact settings: the enabled toggle and mailto address are -// global; the label (the {contact:} buttons' default and the visitor -// dialog's title) and the email subject are per-language strings — the -// selector switches the two text fields between the original and a -// translation override (stored in the chunk-keyed trans store; auto -// translators fill the same store, so this is the manual-override UI). +// Site-wide contact settings: the enabled toggle (combined with the +// section header) and mailto address are global; the label (the +// {contact:} buttons' default and the visitor dialog's title) and the +// email subject are per-language strings — the LangSelect (the article +// editor's flag dropdown, on the shared shell-wide editorLang) switches +// the two text fields between the original and a translation override +// (stored in the chunk-keyed trans store; auto translators fill the same +// store, so this is the manual-override UI). const contactEnabled = ref(true) const contactEmail = ref('') const contactLabel = ref('') const contactSubject = ref('') const contactLabelOrig = ref('') const contactSubjectOrig = ref('') -const contactLang = ref('') // '' = the original strings +const lang = editorLang // '' = the original strings (the primary language) const primaryLang = ref('en') const translateLangs = ref([]) -const translating = computed(() => contactLang.value && contactLang.value !== primaryLang.value) +const translating = computed(() => lang.value && lang.value !== primaryLang.value) + +// The flag selector's options, built like the article editor's: the +// primary language first (tag ''), then the configured targets in the +// geographic grouping. +const contactLangOptions = computed(() => { + const others = langSort(translateLangs.value.filter((l) => l && l !== primaryLang.value)) + return [primaryLang.value, ...others].map((code) => ({ + tag: code === primaryLang.value ? '' : code, + code, + name: langName(code), + flag: flagFor(code), + primary: code === primaryLang.value, + })) +}) async function onContactLangChange() { if (!translating.value) { @@ -83,27 +102,28 @@ async function onContactLangChange() { return } try { - const s = await apiJson(`/_api/settings?lang=${contactLang.value}`) + const s = await apiJson(`/_api/settings?lang=${lang.value}`) contactLabel.value = s.contact_label_tr || '' contactSubject.value = s.contact_subject_tr || '' } catch { /* keep empty */ } } +watch(lang, onContactLangChange) function onContactInput() { // Capture the language being edited: a debounced save must not land in // whatever language happens to be selected when the timer fires. - const lang = contactLang.value - if (!lang || lang === primaryLang.value) { + const tag = lang.value + if (!tag || tag === primaryLang.value) { contactLabelOrig.value = contactLabel.value contactSubjectOrig.value = contactSubject.value } - debounce('contact', () => saveContact(lang, contactLabel.value, contactSubject.value)) + debounce('contact', () => saveContact(tag, contactLabel.value, contactSubject.value)) } -async function saveContact(lang = contactLang.value, label = '', subject = '') { - if (lang && lang !== primaryLang.value) { +async function saveContact(tag = lang.value, label = '', subject = '') { + if (tag && tag !== primaryLang.value) { // Translation override: only the label/subject apply (empty = drop). - const res = await apiFetch(`/_api/settings?lang=${lang}`, { + const res = await apiFetch(`/_api/settings?lang=${tag}`, { method: 'PUT', headers: { 'content-type': 'application/json' }, body: JSON.stringify({ @@ -607,6 +627,9 @@ onMounted(async () => { parent: brandEl.value, }) await loadSettings() + // The shared editorLang may already point at a translation (picked in + // another tab): load its label/subject overrides. + await onContactLangChange() parseFonts(customCss.value) setCssDocument(customCss.value) applyCustomCss(customCss.value) @@ -736,28 +759,20 @@ onUnmounted(() => {
- messaging - + + messaging +
-