chadtmiller.com/pds.js
An atproto PDS in JavaScript, for Cloudflare Workers and Node
0
0
@import "tailwindcss";
/* The same semantic tokens the account pages use, so a repository browsed
here looks like the rest of pds.js. Fonts stay on the system stacks: the
build inlines every asset into one document, and a webfont would multiply
its size. */
/* Every palette below sets the same names, so a component asks for a
meaning and the theme decides its colour. Nothing styles itself against
whether the page is dark: a theme that runs dark says so in one place,
`color-scheme`, and the tokens carry the rest. */
@theme inline {
--color-background: var(--background);
--color-card: var(--card);
--color-muted: var(--muted);
--color-accent: var(--accent);
--color-border: var(--border);
--color-input: var(--input);
--color-foreground: var(--foreground);
--color-muted-foreground: var(--muted-foreground);
--color-faint: var(--faint);
--color-primary: var(--primary);
--color-primary-foreground: var(--primary-foreground);
--color-secondary: var(--secondary);
--color-secondary-foreground: var(--secondary-foreground);
--color-accent-foreground: var(--accent-foreground);
--color-destructive: var(--destructive);
--color-destructive-dim: var(--destructive-dim);
--color-success: var(--success);
--color-success-dim: var(--success-dim);
--color-ring: var(--ring);
--color-key: var(--key);
/* Diff surfaces. Each pairs a wash for the row with ink for its text, so
an added and a deleted line stay apart for a red-green viewer by
lightness as well as hue. */
--color-diff-add: var(--diff-add);
--color-diff-add-ink: var(--diff-add-ink);
--color-diff-del: var(--diff-del);
--color-diff-del-ink: var(--diff-del-ink);
--color-diff-meta: var(--diff-meta);
/* One radius scale for every surface. Panels are divided by rules rather
than drawn as tiles, so the corners are small: a control takes the
middle step and a floating panel one above it. Every rounded-* utility
resolves here, so a component asks for the shape it wants and gets
this. */
--radius-sm: 4px;
--radius-md: 6px;
--radius-lg: 6px;
--radius-xl: 8px;
--radius-2xl: 8px;
--radius-3xl: 10px;
--font-sans: system-ui, -apple-system, "Segoe UI", sans-serif;
--font-mono: ui-monospace, SFMono-Regular, menlo, monospace;
}
/* One ramp, no hue. A reading is told from its neighbours by how light it is
and where it sits, the way a segment display tells them apart. A failure is
the one exception: a reader must not miss one, and the shape of a glyph
asks too much of them on its own. */
:root {
color-scheme: light dark;
/* The margin every band above the panes is set against, so the heading,
the sections, the view controls and the commit line all begin on one
line down the left. */
--gutter: 1.25rem;
--background: #f4f4f2;
--card: #fbfbf9;
--muted: #ebebe8;
--accent: #e1e1dd;
--border: #d8d8d3;
--input: #c2c2bc;
--foreground: #121212;
--muted-foreground: #565654;
--faint: #868682;
--primary: #121212;
--primary-foreground: #f4f4f2;
--secondary: #e6e6e2;
--secondary-foreground: #121212;
--accent-foreground: #121212;
--destructive: #a8291f;
--destructive-dim: #eee2e0;
--success: #4a4a48;
--success-dim: #e6e6e2;
--ring: #868682;
--key: #121212;
/* A line added reads at full contrast and one taken away at half. The sign
in the gutter says which; the ink says how much it matters now. */
--diff-add: #e2e2dd;
--diff-add-ink: #121212;
--diff-del: #f0f0ec;
--diff-del-ink: #868682;
--diff-meta: #6b6b68;
--code-comment: #8a8a86;
--code-keyword: #121212;
--code-string: #4a4a48;
--code-number: #333331;
--code-title: #1c1c1a;
--code-attr: #4a4a48;
--code-meta: #6b6b68;
}
@media (prefers-color-scheme: dark) {
:root:not([data-theme]) {
--background: #0b0b0b;
--card: #111111;
--muted: #161616;
--accent: #1f1f1f;
--border: #282828;
--input: #363634;
--foreground: #ededeb;
--muted-foreground: #9a9a96;
--faint: #6b6b68;
--primary: #ededeb;
--primary-foreground: #0b0b0b;
--secondary: #242422;
--secondary-foreground: #ededeb;
--accent-foreground: #ededeb;
--destructive: #e0655c;
--destructive-dim: #1a1312;
--success: #a3a39e;
--success-dim: #171717;
--ring: #7a7a76;
--key: #ededeb;
--diff-add: #1e1e1c;
--diff-add-ink: #ededeb;
--diff-del: #121212;
--diff-del-ink: #868682;
--diff-meta: #868682;
--code-comment: #6f6f6b;
--code-keyword: #ededeb;
--code-string: #b4b4b0;
--code-number: #cfcfca;
--code-title: #e2e2de;
--code-attr: #b4b4b0;
--code-meta: #9a9a96;
}
}
:root[data-theme="dark"] {
--background: #0b0b0b;
--card: #111111;
--muted: #161616;
--accent: #1f1f1f;
--border: #282828;
--input: #363634;
--foreground: #ededeb;
--muted-foreground: #9a9a96;
--faint: #6b6b68;
--primary: #ededeb;
--primary-foreground: #0b0b0b;
--secondary: #242422;
--secondary-foreground: #ededeb;
--accent-foreground: #ededeb;
--destructive: #e0655c;
--destructive-dim: #1a1312;
--success: #a3a39e;
--success-dim: #171717;
--ring: #7a7a76;
--key: #ededeb;
--diff-add: #1e1e1c;
--diff-add-ink: #ededeb;
--diff-del: #121212;
--diff-del-ink: #868682;
--diff-meta: #868682;
--code-comment: #6f6f6b;
--code-keyword: #ededeb;
--code-string: #b4b4b0;
--code-number: #cfcfca;
--code-title: #e2e2de;
--code-attr: #b4b4b0;
--code-meta: #9a9a96;
}
@media (min-width: 640px) {
:root {
--gutter: 1.75rem;
}
}
:root[data-theme="github"] {
color-scheme: dark;
--background: #0d1117;
--card: #161b22;
--muted: #161b22;
--accent: #21262d;
--border: #30363d;
--input: #484f58;
--foreground: #e6edf3;
--muted-foreground: #8b949e;
--faint: #6e7681;
--primary: #e6edf3;
--primary-foreground: #0d1117;
--secondary: #21262d;
--secondary-foreground: #e6edf3;
--accent-foreground: #e6edf3;
--destructive: #f85149;
--destructive-dim: #2a1416;
--success: #3fb950;
--success-dim: #12261e;
--ring: #2f81f7;
--key: #2f81f7;
--diff-add: #0f2e1a;
--diff-add-ink: #aff5b4;
--diff-del: #2d1214;
--diff-del-ink: #ffdcd7;
--diff-meta: #8b949e;
--code-comment: #8b949e;
--code-keyword: #ff7b72;
--code-string: #a5d6ff;
--code-number: #79c0ff;
--code-title: #d2a8ff;
--code-attr: #7ee787;
--code-meta: #8b949e;
}
:root[data-theme="github-light"] {
color-scheme: light;
--background: #ffffff;
--card: #ffffff;
--muted: #f6f8fa;
--accent: #eaeef2;
--border: #d0d7de;
--input: #afb8c1;
--foreground: #1f2328;
--muted-foreground: #656d76;
--faint: #8c959f;
--primary: #1f2328;
--primary-foreground: #ffffff;
--secondary: #eaeef2;
--secondary-foreground: #1f2328;
--accent-foreground: #1f2328;
--destructive: #cf222e;
--destructive-dim: #ffebe9;
--success: #1a7f37;
--success-dim: #dafbe1;
--ring: #0969da;
--key: #0969da;
--diff-add: #e6ffec;
--diff-add-ink: #1f2328;
--diff-del: #ffebe9;
--diff-del-ink: #82071e;
--diff-meta: #656d76;
--code-comment: #6e7781;
--code-keyword: #cf222e;
--code-string: #0a3069;
--code-number: #0550ae;
--code-title: #8250df;
--code-attr: #116329;
--code-meta: #656d76;
}
:root[data-theme="catppuccin-mocha"] {
color-scheme: dark;
--background: #1e1e2e;
--card: #181825;
--muted: #181825;
--accent: #313244;
--border: #313244;
--input: #45475a;
--foreground: #cdd6f4;
--muted-foreground: #a6adc8;
--faint: #6c7086;
--primary: #cdd6f4;
--primary-foreground: #1e1e2e;
--secondary: #313244;
--secondary-foreground: #cdd6f4;
--accent-foreground: #cdd6f4;
--destructive: #f38ba8;
--destructive-dim: #2a1c26;
--success: #a6e3a1;
--success-dim: #1c2a22;
--ring: #cba6f7;
--key: #cba6f7;
--diff-add: #1f2d26;
--diff-add-ink: #cdd6f4;
--diff-del: #302430;
--diff-del-ink: #bac2de;
--diff-meta: #9399b2;
--code-comment: #6c7086;
--code-keyword: #cba6f7;
--code-string: #a6e3a1;
--code-number: #fab387;
--code-title: #89b4fa;
--code-attr: #f9e2af;
--code-meta: #9399b2;
}
:root[data-theme="catppuccin-latte"] {
color-scheme: light;
--background: #eff1f5;
--card: #ffffff;
--muted: #e6e9ef;
--accent: #dce0e8;
--border: #ccd0da;
--input: #bcc0cc;
--foreground: #4c4f69;
--muted-foreground: #6c6f85;
--faint: #9ca0b0;
--primary: #4c4f69;
--primary-foreground: #eff1f5;
--secondary: #dce0e8;
--secondary-foreground: #4c4f69;
--accent-foreground: #4c4f69;
--destructive: #d20f39;
--destructive-dim: #f6e0e4;
--success: #40a02b;
--success-dim: #e3f0e0;
--ring: #8839ef;
--key: #8839ef;
--diff-add: #e3f0e0;
--diff-add-ink: #4c4f69;
--diff-del: #f6e0e4;
--diff-del-ink: #6c6f85;
--diff-meta: #7c7f93;
--code-comment: #9ca0b0;
--code-keyword: #8839ef;
--code-string: #40a02b;
--code-number: #fe640b;
--code-title: #1e66f5;
--code-attr: #df8e1d;
--code-meta: #6c6f85;
}
:root[data-theme="cyberpunk"] {
color-scheme: dark;
--background: #0a0714;
--card: #100b1f;
--muted: #100b1f;
--accent: #1b1136;
--border: #2a1b4d;
--input: #3d2a66;
--foreground: #e8e2ff;
--muted-foreground: #a294cf;
--faint: #7565ab;
--primary: #e8e2ff;
--primary-foreground: #0a0714;
--secondary: #1b1136;
--secondary-foreground: #e8e2ff;
--accent-foreground: #e8e2ff;
--destructive: #ff3864;
--destructive-dim: #26091a;
--success: #39ff88;
--success-dim: #07220f;
--ring: #ff2bd6;
--key: #00f0ff;
--diff-add: #0b2419;
--diff-add-ink: #7dffb8;
--diff-del: #2a0a1c;
--diff-del-ink: #ff90b8;
--diff-meta: #a294cf;
--code-comment: #7565ab;
--code-keyword: #ff2bd6;
--code-string: #39ff88;
--code-number: #ffd23f;
--code-title: #00f0ff;
--code-attr: #c77dff;
--code-meta: #a294cf;
}
:root[data-theme="dracula"] {
color-scheme: dark;
--background: #282a36;
--card: #21222c;
--muted: #21222c;
--accent: #343746;
--border: #44475a;
--input: #6272a4;
--foreground: #f8f8f2;
--muted-foreground: #b6b9cc;
--faint: #6272a4;
--primary: #f8f8f2;
--primary-foreground: #282a36;
--secondary: #343746;
--secondary-foreground: #f8f8f2;
--accent-foreground: #f8f8f2;
--destructive: #ff5555;
--destructive-dim: #2f1f26;
--success: #50fa7b;
--success-dim: #1d2b21;
--ring: #bd93f9;
--key: #bd93f9;
--diff-add: #23372a;
--diff-add-ink: #f8f8f2;
--diff-del: #3a2430;
--diff-del-ink: #d9d6e0;
--diff-meta: #6272a4;
--code-comment: #6272a4;
--code-keyword: #ff79c6;
--code-string: #f1fa8c;
--code-number: #bd93f9;
--code-title: #50fa7b;
--code-attr: #8be9fd;
--code-meta: #6272a4;
}
:root[data-theme="tokyo-night"] {
color-scheme: dark;
--background: #1a1b26;
--card: #16161e;
--muted: #16161e;
--accent: #292e42;
--border: #292e42;
--input: #414868;
--foreground: #c0caf5;
--muted-foreground: #a9b1d6;
--faint: #565f89;
--primary: #c0caf5;
--primary-foreground: #1a1b26;
--secondary: #292e42;
--secondary-foreground: #c0caf5;
--accent-foreground: #c0caf5;
--destructive: #f7768e;
--destructive-dim: #2a1a22;
--success: #9ece6a;
--success-dim: #1b2418;
--ring: #7aa2f7;
--key: #7aa2f7;
--diff-add: #1e2b22;
--diff-add-ink: #c0caf5;
--diff-del: #2c1f28;
--diff-del-ink: #a9b1d6;
--diff-meta: #565f89;
--code-comment: #565f89;
--code-keyword: #bb9af7;
--code-string: #9ece6a;
--code-number: #ff9e64;
--code-title: #7aa2f7;
--code-attr: #7dcfff;
--code-meta: #a9b1d6;
}
/* The instrument is set in mono: every reading lines up under the one above
it, and a figure keeps its width as it counts. What is rendered from
markdown keeps that face too, so a description reads as part of the page
rather than as a document pasted into it. */
body {
margin: 0;
background: var(--background);
color: var(--foreground);
font-family: var(--font-mono);
font-variant-numeric: tabular-nums;
-webkit-font-smoothing: antialiased;
}
/* Rendered markdown inherits the page's own face. Its figures are prose
rather than readings, so they do not hold the column a table's do. */
.markdown {
font-variant-numeric: normal;
}
/* highlight.js token classes. The grammars emit many names for a handful of
roles, so each rule lists every name that should read the same way. */
.hljs-comment,
.hljs-quote {
color: var(--code-comment);
font-style: italic;
}
.hljs-keyword,
.hljs-selector-tag,
.hljs-literal,
.hljs-type,
.hljs-built_in,
.hljs-name,
.hljs-tag {
color: var(--code-keyword);
}
.hljs-string,
.hljs-regexp,
.hljs-addition,
.hljs-template-string,
.hljs-link {
color: var(--code-string);
}
.hljs-number,
.hljs-symbol,
.hljs-bullet,
.hljs-variable,
.hljs-template-variable {
color: var(--code-number);
}
.hljs-title,
.hljs-title\.function_,
.hljs-title\.class_,
.hljs-section,
.hljs-selector-id,
.hljs-selector-class {
color: var(--code-title);
}
.hljs-attr,
.hljs-attribute,
.hljs-property,
.hljs-params,
.hljs-doctag {
color: var(--code-attr);
}
.hljs-meta,
.hljs-comment .hljs-doctag,
.hljs-deletion {
color: var(--code-meta);
}
.hljs-strong {
font-weight: 600;
}
.hljs-emphasis {
font-style: italic;
}
/* The read indicator eases in rather than appearing, so a read that finishes
just past the quiet window does not snap on and straight off again. */
@keyframes fade-in {
from {
opacity: 0;
}
to {
opacity: 1;
}
}
.fade-in {
animation: fade-in 180ms ease-out both;
}
@media (prefers-reduced-motion: reduce) {
.fade-in {
animation: none;
}
}
/* Rendered markdown. Sized to sit beside the file listing rather than to be
read as a page of prose on its own. */
.markdown {
font-size: 15px;
line-height: 1.65;
overflow-wrap: anywhere;
}
/* Prose about the work rather than in it: a description, a review, an issue.
It sits among the app's own text and reads at the app's own size, where a
readme has a pane to itself and can be larger. This rule is unlayered, the
way .markdown is, because a Tailwind size utility is in a layer and would
lose to the rule above whatever the caller asked for. */
.markdown-prose {
font-size: 13.5px;
line-height: 1.6;
}
.markdown > *:first-child {
margin-top: 0;
}
.markdown > *:last-child {
margin-bottom: 0;
}
.markdown h1,
.markdown h2,
.markdown h3,
.markdown h4,
.markdown h5,
.markdown h6 {
margin: 1.6em 0 0.6em;
font-weight: 650;
line-height: 1.3;
letter-spacing: -0.01em;
}
.markdown h1 {
font-size: 1.6em;
padding-bottom: 0.3em;
border-bottom: 1px solid var(--border);
}
.markdown h2 {
font-size: 1.3em;
padding-bottom: 0.3em;
border-bottom: 1px solid var(--border);
}
.markdown h3 {
font-size: 1.1em;
}
.markdown h4,
.markdown h5,
.markdown h6 {
font-size: 1em;
}
.markdown p,
.markdown ul,
.markdown ol,
.markdown blockquote,
.markdown table,
.markdown pre {
margin: 0 0 1em;
}
.markdown ul,
.markdown ol {
padding-left: 1.6em;
}
.markdown ul {
list-style: disc;
}
.markdown ol {
list-style: decimal;
}
.markdown li {
margin: 0.25em 0;
}
.markdown li > ul,
.markdown li > ol {
margin: 0.25em 0;
}
.markdown a {
color: var(--key);
text-decoration: underline;
text-underline-offset: 2px;
}
.markdown blockquote {
padding: 0.1em 0 0.1em 1em;
border-left: 3px solid var(--border);
color: var(--muted-foreground);
}
.markdown code {
font-family: var(--font-mono);
font-size: 0.87em;
background: var(--muted);
border: 1px solid var(--border);
border-radius: var(--radius-sm);
padding: 0.1em 0.35em;
}
.markdown pre.md-code {
background: var(--muted);
border: 1px solid var(--border);
border-radius: var(--radius-lg);
padding: 14px 16px;
overflow-x: auto;
}
/* A fence carries its own surface, so the span inside it drops the one a
lone code span wears. */
.markdown pre.md-code code {
background: none;
border: 0;
padding: 0;
font-size: 12.5px;
line-height: 1.6;
}
.markdown table {
border-collapse: collapse;
display: block;
overflow-x: auto;
font-size: 0.93em;
}
.markdown th,
.markdown td {
border: 1px solid var(--border);
padding: 6px 12px;
text-align: left;
}
.markdown th {
background: var(--muted);
font-weight: 620;
}
.markdown hr {
margin: 1.6em 0;
border: 0;
border-top: 1px solid var(--border);
}
.markdown img {
max-width: 100%;
height: auto;
border-radius: var(--radius-lg);
}
.markdown input[type="checkbox"] {
margin-right: 0.4em;
}
/* A document aligns a table cell or a banner with the align attribute. An
author rule beats that attribute, and the rules above set text-align on a
cell, so the attribute needs a rule of its own. */
.markdown [align="center"] {
text-align: center;
}
.markdown [align="right"] {
text-align: right;
}
.markdown [align="left"] {
text-align: left;
}
.markdown details {
margin: 0 0 1em;
}
.markdown summary {
cursor: pointer;
font-weight: 620;
}
.markdown figure {
margin: 0 0 1em;
}
.markdown .md-lfs {
display: inline-block;
padding: 0.5em 0.8em;
border: 1px dashed var(--border);
border-radius: var(--radius-lg);
color: var(--faint);
font-size: 0.9em;
}