80 lines
9.3 KiB
HTML
80 lines
9.3 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
<script src="./support.js"></script>
|
|
</head>
|
|
<body>
|
|
<x-dc>
|
|
<helmet>
|
|
<meta name="design_doc_mode" content="canvas">
|
|
<link rel="icon" href="brand/favicon.svg">
|
|
<link href="https://fonts.googleapis.com/css2?family=IBM+Plex+Sans:wght@400;500;600&family=IBM+Plex+Mono:wght@400;500&display=swap" rel="stylesheet">
|
|
<style>body{margin:0;font-family:'IBM Plex Sans',sans-serif;font-size:13px;line-height:20px}*{box-sizing:border-box}a{color:inherit;text-underline-offset:3px}a:hover{opacity:.8}code{font-family:'IBM Plex Mono',monospace;font-size:12px}</style>
|
|
</helmet>
|
|
<div ref="{{ rootRef }}" data-screen-label="Schema screens" style="background:var(--rc-canvas);color:var(--ui-text);padding:64px;display:flex;flex-direction:column;gap:72px;width:max-content;min-width:100%">
|
|
<div style="display:flex;align-items:flex-end;gap:32px;max-width:1400px">
|
|
<div style="flex:1;display:flex;flex-direction:column;gap:10px">
|
|
<h1 style="margin:0;font:600 36px/44px 'IBM Plex Sans',sans-serif;letter-spacing:-0.02em;color:var(--ui-text-highlighted)">Screens: custom content types</h1>
|
|
<p style="margin:0;max-width:900px;font-size:16px;line-height:26px;color:var(--ui-text-toned);text-wrap:pretty">Schema list, builder, change review, field-type gallery, content navigation, entry list and entry editor, plus the later screens: relations, permissions, export and import. Every state at 1440 px (shown at 50%) and 390 px (shown at 75%); the switch shows dark. Each state is tagged <b>Available now</b> or <b>Later</b>. Spec tables at the end: scope, routes, components with their Nuxt UI mapping, errors, needs backend, decisions, accessibility. Same shell, tokens and copy tone as <a href="RenewCMS Screens Back-office.dc.html">the back-office board</a>. Changed in AppFrame: a Schema item and a Content group in the sidebar and the mobile drawer.</p>
|
|
</div>
|
|
<div role="radiogroup" aria-label="Theme" style="display:flex;border:1px solid var(--ui-border-accented);background:var(--ui-bg)">
|
|
<sc-for list="{{ modes }}" as="m" hint-placeholder-count="3">
|
|
<button role="radio" aria-checked="{{ m.on }}" onClick="{{ m.pick }}" style="all:unset;cursor:pointer;height:36px;padding:0 14px;display:flex;align-items:center;font-weight:500;font-size:14px;background:{{ m.bg }};color:{{ m.fg }}" style-focus-visible="outline:2px solid var(--ui-primary);outline-offset:2px">{{ m.label }}</button>
|
|
</sc-for>
|
|
</div>
|
|
</div>
|
|
<sc-for list="{{ groups }}" as="g" hint-placeholder-count="9">
|
|
<section data-screen-label="{{ g.label }}" style="display:flex;flex-direction:column;gap:28px">
|
|
<div style="display:flex;flex-direction:column;gap:6px;max-width:1100px">
|
|
<h2 style="margin:0;font:600 28px/36px 'IBM Plex Sans',sans-serif;color:var(--ui-text-highlighted)">{{ g.title }}</h2>
|
|
<div style="display:flex;gap:16px;flex-wrap:wrap;font:400 14px/22px 'IBM Plex Mono',monospace;color:var(--ui-text-toned)"><span>{{ g.route }}</span><span style="color:var(--ui-text-muted)">{{ g.api }}</span><span style="color:var(--ui-text-muted)">Auth: {{ g.auth }}</span></div>
|
|
<p style="margin:4px 0 0;font-size:15px;line-height:24px;color:var(--ui-text-toned);text-wrap:pretty">{{ g.note }}</p>
|
|
</div>
|
|
<div style="display:flex;flex-wrap:wrap;gap:48px 40px;align-items:flex-start">
|
|
<sc-for list="{{ g.states }}" as="st" hint-placeholder-count="4">
|
|
<div style="display:flex;flex-direction:column;gap:12px;width:1037px">
|
|
<div style="display:flex;flex-direction:column;gap:2px"><span style="font:600 16px/24px 'IBM Plex Sans',sans-serif;color:var(--ui-text-highlighted)">{{ st.name }}<span style="margin-left:10px;padding:1px 6px;border:{{ st.chipBd }};color:var(--ui-text-toned);font:500 11px/16px 'IBM Plex Mono',monospace;vertical-align:middle">{{ st.scopeLabel }}</span></span><span style="font-size:13px;color:var(--ui-text-muted)">{{ st.trigger }}</span></div>
|
|
<div style="display:flex;gap:24px;align-items:flex-start">
|
|
<div style="width:720px;height:450px;overflow:hidden;border:1px solid var(--ui-border);flex-shrink:0"><div style="width:1440px;height:900px;zoom:0.5"><dc-import name="SchemaFrame" s="{{ st.s }}" mobile="{{ false }}" hint-size="1440px,900px"></dc-import></div></div>
|
|
<div style="width:293px;height:633px;overflow:hidden;border:1px solid var(--ui-border);flex-shrink:0"><div style="width:390px;height:844px;zoom:0.75"><dc-import name="SchemaFrame" s="{{ st.s }}" mobile="{{ true }}" hint-size="390px,844px"></dc-import></div></div>
|
|
</div>
|
|
<p style="margin:0;font-size:12px;line-height:18px;color:var(--ui-text-muted);text-wrap:pretty"><b style="color:var(--ui-text-toned)">Copy:</b> {{ st.copy }}</p>
|
|
</div>
|
|
</sc-for>
|
|
</div>
|
|
</section>
|
|
</sc-for>
|
|
<sc-for list="{{ tables }}" as="t" hint-placeholder-count="3">
|
|
<section style="display:flex;flex-direction:column;gap:10px;max-width:1240px">
|
|
<h2 style="margin:0;font:600 22px/30px 'IBM Plex Sans',sans-serif;color:var(--ui-text-highlighted)">{{ t.title }}</h2>
|
|
<div style="background:var(--ui-bg);border:1px solid var(--ui-border)">
|
|
<div style="display:grid;grid-template-columns:{{ t.tpl }};gap:16px;padding:8px 12px;background:var(--ui-bg-elevated);color:var(--ui-text-muted);font-weight:500"><sc-for list="{{ t.cols }}" as="c" hint-placeholder-count="3"><span>{{ c }}</span></sc-for></div>
|
|
<sc-for list="{{ t.rows }}" as="r" hint-placeholder-count="4"><div style="display:grid;grid-template-columns:{{ t.tpl }};gap:16px;padding:10px 12px;border-top:1px solid var(--ui-border);line-height:20px"><sc-for list="{{ r.cells }}" as="c" hint-placeholder-count="3"><span style="color:var(--ui-text-highlighted);text-wrap:pretty;overflow-wrap:anywhere">{{ c }}</span></sc-for></div></sc-for>
|
|
</div>
|
|
</section>
|
|
</sc-for>
|
|
</div>
|
|
</x-dc>
|
|
<script type="text/x-dc" data-dc-script data-props="{"theme":{"editor":"enum","default":"light","options":["system","light","dark"],"tsType":"string"}}">
|
|
class Component extends DCLogic {
|
|
state = { mode: this.props.theme ?? 'light', spec: { groups: [], tables: [] } }
|
|
rootRef = React.createRef()
|
|
light = { '--ui-bg': '#ffffff', '--ui-bg-muted': '#fafafa', '--ui-bg-elevated': '#f3f2f0', '--ui-bg-accented': '#e6e4e0', '--ui-bg-inverted': '#111111', '--ui-text-dimmed': '#999999', '--ui-text-muted': '#666666', '--ui-text-toned': '#444444', '--ui-text': '#222222', '--ui-text-highlighted': '#111111', '--ui-text-inverted': '#ffffff', '--ui-border': '#e6e4e0', '--ui-border-muted': '#f3f2f0', '--ui-border-accented': '#8a8783', '--ui-primary': '#111111', '--ui-secondary': '#635643', '--ui-success': '#315b33', '--ui-info': '#34536d', '--ui-warning': '#6c4700', '--ui-error': '#882c21', '--rc-sand': '#e8dfd1', '--rc-on-sand': '#111111', '--rc-success-soft': '#eaefea', '--rc-info-soft': '#ebeef0', '--rc-warning-soft': '#f0ede6', '--rc-error-soft': '#f3eae9', '--rc-overlay': 'rgb(10 10 10 / 0.4)', '--rc-shadow-pop': '0 4px 16px rgb(17 17 17 / 0.08), 0 1px 2px rgb(17 17 17 / 0.06)', '--rc-shadow-modal': '0 16px 48px rgb(17 17 17 / 0.18)', '--rc-canvas': '#ecebe8' }
|
|
dark = { '--ui-bg': '#111111', '--ui-bg-muted': '#0a0a0a', '--ui-bg-elevated': '#1a1a1a', '--ui-bg-accented': '#222222', '--ui-bg-inverted': '#fafafa', '--ui-text-dimmed': '#666666', '--ui-text-muted': '#999999', '--ui-text-toned': '#cfccc7', '--ui-text': '#e6e4e0', '--ui-text-highlighted': '#fafafa', '--ui-text-inverted': '#111111', '--ui-border': '#333333', '--ui-border-muted': '#222222', '--ui-border-accented': '#666666', '--ui-primary': '#fafafa', '--ui-secondary': '#d4c5b0', '--ui-success': '#a3caa3', '--ui-info': '#a5c2db', '--ui-warning': '#dfb67d', '--ui-error': '#fba394', '--rc-sand': '#d4c5b0', '--rc-on-sand': '#111111', '--rc-success-soft': '#1f241f', '--rc-info-soft': '#202428', '--rc-warning-soft': '#2a251e', '--rc-error-soft': '#2c201f', '--rc-overlay': 'rgb(0 0 0 / 0.6)', '--rc-shadow-pop': '0 4px 16px rgb(0 0 0 / 0.5)', '--rc-shadow-modal': '0 16px 48px rgb(0 0 0 / 0.6)', '--rc-canvas': '#1c1c1c' }
|
|
resolved() { if (this.state.mode === 'system') return window.matchMedia && window.matchMedia('(prefers-color-scheme: dark)').matches ? 'dark' : 'light'; return this.state.mode }
|
|
apply() { const el = this.rootRef.current; if (!el) return; const vars = this.resolved() === 'dark' ? this.dark : this.light; for (const k in vars) el.style.setProperty(k, vars[k]); document.body.style.background = vars['--rc-canvas'] }
|
|
componentDidMount() { this.apply(); import('./schema-spec.js').then(x => this.setState({ spec: { groups: x.groups, tables: x.tables } })).catch(() => {}) }
|
|
componentDidUpdate(p) { if (p.theme !== this.props.theme && this.props.theme) this.setState({ mode: this.props.theme }); this.apply() }
|
|
renderVals() {
|
|
const modes = [['system', 'System'], ['light', 'Light'], ['dark', 'Dark']].map(([k, label]) => { const on = this.state.mode === k; return { label, on, bg: on ? 'var(--ui-primary)' : 'transparent', fg: on ? 'var(--ui-bg)' : 'var(--ui-text-toned)', pick: () => this.setState({ mode: k }) } })
|
|
const groups = this.state.spec.groups.map(g => ({ ...g, states: g.states.map(s => ({ ...s, scopeLabel: s.scope === 'later' ? 'Later' : 'Available now', chipBd: s.scope === 'later' ? '1px dashed var(--ui-border-accented)' : '1px solid var(--ui-border-accented)' })) }))
|
|
const tables = this.state.spec.tables.map(t => ({ ...t, rows: t.rows.map(r => ({ cells: r })) }))
|
|
return { rootRef: this.rootRef, modes, groups, tables }
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html>
|