openvibers/openvibe.exchange Commits
On a phone, a wide table shows each row as a labelled card (#41)
Changes
@@@ -144,3 +144,18 @@ html[data-ov-motion=reduced] .ex-motif-arrows path, html[data-ov-motion=reduced]/* A theme's preview palette: up to six small swatches, plain <i> elements; the session restyles them. */.ex-palette { display: inline-flex; flex-wrap: wrap; gap: 4px; }.ex-palette i { display: inline-block; width: 16px; height: 16px; border-radius: 5px; border: 1px solid var(--border, #1f2d47); }++++/* Tables on a phone (phone sweep, 2026-11-01): a table of three columns or more shows each row as a card, the first++ cell its title and every other cell named by its column (html.js gives each cell its data-label). Narrower tables++ stay tables. Nothing is left out and nothing scrolls sideways. */++@media (max-width: 640px) {++ .table-wrap:has(> table thead th:nth-child(3)) { overflow: visible; }++ .table-wrap > table:has(thead th:nth-child(3)) { display: block; }++ .table-wrap > table:has(thead th:nth-child(3)) thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }++ .table-wrap > table:has(thead th:nth-child(3)) tbody { display: grid; gap: 10px; }++ .table-wrap > table:has(thead th:nth-child(3)) tr { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--border, #1f2d47); border-radius: 14px; background: var(--bg-card, var(--bg-secondary, #101828)); }++ .table-wrap > table:has(thead th:nth-child(3)) td { display: block; min-width: 0; padding: 0; border: 0; overflow-wrap: anywhere; }++ .table-wrap > table:has(thead th:nth-child(3)) td:first-child { font-weight: 700; color: var(--text-primary, #e6edf7); }++ .table-wrap > table:has(thead th:nth-child(3)) td[data-label]:not(:first-child)::before { content: attr(data-label); display: block; margin-bottom: 2px; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted, #7386a3); }++ .table-wrap > table:has(thead th:nth-child(3)) td:empty { display: none; }++}@@@ -23,7 +23,7 @@ const time = (iso) => (iso ? html`<time datetime="${iso}">${String(iso).replace(function table(headers, rows, { cls = '', empty = 'Nothing here yet.' } = {}) {if (!rows.length) return html`<p class="muted">${empty}</p>`;-- return html`<div class="table-wrap"><table class="${cls}"><thead><tr>${headers.map((h) => html`<th scope="col">${h}</th>`)}</tr></thead><tbody>${rows.map((r) => html`<tr>${r.map((c) => html`<td>${c}</td>`)}</tr>`)}</tbody></table></div>`;++ return html`<div class="table-wrap"><table class="${cls}"><thead><tr>${headers.map((h) => html`<th scope="col">${h}</th>`)}</tr></thead><tbody>${rows.map((r) => html`<tr>${r.map((c, i) => (typeof headers[i] === 'string' && headers[i] ? html`<td data-label="${headers[i]}">${c}</td>` : html`<td>${c}</td>`))}</tr>`)}</tbody></table></div>`;}const notice = (text, kind = 'info') => html`<div class="notice ${kind}" role="status">${text}</div>`;
@@ -144,3 +144,18 @@ html[data-ov-motion=reduced] .ex-motif-arrows path, html[data-ov-motion=reduced]
@@ -144,3 +144,18 @@ html[data-ov-motion=reduced] .ex-motif-arrows path, html[data-ov-motion=reduced]
/* A theme's preview palette: up to six small swatches, plain <i> elements; the session restyles them. */
/* A theme's preview palette: up to six small swatches, plain <i> elements; the session restyles them. */
.ex-palette { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.ex-palette { display: inline-flex; flex-wrap: wrap; gap: 4px; }
.ex-palette i { display: inline-block; width: 16px; height: 16px; border-radius: 5px; border: 1px solid var(--border, #1f2d47); }
.ex-palette i { display: inline-block; width: 16px; height: 16px; border-radius: 5px; border: 1px solid var(--border, #1f2d47); }
+
+/* Tables on a phone (phone sweep, 2026-11-01): a table of three columns or more shows each row as a card, the first
+ cell its title and every other cell named by its column (html.js gives each cell its data-label). Narrower tables
+ stay tables. Nothing is left out and nothing scrolls sideways. */
+@media (max-width: 640px) {
+ .table-wrap:has(> table thead th:nth-child(3)) { overflow: visible; }
+ .table-wrap > table:has(thead th:nth-child(3)) { display: block; }
+ .table-wrap > table:has(thead th:nth-child(3)) thead { position: absolute; width: 1px; height: 1px; overflow: hidden; clip: rect(0 0 0 0); white-space: nowrap; }
+ .table-wrap > table:has(thead th:nth-child(3)) tbody { display: grid; gap: 10px; }
+ .table-wrap > table:has(thead th:nth-child(3)) tr { display: grid; gap: 8px; padding: 12px 14px; border: 1px solid var(--border, #1f2d47); border-radius: 14px; background: var(--bg-card, var(--bg-secondary, #101828)); }
+ .table-wrap > table:has(thead th:nth-child(3)) td { display: block; min-width: 0; padding: 0; border: 0; overflow-wrap: anywhere; }
+ .table-wrap > table:has(thead th:nth-child(3)) td:first-child { font-weight: 700; color: var(--text-primary, #e6edf7); }
+ .table-wrap > table:has(thead th:nth-child(3)) td[data-label]:not(:first-child)::before { content: attr(data-label); display: block; margin-bottom: 2px; font-size: 11px; font-weight: 700; letter-spacing: .05em; text-transform: uppercase; color: var(--text-muted, #7386a3); }
+ .table-wrap > table:has(thead th:nth-child(3)) td:empty { display: none; }
+}
@@ -23,7 +23,7 @@ const time = (iso) => (iso ? html`<time datetime="${iso}">${String(iso).replace(
@@ -23,7 +23,7 @@ const time = (iso) => (iso ? html`<time datetime="${iso}">${String(iso).replace(
function table(headers, rows, { cls = '', empty = 'Nothing here yet.' } = {}) {
function table(headers, rows, { cls = '', empty = 'Nothing here yet.' } = {}) {
if (!rows.length) return html`<p class="muted">${empty}</p>`;
if (!rows.length) return html`<p class="muted">${empty}</p>`;
- return html`<div class="table-wrap"><table class="${cls}"><thead><tr>${headers.map((h) => html`<th scope="col">${h}</th>`)}</tr></thead><tbody>${rows.map((r) => html`<tr>${r.map((c) => html`<td>${c}</td>`)}</tr>`)}</tbody></table></div>`;
+ return html`<div class="table-wrap"><table class="${cls}"><thead><tr>${headers.map((h) => html`<th scope="col">${h}</th>`)}</tr></thead><tbody>${rows.map((r) => html`<tr>${r.map((c, i) => (typeof headers[i] === 'string' && headers[i] ? html`<td data-label="${headers[i]}">${c}</td>` : html`<td>${c}</td>`))}</tr>`)}</tbody></table></div>`;
}
}
const notice = (text, kind = 'info') => html`<div class="notice ${kind}" role="status">${text}</div>`;
const notice = (text, kind = 'info') => html`<div class="notice ${kind}" role="status">${text}</div>`;