diff --git a/docs/Website/app.css b/docs/Website/app.css index c29808c..27b55fe 100644 --- a/docs/Website/app.css +++ b/docs/Website/app.css @@ -55,6 +55,28 @@ /* --- Hero ------------------------------------------------------------------ */ +/* The band behind the hero, lit the way the Graphite wallpaper is: a light + from the upper left, and a pool of the accent on the surface the window + stands on. Mixed from the system's own tokens rather than from the picture, + so it follows the brand and the appearance instead of fighting the copy. */ +.heroband { + background: + radial-gradient(ellipse 45% 38% at 68% 62%, + color-mix(in oklab, var(--nv-color-accent) 45%, transparent), transparent 72%), + radial-gradient(ellipse 60% 70% at 18% 0%, + color-mix(in oklab, var(--nv-color-text-primary) 7%, transparent), transparent 70%), + var(--nv-color-background); + padding-block-end: var(--nv-space-12); +} + +.hero__tile { + flex: none; +} + +.hero__slogan { + max-inline-size: 22ch; +} + .hero { display: grid; gap: var(--nv-space-12); @@ -88,6 +110,41 @@ block-size: 1.15em; } +/* --- Wallpapers ----------------------------------------------------------- */ + +/* Two across, not auto-fit: four of anything at three per row leaves one + alone on the last, which reads as an afterthought. */ +.walls, +#docs .nv-card-grid { + display: grid; + gap: var(--nv-space-5); + grid-template-columns: repeat(2, minmax(0, 1fr)); +} + +@media (max-width: 48rem) { + .walls, + #docs .nv-card-grid { grid-template-columns: 1fr; } +} + +.wall { + margin: 0; + overflow: hidden; +} + +.wall__img { + inline-size: 100%; + block-size: auto; + aspect-ratio: 16 / 9; + object-fit: cover; +} + +.wall__caption { + display: flex; + flex-direction: column; + gap: var(--nv-space-2); + padding: var(--nv-space-4) var(--nv-space-5) var(--nv-space-5); +} + /* --- The console ----------------------------------------------------------- */ /* A terminal is a window into the machine, so it is drawn as one: a solid @@ -367,11 +424,18 @@ */ .docshell { - max-inline-size: var(--nv-layout-max-width); + /* Wider than the rest of the site: the document column carries tables and + diagrams that the prose measure would squeeze, and both side panels have + to fit beside it. */ + max-inline-size: calc(var(--nv-layout-max-width) + 16rem); margin-inline: auto; padding-inline: var(--nv-layout-gutter); padding-block: var(--nv-space-8) var(--nv-space-16); display: grid; + /* minmax(0, ...) even with one column: a code block is white-space: pre, + and an auto column grows to its longest line -- which on a phone made + the whole page wider than the screen. */ + grid-template-columns: minmax(0, 1fr); gap: var(--nv-space-8); align-items: start; } @@ -385,6 +449,13 @@ @media (max-width: 64rem) { .docshell__rail { display: none; } + + /* One column: the index stops following the reader and folds away, so + the document is the first thing on the screen rather than the fortieth. */ + .docshell__aside { + position: static; + max-block-size: none; + } } /* Both panels follow the reader down the page, under the bar rather than @@ -457,6 +528,36 @@ border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle); } +/* A code block is a small window: a raised strip naming the language, with + the copy key on it, over the recess the code sits in. */ +.codeframe { + margin: 0; + border-radius: var(--nv-radius-md); + overflow: hidden; + background: var(--nv-color-surface-elevated); + box-shadow: var(--nv-elevation-1); +} + +.codeframe__bar { + display: flex; + align-items: center; + justify-content: space-between; + padding: var(--nv-space-1) var(--nv-space-1) var(--nv-space-1) var(--nv-space-4); + border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle); +} + +.codeframe__lang { + font-family: var(--nv-font-family-mono); + font-size: var(--nv-font-size-xs); + letter-spacing: var(--nv-letter-spacing-wide); + text-transform: uppercase; + color: var(--nv-color-text-tertiary); +} + +.codeframe .doc__pre { + border-radius: 0; +} + .doc__pre { margin: 0; padding: var(--nv-space-4); @@ -496,3 +597,94 @@ .features { --nv-scroller-item: 21rem; } + +/* --- The reader's furniture ----------------------------------------------- */ + +/* Where this document sits, and how long it is. */ +.dochead { + display: flex; + flex-wrap: wrap; + align-items: center; + justify-content: space-between; + gap: var(--nv-space-2) var(--nv-space-4); + padding-block-end: var(--nv-space-4); + border-block-end: var(--nv-border-width) solid var(--nv-color-border-subtle); +} + +.doc > .dochead + * { + margin-block-start: var(--nv-space-6); +} + +/* Previous and next, as two keys. */ +.docpager { + display: grid; + grid-template-columns: 1fr 1fr; + gap: var(--nv-space-4); + margin-block-start: var(--nv-space-12); +} + +.docpager__key { + display: flex; + flex-direction: column; + gap: var(--nv-space-1); + padding: var(--nv-space-4) var(--nv-space-5); + text-decoration: none; + color: inherit; +} + +.docpager__key--next { + text-align: end; + align-items: flex-end; + grid-column: 2; +} + +@media (max-width: 40rem) { + .docpager { grid-template-columns: 1fr; } + .docpager__key--next { grid-column: auto; } +} + +/* The filter well above the index. */ +.docfind { + margin-block-end: var(--nv-space-5); +} + +.docfind .nv-input { + inline-size: 100%; +} + +/* Reading progress: a hairline of accent under the bar, growing from the + left. Transform rather than width, so it costs a composite and no layout. */ +.readbar { + position: sticky; + inset-block-start: 0; + z-index: 10; + block-size: var(--nv-border-width-strong); + margin-block-end: calc(var(--nv-border-width-strong) * -1); +} + +.readbar span { + display: block; + block-size: 100%; + background: var(--nv-color-accent); + box-shadow: 0 0 var(--nv-space-2) var(--nv-color-accent); + transform: scaleX(0); + transform-origin: left; +} + +/* The contents entry for the section being read. */ +#toc .nv-nav__item[aria-current="location"] { + color: var(--nv-color-accent-text); +} + +/* The index's fold. Open on a wide screen, where it is a column; closed on a + narrow one (docs.js), where it would push the document out of view. */ +.docindex > summary { + display: none; +} + +@media (max-width: 64rem) { + .docindex > summary { + display: flex; + margin-block-end: var(--nv-space-3); + } +} diff --git a/docs/Website/docs.html b/docs/Website/docs.html index e978fd2..124d28f 100644 --- a/docs/Website/docs.html +++ b/docs/Website/docs.html @@ -52,13 +52,23 @@ + +
diff --git a/docs/Website/docs.js b/docs/Website/docs.js index 7996024..dff0158 100644 --- a/docs/Website/docs.js +++ b/docs/Website/docs.js @@ -26,21 +26,27 @@ ["architecture/README.md", "The system, layer by layer"], ["architecture/boot.md", "Boot"], ["architecture/kernel.md", "Kernel"], + ["architecture/scheduler.md", "Scheduler"], ["architecture/syscalls.md", "Syscalls"], ["architecture/filesystem.md", "The VFS"], ["architecture/schfs.md", "SchFS"], + ["architecture/fat.md", "FAT"], ["architecture/terminals.md", "Virtual terminals"], ["architecture/devices.md", "Device model"], ["architecture/usb.md", "USB"], ["architecture/graphics.md", "Graphics"], + ["architecture/audio.md", "Audio"], ["architecture/networking.md", "Networking"], - ["architecture/init.md", "init"] + ["architecture/init.md", "init"], + ["architecture/ldls.md", "Linux drivers (LDLS)"], + ["architecture/debugging.md", "Debugging"] ]}, { group: "Guides", items: [ ["guides/building.md", "Building"], ["guides/testing.md", "Testing"], ["guides/layout.md", "Tree layout"], - ["guides/adding-a-driver.md", "Adding a driver"] + ["guides/adding-a-driver.md", "Adding a driver"], + ["guides/hardware-report.md", "Reporting hardware"] ]}, { group: "Plan", items: [ ["plan/README.md", "What plan/ is for"], @@ -57,7 +63,7 @@ ["history/moving-to-linux.md", "Moving to Linux"] ]}, { group: "Branding", items: [ - ["branding/README.md", "The three marks"] + ["branding/README.md", "Shift, and the wallpapers"] ]} ]; @@ -178,9 +184,17 @@ i++; while (i < L.length && !/^\s*```/.test(L[i])) buf.push(L[i++]); i++; - out.push('
' +
+                 '
' + + '' + esc(lang || "text") + "" + + '' + + "
" + + '
" + esc(buf.join("\n")) + "
"); + ">" + esc(buf.join("\n")) + "
"); continue; } @@ -307,6 +321,77 @@ tocEl.appendChild(ul); } + /* Every document in index order, with the group it belongs to. */ + var FLAT = []; + DOCS.forEach(function (g) { + g.items.forEach(function (it) { FLAT.push({ path: it[0], title: it[1], group: g.group }); }); + }); + function indexOf(path) { + for (var k = 0; k < FLAT.length; k++) if (FLAT[k].path === path) return k; + return -1; + } + + /* Where the reader is, how long it will take, and where the file lives -- + above the document, because a page arrived at from a search has no other + way to say which part of the docs it belongs to. */ + function header(path, text) { + var at = FLAT[indexOf(path)] || { group: "Docs", title: path }; + var words = text.split(/\s+/).length; + var mins = Math.max(1, Math.round(words / 230)); + return '
' + + '
    ' + + '
  1. Docs
  2. ' + + "
  3. " + esc(at.group) + "
  4. " + + '
  5. ' + esc(at.title) + "
  6. " + + "
" + + '' + + mins + " min read · " + + '' + esc(path) + "" + + "" + + "
"; + } + + /* The next and previous document, as two keys at the foot of the page. A + reader who reaches the end of one has nearly always come to read the + section, not the file. */ + function pager(path) { + var k = indexOf(path), html = '"; + } + + /* Light the contents entry for the section being read. */ + var spy; + function watchHeadings() { + if (spy) spy.disconnect(); + if (!("IntersectionObserver" in window)) return; + var links = {}; + Array.prototype.forEach.call(tocEl.querySelectorAll("a"), function (a) { + links[a.getAttribute("href").slice(1)] = a; + }); + spy = new IntersectionObserver(function (entries) { + entries.forEach(function (e) { + if (!e.isIntersecting || !links[e.target.id]) return; + Array.prototype.forEach.call(tocEl.querySelectorAll("a"), function (a) { + a.removeAttribute("aria-current"); + }); + links[e.target.id].setAttribute("aria-current", "location"); + }); + }, { rootMargin: "0px 0px -70% 0px" }); + Array.prototype.forEach.call(article.querySelectorAll("h2[id], h3[id]"), function (h) { + spy.observe(h); + }); + } + function fail(title, body) { article.innerHTML = "

" + title + "

" + body; tocEl.hidden = true; @@ -322,8 +407,9 @@ return r.text(); }).then(function (text) { var headings = []; - article.innerHTML = render(text, path, headings); + article.innerHTML = header(path, text) + render(text, path, headings) + pager(path); buildToc(headings); + watchHeadings(); article.removeAttribute("aria-busy"); if (headings.length) document.title = headings[0].text + " — SchOS docs"; var hash = location.hash.slice(1); @@ -340,7 +426,7 @@ "

Browsers block fetch() on file:// URLs, so the " + "reader cannot load the Markdown. The rest of the site works from a file; " + "this page does not. Serve the repository root:

" + - '
cd /home/nexoniarz/Dokumenty/Projects/SchOS\n' +
+             '
cd path/to/SchOS\n' +
              "python3 -m http.server 8000
" + "

Then open http://localhost:8000/docs/Website/docs.html.

" + '

Or read this one directly: ' + esc(path) + "

"); @@ -365,6 +451,54 @@ buildNav(); load(pathFromUrl()); + /* Fold the index on a narrow screen, and fold it again after picking a + document there -- the choice is made, and the document is what was asked + for. */ + var fold = document.getElementById("docindex"); + var narrow = window.matchMedia && window.matchMedia("(max-width: 64rem)"); + if (fold && narrow && narrow.matches) fold.open = false; + nav.addEventListener("click", function () { + if (fold && narrow && narrow.matches) fold.open = false; + }); + + /* Filter the index as you type. Groups with nothing left in them go too, + so the heading of an empty section does not sit there implying a match. */ + var filter = document.getElementById("docfilter"); + if (filter) filter.addEventListener("input", function () { + var q = filter.value.trim().toLowerCase(); + Array.prototype.forEach.call(nav.querySelectorAll(".nv-nav__list"), function (ul) { + var any = false; + Array.prototype.forEach.call(ul.querySelectorAll("li"), function (li) { + var hit = !q || li.textContent.toLowerCase().indexOf(q) >= 0; + li.hidden = !hit; + any = any || hit; + }); + ul.hidden = !any; + if (ul.previousElementSibling) ul.previousElementSibling.hidden = !any; + }); + }); + + /* Copy a code block. The label says what happened, then goes back. */ + article.addEventListener("click", function (ev) { + var b = ev.target.closest ? ev.target.closest("[data-copy]") : null; + if (!b) return; + var code = b.closest(".codeframe").querySelector("code").textContent; + var done = function (ok) { + b.textContent = ok ? "Copied" : "Select and copy"; + setTimeout(function () { b.textContent = "Copy"; }, 1600); + }; + if (navigator.clipboard) navigator.clipboard.writeText(code).then(function () { done(true); }, function () { done(false); }); + else done(false); + }); + + /* How far down the document the reader is: a hairline under the bar. */ + var bar = document.getElementById("readbar"); + if (bar) window.addEventListener("scroll", function () { + var h = document.documentElement; + var f = h.scrollHeight > h.clientHeight ? h.scrollTop / (h.scrollHeight - h.clientHeight) : 0; + bar.style.transform = "scaleX(" + Math.min(1, Math.max(0, f)) + ")"; + }, { passive: true }); + /* Intercept in-page navigation so the reader does not reload its own shell. */ document.addEventListener("click", function (ev) { var a = ev.target.closest ? ev.target.closest("a") : null; diff --git a/docs/Website/index.html b/docs/Website/index.html index d6c4818..80340e8 100644 --- a/docs/Website/index.html +++ b/docs/Website/index.html @@ -3,7 +3,7 @@ -SchOS — a 64-bit operating system written from scratch +SchOS — every layer its own @@ -47,6 +47,7 @@
  • What it has
  • Hybrid
  • Numbers
  • +
  • Wallpapers
  • @@ -69,7 +70,9 @@
    -
    + +
    +
    @@ -77,9 +80,11 @@

    - SchOS + SchOS

    +

    Every layer its own — from the first instruction to the last pixel.

    +

    A 64-bit operating system written from scratch — its own kernel, its own filesystem, its own bootloader. It boots on UEFI, drives real hardware, @@ -109,13 +114,14 @@

    
       
    +

    Origin

    -

    It started as a teaching kernel and stopped being one

    +

    A teaching kernel that outgrew its lessons

    SchOS began as xv6, MIT's teaching operating system: 32-bit, single core, one filesystem, a few dozen @@ -195,7 +201,7 @@

    Architecture

    -

    Three seams hold the whole thing together

    +

    Three seams, and everything else is arrangement

    Above the syscall table, software is ordinary and portable. Below the device model, a driver never names its consumer and a consumer never names a driver. @@ -261,7 +267,7 @@

    What it has

    -

    Built and running, and honest about the rest

    +

    Running today, and honest about the rest

    Every card marked runs is in the tree and works today. The tags are not aspirational; the things that are not finished say so. @@ -536,7 +542,7 @@

    Numbers

    -

    The size of it

    +

    Measured, not marketed

    @@ -583,6 +589,66 @@
    + +
    +
    +

    Wallpapers

    +

    Four surfaces to sit on

    +

    + Every one is the Shift mark under a different light, generated from the + same geometry the loader draws — so they change when the mark does. + 3840×2160, free to use under the same licence as the rest of the tree. +

    +
    + +
    +
    + Graphite: Shift on warm graphite, throwing a pool of violet on the surface. The default. +
    + Graphite + Shift on warm graphite, throwing a pool of violet on the surface. The default. + + 4K JPEG + SVG + +
    +
    +
    + Strata: The slabs repeated into a cascade that recedes into indigo. +
    + Strata + The slabs repeated into a cascade that recedes into indigo. + + 4K JPEG + SVG + +
    +
    +
    + Porcelain: The light one: glazed porcelain on paper, the top slab in the accent. +
    + Porcelain + The light one: glazed porcelain on paper, the top slab in the accent. + + 4K JPEG + SVG + +
    +
    +
    + Dial: The SchFS uberblock ring as hardware — the newest slot and the root lit. +
    + Dial + The SchFS uberblock ring as hardware — the newest slot and the root lit. + + 4K JPEG + SVG + +
    +
    +
    +
    +
    @@ -648,7 +714,7 @@

    Try it

    -

    One ISO, one stick, nothing written to your disks

    +

    One ISO. One stick. Your disks untouched.

    It runs from RAM and leaves the machine as it found it. Or skip the stick entirely — make qemu is the same @@ -667,7 +733,7 @@