feat: article editor header redesign
This commit is contained in:
1 parent
58fd753559
commit
680b9a1308
6 files changed
+34
-36
No files matched your search
@@ -84,15 +84,15 @@ class Component extends DCLogic {
|
||||
const LONGT = 'Comment nous chiffrons une rénovation de salle de bain, poste par poste, avec les coûts cachés derrière les carreaux, sous la baignoire et autour des canalisations anciennes, expliqués avant la commande du premier carreau et de la première vanne'
|
||||
const TitleIn = (L, o) => {
|
||||
const st = o.tst || 'pristine', cap = o.cap, lab = 'Title (' + L.n + ')'
|
||||
if (!cap.e) return D('display:flex;flex-direction:column;gap:2px', S('font-size:12px;' + MU, lab), D('display:flex;align-items:center;gap:8px;min-height:' + (m ? 44 : 36) + 'px', A('div', { dir: L.dir, lang: L.lang, role: 'textbox', 'aria-readonly': 'true', 'aria-label': lab, tabIndex: 0 }, 'flex:1;min-width:0;font:600 ' + (m ? 18 : 20) + 'px/28px \'IBM Plex Sans\',sans-serif;' + HL, L.t), Ic('lock', 14)))
|
||||
if (!cap.e) return D('display:flex;flex-direction:column;gap:2px', D('display:flex;align-items:center;gap:8px;min-height:' + (m ? 44 : 36) + 'px', A('div', { dir: L.dir, lang: L.lang, role: 'textbox', 'aria-readonly': 'true', 'aria-label': lab, tabIndex: 0 }, 'flex:1;min-width:0;font:600 ' + (m ? 18 : 20) + 'px/28px \'IBM Plex Sans\',sans-serif;' + HL, L.t), Ic('lock', 14)))
|
||||
const val = { invalid: '', short: 'Sa', long: LONGT.slice(0, 203), edit: L.t + ' en 2026', unsaved: L.t + ' en 2026' }[st] ?? (o.titleVal ?? L.t)
|
||||
const err = ['invalid', 'short', 'long', 'failed'].includes(st), on = ['focus', 'edit'].includes(st), cnt = ['focus', 'edit', 'short', 'long'].includes(st)
|
||||
const msg = { invalid: 'Enter a title', short: 'Use at least 3 characters', long: 'Use 200 characters or fewer' }[st]
|
||||
return D('display:flex;flex-direction:column;gap:4px', S('font-size:12px;' + MU, lab),
|
||||
D('display:flex;align-items:center;gap:8px;min-height:' + (m ? 44 : 40) + 'px;padding:2px 10px;border:1px solid ' + (err ? 'var(--ui-error)' : on ? 'var(--ui-primary)' : 'var(--ui-border-accented)') + ';background:var(--ui-bg);' + (st === 'focus' ? 'outline:2px solid var(--ui-primary);outline-offset:1px' : ''),
|
||||
return D('display:flex;flex-direction:column;gap:2px',
|
||||
D('display:flex;align-items:center;gap:8px;min-height:' + (m ? 44 : 40) + 'px;padding:2px 4px;border:0;border-bottom:' + (on || err ? 2 : 1) + 'px solid ' + (err ? 'var(--ui-error)' : on ? 'var(--ui-primary)' : 'var(--ui-border-accented)') + ';background:' + (on ? 'var(--ui-bg)' : 'transparent') + ';' + (st === 'focus' ? 'box-shadow:0 2px 0 0 var(--ui-primary)' : ''),
|
||||
A('div', { dir: L.dir, lang: L.lang, role: 'textbox', 'aria-label': lab, 'aria-invalid': err || undefined, 'aria-describedby': 'title-help', tabIndex: 0 }, 'flex:1;min-width:0;font:600 ' + (m ? 18 : 20) + 'px/28px \'IBM Plex Sans\',sans-serif;' + (st === 'invalid' ? MU : HL) + ';text-wrap:pretty;' + (m ? '' : 'overflow:hidden;text-overflow:ellipsis;white-space:nowrap'), st === 'invalid' ? 'Title' : val),
|
||||
cnt && S(mono + ';flex-shrink:0;color:' + (err ? 'var(--ui-error)' : 'var(--ui-text-muted)'), val.length + ' / 200'), st === 'saving' ? Ic('loader-circle', 14) : st === 'failed' ? Ic('circle-x', 14) : Ic('pencil', 14)),
|
||||
A('div', { id: 'title-help', role: err ? 'alert' : undefined }, 'display:flex;gap:8px;align-items:center;flex-wrap:wrap;font-size:12px;line-height:18px;' + (err ? 'color:var(--ui-error)' : MU),
|
||||
A('div', { id: 'title-help', role: err ? 'alert' : undefined }, 'display:flex;gap:8px;align-items:center;flex-wrap:wrap;padding:0 4px;font-size:12px;line-height:18px;' + (err ? 'color:var(--ui-error)' : MU),
|
||||
err && Ic('circle-x', 14), msg || (st === 'failed' ? 'Couldn\'t save the title. Your text is kept.' : st === 'saving' ? 'Saving title…' : (on || st === 'unsaved') ? 'Changing the title doesn\'t change the address.' : null), st === 'failed' && Btn('Try again', 'secondary', { sm: true })))
|
||||
}
|
||||
const Acts = (L, o) => {
|
||||
@@ -128,7 +128,8 @@ class Component extends DCLogic {
|
||||
const status = o.saving ? Bd('Saving…', 'neutral', 'loader-circle') : o.saveFail ? Bd('Save failed', 'error', 'circle-x') : o.pubFail || o.saved ? Bd('Saved', 'success', 'check') : (o.dirty || o.tst === 'unsaved') ? Bd('Unsaved changes', 'neutral', 'circle-dot') : null
|
||||
const fresh = o.fresh && (nr ? A('span', { 'aria-label': o.fresh, title: o.fresh }, 'display:inline-flex;align-items:center;justify-content:center;width:24px;height:20px;flex-shrink:0;border:1px solid currentColor;background:var(--ui-bg);color:var(--ui-warning)', Ic('refresh-cw', 12)) : Fr(o.fresh))
|
||||
const left = D('flex:1 1 auto;min-width:0;display:flex;align-items:center;gap:8px;flex-wrap:wrap', LangBtn(L.n, { code: L.c, open: !!o.open }), Pub(o.pub), status, fresh, !cap.e && Bd('Read only', 'neutral', 'lock'))
|
||||
const right = !m && D('display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto', Btn(nr ? '' : refL, 'secondary', { ic: 'columns-2', al: refL }), a.un && !nr && Btn(a.un.l), ...a.sec.map(x2 => Btn(x2.l, 'secondary', { dis: x2.dis })), pb(a.prim), items.length ? Btn('', 'secondary', { ic: 'ellipsis', al: 'More actions' }) : null)
|
||||
const right = !m && D('display:flex;align-items:center;gap:8px;flex-shrink:0;margin-left:auto;height:40px', Btn(nr ? '' : refL, 'secondary', { ic: 'columns-2', al: refL }), a.un && !nr && Btn(a.un.l), ...a.sec.map(x2 => Btn(x2.l, 'secondary', { dis: x2.dis })), pb(a.prim), items.length ? Btn('', 'secondary', { ic: 'ellipsis', al: 'More actions' }) : null)
|
||||
if (!m) return D('flex:1 1 100%;min-width:0;display:flex;align-items:flex-start;gap:12px;flex-wrap:' + (nr ? 'wrap' : 'nowrap'), D('height:40px;display:flex;align-items:center;' + MU, Ic('arrow-left', 16)), D('display:flex;align-items:center;gap:8px;height:40px;flex-shrink:0;flex-wrap:nowrap', ...[LangBtn(L.n, { code: L.c, open: !!o.open }), Pub(o.pub), status, fresh, !cap.e && Bd('Read only', 'neutral', 'lock')].filter(Boolean)), D('flex:1 1 ' + (nr ? '100%' : '240px') + ';min-width:0;order:' + (nr ? 3 : 0), TitleIn(L, o)), right)
|
||||
return D('flex:1 1 100%;min-width:0;display:flex;flex-direction:column;gap:10px', D('display:flex;align-items:flex-start;gap:8px', !m && D('height:60px;display:flex;align-items:flex-end;' + MU, Ic('arrow-left', 16)), D('flex:1;min-width:0', TitleIn(L, o))), D('display:flex;align-items:center;gap:12px;flex-wrap:wrap', left, right))
|
||||
}
|
||||
const MBar = (L, o) => {
|
||||
|
||||
@@ -2096,7 +2096,7 @@ window.LOC = {
|
||||
],
|
||||
[
|
||||
"Header priority",
|
||||
"Left to right: title input (own row), language dropdown, publication badge, status badge (unsaved, saving, saved, failed), freshness badge, Read only tag; then reference button, Unpublish, Save, primary, overflow. At most one filled button. Collapse order: reference label, Unpublish to overflow, freshness to icon",
|
||||
"Left to right: language dropdown, publication badge, status badge (unsaved, saving, saved, failed), freshness badge, Read only tag, title input (fills the remaining width, same row on desktop), then reference button, Unpublish, Save, primary, overflow. At most one filled button. Collapse order: reference label, Unpublish to overflow, freshness to icon",
|
||||
"The primary action is never hidden",
|
||||
"Editor header",
|
||||
"None",
|
||||
@@ -2426,7 +2426,7 @@ window.LOC = {
|
||||
],
|
||||
[
|
||||
"Title input",
|
||||
"Label \"Title (French)\"; aria-describedby points to the help or error text; invalid sets aria-invalid and the message is an alert",
|
||||
"Accessible name \"Title (French)\", no visible label (the language dropdown beside it names the version); aria-describedby points to the help or error text; invalid sets aria-invalid and the message is an alert",
|
||||
"Stays in the field; on Try again, back to the field",
|
||||
"Polite: \"Saving title\", \"Title saved\"; errors are announced"
|
||||
],
|
||||
@@ -2869,7 +2869,7 @@ window.LOC = {
|
||||
"rows": [
|
||||
[
|
||||
"Title editing",
|
||||
"Inline input in heading style. States: pristine, focus, editing, unsaved, invalid (\"Enter a title\"), too short, too long, saving, failed (value kept). Bounds 3 to 200 characters. Accessible label \"Title (French)\". Editing the title never changes the slug"
|
||||
"Inline underline input in heading style, on the same row as the language, badges and actions on desktop (no box, no visible label). States: pristine, focus, editing, unsaved, invalid (\"Enter a title\"), too short, too long, saving, failed (value kept). Bounds 3 to 200 characters. Accessible label \"Title (French)\". Editing the title never changes the slug"
|
||||
],
|
||||
[
|
||||
"Slug",
|
||||
@@ -2970,7 +2970,7 @@ window.LOC = {
|
||||
"rows": [
|
||||
[
|
||||
"1",
|
||||
"Title input (own row, heading style)",
|
||||
"Title input (underline, heading style; own row on mobile, shares the header row on desktop)",
|
||||
"Full width",
|
||||
"Full width",
|
||||
"Full width"
|
||||
@@ -3169,7 +3169,7 @@ window.LOC = {
|
||||
],
|
||||
[
|
||||
"Focus",
|
||||
"Primary outline",
|
||||
"Primary 2px underline",
|
||||
"\"Changing the title doesn't change the address.\"",
|
||||
"Off"
|
||||
],
|
||||
|
||||
Reference in new issue
Block a user