@bkazemi/verily 0.9.4 → 0.10.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -5
- package/dist/browser/badge.css.d.ts +2 -0
- package/dist/browser/badge.css.js +2 -0
- package/dist/browser/badge.js +2 -66
- package/dist/browser/connect-dialog.css.d.ts +2 -0
- package/dist/browser/connect-dialog.css.js +2 -0
- package/dist/browser/connect-dialog.js +4 -24
- package/dist/browser/evidence-dialog.css.d.ts +2 -0
- package/dist/browser/evidence-dialog.css.js +2 -0
- package/dist/browser/evidence-dialog.d.ts +6 -1
- package/dist/browser/evidence-dialog.js +42 -119
- package/dist/browser/index.d.ts +7 -1
- package/dist/browser/index.js +37 -8
- package/dist/browser/mark.css.d.ts +2 -0
- package/dist/browser/mark.css.js +2 -0
- package/dist/browser/mark.d.ts +1 -1
- package/dist/browser/mark.js +2 -6
- package/dist/core/index.d.ts +24 -0
- package/dist/core/index.js +40 -0
- package/dist/instance/bin.js +31 -1
- package/dist/instance/github-app.d.ts +26 -0
- package/dist/instance/github-app.js +94 -0
- package/dist/instance/index.js +4 -2
- package/dist/instance/starter.js +1 -1
- package/dist/server/index.js +4 -2
- package/dist/server/service.d.ts +2 -0
- package/dist/server/service.js +23 -2
- package/dist/server/style.css.d.ts +2 -0
- package/dist/server/style.css.js +2 -0
- package/dist/server/style.d.ts +1 -1
- package/dist/server/style.js +2 -455
- package/dist/site/index.d.ts +6 -3
- package/dist/site/index.js +6 -3
- package/dist/verily.js +632 -223
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +8 -1
package/dist/server/style.d.ts
CHANGED
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
* leaves. So the styling does the two things that helps with, a measured column and a
|
|
9
9
|
* legible hierarchy, and nothing that would make a record look like a product.
|
|
10
10
|
*/
|
|
11
|
-
export declare const stylesheet = ":root {\n --ink: #23312b;\n --muted: #6b786f;\n --line: #dce2de;\n --surface: #fff;\n --raised: #f7f9f7;\n --accent: #245f43;\n --warn: #a4442b;\n --caution: #b07a12;\n --syntax-tag: #245f43;\n --syntax-attr: #8a5a0b;\n --syntax-string: #2b5f8a;\n color-scheme: light dark;\n accent-color: var(--accent);\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --ink: #dde5e0;\n --muted: #96a39b;\n --line: #2f3b35;\n --surface: #161a18;\n --raised: #1d2220;\n --accent: #7fc4a2;\n --warn: #e59a82;\n --caution: #d9a843;\n --syntax-tag: #7fc4a2;\n --syntax-attr: #d9a843;\n --syntax-string: #8fbbe0;\n }\n}\n\n* { box-sizing: border-box; }\n\nbody {\n margin: 0;\n padding: 0 1rem 4rem;\n background: var(--surface);\n color: var(--ink);\n font: 16px/1.65 system-ui, -apple-system, 'Segoe UI', sans-serif;\n text-rendering: optimizeLegibility;\n}\n\nmain {\n max-width: 34rem;\n margin: 0 auto;\n padding-top: 3rem;\n}\n\n/*\n * The logotype, above the page's own heading, on its own dark plate. Sized so the word is\n * the height it was without the plate, whose margin makes the box that much taller. The\n * word is white in either scheme: the plate is what it is read against, not the page.\n */\n.logo {\n display: block;\n height: 2.5rem;\n margin-bottom: 1.5rem;\n}\n\nh1 {\n margin: 0 0 1.75rem;\n padding-bottom: 1rem;\n border-bottom: 1px solid var(--line);\n font-size: 1.5rem;\n font-weight: 620;\n letter-spacing: -.02em;\n line-height: 1.25;\n}\n\n/*\n * A page holding one thing needs no rule under its heading. The rule divides a heading\n * from the record beneath it, and a page that only asks for a key has no record to divide.\n */\nmain.single h1 { margin-bottom: 1.25rem; padding-bottom: 0; border-bottom: none; }\n\n/*\n * A page holding one thing sits in the middle of the window rather than at its top,\n * where it would leave most of the window empty below it.\n */\nbody:has(main.single) { display: flex; min-height: 100vh; min-height: 100dvh; }\nmain.single { width: 100%; max-width: 24rem; margin: auto; padding-bottom: 3rem; }\n\nh2 { margin: 2rem 0 .75rem; font-size: 1.125rem; font-weight: 620; letter-spacing: -.01em; }\n\nh3 { margin: 0 0 .5rem; font-size: 1rem; font-weight: 620; }\n\np { margin: 0 0 1rem; overflow-wrap: break-word; }\n\na { color: var(--accent); text-underline-offset: 3px; overflow-wrap: anywhere; }\n\na:hover { text-decoration-thickness: 2px; }\n\n/*\n * Something to be run or published exactly as written. Its own line breaks are kept and a\n * long line is soft-wrapped rather than cut off: a soft wrap is drawn, not inserted, so\n * what is copied is still character for character what was written. Selecting inside the\n * block takes all of it, since half a command is worse than none.\n */\npre {\n position: relative;\n margin: 0 0 1rem;\n /* Room along the top line for the copy button, which sits over the block rather than in it. */\n padding: .75rem 5.25rem .75rem .875rem;\n border: 1px solid var(--line);\n border-radius: 6px;\n background: var(--raised);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n user-select: all;\n}\n\ncode { font: .8125rem/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; }\n\n/* Highlighted HTML, marked up by highlight.js. Brackets stay muted so the names read first. */\n.hljs-tag { color: var(--muted); }\n.hljs-name { color: var(--syntax-tag); }\n.hljs-attr { color: var(--syntax-attr); }\n.hljs-string { color: var(--syntax-string); }\n\n/* Made by a script, so it exists only where it works. Quiet: the block is the point. */\n.copy {\n position: absolute;\n top: .5rem;\n right: .5rem;\n padding: .1875rem .5rem;\n border: 1px solid var(--line);\n border-radius: 5px;\n background: var(--surface);\n color: var(--muted);\n font: 500 .75rem/1.5 system-ui, sans-serif;\n user-select: none;\n}\n\n.copy:hover { color: var(--ink); border-color: var(--muted); }\n\n/*\n * The two sides of the link, which is what a reader came to read. Each fact about a side\n * gets its own line: what it is, what it is called, the identifier behind that, and how it\n * was shown. Everything else on the page qualifies the pair, so it is set quieter.\n */\n.side {\n margin-bottom: .75rem;\n padding: .875rem 1rem;\n border: 1px solid var(--line);\n border-radius: 8px;\n background: var(--raised);\n}\n\n/*\n * A subject's accounts are peers, so where there is room they sit two across. The page\n * that lists them is wider for it, and a narrow one keeps them in a single column.\n */\nmain:has(.accounts) { max-width: 54rem; }\n\n.accounts {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: .75rem;\n margin-bottom: .75rem;\n}\n\n.accounts .side { position: relative; display: flex; flex-direction: column; margin-bottom: 0; }\n\n/* How the holder lists the account, in the card's corner and out of the lines below. */\n.listing {\n position: absolute;\n top: .75rem;\n right: .875rem;\n padding: .0625rem .5rem;\n border: 1px solid var(--line);\n border-radius: 999px;\n color: var(--muted);\n font-size: .6875rem;\n font-weight: 550;\n}\n\n.listing.preferred { border-color: var(--accent); color: var(--accent); }\n\n/* The times sit at the foot of the card, so they line up along a row of uneven cards. */\n.accounts .side dl { margin-top: auto; }\n.accounts .rest { display: flex; flex-direction: column; }\n.accounts .rest > p:last-of-type { margin-bottom: .625rem; }\n\n/*\n * Two across, with the subject one card wide and centred above them. Every card on the\n * page is then the same width.\n */\n@media (min-width: 48rem) {\n .accounts { grid-template-columns: repeat(2, minmax(0, 1fr)); }\n /* Each card is three rows of the grid: who, its verdict, and the rest. A row is as tall\n as the taller card's part, so the verdicts and times of neighbouring cards line up. */\n .accounts > .side { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; }\n .subject { width: calc(50% - .375rem); margin-inline: auto; text-align: center; }\n .subject .name { justify-content: center; }\n}\n\n/* Between a subject and its accounts on the page that lists them. */\n.joiner { display: block; width: 1.25rem; height: 1.25rem; margin: 0 auto .75rem; color: var(--muted); }\n\n.who {\n margin: 0 0 .125rem;\n color: var(--muted);\n font-size: .75rem;\n font-weight: 550;\n letter-spacing: .02em;\n}\n\n/* A provider's mark before its name, at the height of the letters. */\n.who .provider { display: inline-block; width: .875rem; height: .875rem; margin-right: .375rem; vertical-align: -.125rem; }\n\n/* Clipped 4px left of the text, which hides the date's dot when the date wraps to a new line. */\n.name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 1rem; margin: 0 0 0 -4px; padding-left: 4px; overflow-x: clip; font-size: 1.0625rem; font-weight: 620; letter-spacing: -.01em; }\n\n/* The account's creation date, after the name and a dot. It wraps under a long name. */\n.name .since { position: relative; color: var(--muted); font-size: .8125rem; font-weight: 400; letter-spacing: 0; white-space: nowrap; }\n\n/* The dot sits in the gap before the date. */\n.name .since::before { content: \"\u00B7\"; position: absolute; left: -.5rem; transform: translateX(-50%); }\n\n/* The name is the card's subject before it is a link, so the rule is drawn on hover. */\n.name a { text-decoration: none; }\n\n.name a:hover { text-decoration: underline; }\n\n.reference, .how { margin: 0; color: var(--muted); font-size: .8125rem; line-height: 1.5; }\n\n.identity + .how { margin-top: .5rem; }\n.fingerprint { font-family: ui-monospace, monospace; text-wrap: balance; }\n.fingerprint span { display: inline-block; margin-right: .5ch; }\n.how.additional { padding-left: .75rem; }\n/* The \"signed\" pill after the verifier's name, one size smaller than the line it sits on. */\n.how .signed-mark { display: inline-block; margin-left: .3125rem; padding: 0 .375rem; border: 1px solid var(--line); border-radius: 999px; font-size: .625rem; font-weight: 550; line-height: 1.3; text-decoration: none; vertical-align: .0625rem; }\n\n.fine { color: var(--muted); font-size: .8125rem; line-height: 1.55; margin-bottom: .625rem; }\n\n/* That the record is signed is a fact about it, so it is set as one and not as fine print. */\n.signed { font-size: .875rem; line-height: 1.55; margin-bottom: .875rem; }\n/* Arrived at from a badge's \"signed\" link, so the reader is shown where they landed. */\n.signed:target { margin-inline: -.75rem; padding: .625rem .75rem; border-radius: 8px; background: var(--raised); }\n\n/* Every time on the record in one column, so they can be compared rather than hunted for. */\ndl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: .3rem 1.5rem;\n margin: 1.25rem 0;\n padding-top: 1rem;\n border-top: 1px solid var(--line);\n font-size: .8125rem;\n}\n\ndt { color: var(--muted); }\n\ndd { margin: 0; font-variant-numeric: tabular-nums; }\n\n/* Inside a card the rule above it is the card's own edge, so the list needs none. */\nsection dl { margin: .5rem 0 1rem; padding-top: 0; border-top: 0; }\n\n/* Right under the heading, the heading's own rule is the one above it. */\nh1 + dl { padding-top: 0; border-top: 0; }\n.side dl { margin: .625rem 0 0; padding-top: .625rem; }\n\n/* The links under a record, ruled off from the record and its disclaimer. */\nfooter { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line); }\nfooter > :last-child { margin-bottom: 0; }\n\nsection {\n margin: 0 0 1.25rem;\n padding: 1.25rem 1.375rem;\n border: 1px solid var(--line);\n border-radius: 10px;\n}\n\nsection > :last-child { margin-bottom: 0; }\n\n/* What holds a control that cannot be undone. */\nsection.danger, section.caution { margin-top: 2rem; }\nsection.danger { border-color: var(--warn); }\n\n/* What holds a control that breaks something for a while, but can be recovered from. */\nsection.caution { border-color: var(--caution); }\nsection > h2:first-child { margin-top: 0; }\n\nform { margin: 0 0 1.5rem; }\n\nlabel { display: block; margin: 0 0 .75rem; color: var(--muted); font-size: .8125rem; }\n\ninput, textarea {\n display: block;\n width: 100%;\n margin-top: .375rem;\n padding: .5rem .625rem;\n border: 1px solid var(--line);\n border-radius: 6px;\n background: var(--surface);\n color: var(--ink);\n font: .875rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;\n}\n\n/* Height comes from the rows attribute, which differs per box. */\ntextarea { resize: vertical; }\n\ninput:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }\n\nbutton {\n padding: .5rem 1rem;\n border: 1px solid var(--accent);\n border-radius: 6px;\n background: var(--accent);\n color: var(--surface);\n font: 500 .9375rem/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;\n cursor: pointer;\n}\n\n/* A link that starts something, drawn as a button. */\na.button {\n display: inline-block;\n padding: .5rem 1rem;\n border: 1px solid var(--accent);\n border-radius: 6px;\n background: var(--accent);\n color: var(--surface);\n font-weight: 500;\n font-size: .9375rem;\n line-height: 1.4;\n text-decoration: none;\n}\n\nbutton + button { margin-left: .5rem; border-color: var(--line); background: none; color: var(--ink); }\n\n/* The other choice beside a page's one action, such as Cancel. */\na.button.secondary { border-color: var(--line); background: none; color: var(--ink); }\n\n/* A page's action and its alternative, side by side. */\n.choice { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }\n.choice form { margin: 0; }\n\n/* Ways to verify: one full-width button per method, none filled over the others. */\n.choices { display: grid; gap: .5rem; margin-bottom: 1.5rem; }\n.choices form { margin: 0; }\n\n.choices button {\n width: 100%;\n text-align: left;\n border-color: var(--line);\n background: var(--surface);\n color: var(--ink);\n}\n\n.choices button:hover { border-color: var(--muted); }\n\n/* A provider's mark before a button's label, at the height of the letters. */\nbutton .provider { width: 1rem; height: 1rem; margin-right: .5rem; vertical-align: -.1875rem; }\n\n/* A control that ends something. Filled where it is the page's one action. */\nbutton.danger { border-color: var(--warn); background: var(--warn); }\n\n/*\n * A connection on the settings page: the account's card, then what can be done with it.\n * Its state sits in the card's corner, on the line that names the method.\n */\n.connection { position: relative; margin-bottom: 1rem; }\n\n.state {\n position: absolute;\n top: .75rem;\n right: .875rem;\n display: flex;\n align-items: center;\n gap: .375rem;\n height: 1.625rem;\n padding: 0 .75rem 0 .5rem;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--surface);\n color: var(--ink);\n font-size: .8125rem;\n font-weight: 550;\n}\n\n/*\n * The V the badge draws, in the tone that says how the record stands. A record that claims\n * nothing is drawn faint in the text colour, as the badge draws it.\n */\n.verdict { flex-shrink: 0; width: 1rem; height: 1rem; }\n.verdict.pending { opacity: .45; }\n.how .verdict { width: .875rem; height: .875rem; margin-right: .3125rem; vertical-align: -.125rem; }\n/* Cropped to its strokes and taller than the heading's letters, centred beside them. */\nh1:has(.verdict) { display: flex; align-items: center; gap: .75rem; }\nh1 .verdict { width: auto; height: 2.25rem; }\n\n/*\n * In a state pill the V is cropped to its strokes and fills the pill's height, so its arms\n * and its foot meet the border. The pill's left padding keeps the arms clear of its curve.\n */\n.state .verdict { width: auto; height: 100%; }\n\n/*\n * A pill's line includes room for descenders below the letters, which leaves its text\n * sitting high. Trimmed to the letters, the padding alone sets the space above and below.\n * In a state pill the word alone is trimmed, so it centres on the V by its letters.\n */\n@supports (text-box: trim-both cap alphabetic) {\n .listing { padding: .3125rem .5rem; text-box: trim-both cap alphabetic; }\n .state > span { text-box: trim-both cap alphabetic; }\n}\n\n/* Links that sit together on one line, wrapping where there is no room. */\n.links { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem; font-size: .875rem; }\n\n/* Under the account's id, with the facts about it rather than the controls. */\n.evidence { margin: .375rem 0 0; font-size: .8125rem; }\n\n.connection dl { margin-bottom: .75rem; }\n.connection .side > :last-child { margin-bottom: 0; }\n.connection pre { margin: .75rem 0; background: var(--surface); }\n.connection .actions { margin-top: .875rem; }\n\n/* The buttons for one connection in a row, wrapping where there is no room. */\n.actions { display: flex; flex-wrap: wrap; gap: .5rem; }\n.actions form { display: contents; }\n\n.actions button, .actions a.button {\n margin: 0;\n padding: .3125rem .75rem;\n border-color: var(--line);\n background: var(--surface);\n color: var(--ink);\n font-size: .8125rem;\n}\n\n.actions button:hover, .actions a.button:hover { border-color: var(--muted); }\n\n/* The controls that cannot be undone, together at the foot of the card. */\n.ending { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); }\n.ending form { margin: 0; }\n\n.ending button.danger {\n padding: .3125rem .75rem;\n background: var(--surface);\n color: var(--warn);\n font-size: .8125rem;\n}\n\nfieldset { margin: 0 0 1.25rem; padding: 1rem 1.125rem .25rem; border: 1px solid var(--line); border-radius: 8px; }\n\nlegend { padding: 0 .375rem; color: var(--muted); font-size: .8125rem; }\n\nfieldset label { display: flex; align-items: baseline; gap: .5rem; color: var(--ink); font-size: .9375rem; }\n\nfieldset input { width: auto; margin: 0; }\n\nfieldset p { margin: .25rem 0 .875rem 1.5rem; color: var(--muted); font-size: .8125rem; }\n";
|
|
11
|
+
export declare const stylesheet = ":root {\n --ink: #23312b;\n --muted: #6b786f;\n --line: #dce2de;\n --surface: #fff;\n --raised: #f7f9f7;\n --accent: #245f43;\n --warn: #a4442b;\n --caution: #b07a12;\n --syntax-tag: #245f43;\n --syntax-attr: #8a5a0b;\n --syntax-string: #2b5f8a;\n color-scheme: light dark;\n accent-color: var(--accent);\n}\n\n@media (prefers-color-scheme: dark) {\n :root {\n --ink: #dde5e0;\n --muted: #96a39b;\n --line: #2f3b35;\n --surface: #161a18;\n --raised: #1d2220;\n --accent: #7fc4a2;\n --warn: #e59a82;\n --caution: #d9a843;\n --syntax-tag: #7fc4a2;\n --syntax-attr: #d9a843;\n --syntax-string: #8fbbe0;\n }\n}\n\n* {\n box-sizing: border-box;\n}\n\nbody {\n margin: 0;\n padding: 0 1rem 4rem;\n background: var(--surface);\n color: var(--ink);\n font:\n 16px/1.65 system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n text-rendering: optimizeLegibility;\n}\n\nmain {\n max-width: 34rem;\n margin: 0 auto;\n padding-top: 3rem;\n}\n\n/*\n * The logotype, above the page's own heading, on its own dark plate. Sized so the word is\n * the height it was without the plate, whose margin makes the box that much taller. The\n * word is white in either scheme: the plate is what it is read against, not the page.\n */\n.logo {\n display: block;\n height: 2.5rem;\n margin-bottom: 1.5rem;\n}\n\nh1 {\n margin: 0 0 1.75rem;\n padding-bottom: 1rem;\n border-bottom: 1px solid var(--line);\n font-size: 1.5rem;\n font-weight: 620;\n letter-spacing: -0.02em;\n line-height: 1.25;\n}\n\n/*\n * A page holding one thing needs no rule under its heading. The rule divides a heading\n * from the record beneath it, and a page that only asks for a key has no record to divide.\n */\nmain.single h1 {\n margin-bottom: 1.25rem;\n padding-bottom: 0;\n border-bottom: none;\n}\n\n/*\n * A page holding one thing sits in the middle of the window rather than at its top,\n * where it would leave most of the window empty below it.\n */\nbody:has(main.single) {\n display: flex;\n min-height: 100vh;\n min-height: 100dvh;\n}\nmain.single {\n width: 100%;\n max-width: 24rem;\n margin: auto;\n padding-bottom: 3rem;\n}\n\nh2 {\n margin: 2rem 0 0.75rem;\n font-size: 1.125rem;\n font-weight: 620;\n letter-spacing: -0.01em;\n}\n\nh3 {\n margin: 0 0 0.5rem;\n font-size: 1rem;\n font-weight: 620;\n}\n\np {\n margin: 0 0 1rem;\n overflow-wrap: break-word;\n}\n\na {\n color: var(--accent);\n text-underline-offset: 3px;\n overflow-wrap: anywhere;\n}\n\na:hover {\n text-decoration-thickness: 2px;\n}\n\n/*\n * Something to be run or published exactly as written. Its own line breaks are kept and a\n * long line is soft-wrapped rather than cut off: a soft wrap is drawn, not inserted, so\n * what is copied is still character for character what was written. Selecting inside the\n * block takes all of it, since half a command is worse than none.\n */\npre {\n position: relative;\n margin: 0 0 1rem;\n /* Room along the top line for the copy button, which sits over the block rather than in it. */\n padding: 0.75rem 5.25rem 0.75rem 0.875rem;\n border: 1px solid var(--line);\n border-radius: 6px;\n background: var(--raised);\n white-space: pre-wrap;\n overflow-wrap: anywhere;\n user-select: all;\n}\n\ncode {\n font:\n 0.8125rem/1.6 ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n}\n\n/* Highlighted HTML, marked up by highlight.js. Brackets stay muted so the names read first. */\n.hljs-tag {\n color: var(--muted);\n}\n.hljs-name {\n color: var(--syntax-tag);\n}\n.hljs-attr {\n color: var(--syntax-attr);\n}\n.hljs-string {\n color: var(--syntax-string);\n}\n\n/* Made by a script, so it exists only where it works. Quiet: the block is the point. */\n.copy {\n position: absolute;\n top: 0.5rem;\n right: 0.5rem;\n padding: 0.1875rem 0.5rem;\n border: 1px solid var(--line);\n border-radius: 5px;\n background: var(--surface);\n color: var(--muted);\n font:\n 500 0.75rem/1.5 system-ui,\n sans-serif;\n user-select: none;\n}\n\n.copy:hover {\n color: var(--ink);\n border-color: var(--muted);\n}\n\n/*\n * The two sides of the link, which is what a reader came to read. Each fact about a side\n * gets its own line: what it is, what it is called, the identifier behind that, and how it\n * was shown. Everything else on the page qualifies the pair, so it is set quieter.\n */\n.side {\n margin-bottom: 0.75rem;\n padding: 0.875rem 1rem;\n border: 1px solid var(--line);\n border-radius: 8px;\n background: var(--raised);\n}\n\n/*\n * A subject's accounts are peers, so where there is room they sit two across. The page\n * that lists them is wider for it, and a narrow one keeps them in a single column.\n */\nmain:has(.accounts) {\n max-width: 54rem;\n}\n\n.accounts {\n display: grid;\n grid-template-columns: minmax(0, 1fr);\n gap: 0.75rem;\n margin-bottom: 0.75rem;\n}\n\n.accounts .side {\n position: relative;\n display: flex;\n flex-direction: column;\n margin-bottom: 0;\n}\n\n/* How the holder lists the account, in the card's corner and out of the lines below. */\n.listing {\n position: absolute;\n top: 0.75rem;\n right: 0.875rem;\n padding: 0.0625rem 0.5rem;\n border: 1px solid var(--line);\n border-radius: 999px;\n color: var(--muted);\n font-size: 0.6875rem;\n font-weight: 550;\n}\n\n.listing.preferred {\n border-color: var(--accent);\n color: var(--accent);\n}\n\n/* The times sit at the foot of the card, so they line up along a row of uneven cards. */\n.accounts .side dl {\n margin-top: auto;\n}\n.accounts .rest {\n display: flex;\n flex-direction: column;\n}\n.accounts .rest > p:last-of-type {\n margin-bottom: 0.625rem;\n}\n\n/*\n * Two across, with the subject one card wide and centred above them. Every card on the\n * page is then the same width.\n */\n@media (min-width: 48rem) {\n .accounts {\n grid-template-columns: repeat(2, minmax(0, 1fr));\n }\n /* Each card is three rows of the grid: who, its verdict, and the rest. A row is as tall\n as the taller card's part, so the verdicts and times of neighbouring cards line up. */\n .accounts > .side {\n display: grid;\n grid-row: span 3;\n grid-template-rows: subgrid;\n row-gap: 0;\n }\n .subject {\n width: calc(50% - 0.375rem);\n margin-inline: auto;\n text-align: center;\n }\n .subject .name {\n justify-content: center;\n }\n}\n\n/* Between a subject and its accounts on the page that lists them. */\n.joiner {\n display: block;\n width: 1.25rem;\n height: 1.25rem;\n margin: 0 auto 0.75rem;\n color: var(--muted);\n}\n\n.who {\n margin: 0 0 0.125rem;\n color: var(--muted);\n font-size: 0.75rem;\n font-weight: 550;\n letter-spacing: 0.02em;\n}\n\n/* A provider's mark before its name, at the height of the letters. */\n.who .provider {\n display: inline-block;\n width: 0.875rem;\n height: 0.875rem;\n margin-right: 0.375rem;\n vertical-align: -0.125rem;\n}\n\n/* Clipped 4px left of the text, which hides the date's dot when the date wraps to a new line. */\n.name {\n display: flex;\n flex-wrap: wrap;\n align-items: baseline;\n gap: 0 1rem;\n margin: 0 0 0 -4px;\n padding-left: 4px;\n overflow-x: clip;\n font-size: 1.0625rem;\n font-weight: 620;\n letter-spacing: -0.01em;\n}\n\n/* The account's creation date, after the name and a dot. It wraps under a long name. */\n.name .since {\n position: relative;\n color: var(--muted);\n font-size: 0.8125rem;\n font-weight: 400;\n letter-spacing: 0;\n white-space: nowrap;\n}\n\n/* The dot sits in the gap before the date. */\n.name .since::before {\n content: '\u00B7';\n position: absolute;\n left: -0.5rem;\n transform: translateX(-50%);\n}\n\n/* The name is the card's subject before it is a link, so the rule is drawn on hover. */\n.name a {\n text-decoration: none;\n}\n\n.name a:hover {\n text-decoration: underline;\n}\n\n.reference,\n.how {\n margin: 0;\n color: var(--muted);\n font-size: 0.8125rem;\n line-height: 1.5;\n}\n\n.identity + .how {\n margin-top: 0.5rem;\n}\n.fingerprint {\n font-family: ui-monospace, monospace;\n text-wrap: balance;\n}\n.fingerprint span {\n display: inline-block;\n margin-right: 0.5ch;\n}\n.how.additional {\n padding-left: 0.75rem;\n}\n/* The \"signed\" pill after the verifier's name, one size smaller than the line it sits on. */\n.how .signed-mark {\n display: inline-block;\n margin-left: 0.3125rem;\n padding: 0 0.375rem;\n border: 1px solid var(--line);\n border-radius: 999px;\n font-size: 0.625rem;\n font-weight: 550;\n line-height: 1.3;\n text-decoration: none;\n vertical-align: 0.0625rem;\n}\n\n.fine {\n color: var(--muted);\n font-size: 0.8125rem;\n line-height: 1.55;\n margin-bottom: 0.625rem;\n}\n\n/* That the record is signed is a fact about it, so it is set as one and not as fine print. */\n.signed {\n font-size: 0.875rem;\n line-height: 1.55;\n margin-bottom: 0.875rem;\n}\n/* Arrived at from a badge's \"signed\" link, so the reader is shown where they landed. */\n.signed:target {\n margin-inline: -0.75rem;\n padding: 0.625rem 0.75rem;\n border-radius: 8px;\n background: var(--raised);\n}\n\n/* Every time on the record in one column, so they can be compared rather than hunted for. */\ndl {\n display: grid;\n grid-template-columns: auto 1fr;\n gap: 0.3rem 1.5rem;\n margin: 1.25rem 0;\n padding-top: 1rem;\n border-top: 1px solid var(--line);\n font-size: 0.8125rem;\n}\n\ndt {\n color: var(--muted);\n}\n\ndd {\n margin: 0;\n font-variant-numeric: tabular-nums;\n}\n\n/* Inside a card the rule above it is the card's own edge, so the list needs none. */\nsection dl {\n margin: 0.5rem 0 1rem;\n padding-top: 0;\n border-top: 0;\n}\n\n/* Right under the heading, the heading's own rule is the one above it. */\nh1 + dl {\n padding-top: 0;\n border-top: 0;\n}\n.side dl {\n margin: 0.625rem 0 0;\n padding-top: 0.625rem;\n}\n\n/* The links under a record, ruled off from the record and its disclaimer. */\nfooter {\n margin-top: 1.25rem;\n padding-top: 1rem;\n border-top: 1px solid var(--line);\n}\nfooter > :last-child {\n margin-bottom: 0;\n}\n\nsection {\n margin: 0 0 1.25rem;\n padding: 1.25rem 1.375rem;\n border: 1px solid var(--line);\n border-radius: 10px;\n}\n\nsection > :last-child {\n margin-bottom: 0;\n}\n\n/* What holds a control that cannot be undone. */\nsection.danger,\nsection.caution {\n margin-top: 2rem;\n}\nsection.danger {\n border-color: var(--warn);\n}\n\n/* What holds a control that breaks something for a while, but can be recovered from. */\nsection.caution {\n border-color: var(--caution);\n}\nsection > h2:first-child {\n margin-top: 0;\n}\n\nform {\n margin: 0 0 1.5rem;\n}\n\nlabel {\n display: block;\n margin: 0 0 0.75rem;\n color: var(--muted);\n font-size: 0.8125rem;\n}\n\ninput,\ntextarea {\n display: block;\n width: 100%;\n margin-top: 0.375rem;\n padding: 0.5rem 0.625rem;\n border: 1px solid var(--line);\n border-radius: 6px;\n background: var(--surface);\n color: var(--ink);\n font:\n 0.875rem/1.5 ui-monospace,\n SFMono-Regular,\n Menlo,\n monospace;\n}\n\n/* Height comes from the rows attribute, which differs per box. */\ntextarea {\n resize: vertical;\n}\n\ninput:focus-visible,\ntextarea:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n\nbutton {\n padding: 0.5rem 1rem;\n border: 1px solid var(--accent);\n border-radius: 6px;\n background: var(--accent);\n color: var(--surface);\n font:\n 500 0.9375rem/1.4 system-ui,\n -apple-system,\n 'Segoe UI',\n sans-serif;\n cursor: pointer;\n}\n\n/* A link that starts something, drawn as a button. */\na.button {\n display: inline-block;\n padding: 0.5rem 1rem;\n border: 1px solid var(--accent);\n border-radius: 6px;\n background: var(--accent);\n color: var(--surface);\n font-weight: 500;\n font-size: 0.9375rem;\n line-height: 1.4;\n text-decoration: none;\n}\n\nbutton + button {\n margin-left: 0.5rem;\n border-color: var(--line);\n background: none;\n color: var(--ink);\n}\n\n/* The other choice beside a page's one action, such as Cancel. */\na.button.secondary {\n border-color: var(--line);\n background: none;\n color: var(--ink);\n}\n\n/* A page's action and its alternative, side by side. */\n.choice {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n margin-bottom: 1.5rem;\n}\n.choice form {\n margin: 0;\n}\n\n/* Ways to verify: one full-width button per method, none filled over the others. */\n.choices {\n display: grid;\n gap: 0.5rem;\n margin-bottom: 1.5rem;\n}\n.choices form {\n margin: 0;\n}\n\n.choices button {\n width: 100%;\n text-align: left;\n border-color: var(--line);\n background: var(--surface);\n color: var(--ink);\n}\n\n.choices button:hover {\n border-color: var(--muted);\n}\n\n/* A provider's mark before a button's label, at the height of the letters. */\nbutton .provider {\n width: 1rem;\n height: 1rem;\n margin-right: 0.5rem;\n vertical-align: -0.1875rem;\n}\n\n/* A control that ends something. Filled where it is the page's one action. */\nbutton.danger {\n border-color: var(--warn);\n background: var(--warn);\n}\n\n/*\n * A connection on the settings page: the account's card, then what can be done with it.\n * Its state sits in the card's corner, on the line that names the method.\n */\n.connection {\n position: relative;\n margin-bottom: 1rem;\n}\n\n.state {\n position: absolute;\n top: 0.75rem;\n right: 0.875rem;\n display: flex;\n align-items: center;\n gap: 0.375rem;\n height: 1.625rem;\n padding: 0 0.75rem 0 0.5rem;\n border: 1px solid var(--line);\n border-radius: 999px;\n background: var(--surface);\n color: var(--ink);\n font-size: 0.8125rem;\n font-weight: 550;\n}\n\n/*\n * The V the badge draws, in the tone that says how the record stands. A record that claims\n * nothing is drawn faint in the text colour, as the badge draws it.\n */\n.verdict {\n flex-shrink: 0;\n width: 1rem;\n height: 1rem;\n}\n.verdict.pending {\n opacity: 0.45;\n}\n.how .verdict {\n width: 0.875rem;\n height: 0.875rem;\n margin-right: 0.3125rem;\n vertical-align: -0.125rem;\n}\n/* Cropped to its strokes and taller than the heading's letters, centred beside them. */\nh1:has(.verdict) {\n display: flex;\n align-items: center;\n gap: 0.75rem;\n}\nh1 .verdict {\n width: auto;\n height: 2.25rem;\n}\n\n/*\n * In a state pill the V is cropped to its strokes and fills the pill's height, so its arms\n * and its foot meet the border. The pill's left padding keeps the arms clear of its curve.\n */\n.state .verdict {\n width: auto;\n height: 100%;\n}\n\n/*\n * A pill's line includes room for descenders below the letters, which leaves its text\n * sitting high. Trimmed to the letters, the padding alone sets the space above and below.\n * In a state pill the word alone is trimmed, so it centres on the V by its letters.\n */\n@supports (text-box: trim-both cap alphabetic) {\n .listing {\n padding: 0.3125rem 0.5rem;\n text-box: trim-both cap alphabetic;\n }\n .state > span {\n text-box: trim-both cap alphabetic;\n }\n}\n\n/* Links that sit together on one line, wrapping where there is no room. */\n.links {\n display: flex;\n flex-wrap: wrap;\n align-items: center;\n gap: 0.5rem 1.25rem;\n font-size: 0.875rem;\n}\n\n/* Under the account's id, with the facts about it rather than the controls. */\n.evidence {\n margin: 0.375rem 0 0;\n font-size: 0.8125rem;\n}\n\n.connection dl {\n margin-bottom: 0.75rem;\n}\n.connection .side > :last-child {\n margin-bottom: 0;\n}\n.connection pre {\n margin: 0.75rem 0;\n background: var(--surface);\n}\n\n/* The embed snippet is copied once, so it stays closed until asked for. */\n.embed summary {\n width: fit-content;\n cursor: pointer;\n}\n.embed summary:focus-visible {\n outline: 2px solid var(--accent);\n outline-offset: 1px;\n}\n.embed pre {\n margin-top: 0;\n}\n.connection .actions {\n margin-top: 0.875rem;\n}\n\n/* The buttons for one connection in a row, wrapping where there is no room. */\n.actions {\n display: flex;\n flex-wrap: wrap;\n gap: 0.5rem;\n}\n.actions form {\n display: contents;\n}\n\n.actions button,\n.actions a.button {\n margin: 0;\n padding: 0.3125rem 0.75rem;\n border-color: var(--line);\n background: var(--surface);\n color: var(--ink);\n font-size: 0.8125rem;\n}\n\n.actions button:hover,\n.actions a.button:hover {\n border-color: var(--muted);\n}\n\n/* The controls that cannot be undone, together at the foot of the card. */\n.ending {\n display: flex;\n flex-wrap: wrap;\n justify-content: flex-end;\n gap: 0.5rem;\n margin-top: 0.75rem;\n padding-top: 0.75rem;\n border-top: 1px solid var(--line);\n}\n.ending form {\n margin: 0;\n}\n\n.ending button.danger {\n padding: 0.3125rem 0.75rem;\n background: var(--surface);\n color: var(--warn);\n font-size: 0.8125rem;\n}\n\nfieldset {\n margin: 0 0 1.25rem;\n padding: 1rem 1.125rem 0.25rem;\n border: 1px solid var(--line);\n border-radius: 8px;\n}\n\nlegend {\n padding: 0 0.375rem;\n color: var(--muted);\n font-size: 0.8125rem;\n}\n\nfieldset label {\n display: flex;\n align-items: baseline;\n gap: 0.5rem;\n color: var(--ink);\n font-size: 0.9375rem;\n}\n\nfieldset input {\n width: auto;\n margin: 0;\n}\n\nfieldset p {\n margin: 0.25rem 0 0.875rem 1.5rem;\n color: var(--muted);\n font-size: 0.8125rem;\n}\n";
|
|
12
12
|
/**
|
|
13
13
|
* A short digest of the sheet above, put in the link's query so a release that changes the
|
|
14
14
|
* styling changes its address. Without that the only safe cache is no cache: a reader who
|
package/dist/server/style.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import css from './style.css.js';
|
|
1
2
|
/**
|
|
2
3
|
* The one stylesheet for every page this library serves, and for the owner page of a
|
|
3
4
|
* deployment that mounts it. Served as a file rather than inlined so the pages can keep a
|
|
@@ -8,461 +9,7 @@
|
|
|
8
9
|
* leaves. So the styling does the two things that helps with, a measured column and a
|
|
9
10
|
* legible hierarchy, and nothing that would make a record look like a product.
|
|
10
11
|
*/
|
|
11
|
-
export const stylesheet =
|
|
12
|
-
--ink: #23312b;
|
|
13
|
-
--muted: #6b786f;
|
|
14
|
-
--line: #dce2de;
|
|
15
|
-
--surface: #fff;
|
|
16
|
-
--raised: #f7f9f7;
|
|
17
|
-
--accent: #245f43;
|
|
18
|
-
--warn: #a4442b;
|
|
19
|
-
--caution: #b07a12;
|
|
20
|
-
--syntax-tag: #245f43;
|
|
21
|
-
--syntax-attr: #8a5a0b;
|
|
22
|
-
--syntax-string: #2b5f8a;
|
|
23
|
-
color-scheme: light dark;
|
|
24
|
-
accent-color: var(--accent);
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
@media (prefers-color-scheme: dark) {
|
|
28
|
-
:root {
|
|
29
|
-
--ink: #dde5e0;
|
|
30
|
-
--muted: #96a39b;
|
|
31
|
-
--line: #2f3b35;
|
|
32
|
-
--surface: #161a18;
|
|
33
|
-
--raised: #1d2220;
|
|
34
|
-
--accent: #7fc4a2;
|
|
35
|
-
--warn: #e59a82;
|
|
36
|
-
--caution: #d9a843;
|
|
37
|
-
--syntax-tag: #7fc4a2;
|
|
38
|
-
--syntax-attr: #d9a843;
|
|
39
|
-
--syntax-string: #8fbbe0;
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
* { box-sizing: border-box; }
|
|
44
|
-
|
|
45
|
-
body {
|
|
46
|
-
margin: 0;
|
|
47
|
-
padding: 0 1rem 4rem;
|
|
48
|
-
background: var(--surface);
|
|
49
|
-
color: var(--ink);
|
|
50
|
-
font: 16px/1.65 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
51
|
-
text-rendering: optimizeLegibility;
|
|
52
|
-
}
|
|
53
|
-
|
|
54
|
-
main {
|
|
55
|
-
max-width: 34rem;
|
|
56
|
-
margin: 0 auto;
|
|
57
|
-
padding-top: 3rem;
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
/*
|
|
61
|
-
* The logotype, above the page's own heading, on its own dark plate. Sized so the word is
|
|
62
|
-
* the height it was without the plate, whose margin makes the box that much taller. The
|
|
63
|
-
* word is white in either scheme: the plate is what it is read against, not the page.
|
|
64
|
-
*/
|
|
65
|
-
.logo {
|
|
66
|
-
display: block;
|
|
67
|
-
height: 2.5rem;
|
|
68
|
-
margin-bottom: 1.5rem;
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
h1 {
|
|
72
|
-
margin: 0 0 1.75rem;
|
|
73
|
-
padding-bottom: 1rem;
|
|
74
|
-
border-bottom: 1px solid var(--line);
|
|
75
|
-
font-size: 1.5rem;
|
|
76
|
-
font-weight: 620;
|
|
77
|
-
letter-spacing: -.02em;
|
|
78
|
-
line-height: 1.25;
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
/*
|
|
82
|
-
* A page holding one thing needs no rule under its heading. The rule divides a heading
|
|
83
|
-
* from the record beneath it, and a page that only asks for a key has no record to divide.
|
|
84
|
-
*/
|
|
85
|
-
main.single h1 { margin-bottom: 1.25rem; padding-bottom: 0; border-bottom: none; }
|
|
86
|
-
|
|
87
|
-
/*
|
|
88
|
-
* A page holding one thing sits in the middle of the window rather than at its top,
|
|
89
|
-
* where it would leave most of the window empty below it.
|
|
90
|
-
*/
|
|
91
|
-
body:has(main.single) { display: flex; min-height: 100vh; min-height: 100dvh; }
|
|
92
|
-
main.single { width: 100%; max-width: 24rem; margin: auto; padding-bottom: 3rem; }
|
|
93
|
-
|
|
94
|
-
h2 { margin: 2rem 0 .75rem; font-size: 1.125rem; font-weight: 620; letter-spacing: -.01em; }
|
|
95
|
-
|
|
96
|
-
h3 { margin: 0 0 .5rem; font-size: 1rem; font-weight: 620; }
|
|
97
|
-
|
|
98
|
-
p { margin: 0 0 1rem; overflow-wrap: break-word; }
|
|
99
|
-
|
|
100
|
-
a { color: var(--accent); text-underline-offset: 3px; overflow-wrap: anywhere; }
|
|
101
|
-
|
|
102
|
-
a:hover { text-decoration-thickness: 2px; }
|
|
103
|
-
|
|
104
|
-
/*
|
|
105
|
-
* Something to be run or published exactly as written. Its own line breaks are kept and a
|
|
106
|
-
* long line is soft-wrapped rather than cut off: a soft wrap is drawn, not inserted, so
|
|
107
|
-
* what is copied is still character for character what was written. Selecting inside the
|
|
108
|
-
* block takes all of it, since half a command is worse than none.
|
|
109
|
-
*/
|
|
110
|
-
pre {
|
|
111
|
-
position: relative;
|
|
112
|
-
margin: 0 0 1rem;
|
|
113
|
-
/* Room along the top line for the copy button, which sits over the block rather than in it. */
|
|
114
|
-
padding: .75rem 5.25rem .75rem .875rem;
|
|
115
|
-
border: 1px solid var(--line);
|
|
116
|
-
border-radius: 6px;
|
|
117
|
-
background: var(--raised);
|
|
118
|
-
white-space: pre-wrap;
|
|
119
|
-
overflow-wrap: anywhere;
|
|
120
|
-
user-select: all;
|
|
121
|
-
}
|
|
122
|
-
|
|
123
|
-
code { font: .8125rem/1.6 ui-monospace, SFMono-Regular, Menlo, monospace; }
|
|
124
|
-
|
|
125
|
-
/* Highlighted HTML, marked up by highlight.js. Brackets stay muted so the names read first. */
|
|
126
|
-
.hljs-tag { color: var(--muted); }
|
|
127
|
-
.hljs-name { color: var(--syntax-tag); }
|
|
128
|
-
.hljs-attr { color: var(--syntax-attr); }
|
|
129
|
-
.hljs-string { color: var(--syntax-string); }
|
|
130
|
-
|
|
131
|
-
/* Made by a script, so it exists only where it works. Quiet: the block is the point. */
|
|
132
|
-
.copy {
|
|
133
|
-
position: absolute;
|
|
134
|
-
top: .5rem;
|
|
135
|
-
right: .5rem;
|
|
136
|
-
padding: .1875rem .5rem;
|
|
137
|
-
border: 1px solid var(--line);
|
|
138
|
-
border-radius: 5px;
|
|
139
|
-
background: var(--surface);
|
|
140
|
-
color: var(--muted);
|
|
141
|
-
font: 500 .75rem/1.5 system-ui, sans-serif;
|
|
142
|
-
user-select: none;
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
.copy:hover { color: var(--ink); border-color: var(--muted); }
|
|
146
|
-
|
|
147
|
-
/*
|
|
148
|
-
* The two sides of the link, which is what a reader came to read. Each fact about a side
|
|
149
|
-
* gets its own line: what it is, what it is called, the identifier behind that, and how it
|
|
150
|
-
* was shown. Everything else on the page qualifies the pair, so it is set quieter.
|
|
151
|
-
*/
|
|
152
|
-
.side {
|
|
153
|
-
margin-bottom: .75rem;
|
|
154
|
-
padding: .875rem 1rem;
|
|
155
|
-
border: 1px solid var(--line);
|
|
156
|
-
border-radius: 8px;
|
|
157
|
-
background: var(--raised);
|
|
158
|
-
}
|
|
159
|
-
|
|
160
|
-
/*
|
|
161
|
-
* A subject's accounts are peers, so where there is room they sit two across. The page
|
|
162
|
-
* that lists them is wider for it, and a narrow one keeps them in a single column.
|
|
163
|
-
*/
|
|
164
|
-
main:has(.accounts) { max-width: 54rem; }
|
|
165
|
-
|
|
166
|
-
.accounts {
|
|
167
|
-
display: grid;
|
|
168
|
-
grid-template-columns: minmax(0, 1fr);
|
|
169
|
-
gap: .75rem;
|
|
170
|
-
margin-bottom: .75rem;
|
|
171
|
-
}
|
|
172
|
-
|
|
173
|
-
.accounts .side { position: relative; display: flex; flex-direction: column; margin-bottom: 0; }
|
|
174
|
-
|
|
175
|
-
/* How the holder lists the account, in the card's corner and out of the lines below. */
|
|
176
|
-
.listing {
|
|
177
|
-
position: absolute;
|
|
178
|
-
top: .75rem;
|
|
179
|
-
right: .875rem;
|
|
180
|
-
padding: .0625rem .5rem;
|
|
181
|
-
border: 1px solid var(--line);
|
|
182
|
-
border-radius: 999px;
|
|
183
|
-
color: var(--muted);
|
|
184
|
-
font-size: .6875rem;
|
|
185
|
-
font-weight: 550;
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
.listing.preferred { border-color: var(--accent); color: var(--accent); }
|
|
189
|
-
|
|
190
|
-
/* The times sit at the foot of the card, so they line up along a row of uneven cards. */
|
|
191
|
-
.accounts .side dl { margin-top: auto; }
|
|
192
|
-
.accounts .rest { display: flex; flex-direction: column; }
|
|
193
|
-
.accounts .rest > p:last-of-type { margin-bottom: .625rem; }
|
|
194
|
-
|
|
195
|
-
/*
|
|
196
|
-
* Two across, with the subject one card wide and centred above them. Every card on the
|
|
197
|
-
* page is then the same width.
|
|
198
|
-
*/
|
|
199
|
-
@media (min-width: 48rem) {
|
|
200
|
-
.accounts { grid-template-columns: repeat(2, minmax(0, 1fr)); }
|
|
201
|
-
/* Each card is three rows of the grid: who, its verdict, and the rest. A row is as tall
|
|
202
|
-
as the taller card's part, so the verdicts and times of neighbouring cards line up. */
|
|
203
|
-
.accounts > .side { display: grid; grid-row: span 3; grid-template-rows: subgrid; row-gap: 0; }
|
|
204
|
-
.subject { width: calc(50% - .375rem); margin-inline: auto; text-align: center; }
|
|
205
|
-
.subject .name { justify-content: center; }
|
|
206
|
-
}
|
|
207
|
-
|
|
208
|
-
/* Between a subject and its accounts on the page that lists them. */
|
|
209
|
-
.joiner { display: block; width: 1.25rem; height: 1.25rem; margin: 0 auto .75rem; color: var(--muted); }
|
|
210
|
-
|
|
211
|
-
.who {
|
|
212
|
-
margin: 0 0 .125rem;
|
|
213
|
-
color: var(--muted);
|
|
214
|
-
font-size: .75rem;
|
|
215
|
-
font-weight: 550;
|
|
216
|
-
letter-spacing: .02em;
|
|
217
|
-
}
|
|
218
|
-
|
|
219
|
-
/* A provider's mark before its name, at the height of the letters. */
|
|
220
|
-
.who .provider { display: inline-block; width: .875rem; height: .875rem; margin-right: .375rem; vertical-align: -.125rem; }
|
|
221
|
-
|
|
222
|
-
/* Clipped 4px left of the text, which hides the date's dot when the date wraps to a new line. */
|
|
223
|
-
.name { display: flex; flex-wrap: wrap; align-items: baseline; gap: 0 1rem; margin: 0 0 0 -4px; padding-left: 4px; overflow-x: clip; font-size: 1.0625rem; font-weight: 620; letter-spacing: -.01em; }
|
|
224
|
-
|
|
225
|
-
/* The account's creation date, after the name and a dot. It wraps under a long name. */
|
|
226
|
-
.name .since { position: relative; color: var(--muted); font-size: .8125rem; font-weight: 400; letter-spacing: 0; white-space: nowrap; }
|
|
227
|
-
|
|
228
|
-
/* The dot sits in the gap before the date. */
|
|
229
|
-
.name .since::before { content: "·"; position: absolute; left: -.5rem; transform: translateX(-50%); }
|
|
230
|
-
|
|
231
|
-
/* The name is the card's subject before it is a link, so the rule is drawn on hover. */
|
|
232
|
-
.name a { text-decoration: none; }
|
|
233
|
-
|
|
234
|
-
.name a:hover { text-decoration: underline; }
|
|
235
|
-
|
|
236
|
-
.reference, .how { margin: 0; color: var(--muted); font-size: .8125rem; line-height: 1.5; }
|
|
237
|
-
|
|
238
|
-
.identity + .how { margin-top: .5rem; }
|
|
239
|
-
.fingerprint { font-family: ui-monospace, monospace; text-wrap: balance; }
|
|
240
|
-
.fingerprint span { display: inline-block; margin-right: .5ch; }
|
|
241
|
-
.how.additional { padding-left: .75rem; }
|
|
242
|
-
/* The "signed" pill after the verifier's name, one size smaller than the line it sits on. */
|
|
243
|
-
.how .signed-mark { display: inline-block; margin-left: .3125rem; padding: 0 .375rem; border: 1px solid var(--line); border-radius: 999px; font-size: .625rem; font-weight: 550; line-height: 1.3; text-decoration: none; vertical-align: .0625rem; }
|
|
244
|
-
|
|
245
|
-
.fine { color: var(--muted); font-size: .8125rem; line-height: 1.55; margin-bottom: .625rem; }
|
|
246
|
-
|
|
247
|
-
/* That the record is signed is a fact about it, so it is set as one and not as fine print. */
|
|
248
|
-
.signed { font-size: .875rem; line-height: 1.55; margin-bottom: .875rem; }
|
|
249
|
-
/* Arrived at from a badge's "signed" link, so the reader is shown where they landed. */
|
|
250
|
-
.signed:target { margin-inline: -.75rem; padding: .625rem .75rem; border-radius: 8px; background: var(--raised); }
|
|
251
|
-
|
|
252
|
-
/* Every time on the record in one column, so they can be compared rather than hunted for. */
|
|
253
|
-
dl {
|
|
254
|
-
display: grid;
|
|
255
|
-
grid-template-columns: auto 1fr;
|
|
256
|
-
gap: .3rem 1.5rem;
|
|
257
|
-
margin: 1.25rem 0;
|
|
258
|
-
padding-top: 1rem;
|
|
259
|
-
border-top: 1px solid var(--line);
|
|
260
|
-
font-size: .8125rem;
|
|
261
|
-
}
|
|
262
|
-
|
|
263
|
-
dt { color: var(--muted); }
|
|
264
|
-
|
|
265
|
-
dd { margin: 0; font-variant-numeric: tabular-nums; }
|
|
266
|
-
|
|
267
|
-
/* Inside a card the rule above it is the card's own edge, so the list needs none. */
|
|
268
|
-
section dl { margin: .5rem 0 1rem; padding-top: 0; border-top: 0; }
|
|
269
|
-
|
|
270
|
-
/* Right under the heading, the heading's own rule is the one above it. */
|
|
271
|
-
h1 + dl { padding-top: 0; border-top: 0; }
|
|
272
|
-
.side dl { margin: .625rem 0 0; padding-top: .625rem; }
|
|
273
|
-
|
|
274
|
-
/* The links under a record, ruled off from the record and its disclaimer. */
|
|
275
|
-
footer { margin-top: 1.25rem; padding-top: 1rem; border-top: 1px solid var(--line); }
|
|
276
|
-
footer > :last-child { margin-bottom: 0; }
|
|
277
|
-
|
|
278
|
-
section {
|
|
279
|
-
margin: 0 0 1.25rem;
|
|
280
|
-
padding: 1.25rem 1.375rem;
|
|
281
|
-
border: 1px solid var(--line);
|
|
282
|
-
border-radius: 10px;
|
|
283
|
-
}
|
|
284
|
-
|
|
285
|
-
section > :last-child { margin-bottom: 0; }
|
|
286
|
-
|
|
287
|
-
/* What holds a control that cannot be undone. */
|
|
288
|
-
section.danger, section.caution { margin-top: 2rem; }
|
|
289
|
-
section.danger { border-color: var(--warn); }
|
|
290
|
-
|
|
291
|
-
/* What holds a control that breaks something for a while, but can be recovered from. */
|
|
292
|
-
section.caution { border-color: var(--caution); }
|
|
293
|
-
section > h2:first-child { margin-top: 0; }
|
|
294
|
-
|
|
295
|
-
form { margin: 0 0 1.5rem; }
|
|
296
|
-
|
|
297
|
-
label { display: block; margin: 0 0 .75rem; color: var(--muted); font-size: .8125rem; }
|
|
298
|
-
|
|
299
|
-
input, textarea {
|
|
300
|
-
display: block;
|
|
301
|
-
width: 100%;
|
|
302
|
-
margin-top: .375rem;
|
|
303
|
-
padding: .5rem .625rem;
|
|
304
|
-
border: 1px solid var(--line);
|
|
305
|
-
border-radius: 6px;
|
|
306
|
-
background: var(--surface);
|
|
307
|
-
color: var(--ink);
|
|
308
|
-
font: .875rem/1.5 ui-monospace, SFMono-Regular, Menlo, monospace;
|
|
309
|
-
}
|
|
310
|
-
|
|
311
|
-
/* Height comes from the rows attribute, which differs per box. */
|
|
312
|
-
textarea { resize: vertical; }
|
|
313
|
-
|
|
314
|
-
input:focus-visible, textarea:focus-visible { outline: 2px solid var(--accent); outline-offset: 1px; }
|
|
315
|
-
|
|
316
|
-
button {
|
|
317
|
-
padding: .5rem 1rem;
|
|
318
|
-
border: 1px solid var(--accent);
|
|
319
|
-
border-radius: 6px;
|
|
320
|
-
background: var(--accent);
|
|
321
|
-
color: var(--surface);
|
|
322
|
-
font: 500 .9375rem/1.4 system-ui, -apple-system, 'Segoe UI', sans-serif;
|
|
323
|
-
cursor: pointer;
|
|
324
|
-
}
|
|
325
|
-
|
|
326
|
-
/* A link that starts something, drawn as a button. */
|
|
327
|
-
a.button {
|
|
328
|
-
display: inline-block;
|
|
329
|
-
padding: .5rem 1rem;
|
|
330
|
-
border: 1px solid var(--accent);
|
|
331
|
-
border-radius: 6px;
|
|
332
|
-
background: var(--accent);
|
|
333
|
-
color: var(--surface);
|
|
334
|
-
font-weight: 500;
|
|
335
|
-
font-size: .9375rem;
|
|
336
|
-
line-height: 1.4;
|
|
337
|
-
text-decoration: none;
|
|
338
|
-
}
|
|
339
|
-
|
|
340
|
-
button + button { margin-left: .5rem; border-color: var(--line); background: none; color: var(--ink); }
|
|
341
|
-
|
|
342
|
-
/* The other choice beside a page's one action, such as Cancel. */
|
|
343
|
-
a.button.secondary { border-color: var(--line); background: none; color: var(--ink); }
|
|
344
|
-
|
|
345
|
-
/* A page's action and its alternative, side by side. */
|
|
346
|
-
.choice { display: flex; flex-wrap: wrap; gap: .5rem; margin-bottom: 1.5rem; }
|
|
347
|
-
.choice form { margin: 0; }
|
|
348
|
-
|
|
349
|
-
/* Ways to verify: one full-width button per method, none filled over the others. */
|
|
350
|
-
.choices { display: grid; gap: .5rem; margin-bottom: 1.5rem; }
|
|
351
|
-
.choices form { margin: 0; }
|
|
352
|
-
|
|
353
|
-
.choices button {
|
|
354
|
-
width: 100%;
|
|
355
|
-
text-align: left;
|
|
356
|
-
border-color: var(--line);
|
|
357
|
-
background: var(--surface);
|
|
358
|
-
color: var(--ink);
|
|
359
|
-
}
|
|
360
|
-
|
|
361
|
-
.choices button:hover { border-color: var(--muted); }
|
|
362
|
-
|
|
363
|
-
/* A provider's mark before a button's label, at the height of the letters. */
|
|
364
|
-
button .provider { width: 1rem; height: 1rem; margin-right: .5rem; vertical-align: -.1875rem; }
|
|
365
|
-
|
|
366
|
-
/* A control that ends something. Filled where it is the page's one action. */
|
|
367
|
-
button.danger { border-color: var(--warn); background: var(--warn); }
|
|
368
|
-
|
|
369
|
-
/*
|
|
370
|
-
* A connection on the settings page: the account's card, then what can be done with it.
|
|
371
|
-
* Its state sits in the card's corner, on the line that names the method.
|
|
372
|
-
*/
|
|
373
|
-
.connection { position: relative; margin-bottom: 1rem; }
|
|
374
|
-
|
|
375
|
-
.state {
|
|
376
|
-
position: absolute;
|
|
377
|
-
top: .75rem;
|
|
378
|
-
right: .875rem;
|
|
379
|
-
display: flex;
|
|
380
|
-
align-items: center;
|
|
381
|
-
gap: .375rem;
|
|
382
|
-
height: 1.625rem;
|
|
383
|
-
padding: 0 .75rem 0 .5rem;
|
|
384
|
-
border: 1px solid var(--line);
|
|
385
|
-
border-radius: 999px;
|
|
386
|
-
background: var(--surface);
|
|
387
|
-
color: var(--ink);
|
|
388
|
-
font-size: .8125rem;
|
|
389
|
-
font-weight: 550;
|
|
390
|
-
}
|
|
391
|
-
|
|
392
|
-
/*
|
|
393
|
-
* The V the badge draws, in the tone that says how the record stands. A record that claims
|
|
394
|
-
* nothing is drawn faint in the text colour, as the badge draws it.
|
|
395
|
-
*/
|
|
396
|
-
.verdict { flex-shrink: 0; width: 1rem; height: 1rem; }
|
|
397
|
-
.verdict.pending { opacity: .45; }
|
|
398
|
-
.how .verdict { width: .875rem; height: .875rem; margin-right: .3125rem; vertical-align: -.125rem; }
|
|
399
|
-
/* Cropped to its strokes and taller than the heading's letters, centred beside them. */
|
|
400
|
-
h1:has(.verdict) { display: flex; align-items: center; gap: .75rem; }
|
|
401
|
-
h1 .verdict { width: auto; height: 2.25rem; }
|
|
402
|
-
|
|
403
|
-
/*
|
|
404
|
-
* In a state pill the V is cropped to its strokes and fills the pill's height, so its arms
|
|
405
|
-
* and its foot meet the border. The pill's left padding keeps the arms clear of its curve.
|
|
406
|
-
*/
|
|
407
|
-
.state .verdict { width: auto; height: 100%; }
|
|
408
|
-
|
|
409
|
-
/*
|
|
410
|
-
* A pill's line includes room for descenders below the letters, which leaves its text
|
|
411
|
-
* sitting high. Trimmed to the letters, the padding alone sets the space above and below.
|
|
412
|
-
* In a state pill the word alone is trimmed, so it centres on the V by its letters.
|
|
413
|
-
*/
|
|
414
|
-
@supports (text-box: trim-both cap alphabetic) {
|
|
415
|
-
.listing { padding: .3125rem .5rem; text-box: trim-both cap alphabetic; }
|
|
416
|
-
.state > span { text-box: trim-both cap alphabetic; }
|
|
417
|
-
}
|
|
418
|
-
|
|
419
|
-
/* Links that sit together on one line, wrapping where there is no room. */
|
|
420
|
-
.links { display: flex; flex-wrap: wrap; align-items: center; gap: .5rem 1.25rem; font-size: .875rem; }
|
|
421
|
-
|
|
422
|
-
/* Under the account's id, with the facts about it rather than the controls. */
|
|
423
|
-
.evidence { margin: .375rem 0 0; font-size: .8125rem; }
|
|
424
|
-
|
|
425
|
-
.connection dl { margin-bottom: .75rem; }
|
|
426
|
-
.connection .side > :last-child { margin-bottom: 0; }
|
|
427
|
-
.connection pre { margin: .75rem 0; background: var(--surface); }
|
|
428
|
-
.connection .actions { margin-top: .875rem; }
|
|
429
|
-
|
|
430
|
-
/* The buttons for one connection in a row, wrapping where there is no room. */
|
|
431
|
-
.actions { display: flex; flex-wrap: wrap; gap: .5rem; }
|
|
432
|
-
.actions form { display: contents; }
|
|
433
|
-
|
|
434
|
-
.actions button, .actions a.button {
|
|
435
|
-
margin: 0;
|
|
436
|
-
padding: .3125rem .75rem;
|
|
437
|
-
border-color: var(--line);
|
|
438
|
-
background: var(--surface);
|
|
439
|
-
color: var(--ink);
|
|
440
|
-
font-size: .8125rem;
|
|
441
|
-
}
|
|
442
|
-
|
|
443
|
-
.actions button:hover, .actions a.button:hover { border-color: var(--muted); }
|
|
444
|
-
|
|
445
|
-
/* The controls that cannot be undone, together at the foot of the card. */
|
|
446
|
-
.ending { display: flex; flex-wrap: wrap; justify-content: flex-end; gap: .5rem; margin-top: .75rem; padding-top: .75rem; border-top: 1px solid var(--line); }
|
|
447
|
-
.ending form { margin: 0; }
|
|
448
|
-
|
|
449
|
-
.ending button.danger {
|
|
450
|
-
padding: .3125rem .75rem;
|
|
451
|
-
background: var(--surface);
|
|
452
|
-
color: var(--warn);
|
|
453
|
-
font-size: .8125rem;
|
|
454
|
-
}
|
|
455
|
-
|
|
456
|
-
fieldset { margin: 0 0 1.25rem; padding: 1rem 1.125rem .25rem; border: 1px solid var(--line); border-radius: 8px; }
|
|
457
|
-
|
|
458
|
-
legend { padding: 0 .375rem; color: var(--muted); font-size: .8125rem; }
|
|
459
|
-
|
|
460
|
-
fieldset label { display: flex; align-items: baseline; gap: .5rem; color: var(--ink); font-size: .9375rem; }
|
|
461
|
-
|
|
462
|
-
fieldset input { width: auto; margin: 0; }
|
|
463
|
-
|
|
464
|
-
fieldset p { margin: .25rem 0 .875rem 1.5rem; color: var(--muted); font-size: .8125rem; }
|
|
465
|
-
`;
|
|
12
|
+
export const stylesheet = css;
|
|
466
13
|
/**
|
|
467
14
|
* A short digest of the sheet above, put in the link's query so a release that changes the
|
|
468
15
|
* styling changes its address. Without that the only safe cache is no cache: a reader who
|
package/dist/site/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type
|
|
1
|
+
import { type Evidence, type LocalKind, type Visibility } from '../core/index.js';
|
|
2
2
|
/**
|
|
3
3
|
* For a site that uses a hosted Verily instance instead of running its own. The site's
|
|
4
4
|
* backend does three things, and this is all of them: it vouches to the instance for its
|
|
@@ -120,10 +120,13 @@ export declare function createSiteClient(options: SiteClientOptions): {
|
|
|
120
120
|
* them with. Only this site can read them. Every id asked for is in the answer, with an
|
|
121
121
|
* empty list for a subject who has none. Revoked and expired records are included, so
|
|
122
122
|
* show one only when its `status` is `verified`. With `cacheMs` set, an answer read
|
|
123
|
-
* within it is reused unless `fresh` asks for a new one.
|
|
123
|
+
* within it is reused unless `fresh` asks for a new one. With `maxAgeMs` set, a
|
|
124
|
+
* verified record whose account was last proved longer ago than that reads as
|
|
125
|
+
* `unconfirmed`.
|
|
124
126
|
*/
|
|
125
|
-
connections(ids: string[], { fresh }?: {
|
|
127
|
+
connections(ids: string[], { fresh, maxAgeMs }?: {
|
|
126
128
|
fresh?: boolean;
|
|
129
|
+
maxAgeMs?: number;
|
|
127
130
|
}): Promise<Record<string, Evidence[]>>;
|
|
128
131
|
/**
|
|
129
132
|
* For the return endpoint: the result a user came back with, if the instance signed it
|
package/dist/site/index.js
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { withMaxAge } from '../core/index.js';
|
|
1
2
|
/** How many subjects the instance reads in one request. */
|
|
2
3
|
const maxReadIds = 50;
|
|
3
4
|
const encoder = new TextEncoder();
|
|
@@ -127,9 +128,11 @@ export function createSiteClient(options) {
|
|
|
127
128
|
* them with. Only this site can read them. Every id asked for is in the answer, with an
|
|
128
129
|
* empty list for a subject who has none. Revoked and expired records are included, so
|
|
129
130
|
* show one only when its `status` is `verified`. With `cacheMs` set, an answer read
|
|
130
|
-
* within it is reused unless `fresh` asks for a new one.
|
|
131
|
+
* within it is reused unless `fresh` asks for a new one. With `maxAgeMs` set, a
|
|
132
|
+
* verified record whose account was last proved longer ago than that reads as
|
|
133
|
+
* `unconfirmed`.
|
|
131
134
|
*/
|
|
132
|
-
async connections(ids, { fresh = false } = {}) {
|
|
135
|
+
async connections(ids, { fresh = false, maxAgeMs } = {}) {
|
|
133
136
|
// No prototype, so an id such as `__proto__` is an entry like any other.
|
|
134
137
|
const answer = Object.create(null);
|
|
135
138
|
const found = Object.create(null);
|
|
@@ -169,7 +172,7 @@ export function createSiteClient(options) {
|
|
|
169
172
|
}
|
|
170
173
|
}
|
|
171
174
|
for (const [id, name] of names)
|
|
172
|
-
answer[id] = found[name] ?? [];
|
|
175
|
+
answer[id] = (found[name] ?? []).map((e) => withMaxAge(e, maxAgeMs, now));
|
|
173
176
|
return answer;
|
|
174
177
|
},
|
|
175
178
|
/**
|