mirror of
https://github.com/zed-industries/zed.git
synced 2026-07-09 16:00:35 +00:00
Some checks are pending
Congratsbot / check-author (push) Waiting to run
Congratsbot / congrats (push) Blocked by required conditions
deploy_nightly_docs / deploy_docs (push) Waiting to run
run_tests / orchestrate (push) Waiting to run
run_tests / check_style (push) Waiting to run
run_tests / clippy_windows (push) Blocked by required conditions
run_tests / clippy_linux (push) Blocked by required conditions
run_tests / clippy_mac (push) Blocked by required conditions
run_tests / clippy_mac_x86_64 (push) Blocked by required conditions
run_tests / run_tests_windows (push) Blocked by required conditions
run_tests / run_tests_linux (push) Blocked by required conditions
run_tests / run_tests_mac (push) Blocked by required conditions
run_tests / miri_scheduler (push) Blocked by required conditions
run_tests / doctests (push) Blocked by required conditions
run_tests / check_workspace_binaries (push) Blocked by required conditions
run_tests / build_visual_tests_binary (push) Blocked by required conditions
run_tests / check_wasm (push) Blocked by required conditions
run_tests / check_dependencies (push) Blocked by required conditions
run_tests / check_docs (push) Blocked by required conditions
run_tests / check_licenses (push) Blocked by required conditions
run_tests / check_scripts (push) Blocked by required conditions
run_tests / check_postgres_and_protobuf_migrations (push) Blocked by required conditions
run_tests / extension_tests (push) Blocked by required conditions
run_tests / tests_pass (push) Blocked by required conditions
Context This PR makes the Zed docs easier for AI tools, search crawlers, and users to consume without changing the visible docs content. The current production docs are primarily optimized for browser navigation. They do not expose first-class Markdown URLs, an `llms.txt` index, page-level copy affordances, or machine-readable freshness metadata that let users and agents grab clean, current page content. Changes - Generate Markdown copies for docs pages during the mdBook postprocess step, including `/docs/index.md` as an alias for Getting Started. - Generate `/docs/llms.txt` from the mdBook chapter list, grouped by `SUMMARY.md` sections and annotated with page frontmatter descriptions. - Generate `/docs/sitemap.xml` with `<lastmod>` values for every docs page. - Emit machine-readable freshness metadata in HTML via `last-modified` and `article:modified_time` meta tags. - Generate Cloudflare Pages `_redirects` for `.html`, extensionless, and `.md` redirect variants, with channel-aware docs destinations. - Add discovery hints for agents and crawlers: `rel="llms.txt"`, `rel="alternate" type="text/markdown"`, and a short generated `llms.txt` directive in copied Markdown pages. - Update the docs proxy so `Accept: text/markdown`, `/docs.md`, and direct `.md` requests can resolve to the generated Markdown artifacts. - Move primary docs content earlier in the HTML source while preserving the visible layout, so crawlers and agent scorers encounter the article before sidebar chrome. - Move the existing copy-as-Markdown control from the top navigation into the page-title row, using the generated Markdown alternate link as the source of truth. - Split AI-discovery artifact generation out of `docs_preprocessor/src/main.rs` into a focused module. Best Practices Adopted - Use `llms.txt` as a concise navigation index, not a dump of full page content. - Link to absolute, canonical Markdown URLs from `llms.txt`. - Preserve the docs hierarchy in `llms.txt` instead of emitting a flat sitemap-like list. - Include short per-link descriptions from existing metadata rather than inventing summaries. - Keep `llms.txt`, Markdown copies, sitemap data, redirects, and freshness metadata generated from the same mdBook source to avoid drift. - Advertise Markdown alternates with standard HTML metadata and same-origin URLs. - Support both explicit Markdown URLs and content negotiation for clients that prefer Markdown. - Keep browser copy behavior pointed at generated Markdown alternate links instead of duplicating route inference in JavaScript. - Keep the copy-as-Markdown affordance in the page title row without duplicating header chrome controls. Validation - `cargo check -p docs_preprocessor` - `cargo test -p docs_preprocessor` - `./script/clippy -p docs_preprocessor` - `mdbook build ./docs --dest-dir=../target/deploy/docs/` - `node --check docs/theme/plugins.js` - `pnpm dlx prettier@3.5.0 docs/theme/plugins.js --check` - `git diff --check` - Local artifact checks confirmed generated Markdown pages, `llms.txt`, `sitemap.xml` lastmod values, HTML freshness metadata, Markdown alternate links, redirect targets, and preprocessed action/keybinding tags resolve as expected. - Worker URL rewrite mock covered `/docs/`, `/docs.md`, `/docs/index.md`, extensionless docs routes, `.html` routes, `/docs/llms.txt`, and `/docs/sitemap.xml`. - High-effort adversarial subagent review found blockers around channel-aware redirects, shallow-checkout date fallback, file size, duplicated Markdown path inference, and process spawning. Those were addressed. Remaining Notes - Local `python -m http.server` does not emulate Cloudflare Pages pretty URLs, `_redirects`, or the docs-proxy Worker, so full local `afdocs` still cannot prove content negotiation end to end. - Existing production remains unchanged until this PR is deployed through the docs workflow. - Production baseline `npx afdocs check https://zed.dev/docs/ --fixes --verbose` still reports the original failures before this PR is deployed: 12 passed, 8 failed, 3 skipped. Release Notes: - Improved docs AI-readiness by adding machine-readable discovery, Markdown access, and freshness metadata. --------- Co-authored-by: Katie Geer <katie@zed.dev> Co-authored-by: Ben Kunkle <ben@zed.dev>
474 lines
8.1 KiB
CSS
474 lines
8.1 KiB
CSS
/* Base styles and content styles */
|
|
|
|
@import "variables.css";
|
|
|
|
:root {
|
|
/* Browser default font-size is 16px, this way 1 rem = 10px */
|
|
font-size: 62.5%;
|
|
color-scheme: var(--color-scheme);
|
|
}
|
|
|
|
html {
|
|
font-family: var(--font);
|
|
color: var(--fg);
|
|
background-color: var(--bg);
|
|
text-size-adjust: none;
|
|
-webkit-text-size-adjust: none;
|
|
|
|
text-rendering: geometricPrecision !important;
|
|
-webkit-font-smoothing: antialiased !important;
|
|
text-shadow: 1px 1px 1px rgba(0, 0, 0, 0.005);
|
|
}
|
|
|
|
body {
|
|
margin: 0;
|
|
font-size: 1.6rem;
|
|
overflow: hidden;
|
|
height: 100vh;
|
|
overscroll-behavior-y: none;
|
|
}
|
|
|
|
#body-container {
|
|
display: flex;
|
|
flex-direction: column;
|
|
height: 100vh;
|
|
overflow: hidden;
|
|
}
|
|
|
|
code {
|
|
font-family: var(--mono-font) !important;
|
|
font-size: var(--code-font-size);
|
|
direction: ltr !important;
|
|
}
|
|
|
|
/* make long words/inline code not x overflow */
|
|
main {
|
|
overflow-wrap: break-word;
|
|
}
|
|
|
|
.noise-pattern {
|
|
pointer-events: none;
|
|
user-select: none;
|
|
z-index: 105;
|
|
position: absolute;
|
|
inset: 0;
|
|
background-size: 180px;
|
|
background-repeat: repeat;
|
|
opacity: var(--noise-opacity);
|
|
}
|
|
|
|
/* make wide tables scroll if they overflow */
|
|
.table-wrapper {
|
|
overflow-x: auto;
|
|
}
|
|
|
|
h1,
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
position: relative;
|
|
font-family: var(--title-font);
|
|
font-weight: 400;
|
|
}
|
|
|
|
h1 {
|
|
color: var(--title-color);
|
|
}
|
|
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5,
|
|
h6 {
|
|
color: var(--full-contrast);
|
|
}
|
|
|
|
/* Don't change font size in headers. */
|
|
h1 code,
|
|
h2 code,
|
|
h3 code,
|
|
h4 code,
|
|
h5 code,
|
|
h6 code {
|
|
font-size: unset;
|
|
}
|
|
|
|
.left {
|
|
float: left;
|
|
}
|
|
.right {
|
|
float: right;
|
|
}
|
|
.boring {
|
|
opacity: 0.6;
|
|
}
|
|
.hide-boring .boring {
|
|
display: none;
|
|
}
|
|
.hidden {
|
|
display: none !important;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 3.4rem;
|
|
}
|
|
|
|
h2 {
|
|
padding-bottom: 1rem;
|
|
border-bottom: 1px solid;
|
|
border-color: var(--border-light);
|
|
}
|
|
|
|
h3 {
|
|
font-size: 2rem;
|
|
padding-bottom: 0.8rem;
|
|
border-bottom: 1px dashed;
|
|
border-color: var(--border-light);
|
|
}
|
|
|
|
h4 {
|
|
font-size: 1.8rem;
|
|
}
|
|
|
|
h5 {
|
|
font-size: 1.6rem;
|
|
}
|
|
|
|
h2,
|
|
h3,
|
|
h4,
|
|
h5 {
|
|
margin-block-start: 1.5em;
|
|
margin-block-end: 0;
|
|
}
|
|
|
|
strong {
|
|
color: var(--full-contrast);
|
|
}
|
|
|
|
code:focus-visible,
|
|
pre:focus-visible,
|
|
li:focus-visible,
|
|
button:focus-visible,
|
|
a:focus-visible {
|
|
outline: 3px solid #094ece80;
|
|
}
|
|
|
|
.header + .header h3,
|
|
.header + .header h4,
|
|
.header + .header h5 {
|
|
margin-block-start: 1em;
|
|
}
|
|
|
|
h1:target::before,
|
|
h2:target::before,
|
|
h3:target::before,
|
|
h4:target::before,
|
|
h5:target::before,
|
|
h6:target::before {
|
|
content: "»";
|
|
position: absolute;
|
|
left: -1.5ch;
|
|
}
|
|
|
|
hr {
|
|
border: 0px solid;
|
|
color: transparent;
|
|
width: 100%;
|
|
height: 1px;
|
|
background-color: var(--border-light);
|
|
}
|
|
|
|
/* This is broken on Safari as of version 14, but is fixed
|
|
in Safari Technology Preview 117 which I think will be Safari 14.2.
|
|
https://bugs.webkit.org/show_bug.cgi?id=218076
|
|
*/
|
|
:target {
|
|
/* Safari does not support logical properties */
|
|
scroll-margin-top: calc(var(--menu-bar-height) + 2rem);
|
|
}
|
|
|
|
.page-wrapper {
|
|
box-sizing: border-box;
|
|
background-color: var(--bg);
|
|
display: flex;
|
|
flex: 1;
|
|
overflow: hidden;
|
|
min-height: 0;
|
|
}
|
|
|
|
.page {
|
|
outline: 0;
|
|
order: 1;
|
|
flex: 1;
|
|
display: flex;
|
|
flex-direction: column;
|
|
overflow-x: hidden;
|
|
overflow-y: auto;
|
|
overscroll-behavior-y: none;
|
|
min-width: 0;
|
|
position: relative;
|
|
}
|
|
|
|
.no-js .page-wrapper,
|
|
.js:not(.sidebar-resizing) .page-wrapper {
|
|
transition:
|
|
margin-left 0.3s ease,
|
|
transform 0.3s ease; /* Animation: slide away */
|
|
}
|
|
[dir="rtl"] .js:not(.sidebar-resizing) .page-wrapper {
|
|
transition:
|
|
margin-right 0.3s ease,
|
|
transform 0.3s ease; /* Animation: slide away */
|
|
}
|
|
|
|
.content {
|
|
padding: 32px 32px 0 32px;
|
|
display: flex;
|
|
justify-content: space-between;
|
|
gap: 36px;
|
|
}
|
|
|
|
.content main {
|
|
margin-inline-start: auto;
|
|
margin-inline-end: auto;
|
|
max-width: var(--content-max-width);
|
|
}
|
|
|
|
.content p {
|
|
line-height: 1.625em;
|
|
}
|
|
.content div.video {
|
|
z-index: 150;
|
|
margin-top: 1rem;
|
|
border: 1px solid;
|
|
border-color: var(--border);
|
|
border-radius: 8px;
|
|
overflow: clip;
|
|
}
|
|
.content div.video iframe {
|
|
margin: 0;
|
|
}
|
|
.content ol {
|
|
marker: none;
|
|
line-height: 1.8;
|
|
padding-left: 2em;
|
|
::marker {
|
|
font-size: 1.4rem;
|
|
}
|
|
li {
|
|
padding-left: 0;
|
|
}
|
|
}
|
|
.content ul {
|
|
line-height: 1.8;
|
|
padding-left: 1.8em;
|
|
}
|
|
.content a {
|
|
text-decoration: underline;
|
|
text-decoration-color: var(--link-line-decoration);
|
|
}
|
|
.content a:hover {
|
|
text-decoration-color: var(--link-line-decoration-hover);
|
|
}
|
|
.content img,
|
|
.content video {
|
|
position: relative;
|
|
z-index: 150;
|
|
max-width: 100%;
|
|
background-color: var(--media-bg);
|
|
border: 1px solid;
|
|
border-color: var(--border);
|
|
border-radius: 8px;
|
|
overflow: clip;
|
|
}
|
|
.content h1 .header:link,
|
|
.content h1 .header:visited {
|
|
color: var(--title-color);
|
|
}
|
|
.content :is(h2, h3, h4, h5, h6) .header:link,
|
|
.content :is(h2, h3, h4, h5, h6) .header:visited {
|
|
color: var(--full-contrast);
|
|
}
|
|
.content .header:link,
|
|
.content .header:visited:hover {
|
|
text-decoration: none;
|
|
}
|
|
|
|
iframe {
|
|
margin-top: 1rem;
|
|
margin-bottom: 10rem;
|
|
}
|
|
|
|
table {
|
|
margin-top: 1.4rem;
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
font-size: 1.4rem;
|
|
}
|
|
table td {
|
|
padding: 4px 12px;
|
|
border: 1px var(--table-border-color) solid;
|
|
}
|
|
table thead {
|
|
background: var(--table-header-bg);
|
|
}
|
|
table thead td {
|
|
font-weight: 700;
|
|
border: none;
|
|
}
|
|
table thead th {
|
|
padding: 6px 12px;
|
|
color: var(--full-contrast);
|
|
text-align: left;
|
|
border: 1px var(--table-border-color) solid;
|
|
}
|
|
table thead tr {
|
|
border: 1px var(--table-border-color) solid;
|
|
}
|
|
/* Alternate background colors for rows */
|
|
table tbody tr:nth-child(2n) {
|
|
background: var(--table-alternate-bg);
|
|
}
|
|
|
|
blockquote {
|
|
margin: auto;
|
|
margin-top: 1rem;
|
|
padding: 1rem 1.25rem;
|
|
color: var(--full-contrast);
|
|
background-color: var(--quote-bg);
|
|
border: 1px solid var(--quote-border);
|
|
}
|
|
|
|
blockquote > p {
|
|
margin: 0;
|
|
padding-left: 2.6rem;
|
|
font-size: 1.4rem;
|
|
}
|
|
|
|
blockquote:before {
|
|
--size: 1.4rem;
|
|
position: absolute;
|
|
content: "ⓘ";
|
|
margin: 0.3rem 0;
|
|
width: var(--size);
|
|
height: var(--size);
|
|
font-size: var(--size);
|
|
font-weight: bold;
|
|
color: var(--icons);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
line-height: 1.625em;
|
|
}
|
|
|
|
blockquote .warning:before {
|
|
background-color: var(--quote-bg);
|
|
}
|
|
|
|
.warning {
|
|
margin: auto;
|
|
padding: 1rem 1.25rem;
|
|
color: var(--full-contrast);
|
|
background-color: var(--warning-bg);
|
|
border: 1px solid var(--warning-border);
|
|
}
|
|
|
|
.warning > p {
|
|
margin: 0;
|
|
padding-left: 2.6rem;
|
|
font-size: 1.4rem;
|
|
}
|
|
|
|
.warning:before {
|
|
--size: 1.4rem;
|
|
position: absolute;
|
|
content: "ⓘ";
|
|
margin: 0.3rem 0;
|
|
width: var(--size);
|
|
height: var(--size);
|
|
font-size: var(--size);
|
|
font-weight: bold;
|
|
color: var(--warning-icon);
|
|
display: flex;
|
|
align-items: center;
|
|
justify-content: center;
|
|
line-height: 1.625em;
|
|
}
|
|
|
|
kbd {
|
|
background-color: var(--keybinding-bg);
|
|
padding: 4px 4px 6px 4px;
|
|
border-radius: 4px;
|
|
font-family: var(--mono-font);
|
|
display: inline-block;
|
|
margin: 0 2px;
|
|
border: solid 1px var(--popover-border);
|
|
box-shadow: inset 0 -1px 0 var(--theme-hover);
|
|
font-size: var(--code-font-size);
|
|
color: var(--full-contrast);
|
|
line-height: 10px;
|
|
vertical-align: middle;
|
|
}
|
|
|
|
:not(.footnote-definition) + .footnote-definition,
|
|
.footnote-definition + :not(.footnote-definition) {
|
|
margin-block-start: 2em;
|
|
}
|
|
.footnote-definition {
|
|
font-size: 1.4rem;
|
|
margin: 0.5em 0;
|
|
border-bottom: 1px solid;
|
|
border-color: var(--divider);
|
|
}
|
|
.footnote-definition p {
|
|
display: inline;
|
|
}
|
|
|
|
.tooltiptext {
|
|
position: absolute;
|
|
visibility: hidden;
|
|
color: #fff;
|
|
background-color: #333;
|
|
transform: translateX(
|
|
-50%
|
|
); /* Center by moving tooltip 50% of its width left */
|
|
left: -8px; /* Half of the width of the icon */
|
|
top: -35px;
|
|
font-size: 0.8em;
|
|
text-align: center;
|
|
border-radius: 6px;
|
|
padding: 5px 8px;
|
|
margin: 5px;
|
|
z-index: 1000;
|
|
}
|
|
.tooltipped .tooltiptext {
|
|
visibility: visible;
|
|
}
|
|
|
|
.result-no-output {
|
|
font-style: italic;
|
|
}
|
|
|
|
code:not(pre code).hljs {
|
|
color: var(--code-text) !important;
|
|
background-color: var(--code-bg) !important;
|
|
}
|
|
|
|
@media only screen and (max-width: 1020px) {
|
|
.content {
|
|
padding: 16px 32px 0 32px;
|
|
}
|
|
|
|
.content main {
|
|
width: 100%;
|
|
}
|
|
}
|
|
|
|
@media only screen and (max-width: 400px) {
|
|
.content {
|
|
padding: 16px 16px 0 16px;
|
|
}
|
|
}
|