diff options
Diffstat (limited to 'docs')
| -rw-r--r-- | docs/site/README | 24 | ||||
| -rw-r--r-- | docs/site/fonts/CrimsonPro-VF-italic.woff2 | bin | 0 -> 52448 bytes | |||
| -rw-r--r-- | docs/site/fonts/CrimsonPro-VF-normal.woff2 | bin | 0 -> 49660 bytes | |||
| -rw-r--r-- | docs/site/fonts/DepartureMono-Regular.woff2 | bin | 0 -> 22496 bytes | |||
| -rw-r--r-- | docs/site/fonts/LICENSE-CrimsonPro.txt | 93 | ||||
| -rw-r--r-- | docs/site/fonts/LICENSE-DepartureMono.txt | 93 | ||||
| -rw-r--r-- | docs/site/media/clips.toml | 24 | ||||
| -rw-r--r-- | docs/site/media/placeholder.svg | 1 | ||||
| -rw-r--r-- | docs/site/site.css | 142 | ||||
| -rw-r--r-- | docs/site/site.typ | 161 | ||||
| -rw-r--r-- | docs/typ/README | 8 | ||||
| -rw-r--r-- | docs/typ/book.typ | 4 | ||||
| -rw-r--r-- | docs/typ/building.typ | 3 | ||||
| -rw-r--r-- | docs/typ/cheatsheet-a4.typ | 4 | ||||
| -rw-r--r-- | docs/typ/guide.typ | 6 | ||||
| -rw-r--r-- | docs/typ/html.typ | 24 | ||||
| -rw-r--r-- | docs/typ/install.typ | 8 | ||||
| -rw-r--r-- | docs/typ/setup.typ | 3 | ||||
| -rw-r--r-- | docs/typ/style.typ | 63 |
19 files changed, 622 insertions, 39 deletions
diff --git a/docs/site/README b/docs/site/README new file mode 100644 index 00000000..76c2973f --- /dev/null +++ b/docs/site/README @@ -0,0 +1,24 @@ +docs/site: the pardes website, built from docs/typ + + site.typ the wrapper: every page, the shared tag-line header and + chapter nav, the landing page, and the files it ships. + Pages come from `chapters` in ../typ/style.typ, so a new + chapter is a new page; #doc links resolve across pages. + site.css the whole look (lapis layout from 0x4200.cafe in + pardes's orchard greens; forestbones_light when the + reader prefers light). + fonts/ Departure Mono and Crimson Pro, both SIL OFL, licences + alongside. + media/clips.toml the landing page's recordings, in order: name, caption, + ready. For a clip named N the site ships media/N.webm, + media/N.mp4 and media/N.png (the poster); until `ready` + is true it shows placeholder.svg instead. + +Build (from the repo root): + + typst compile --root . --format bundle --features bundle,html docs/site/site.typ OUT + zig build site -Dplatform=tty --prefix DIR # DIR/share/doc/pardes/site/ + +Every page sits at the top of OUT and every link is relative, so the site +works from file:// and from any static server. The only prose of the +site's own is the landing page; everything else is included from docs/typ. diff --git a/docs/site/fonts/CrimsonPro-VF-italic.woff2 b/docs/site/fonts/CrimsonPro-VF-italic.woff2 Binary files differnew file mode 100644 index 00000000..59923684 --- /dev/null +++ b/docs/site/fonts/CrimsonPro-VF-italic.woff2 diff --git a/docs/site/fonts/CrimsonPro-VF-normal.woff2 b/docs/site/fonts/CrimsonPro-VF-normal.woff2 Binary files differnew file mode 100644 index 00000000..7fd174a4 --- /dev/null +++ b/docs/site/fonts/CrimsonPro-VF-normal.woff2 diff --git a/docs/site/fonts/DepartureMono-Regular.woff2 b/docs/site/fonts/DepartureMono-Regular.woff2 Binary files differnew file mode 100644 index 00000000..b4a23dc1 --- /dev/null +++ b/docs/site/fonts/DepartureMono-Regular.woff2 diff --git a/docs/site/fonts/LICENSE-CrimsonPro.txt b/docs/site/fonts/LICENSE-CrimsonPro.txt new file mode 100644 index 00000000..6a7d97cd --- /dev/null +++ b/docs/site/fonts/LICENSE-CrimsonPro.txt @@ -0,0 +1,93 @@ +Copyright 2018 The Crimson Pro Project Authors (https://github.com/Fonthausen/CrimsonPro) + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +http://scripts.sil.org/OFL + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/site/fonts/LICENSE-DepartureMono.txt b/docs/site/fonts/LICENSE-DepartureMono.txt new file mode 100644 index 00000000..de524761 --- /dev/null +++ b/docs/site/fonts/LICENSE-DepartureMono.txt @@ -0,0 +1,93 @@ +Copyright 2022–2024 Helena Zhang (helenazhang.com). + +This Font Software is licensed under the SIL Open Font License, Version 1.1. +This license is copied below, and is also available with a FAQ at: +https://openfontlicense.org + + +----------------------------------------------------------- +SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007 +----------------------------------------------------------- + +PREAMBLE +The goals of the Open Font License (OFL) are to stimulate worldwide +development of collaborative font projects, to support the font creation +efforts of academic and linguistic communities, and to provide a free and +open framework in which fonts may be shared and improved in partnership +with others. + +The OFL allows the licensed fonts to be used, studied, modified and +redistributed freely as long as they are not sold by themselves. The +fonts, including any derivative works, can be bundled, embedded, +redistributed and/or sold with any software provided that any reserved +names are not used by derivative works. The fonts and derivatives, +however, cannot be released under any other type of license. The +requirement for fonts to remain under this license does not apply +to any document created using the fonts or their derivatives. + +DEFINITIONS +"Font Software" refers to the set of files released by the Copyright +Holder(s) under this license and clearly marked as such. This may +include source files, build scripts and documentation. + +"Reserved Font Name" refers to any names specified as such after the +copyright statement(s). + +"Original Version" refers to the collection of Font Software components as +distributed by the Copyright Holder(s). + +"Modified Version" refers to any derivative made by adding to, deleting, +or substituting -- in part or in whole -- any of the components of the +Original Version, by changing formats or by porting the Font Software to a +new environment. + +"Author" refers to any designer, engineer, programmer, technical +writer or other person who contributed to the Font Software. + +PERMISSION & CONDITIONS +Permission is hereby granted, free of charge, to any person obtaining +a copy of the Font Software, to use, study, copy, merge, embed, modify, +redistribute, and sell modified and unmodified copies of the Font +Software, subject to the following conditions: + +1) Neither the Font Software nor any of its individual components, +in Original or Modified Versions, may be sold by itself. + +2) Original or Modified Versions of the Font Software may be bundled, +redistributed and/or sold with any software, provided that each copy +contains the above copyright notice and this license. These can be +included either as stand-alone text files, human-readable headers or +in the appropriate machine-readable metadata fields within text or +binary files as long as those fields can be easily viewed by the user. + +3) No Modified Version of the Font Software may use the Reserved Font +Name(s) unless explicit written permission is granted by the corresponding +Copyright Holder. This restriction only applies to the primary font name as +presented to the users. + +4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font +Software shall not be used to promote, endorse or advertise any +Modified Version, except to acknowledge the contribution(s) of the +Copyright Holder(s) and the Author(s) or with their explicit written +permission. + +5) The Font Software, modified or unmodified, in part or in whole, +must be distributed entirely under this license, and must not be +distributed under any other license. The requirement for fonts to +remain under this license does not apply to any document created +using the Font Software. + +TERMINATION +This license becomes null and void if any of the above conditions are +not met. + +DISCLAIMER +THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT +OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE +COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL +DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING +FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM +OTHER DEALINGS IN THE FONT SOFTWARE. diff --git a/docs/site/media/clips.toml b/docs/site/media/clips.toml new file mode 100644 index 00000000..f927450f --- /dev/null +++ b/docs/site/media/clips.toml @@ -0,0 +1,24 @@ +# The landing page's recordings, in the order shown. For each clip the +# site ships media/<name>.webm and media/<name>.mp4, with media/<name>.png +# as the poster. While `ready` is false the clip shows placeholder.svg and +# no video, so the site builds before the recordings exist. + +[[clip]] +name = "look-and-execute" +caption = "Right-click opens what you point at; middle-click runs it." +ready = false + +[[clip]] +name = "terminals" +caption = "Terminal panes: type to the program, or move around its output." +ready = false + +[[clip]] +name = "scripting" +caption = "A script drives the session by reading and writing files." +ready = false + +[[clip]] +name = "diff-review" +caption = "Right-click a diff line to open that line of the file." +ready = false diff --git a/docs/site/media/placeholder.svg b/docs/site/media/placeholder.svg new file mode 100644 index 00000000..0b0efde0 --- /dev/null +++ b/docs/site/media/placeholder.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 640 400"><rect width="640" height="400" fill="#121c16"/><rect x="24" y="24" width="592" height="28" fill="#1d2824"/><rect x="24" y="24" width="28" height="28" fill="#add38a"/><rect x="24" y="64" width="592" height="312" fill="none" stroke="#486152" stroke-width="2"/><text x="320" y="230" fill="#b2c3b8" font-family="monospace" font-size="22" text-anchor="middle">recording to come</text></svg> diff --git a/docs/site/site.css b/docs/site/site.css new file mode 100644 index 00000000..bbb1140f --- /dev/null +++ b/docs/site/site.css @@ -0,0 +1,142 @@ +/* pardes docs site. The 0x4200.cafe lapis layout (framed panels, hard + shadows, a tag-line trail, pixel headings over a book hand) in pardes's + orchard greens; light mode follows forestbones_light. Fonts are OFL and + shipped in fonts/. */ + +@font-face { font-family:"Crimson Pro"; src:url("fonts/CrimsonPro-VF-normal.woff2") format("woff2"); font-weight:200 900; font-display:swap; } +@font-face { font-family:"Crimson Pro"; src:url("fonts/CrimsonPro-VF-italic.woff2") format("woff2"); font-weight:200 900; font-style:italic; font-display:swap; } +@font-face { font-family:"Departure Mono"; src:url("fonts/DepartureMono-Regular.woff2") format("woff2"); font-display:swap; size-adjust:72%; } + +/* orchard: field, panel, ink, leaf, amber, plum */ +:root { + --field:#0d1410; --deep:#070c09; --panel:#121c16; --tag:#1d2824; --tag-hi:#26362d; + --ink:#e5eee5; --dim:#b2c3b8; --leaf:#add38a; --leaf-hi:#b9f480; --amber:#f4c086; --plum:#d3b0d9; + --rule:#486152; --shadow:#000c; --stripe:#3c614a; + --hand:"Crimson Pro", Georgia, serif; --pixel:"Departure Mono", ui-monospace, monospace; + --mono:ui-monospace, "DejaVu Sans Mono", Menlo, Consolas, monospace; +} +/* forestbones_light: paper, butter tags, green ink */ +@media (prefers-color-scheme: light) { + :root { + --field:#f3ead2; --deep:#e9dcb8; --panel:#faf3e1; --tag:#f3e2aa; --tag-hi:#e8d48e; + --ink:#2f3b33; --dim:#56645b; --leaf:#3c6b56; --leaf-hi:#2c7a3e; --amber:#9a5810; --plum:#6e4774; + --rule:#b1a26f; --shadow:#4f5b6233; --stripe:#cdd9b0; + } +} + +* { box-sizing:border-box; } +html { background:var(--deep); color:var(--ink); scrollbar-color:var(--leaf) var(--deep); } +body { margin:0; min-height:100vh; background:var(--field) radial-gradient(color-mix(in srgb, var(--leaf) 14%, transparent) 1px, transparent 1.5px) 0 0/22px 22px; } +.shell { max-width:980px; margin:0 auto; padding:24px 16px 40px; display:grid; gap:26px; } + +/* --- the trail: a pane's tag line ------------------------------------------- */ +.trail { + display:flex; flex-wrap:wrap; align-items:baseline; gap:6px 12px; padding:9px 14px; + background:var(--tag); border:2px solid var(--leaf); box-shadow:5px 5px 0 var(--amber); + font:20px/1.3 var(--pixel); +} +.trail .grip { width:.8em; height:.8em; background:var(--leaf); align-self:center; } +.trail a { color:var(--leaf); text-decoration:none; } +.trail a:hover, .trail a[aria-current] { color:var(--amber); } +.trail .home { color:var(--plum); } +.trail .sep { color:var(--amber); } +.trail .here { color:var(--dim); } +.trail .words { display:flex; flex-wrap:wrap; gap:4px 14px; margin-left:auto; font-size:17px; } + +/* --- the folio --------------------------------------------------------------- */ +.panel { min-width:0; padding:14px; background:repeating-linear-gradient(45deg, var(--stripe) 0 2px, var(--panel) 2px 7px); border:2px solid var(--leaf); box-shadow:6px 6px 0 var(--shadow); } +.content { + background:var(--panel); padding:22px clamp(14px, 4vw, 40px) 30px; + box-shadow:inset 0 0 0 2px var(--leaf), inset 0 0 0 5px var(--panel), inset 0 0 0 6px var(--amber); + font:420 20px/1.55 var(--hand); overflow-wrap:break-word; +} +.content p, .content li { hyphens:auto; text-wrap:pretty; } +.content a { color:var(--amber); } +.content a:hover { color:var(--leaf-hi); } +.content strong { color:var(--leaf); font-weight:640; } +.content h2, .content h1 { font:clamp(30px, 5vw, 44px)/1.1 var(--pixel); color:var(--leaf); text-transform:uppercase; margin:.3em 0 .6em; text-shadow:3px 3px 0 var(--shadow); } +.content h3 { font:26px/1.2 var(--pixel); color:var(--amber); text-transform:uppercase; border-bottom:2px dotted var(--leaf); padding-bottom:4px; margin:1.6em 0 .6em; } +.content h3::before { content:"¶ "; color:var(--leaf); } +.content h4 { font:italic 600 23px/1.25 var(--hand); color:var(--leaf); margin:1.3em 0 .4em; } +.content h5 { font:600 20px var(--hand); color:var(--dim); margin:1em 0 .3em; } + +/* code: a window on the machine, titled in stripes */ +.content code, .content pre, .content kbd, .tag { font-family:var(--mono); } +.content code { font-size:.82em; overflow-wrap:break-word; hyphens:none; } +.content pre { + font-size:15px; line-height:1.45; padding:12px 14px; margin:1em 0; overflow-x:auto; + background:var(--deep); border:2px solid var(--leaf); border-top-width:8px; box-shadow:5px 5px 0 var(--shadow); +} +.content pre code { font-size:inherit; overflow-wrap:normal; } +@media (prefers-color-scheme: dark) { .content pre span { color:inherit !important; } } +.content pre.tutor { font-size:14px; } + +/* tables: rows on alternating tints, a pardes #pairs */ +.content table { width:100%; border-collapse:collapse; margin:1em 0; font-size:.92em; display:block; overflow-x:auto; } +.content tbody, .content thead { display:table; width:100%; } +.content td, .content th { padding:5px 9px; vertical-align:top; text-align:left; } +.content tr:nth-child(odd) td { background:color-mix(in srgb, var(--tag) 70%, transparent); } +.content th { font:17px var(--pixel); color:var(--leaf); } + +/* --- the semantic elements (docs/typ/style.typ) ------------------------------ */ +.key { display:inline-block; padding:0 .3em; border-radius:4px; background:color-mix(in srgb, var(--leaf) 20%, transparent); color:var(--ink); font-size:.82em; white-space:nowrap; line-height:1.4; } +.key .plus, .key .then { color:var(--leaf); opacity:.8; padding:0 .12em; } +.word { background:var(--tag); padding:0 .25em; color:var(--dim); } +.word code { font-size:.82em; color:var(--ink); } +.addr code { color:var(--plum); } +.file code { color:var(--leaf); } +.btn, .chord { display:inline-flex; align-items:center; gap:2px; vertical-align:-.38em; margin-block:-.3em; } +.mouse { width:1.15em; height:1.55em; } +.mouse .off { fill:none; stroke:var(--dim); stroke-width:8; } +.mouse .on { fill:var(--amber); stroke:var(--amber); stroke-width:8; } +.mouse .halo { fill:var(--panel); } +.mouse .wheel.off { fill:var(--panel); stroke-width:5; } +.mouse .wheel.on { stroke-width:5; } +.btn .shift { font-size:.9em; color:var(--amber); } +.chord .then { font-size:.9em; color:var(--dim); } +.tag { margin:.6em 0; padding:4px 8px; background:var(--tag); color:var(--dim); font-size:15px; line-height:1.5; } +.tag .grip { display:inline-block; width:.8em; height:.8em; background:var(--leaf); margin-right:.5em; vertical-align:-.05em; } +.tag .path { color:var(--plum); } +.tag code { font-size:inherit; } + +/* --- contents, landing, footer ---------------------------------------------- */ +.toc { margin:0 0 1.6em; border:2px solid var(--leaf); background:var(--deep); box-shadow:5px 5px 0 var(--amber); } +.toc-bar { padding:2px 10px; font:17px var(--pixel); color:var(--leaf); background:repeating-linear-gradient(0deg, var(--leaf) 0 2px, var(--tag) 2px 4px); } +.toc-bar span { background:var(--tag); padding:0 8px; } +.toc-bar, .toc ol { margin:0; } +.toc ol { padding:8px 14px 10px 2.4em; columns:2 14em; font-size:18px; } +.masthead { font:clamp(56px, 12vw, 104px)/1 var(--pixel) !important; text-shadow:5px 5px 0 var(--amber) !important; margin:.1em 0 .1em !important; } +.pitch { font-style:italic; font-size:22px; color:var(--dim); margin-top:0; } +.clips { display:grid; grid-template-columns:repeat(auto-fit, minmax(min(100%, 380px), 1fr)); gap:22px; margin:1.4em 0; } +.clip { margin:0; border:2px solid var(--leaf); background:var(--deep); box-shadow:5px 5px 0 var(--shadow); } +.clip video, .clip img { display:block; width:100%; height:auto; aspect-ratio:16/10; background:var(--deep); } +.clip figcaption { padding:8px 12px; font-size:18px; color:var(--dim); border-top:2px solid var(--leaf); } +.lead { font-size:23px; line-height:1.5; hyphens:manual; margin:.2em 0 .5em; } +.pitch { font-style:italic; font-size:19px; hyphens:manual; color:var(--dim); margin:0 0 .3em; } +.runs { font-size:18px; color:var(--dim); margin:0 0 1.2em; } +.hero { display:block; width:100%; height:auto; margin:0 0 1.4em; border:2px solid var(--leaf); box-shadow:6px 6px 0 var(--shadow); } +.start { display:flex; flex-wrap:wrap; gap:14px; margin:0 0 .8em; } +.start .go { display:inline-block; padding:8px 16px; font:20px var(--pixel); text-decoration:none; color:var(--leaf); background:var(--tag); border:2px solid var(--leaf); box-shadow:4px 4px 0 var(--amber); } +.start .go:first-child { font-size:24px; color:var(--panel); background:var(--leaf); } +.start .go span { font-size:.75em; opacity:.85; } +.start .go:hover { color:var(--amber); } +.rest { display:flex; flex-wrap:wrap; gap:4px 16px; font:17px var(--pixel); margin:0 0 1.2em; } +.rest a { color:var(--leaf); } +.content h2.install { font-size:30px; } +.glossary { margin:1.4em 0; } +.glossary summary { cursor:pointer; list-style-position:inside; } +.glossary summary h3, .glossary summary p { display:inline; margin:0; } +.glossary summary .count { font:20px var(--pixel); color:var(--dim); margin-left:.4em; } +.vh { position:absolute; width:1px; height:1px; overflow:hidden; clip-path:inset(50%); white-space:nowrap; } +.colophon { font:15px var(--pixel); color:var(--dim); text-align:center; } +.colophon a { color:var(--leaf); } +.colophon code { font:inherit; } + +@media (max-width:600px) { + .shell { padding:14px 10px 30px; gap:18px; } + .trail { font-size:17px; padding:8px 10px; } + .trail .words { margin-left:0; font-size:15px; } + .panel { padding:7px; } + .content { font-size:18px; } + .content pre { font-size:13px; } +} diff --git a/docs/site/site.typ b/docs/site/site.typ new file mode 100644 index 00000000..03d9a15d --- /dev/null +++ b/docs/site/site.typ @@ -0,0 +1,161 @@ +// The website: one Typst bundle run writes every page, the stylesheet, the +// fonts and the media. Pages come from `chapters` in ../typ/style.typ, so a +// new chapter is a new page; the only prose of its own is the landing page. +// typst compile --root . --format bundle --features bundle,html docs/site/site.typ OUT +// Every link is relative and every page sits at the top of OUT, so the site +// works from file:// and from any static server. +#import "../typ/style.typ": chapters, tutor-path, doc-links, tagline, project + +#let clips = toml("media/clips.toml").clip +#let pages = ( + (id: "index", title: "pardes"), + ..chapters.filter(c => c.file != none).map(c => (id: c.id, title: c.title, file: c.file)), + (id: "tutor", title: "The tutor"), +) +#let href(id) = id + ".html" + +// --- the files that are not pages -------------------------------------------- + +#asset("site.css", read("site.css", encoding: none)) +#for f in ("DepartureMono-Regular.woff2", "CrimsonPro-VF-normal.woff2", "CrimsonPro-VF-italic.woff2", + "LICENSE-DepartureMono.txt", "LICENSE-CrimsonPro.txt") { + asset("fonts/" + f, read("fonts/" + f, encoding: none)) +} +#asset("media/placeholder.svg", read("media/placeholder.svg", encoding: none)) +#for c in clips.filter(c => c.ready) { + for ext in ("webm", "mp4", "png") { + asset("media/" + c.name + "." + ext, read("media/" + c.name + "." + ext, encoding: none)) + } +} + +// --- the shell every page sits in --------------------------------------------- + +/// An HTML element: el("a", (href: "x.html"))[text], or el("li")[text]. +#let el(tag, ..args) = { + let p = args.pos() + html.elem(tag, attrs: if p.len() > 1 { p.first() } else { (:) }, p.last()) +} + +/// The running head: a tagline, the way a pane's tag reads, with the path +/// of this page and the chapters as its words. +#let trail(id, title) = el("header", (class: "trail"))[ + #el("span", (class: "grip", "aria-hidden": "true"))[] + #el("a", (class: "home", href: href("index")))[pardes] + #if id != "index" { + el("span", (class: "sep", "aria-hidden": "true"))[/] + el("span", (class: "here", "aria-current": "page"))[#title] + } + #el("nav", (class: "words", "aria-label": "Chapters"))[ + #for p in pages.slice(1) { + if p.id == id { el("a", (href: href(p.id), "aria-current": "page"))[#p.title] } + else { el("a", (href: href(p.id)))[#p.title] } + } + ] +] + +#let shell(id, title, body) = html.html(lang: "en", { + html.head({ + html.meta(charset: "utf-8") + el("meta", (name: "viewport", content: "width=device-width, initial-scale=1"))[] + el("meta", (name: "color-scheme", content: "dark light"))[] + html.title(if id == "index" { "pardes" } else { title + " · pardes" }) + el("link", (rel: "stylesheet", href: "site.css"))[] + }) + html.body({ + el("div", (class: "shell"))[ + #trail(id, title) + #el("main", (class: "panel", "data-page": id))[ + #el("article", (class: "content"))[#body] + ] + #el("footer", (class: "colophon"))[ + pardes · + #if project.source != none [#el("a", (href: project.source))[source] · ] + #if project.license != none [#project.license · ] + built from `docs/typ` with Typst · + #el("a", (href: "fonts/LICENSE-DepartureMono.txt"))[fonts] (OFL) + ] + ] + }) +}) + +/// The headings of this page only, as a contents list, when there are +/// enough of them to need one. +#let toc(id) = context { + let hs = query(selector(heading.where(level: 2)).after(label("start-" + id)).before(label("end-" + id))) + if hs.len() >= 4 { + el("nav", (class: "toc", "aria-label": "On this page"))[ + #el("div", (class: "toc-bar"))[#el("span")[On this page]] + #el("ol")[#for h in hs { el("li")[#link(h.location(), h.body)] }] + ] + } +} + +// --- the pages ------------------------------------------------------------------ + +#doc-links.update(true) + +#let ready = clips.filter(c => c.ready) +#let start = ( + (id: "guide", label: [Start: the guide], note: [about 15 min]), + (id: "tutor", label: [Hands on: the tutor], note: none), +) + +#document(href("index"), title: "pardes", shell("index", "pardes")[ + #el("h1", (class: "masthead"))[pardes] + #el("p", (class: "lead"))[pardes is an editor and terminal in columns of panes, each + a file, a terminal, a PDF or an image. Click any text to run it or open + it; the keys are helix's; scripts drive it through files.] + #el("p", (class: "pitch"))[#tagline.] + #el("p", (class: "runs"))[It runs in a terminal or in its own window (SDL), on Linux; + macOS and browser builds are in the tree.] + #if ready.len() > 0 { + el("img", (class: "hero", src: "media/" + ready.first().name + ".png", alt: ready.first().caption))[] + } + #el("div", (class: "start"))[ + #for s in start { + el("a", (class: "go", href: href(s.id)))[#s.label#if s.note != none [ #el("span")[(#s.note)]]] + } + ] + #el("p", (class: "rest"))[ + #for p in pages.slice(1).filter(p => p.id not in start.map(s => s.id)) { + el("a", (href: href(p.id)))[#p.title] + } + ] + #el("div", (class: "clips"))[ + #for c in clips { + el("figure", (class: "clip"))[ + #if c.ready { + el("video", (poster: "media/" + c.name + ".png", muted: "", loop: "", playsinline: "", + controls: "", preload: "none"))[ + #el("source", (src: "media/" + c.name + ".webm", type: "video/webm"))[] + #el("source", (src: "media/" + c.name + ".mp4", type: "video/mp4"))[] + ] + } else { + el("img", (src: "media/placeholder.svg", alt: "", width: "640", height: "400"))[] + } + #el("figcaption")[#c.caption] + ] + } + ] + #el("h2", (class: "install"))[Install] + #include "../typ/install.typ" +]) + +#for p in pages.slice(1, -1) { + document(href(p.id), title: p.title, shell(p.id, p.title)[ + #metadata(none) #label("start-" + p.id) + #heading(level: 1, p.title) #label("ch-" + p.id) + #toc(p.id) + #{ + set heading(offset: 1) + include "../typ/" + p.file + } + #metadata(none) #label("end-" + p.id) + ]) +} + +#document(href("tutor"), title: "The tutor", shell("tutor", "The tutor")[ + #heading(level: 1)[The tutor] <tutor> + The tutor as the editor shows it (#raw("Tutor"), or #raw("SPC h t")). + #el("pre", (class: "tutor"))[#read(tutor-path)] +]) diff --git a/docs/typ/README b/docs/typ/README index 048e5d01..522d99ff 100644 --- a/docs/typ/README +++ b/docs/typ/README @@ -10,8 +10,9 @@ docs/typ: the Typst documentation corpus cheatsheet-a4.typ output wrapper: the one-page A4 cheatsheet. book.typ output wrapper: an A4 book, title page, contents, every chapter, then the tutor (src/tutor.txt). - html.typ output wrapper: one HTML page, every chapter under - an anchor named by its id, then the tutor. + ../site/site.typ output wrapper: the website, a page per chapter plus + the landing page and the tutor, in one Typst bundle + run (see docs/site/README). Wrappers hold layout only, never facts. Chapters: `chapters` in style.typ lists them in reading order (guide, setup, @@ -27,7 +28,8 @@ Build (from the repo root): typst compile --ignore-system-fonts docs/typ/cheatsheet-a4.typ zig build cheatsheet -Dplatform=tty --prefix DIR # DIR/share/doc/pardes/cheatsheet.pdf typst compile --root . --ignore-system-fonts docs/typ/book.typ - typst compile --root . --features html --format html docs/typ/html.typ pardes.html + typst compile --root . --format bundle --features bundle,html docs/site/site.typ OUT + zig build site -Dplatform=tty --prefix DIR # DIR/share/doc/pardes/site/ (--root . because book and HTML read the tutor from src/tutor.txt.) The contract for content files diff --git a/docs/typ/book.typ b/docs/typ/book.typ index a89b52cc..7223ea1d 100644 --- a/docs/typ/book.typ +++ b/docs/typ/book.typ @@ -2,7 +2,7 @@ // content files named by `chapters` in style.typ; this is layout only. // typst compile --root . --ignore-system-fonts docs/typ/book.typ // (--root . because the tutor is read from src/tutor.txt.) -#import "style.typ": palette, mono, chapters, tutor-path, doc-links +#import "style.typ": palette, mono, chapters, tutor-path, doc-links, tagline #set document(title: "pardes") #doc-links.update(true) @@ -29,7 +29,7 @@ v(1fr) text(size: 34pt, weight: "bold", fill: palette.tag-name)[pardes] v(4mm) - text(size: 13pt, style: "italic", fill: palette.tag-fg)[acme's tags and three buttons, helix's keys, terminals as panes, the editor as a 9P filesystem] + text(size: 13pt, style: "italic", fill: palette.tag-fg, tagline) v(2fr) }) diff --git a/docs/typ/building.typ b/docs/typ/building.typ index a261a913..ab26e44c 100644 --- a/docs/typ/building.typ +++ b/docs/typ/building.typ @@ -3,6 +3,9 @@ // threads, detached sessions, the 9P engine, the listeners and mounts. #import "style.typ": key, keys, btn, chord, word, tag, addr, file, cmd, doc, pairs +For contributors: how pardes is built, tested and released, and how its +pieces fit. To install it, see #doc("setup", section: "install"). + = Platforms Zig *0.16.0* (`build.zig.zon` pins `minimum_zig_version`). Dependencies are diff --git a/docs/typ/cheatsheet-a4.typ b/docs/typ/cheatsheet-a4.typ index 6f22f723..7694382f 100644 --- a/docs/typ/cheatsheet-a4.typ +++ b/docs/typ/cheatsheet-a4.typ @@ -2,7 +2,7 @@ // cheatsheet.typ and the elements' look in style.typ; this is page, // type and headings only. // typst compile --ignore-system-fonts docs/typ/cheatsheet-a4.typ -#import "style.typ": palette, mono, density +#import "style.typ": palette, mono, density, tagline #set page(paper: "a4", fill: palette.paper, margin: (x: 9mm, y: 8mm), columns: 3) #set columns(gutter: 4.5mm) @@ -21,7 +21,7 @@ block(width: 100%, inset: (bottom: 2pt), stroke: (bottom: 0.6pt + palette.grip), { text(size: 15pt, weight: "bold", fill: palette.tag-name)[pardes] h(1fr) - text(size: 9pt, style: "italic", fill: palette.tag-fg)[acme's tags and three buttons, helix's keys, terminals as panes, the editor as a 9P filesystem] + text(size: 9pt, style: "italic", fill: palette.tag-fg, tagline) })) #show heading.where(level: 2): it => block( width: 100%, fill: palette.tag-bg, inset: (x: 2pt, y: 2pt), above: 0.75em, below: 0.4em, diff --git a/docs/typ/guide.typ b/docs/typ/guide.typ index a7320865..855fcde4 100644 --- a/docs/typ/guide.typ +++ b/docs/typ/guide.typ @@ -1,7 +1,7 @@ // The guide: pardes day to day, the path a newcomer reads once. Edge cases // live in the reference, the pager and the language servers in setup, the // keys on the cheatsheet. -#import "style.typ": key, keys, btn, chord, word, tag, addr, file, cmd, doc, pairs +#import "style.typ": key, keys, btn, chord, word, tag, addr, file, cmd, doc, pairs, glossary pardes is a screen of columns. Each column holds panes, and each pane is a tag (a line of words) over a body: a file, a terminal, a PDF or an image. @@ -9,9 +9,7 @@ Above the columns runs the workspace tag, and each column has a tag of its own. Any text anywhere can be clicked: #btn("B2") runs it, #btn("B3") looks at it. The keys are helix's, in modes. -= Words you'll see <words> - -#pairs( +#glossary("Words you'll see", <words>, [tag], [the line of words over a pane, a column or the screen; every word in it can be clicked], [the pane with the keyboard], [where your keys go; one pane at a time], [the session's directory], [where pardes started, or the directory `pardes DIR` named; workspace and column tags run there], diff --git a/docs/typ/html.typ b/docs/typ/html.typ deleted file mode 100644 index 5f9082cd..00000000 --- a/docs/typ/html.typ +++ /dev/null @@ -1,24 +0,0 @@ -// The HTML documentation: one page holding every topic in reading order, -// each under an anchor named by its id, then the tutor. -// typst compile --root . --features html --format html docs/typ/html.typ pardes.html -// One page because Typst 0.15's HTML export writes one document per run. -#import "style.typ": chapters, tutor-path, doc-links - -#set document(title: "pardes") -#doc-links.update(true) - -#html.elem("nav", { - for ch in chapters [- #link(label("ch-" + ch.id), ch.title)] - [- #link(<tutor>)[The tutor]] -}) - -#for ch in chapters [ - #heading(level: 1, ch.title) #label("ch-" + ch.id) - #if ch.file == none [_This chapter is not written yet._] else { - set heading(offset: 1) - include ch.file - } -] - -= The tutor <tutor> -#raw(read(tutor-path), block: true) diff --git a/docs/typ/install.typ b/docs/typ/install.typ new file mode 100644 index 00000000..9114f44c --- /dev/null +++ b/docs/typ/install.typ @@ -0,0 +1,8 @@ +// Installing pardes, in three lines: included by setup.typ and by the +// site's landing page, so it is written once. +#import "style.typ": cmd + +With Zig 0.16 (the build fetches everything else): +#cmd("zig build -Dplatform=tty --prefix ~/.local # pardes, in a terminal") +#cmd("zig build -Dplatform=gui --prefix ~/.local # pardes-gui, its own window") +Then run `pardes` or `pardes FILE`. diff --git a/docs/typ/setup.typ b/docs/typ/setup.typ index 45767757..1ed6447b 100644 --- a/docs/typ/setup.typ +++ b/docs/typ/setup.typ @@ -5,6 +5,9 @@ pardes runs as it is; a few lines elsewhere make it fit. += Install <install> +#include "install.typ" + = A 9P mount: 9ns <ninens> `9ns`, from cloud9 (`git.sr.ht/~gbrls/cloud9`, whose `zig build` builds it diff --git a/docs/typ/style.typ b/docs/typ/style.typ index cf55ae86..903a8273 100644 --- a/docs/typ/style.typ +++ b/docs/typ/style.typ @@ -56,9 +56,12 @@ (id: "scripting", title: "Scripting", file: "scripting.typ"), (id: "reference", title: "Reference", file: "reference.typ"), (id: "themes", title: "Themes", file: "themes.typ"), - (id: "building", title: "Building", file: "building.typ"), + (id: "building", title: "Building, for contributors", file: "building.typ"), ) +/// The one-line pitch: the A4 sheet's header and the site's landing page. +#let tagline = "acme's tags and three buttons, helix's keys, terminals as panes, the editor as a 9P filesystem" + /// The tutor, shown as it is in the editor (`Tutor`), from the repo root. #let tutor-path = "/src/tutor.txt" @@ -75,7 +78,9 @@ /// pill: a combination's parts joined by a muted +, a sequence's steps by a /// muted › (`Ctrl-w h` reads Ctrl + w › h). #let key(k) = context if html-out() { - html.elem("kbd", k.split(" ").map(t => html.elem("kbd", t)).join(" ")) + let sep(c, cls) = html.elem("span", attrs: (class: cls, "aria-hidden": "true"), c) + let press(t) = (if t.len() > 1 and t.contains("-") { t.split("-") } else { (t,) }).join(sep("+", "plus")) + html.elem("kbd", attrs: (class: "key"), k.split(" ").map(press).join(sep("›", "then"))) } else { let muted(c) = text(fill: palette.grip.transparentize(25%), size: 0.85em, c) let press(t) = (if t.len() > 1 and t.contains("-") { t.split("-") } else { (t,) }).join(muted[+]) @@ -91,6 +96,9 @@ #let keys(..ks) = context ks.pos().map(key).join(if html-out() [ ] else { h(0.25em) }) #let button-names = ("B1": "left button", "B2": "wheel", "B3": "right button") +#let click-names = ("B1": "left", "B2": "middle", "B3": "right") +/// Text that is read and copied but not shown, beside a drawn glyph. +#let hidden(t) = html.elem("span", attrs: (class: "vh"), t) /// A mouse, about cap height: left button, wheel, right button. The parts /// in `pressed` ("B1", "B2", "B3") are filled. @@ -116,10 +124,33 @@ }) } +/// The same mouse as inline SVG for HTML. Each part is classed `on` +/// (pressed) or `off`, and the stylesheet colours them: the pressed part +/// filled in the accent, the rest outlined and muted. +#let mouse-svg(pressed) = { + let cls(b) = if b in pressed { "on" } else { "off" } + let part(d, b) = html.elem("path", attrs: (class: cls(b), d: d)) + html.elem("svg", attrs: (class: "mouse", viewBox: "-6 -6 96 132", "aria-hidden": "true"), { + // taller buttons and a slimmer wheel than on paper, so a pressed + // button shows as a solid block at body size + part("M0 64H84V78A42 42 0 0 1 0 78Z", none) + part("M0 64V42A42 42 0 0 1 42 0V64Z", "B1") + part("M42 0A42 42 0 0 1 84 42V64H42Z", "B3") + // a pressed wheel is drawn wider, so it reads as pressed, not as a seam + let (hx, hw, wx, ww) = if "B2" in pressed { ("27", "30", "31", "22") } else { ("31", "22", "35", "14") } + html.elem("rect", attrs: (class: "halo", x: hx, y: "4", width: hw, height: "48", rx: "13")) + html.elem("rect", attrs: (class: "wheel " + cls("B2"), x: wx, y: "8", width: ww, height: "40", rx: "9")) + }) +} + /// A mouse button; `shift: true` for the button with Shift held. #let btn(b, shift: false) = context if html-out() { let label = (if shift { "shift " } else { "" }) + button-names.at(b) - html.elem("span", attrs: (class: "btn", aria-label: label, title: label), (if shift { "⇧" } else { "" }) + b) + html.elem("span", attrs: (class: "btn", title: label), { + if shift { html.elem("span", attrs: (class: "shift", "aria-hidden": "true"), "⇧") } + mouse-svg((b,)) + hidden((if shift { "Shift-" } else { "" }) + click-names.at(b) + "-click") + }) } else { if shift { text(size: 0.8em, fill: palette.col-grip)[⇧] } mouse((b,)) @@ -130,7 +161,13 @@ /// down, with arrows between. #let chord(..bs) = context if html-out() { let label = bs.pos().map(b => button-names.at(b)).join(" then ") - html.elem("span", attrs: (class: "chord", aria-label: label, title: label), bs.pos().join("-")) + let (held, ..clicks) = bs.pos() + let arrow = html.elem("span", attrs: (class: "then", "aria-hidden": "true"), "›") + let said = "hold " + click-names.at(held) + ", click " + clicks.map(c => click-names.at(c)).join(", then ") + html.elem("span", attrs: (class: "chord", title: label), { + ((mouse-svg((held,)),) + clicks.map(c => mouse-svg((held, c)))).join(arrow) + hidden(said) + }) } else { let (held, ..clicks) = bs.pos() let arrow = text(size: 0.75em, fill: palette.col-grip)[#h(0.5pt)›#h(0.5pt)] @@ -145,6 +182,7 @@ /// A whole tagline: its grip, the path, then its words. #let tag(words, path: none) = context if html-out() { html.elem("div", attrs: (class: "tag"), { + html.elem("span", attrs: (class: "grip", "aria-hidden": "true"))[] if path != none { span("path", path); [ ] } raw(words) }) @@ -215,3 +253,20 @@ } } } + +/// Where pardes lives and under what licence, for the site's footer (and +/// any output that wants them). none until decided. +#let project = (source: none, license: none) + +/// A glossary: like #pairs, under its own heading. On paper the heading +/// and the table; in HTML a <details> that starts closed, its summary the +/// heading and the count, so a reader who knows the words skips them. +#let glossary(title, lbl, ..cells) = context if html-out() { + html.elem("details", attrs: (class: "glossary"), { + html.elem("summary", [#heading(title) #lbl #html.elem("span", attrs: (class: "count"), "(" + str(calc.quo(cells.pos().len(), 2)) + ")")]) + pairs(..cells) + }) +} else { + [#heading(title) #lbl] + pairs(..cells) +} |
