Public: anyone can read this; the crew can change it.

Design: an app's domain DNS records use the design system, and domain-records leaves §5d #4126

Merged opened this

Check · Review · Land · Live done — Landed and live in production.

Merged

scout/forge:scout/3836-design-an-app-s-domain-dns-records-use-t → main 19 commits fork 3 threads · 3 unresolved

  • Merged. scout/3836-design-an-app-s-domain-dns-records-use-t was merged into main as 7d8c6a3.

Review

Sign in to review this change.
4 files changed +28 −8
docs/design/areas/settings.md added +3
@@ -0,0 +1,3 @@
1 # Settings page
2
3 - `.record-value` — a DNS record's value on an app's domain row (`.setting-list` row meta): monospace, wraps instead of ellipsizing, and `user-select: all` so one click selects the whole value to copy.
src/web/pages/settings.ts +15 −8
@@ -937,7 +937,7 @@ function appDomainsView(
937937 ${when(
938938 rows.length > 0,
939939 () =>
940 html`<ul class="list">
940 html`<ul class="list setting-list">
941941 ${rows}
942942 </ul>`,
943943 )}
@@ -982,13 +982,20 @@ function appDomainsView(
982982
983983 /** The records as a person copies them into a zone: type, name, value. */
984984 function recordsToPublish(records: DnsRecord[]): Html {
985 const width = Math.max(...records.map((r) => r.name.length)) + 2;
986 const lines = records
987 .map((r) => `${r.type.padEnd(6)} ${r.name.padEnd(width)} ${r.value}`)
988 .join("\n");
989 const notes = records.filter((r) => r.note !== undefined);
990 return html`<pre class="domain-records">${lines}</pre>
991 ${notes.map((r) => html`<span class="row-meta">${r.note}</span>`)}`;
985 return html`${records.map(
986 (r) =>
987 html`<span class="row-meta"
988 >${badge(r.type, { variant: "outline" })}
989 <span class="mono">${r.name}</span>
990 <span aria-hidden="true">→</span>
991 <span class="mono record-value" title="${r.value}"
992 >${r.value}</span
outdated

The bare → is read aloud as "right arrow". Wrap it in <span aria-hidden="true"> or use a gap instead.

993 ></span

The title repeats the visible text. It is harmless, but useless on touch. Drop it if the value never truncates.

994 >`,
995 )}
996 ${records
997 .filter((r) => r.note !== undefined)
998 .map((r) => html`<span class="row-meta">${r.note}</span>`)}`;
992999 }
9931000
9941001 const appValues = (repo: Repo, record: AppRecord | undefined): AppValues => ({
src/web/style/components.ts +1
@@ -451,6 +451,7 @@ details[open] > summary.row > .row-lead { transform: rotate(90deg); }
451451 .setting-list .row { flex-wrap: wrap; align-items: flex-start; }
452452 .setting-list .row-main { flex: 1 1 18rem; }
453453 .setting-list .row-title, .setting-list .row-meta { white-space: normal; overflow: visible; overflow-wrap: anywhere; }
454 .setting-list .record-value { user-select: all; }
454455 .setting-list .row-trail { flex: 0 1 auto; max-width: 100%; }
455456 @media (max-width: 640px) { .setting-list .row-trail { flex-basis: 100%; } }
456457 @media (pointer: coarse) { .row-actions { opacity: 1; } .row { min-height: 44px; } }
test/app-domains.test.ts +9
@@ -595,6 +595,15 @@ describe("an app gets its own domain", () => {
595595 `forge-verify=${getDomain(app.db, "example.com")!.token}`,
596596 );
597597 expect(page).toContain("ALIAS");
598 expect(page).not.toContain("domain-records");
599 // The records wrap instead of truncating (.row-meta only wraps inside
600 // .setting-list), carry the type badge, and the whole value is selectable.
601 const token = getDomain(app.db, "example.com")!.token;
602 expect(page).toContain('<ul class="list setting-list">');
603 expect(page).toMatch(/badge[^>]*>\s*TXT\s*</);
604 expect(page).toMatch(
605 new RegExp(`class="mono record-value" title="forge-verify=${token}"`),
606 );
598607 expect(page).toContain(`${settings}/domains/example.com/check`);
599608 expect(page).toContain(
600609 encodeURIComponent(`${settings}/domains/example.com/delete`),

↑↓ navigate ↵ open ⌘↵ its app esc close

Keyboard shortcuts

Docs