@twango/twiki 0.0.0-stage → 0.1.1
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/.github/actions/product-cache/action.yml +32 -0
- package/.github/actions/product-cache/index.mjs +450 -0
- package/LICENSE +21 -0
- package/README.md +146 -2
- package/bun.lock +1701 -0
- package/cli/runtime.test.ts +420 -0
- package/cli/runtime.ts +385 -0
- package/cli/twiki.ts +305 -0
- package/package.json +138 -4
- package/site/_headers +7 -0
- package/site/assets/fonts/OFL.txt +93 -0
- package/site/assets/fonts/OverusedGrotesk-SemiBold.ttf +0 -0
- package/site/assets/social-background.svg +38 -0
- package/site/bun.lock +1701 -0
- package/site/database/index.ts +7 -0
- package/site/database/schema.ts +95 -0
- package/site/drizzle.config.ts +7 -0
- package/site/migrations/0001_auth.sql +14 -0
- package/site/migrations/0002_site_access.sql +5 -0
- package/site/migrations/0003_github_username.sql +1 -0
- package/site/migrations/meta/0002_snapshot.json +432 -0
- package/site/migrations/meta/0003_snapshot.json +439 -0
- package/site/migrations/meta/_journal.json +27 -0
- package/site/package.json +120 -0
- package/site/src/app.d.ts +14 -0
- package/site/src/app.html +11 -0
- package/site/src/hooks.server.ts +12 -0
- package/site/src/lib/analytics-config.json +1 -0
- package/site/src/lib/analytics.ts +40 -0
- package/site/src/lib/auth-config.json +3 -0
- package/site/src/lib/components/SEO.svelte +113 -0
- package/site/src/lib/components/doc/AccessLink.svelte +27 -0
- package/site/src/lib/components/doc/Backlinks.svelte +59 -0
- package/site/src/lib/components/doc/Breadcrumbs.svelte +29 -0
- package/site/src/lib/components/doc/ContentMeta.svelte +61 -0
- package/site/src/lib/components/doc/DocPager.svelte +91 -0
- package/site/src/lib/components/doc/DocShell.svelte +115 -0
- package/site/src/lib/components/doc/LicenseNotice.svelte +26 -0
- package/site/src/lib/components/doc/LockedContent.svelte +29 -0
- package/site/src/lib/components/doc/NavTree.svelte +158 -0
- package/site/src/lib/components/doc/NoteActions.svelte +139 -0
- package/site/src/lib/components/doc/PublicationBadge.svelte +49 -0
- package/site/src/lib/components/doc/ReaderModeToggle.svelte +19 -0
- package/site/src/lib/components/doc/Sidebar.svelte +351 -0
- package/site/src/lib/components/doc/Toc.svelte +339 -0
- package/site/src/lib/components/doc/enhancements.ts +146 -0
- package/site/src/lib/components/doc/heading-tracker.svelte.ts +39 -0
- package/site/src/lib/components/doc/image-preview.ts +114 -0
- package/site/src/lib/components/doc/reader-mode.svelte.ts +40 -0
- package/site/src/lib/components/embeds/mermaid.ts +353 -0
- package/site/src/lib/components/files/FileCode.svelte +81 -0
- package/site/src/lib/components/files/FileExplorer.svelte +74 -0
- package/site/src/lib/components/files/FileHistory.svelte +170 -0
- package/site/src/lib/components/files/FileIcon.svelte +28 -0
- package/site/src/lib/components/files/FileRmd.svelte +209 -0
- package/site/src/lib/components/files/FileTabs.svelte +180 -0
- package/site/src/lib/components/files/FileTree.svelte +67 -0
- package/site/src/lib/components/files/blame-gutter.ts +45 -0
- package/site/src/lib/components/files/code-view.ts +98 -0
- package/site/src/lib/components/files/file-workspace.svelte.ts +100 -0
- package/site/src/lib/components/graph/GraphPanel.svelte +275 -0
- package/site/src/lib/components/graph/GraphView.svelte +100 -0
- package/site/src/lib/components/graph/graph-data.ts +137 -0
- package/site/src/lib/components/graph/graph-model.ts +103 -0
- package/site/src/lib/components/graph/index.ts +3 -0
- package/site/src/lib/components/graph/render-graph.ts +626 -0
- package/site/src/lib/components/popover/index.ts +1 -0
- package/site/src/lib/components/popover/link-popovers.ts +233 -0
- package/site/src/lib/components/popover/popover.css +82 -0
- package/site/src/lib/components/search/SearchButton.svelte +57 -0
- package/site/src/lib/components/search/SearchPalette.svelte +189 -0
- package/site/src/lib/components/search/index.ts +3 -0
- package/site/src/lib/components/search/pagefind-client.svelte.ts +129 -0
- package/site/src/lib/components/search/pagefind-query.ts +22 -0
- package/site/src/lib/components/search/pagefind-url.ts +12 -0
- package/site/src/lib/components/search/search-state.svelte.ts +22 -0
- package/site/src/lib/components/ui/IconButton.svelte +30 -0
- package/site/src/lib/components/ui/ThemeToggle.svelte +22 -0
- package/site/src/lib/components/ui/index.ts +1 -0
- package/site/src/lib/config.ts +9 -0
- package/site/src/lib/content-license.ts +7 -0
- package/site/src/lib/file-history.ts +37 -0
- package/site/src/lib/file-icons.ts +27 -0
- package/site/src/lib/file-tabs.ts +72 -0
- package/site/src/lib/files.ts +73 -0
- package/site/src/lib/github-user.ts +70 -0
- package/site/src/lib/metadata.ts +166 -0
- package/site/src/lib/notebook-nav.ts +63 -0
- package/site/src/lib/publication.ts +1 -0
- package/site/src/lib/rmd.ts +156 -0
- package/site/src/lib/server/access-admin.ts +33 -0
- package/site/src/lib/server/content-model.ts +253 -0
- package/site/src/lib/server/content-provider.ts +266 -0
- package/site/src/lib/server/content.ts +277 -0
- package/site/src/lib/server/runtime-content.ts +34 -0
- package/site/src/lib/site-config.json +9 -0
- package/site/src/lib/social-image.ts +13 -0
- package/site/src/lib/styles/article.css +607 -0
- package/site/src/lib/styles/foundation.css +138 -0
- package/site/src/lib/styles/print.css +115 -0
- package/site/src/lib/styles/shell.css +182 -0
- package/site/src/lib/text-exports.ts +5 -0
- package/site/src/lib/types.ts +140 -0
- package/site/src/lib/utils.ts +6 -0
- package/site/src/routes/+error.svelte +16 -0
- package/site/src/routes/+layout.server.ts +10 -0
- package/site/src/routes/+layout.svelte +72 -0
- package/site/src/routes/+layout.ts +3 -0
- package/site/src/routes/404/+page.svelte +13 -0
- package/site/src/routes/[...slug]/+page.server.ts +24 -0
- package/site/src/routes/[...slug]/+page.svelte +180 -0
- package/site/src/routes/[course]/files/[...file]/+page.svelte +373 -0
- package/site/src/routes/[course]/files/[...file]/+page.ts +38 -0
- package/site/src/routes/admin/access/+page.server.ts +53 -0
- package/site/src/routes/admin/access/+page.svelte +118 -0
- package/site/src/routes/graph.json/+server.ts +7 -0
- package/site/src/routes/index.xml/+server.ts +7 -0
- package/site/src/routes/layout.css +10 -0
- package/site/src/routes/robots.txt/+server.ts +9 -0
- package/site/src/routes/sitemap.xml/+server.ts +7 -0
- package/site/src/routes/tags/+page.server.ts +5 -0
- package/site/src/routes/tags/+page.svelte +38 -0
- package/site/src/routes/tags/[...tag]/+page.server.ts +22 -0
- package/site/src/routes/tags/[...tag]/+page.svelte +52 -0
- package/site/static/favicon.png +0 -0
- package/site/static/fonts/JetBrainsMono-Italic-VF.woff2 +0 -0
- package/site/static/fonts/JetBrainsMono-VF.woff2 +0 -0
- package/site/static/fonts/OverusedGrotesk-VF.woff2 +0 -0
- package/site/static/fonts/OverusedGroteskItalic-VF.woff2 +0 -0
- package/site/static/fonts/Virgil.woff2 +0 -0
- package/site/svelte.config.js +71 -0
- package/site/tooling/LICENSE-quartz +25 -0
- package/site/tooling/adapter.js +55 -0
- package/site/tooling/assets.ts +323 -0
- package/site/tooling/benchmark.ts +191 -0
- package/site/tooling/build.ts +407 -0
- package/site/tooling/cache.ts +133 -0
- package/site/tooling/check-diagrams.ts +164 -0
- package/site/tooling/check-links.ts +86 -0
- package/site/tooling/check-targets.ts +139 -0
- package/site/tooling/compiler.ts +1386 -0
- package/site/tooling/deploy.ts +112 -0
- package/site/tooling/fingerprint.ts +81 -0
- package/site/tooling/lib/app-version.js +92 -0
- package/site/tooling/lib/application-asset-urls.ts +27 -0
- package/site/tooling/lib/application-cache.ts +269 -0
- package/site/tooling/lib/asset-hash-cache.ts +116 -0
- package/site/tooling/lib/autotag.ts +99 -0
- package/site/tooling/lib/build-assembly.ts +148 -0
- package/site/tooling/lib/build-workspace.ts +386 -0
- package/site/tooling/lib/cache-selection.ts +70 -0
- package/site/tooling/lib/cloudflare-prewarm.js +40 -0
- package/site/tooling/lib/comments.ts +32 -0
- package/site/tooling/lib/content-cache.ts +244 -0
- package/site/tooling/lib/content-urls.ts +50 -0
- package/site/tooling/lib/course-cache.ts +298 -0
- package/site/tooling/lib/course-files.ts +281 -0
- package/site/tooling/lib/currency.ts +33 -0
- package/site/tooling/lib/deployment-config.ts +222 -0
- package/site/tooling/lib/deployment-manifest.ts +274 -0
- package/site/tooling/lib/deployment-prepare.ts +325 -0
- package/site/tooling/lib/deployment-upload.ts +293 -0
- package/site/tooling/lib/dev-git-state.ts +130 -0
- package/site/tooling/lib/dev-history.ts +86 -0
- package/site/tooling/lib/dev-social-images.ts +38 -0
- package/site/tooling/lib/dev-state.ts +107 -0
- package/site/tooling/lib/edition-builds.ts +184 -0
- package/site/tooling/lib/edition-paths.js +29 -0
- package/site/tooling/lib/empty-tag-route.js +23 -0
- package/site/tooling/lib/file-history.ts +201 -0
- package/site/tooling/lib/file-icons.ts +93 -0
- package/site/tooling/lib/file-policy.ts +38 -0
- package/site/tooling/lib/file-search.js +13 -0
- package/site/tooling/lib/git-revisions.ts +41 -0
- package/site/tooling/lib/history-pool.ts +74 -0
- package/site/tooling/lib/history-worker.ts +22 -0
- package/site/tooling/lib/knit-rmd.R +38 -0
- package/site/tooling/lib/lastmod.ts +201 -0
- package/site/tooling/lib/markdown-files.ts +51 -0
- package/site/tooling/lib/ofm.ts +634 -0
- package/site/tooling/lib/output.ts +60 -0
- package/site/tooling/lib/product-cache.ts +1006 -0
- package/site/tooling/lib/project-config.ts +288 -0
- package/site/tooling/lib/public-assets.ts +38 -0
- package/site/tooling/lib/public-links.ts +56 -0
- package/site/tooling/lib/publishing.ts +156 -0
- package/site/tooling/lib/r-runtime.ts +257 -0
- package/site/tooling/lib/rebuild-queue.ts +25 -0
- package/site/tooling/lib/rmd-preflight.ts +166 -0
- package/site/tooling/lib/rmd-preview-cache.ts +93 -0
- package/site/tooling/lib/rmd-previews.ts +129 -0
- package/site/tooling/lib/runtime-data-modules.ts +30 -0
- package/site/tooling/lib/runtime-packaging.ts +321 -0
- package/site/tooling/lib/search-cache.js +165 -0
- package/site/tooling/lib/search-inputs.js +129 -0
- package/site/tooling/lib/slug.ts +377 -0
- package/site/tooling/lib/social-images.ts +210 -0
- package/site/tooling/lib/text-exports.ts +51 -0
- package/site/tooling/lib/visit-elements.ts +17 -0
- package/site/tooling/live-test.ts +138 -0
- package/site/tooling/pipeline.ts +103 -0
- package/site/tooling/prepare.ts +3 -0
- package/site/tooling/publish.ts +28 -0
- package/site/tooling/r-cache.ts +45 -0
- package/site/tooling/r-render-profile.json +7 -0
- package/site/tooling/search.js +94 -0
- package/site/tooling/verify-deployment.ts +109 -0
- package/site/tooling/vite-content.ts +240 -0
- package/site/tooling/wrangler-paths.js +25 -0
- package/site/tooling/wrangler.ts +19 -0
- package/site/tsconfig.json +16 -0
- package/site/vite.config.ts +40 -0
- package/site/worker/access.ts +57 -0
- package/site/worker/analytics.ts +100 -0
- package/site/worker/auth-routes.ts +78 -0
- package/site/worker/auth.ts +78 -0
- package/site/worker/content-runtime.ts +226 -0
- package/site/worker/framing.ts +4 -0
- package/site/worker/gate.ts +147 -0
- package/site/worker/index.ts +9 -0
- package/site/worker/login.ts +62 -0
- package/site/worker/publication.ts +44 -0
- package/site/worker/runtime.ts +104 -0
- package/site/worker/tsconfig.json +13 -0
- package/site/wrangler.jsonc +37 -0
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/* ---------------------------------------------------------------------------
|
|
2
|
+
Fonts — same set as twango.dev / cca (Overused Grotesk, JetBrains Mono, Virgil)
|
|
3
|
+
--------------------------------------------------------------------------- */
|
|
4
|
+
@font-face {
|
|
5
|
+
font-family: 'Overused Grotesk';
|
|
6
|
+
src: url('/fonts/OverusedGrotesk-VF.woff2') format('woff2');
|
|
7
|
+
font-weight: 300 900;
|
|
8
|
+
font-style: normal;
|
|
9
|
+
font-display: swap;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
@font-face {
|
|
13
|
+
font-family: 'Overused Grotesk';
|
|
14
|
+
src: url('/fonts/OverusedGroteskItalic-VF.woff2') format('woff2');
|
|
15
|
+
font-weight: 400;
|
|
16
|
+
font-style: italic;
|
|
17
|
+
font-display: swap;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
@font-face {
|
|
21
|
+
font-family: 'JetBrains Mono';
|
|
22
|
+
src: url('/fonts/JetBrainsMono-VF.woff2') format('woff2');
|
|
23
|
+
font-weight: 100 800;
|
|
24
|
+
font-style: normal;
|
|
25
|
+
font-display: swap;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
@font-face {
|
|
29
|
+
font-family: 'JetBrains Mono';
|
|
30
|
+
src: url('/fonts/JetBrainsMono-Italic-VF.woff2') format('woff2');
|
|
31
|
+
font-weight: 100 800;
|
|
32
|
+
font-style: italic;
|
|
33
|
+
font-display: swap;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
@font-face {
|
|
37
|
+
font-family: 'Virgil';
|
|
38
|
+
src: url('/fonts/Virgil.woff2') format('woff2');
|
|
39
|
+
font-weight: 400;
|
|
40
|
+
font-style: normal;
|
|
41
|
+
font-display: swap;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/* ---------------------------------------------------------------------------
|
|
45
|
+
Design tokens — cca's warm-paper palette, wisconsin's red accent
|
|
46
|
+
--------------------------------------------------------------------------- */
|
|
47
|
+
@theme {
|
|
48
|
+
--font-hand: 'Virgil', cursive;
|
|
49
|
+
--font-sans: 'Overused Grotesk', system-ui, sans-serif;
|
|
50
|
+
--font-mono: 'JetBrains Mono', ui-monospace, monospace;
|
|
51
|
+
|
|
52
|
+
--color-bg: #f8f6f1;
|
|
53
|
+
--color-surface: #efede7;
|
|
54
|
+
--color-text: #1a1916;
|
|
55
|
+
--color-muted: #8a8578;
|
|
56
|
+
--color-subtle: #e2dfd8;
|
|
57
|
+
--color-accent: #d35545;
|
|
58
|
+
--color-accent-soft: #f7e4e1;
|
|
59
|
+
|
|
60
|
+
--color-border: var(--color-subtle);
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
@theme static {
|
|
64
|
+
--breakpoint-rail: 1440px;
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
:root {
|
|
68
|
+
--graph-preview-height: 250px;
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
:root.dark {
|
|
72
|
+
--color-bg: #1a1916;
|
|
73
|
+
--color-surface: #23221e;
|
|
74
|
+
--color-text: #e8e5df;
|
|
75
|
+
--color-muted: #7a7568;
|
|
76
|
+
--color-subtle: #2e2d28;
|
|
77
|
+
--color-accent: #e68578;
|
|
78
|
+
--color-accent-soft: #3f1f1b;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
html,
|
|
82
|
+
body {
|
|
83
|
+
background-color: var(--color-bg);
|
|
84
|
+
color: var(--color-text);
|
|
85
|
+
font-family: var(--font-sans);
|
|
86
|
+
-webkit-font-smoothing: antialiased;
|
|
87
|
+
-moz-osx-font-smoothing: grayscale;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
/* ---------------------------------------------------------------------------
|
|
91
|
+
Scrollbars — thin, theme-aware, unobtrusive (site-wide)
|
|
92
|
+
--------------------------------------------------------------------------- */
|
|
93
|
+
* {
|
|
94
|
+
scrollbar-width: thin;
|
|
95
|
+
scrollbar-color: var(--color-subtle) transparent;
|
|
96
|
+
}
|
|
97
|
+
*::-webkit-scrollbar {
|
|
98
|
+
width: 0.625rem;
|
|
99
|
+
height: 0.625rem;
|
|
100
|
+
}
|
|
101
|
+
*::-webkit-scrollbar-track {
|
|
102
|
+
background: transparent;
|
|
103
|
+
}
|
|
104
|
+
*::-webkit-scrollbar-thumb {
|
|
105
|
+
border: 3px solid transparent;
|
|
106
|
+
border-radius: 9999px;
|
|
107
|
+
background-color: var(--color-subtle);
|
|
108
|
+
background-clip: content-box;
|
|
109
|
+
}
|
|
110
|
+
*::-webkit-scrollbar-thumb:hover {
|
|
111
|
+
background-color: var(--color-muted);
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
code,
|
|
115
|
+
kbd,
|
|
116
|
+
samp,
|
|
117
|
+
pre {
|
|
118
|
+
font-family: var(--font-mono);
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
/* ---------------------------------------------------------------------------
|
|
122
|
+
View transitions: subtle, quick crossfade between pages (onNavigate +
|
|
123
|
+
document.startViewTransition in +layout.svelte). Reduced motion is already
|
|
124
|
+
guarded in JS; the media query here is belt-and-braces.
|
|
125
|
+
--------------------------------------------------------------------------- */
|
|
126
|
+
@media (prefers-reduced-motion: no-preference) {
|
|
127
|
+
::view-transition-old(root),
|
|
128
|
+
::view-transition-new(root) {
|
|
129
|
+
animation-duration: 120ms;
|
|
130
|
+
animation-timing-function: ease;
|
|
131
|
+
}
|
|
132
|
+
}
|
|
133
|
+
@media (prefers-reduced-motion: reduce) {
|
|
134
|
+
::view-transition-old(root),
|
|
135
|
+
::view-transition-new(root) {
|
|
136
|
+
animation: none;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
@@ -0,0 +1,115 @@
|
|
|
1
|
+
/* Shared by the note button and the browser's native Print command. */
|
|
2
|
+
@page {
|
|
3
|
+
margin: 16mm;
|
|
4
|
+
}
|
|
5
|
+
|
|
6
|
+
@media print {
|
|
7
|
+
:root,
|
|
8
|
+
:root.dark {
|
|
9
|
+
color-scheme: light;
|
|
10
|
+
--color-bg: #fff;
|
|
11
|
+
--color-surface: #f5f5f5;
|
|
12
|
+
--color-text: #111;
|
|
13
|
+
--color-muted: #555;
|
|
14
|
+
--color-subtle: #ccc;
|
|
15
|
+
--color-accent: #111;
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
html,
|
|
19
|
+
body {
|
|
20
|
+
height: auto !important;
|
|
21
|
+
overflow: visible !important;
|
|
22
|
+
background: white;
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
.doc-shell {
|
|
26
|
+
display: block;
|
|
27
|
+
min-height: 0;
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
.doc-main {
|
|
31
|
+
padding: 0;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
.doc-main > div {
|
|
35
|
+
max-width: none;
|
|
36
|
+
margin: 0;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
.doc-sidebar-left,
|
|
40
|
+
.doc-sidebar-right,
|
|
41
|
+
.doc-mobile-header,
|
|
42
|
+
.doc-reader-controls,
|
|
43
|
+
.doc-nav-backdrop,
|
|
44
|
+
.doc-main nav,
|
|
45
|
+
[data-island='backlinks'],
|
|
46
|
+
.note-actions,
|
|
47
|
+
[data-bits-portal],
|
|
48
|
+
.popover,
|
|
49
|
+
.pswp,
|
|
50
|
+
.mermaid-modal,
|
|
51
|
+
.mermaid-toolbar,
|
|
52
|
+
.prose .copy-button,
|
|
53
|
+
.prose .heading-anchor,
|
|
54
|
+
.prose .fold-callout-icon {
|
|
55
|
+
display: none !important;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
.prose {
|
|
59
|
+
font-size: 11pt;
|
|
60
|
+
orphans: 3;
|
|
61
|
+
widows: 3;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
.prose :where(h1, h2, h3, h4, h5, h6) {
|
|
65
|
+
break-after: avoid;
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
.prose :where(img, svg, figure, tr) {
|
|
69
|
+
break-inside: avoid;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
.prose :where(pre, pre code) {
|
|
73
|
+
white-space: pre-wrap;
|
|
74
|
+
overflow-wrap: anywhere;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
.prose pre,
|
|
78
|
+
.prose pre span,
|
|
79
|
+
:root.dark .prose pre.shiki,
|
|
80
|
+
:root.dark .prose pre.shiki span {
|
|
81
|
+
color: #111 !important;
|
|
82
|
+
background: #f5f5f5 !important;
|
|
83
|
+
text-shadow: none;
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
.prose pre.shiki,
|
|
87
|
+
.prose .katex-display,
|
|
88
|
+
.prose .mermaid-diagram {
|
|
89
|
+
overflow: visible;
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
.prose .mermaid-inline-content {
|
|
93
|
+
min-width: 0;
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
.prose :where(img, .mermaid-inline-content > svg) {
|
|
97
|
+
max-width: 100%;
|
|
98
|
+
max-height: 240mm;
|
|
99
|
+
object-fit: contain;
|
|
100
|
+
}
|
|
101
|
+
|
|
102
|
+
/* Include folded callouts without changing the reader's screen state. */
|
|
103
|
+
.prose blockquote.callout > .callout-content {
|
|
104
|
+
display: block;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
.prose .callout-content-inner {
|
|
108
|
+
overflow: visible;
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
.prose table {
|
|
112
|
+
width: 100%;
|
|
113
|
+
font-size: 9pt;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
@@ -0,0 +1,182 @@
|
|
|
1
|
+
/* Documentation shell: shared breakpoints own all rail and drawer geometry. */
|
|
2
|
+
.doc-shell {
|
|
3
|
+
display: grid;
|
|
4
|
+
width: 100%;
|
|
5
|
+
grid-template-columns: 22rem minmax(0, 1fr) 22rem;
|
|
6
|
+
grid-template-areas: 'left main right';
|
|
7
|
+
}
|
|
8
|
+
.doc-shell-listing {
|
|
9
|
+
grid-template-columns: 22rem minmax(0, 1fr);
|
|
10
|
+
grid-template-areas: 'left main';
|
|
11
|
+
}
|
|
12
|
+
.doc-mobile-header {
|
|
13
|
+
display: none;
|
|
14
|
+
grid-area: mobile-header;
|
|
15
|
+
}
|
|
16
|
+
.doc-sidebar-left {
|
|
17
|
+
grid-area: left;
|
|
18
|
+
position: sticky;
|
|
19
|
+
top: 0;
|
|
20
|
+
height: 100dvh;
|
|
21
|
+
}
|
|
22
|
+
.doc-main {
|
|
23
|
+
grid-area: main;
|
|
24
|
+
padding: 2rem 2rem 3rem;
|
|
25
|
+
}
|
|
26
|
+
.doc-shell.doc-shell-files {
|
|
27
|
+
height: 100dvh;
|
|
28
|
+
min-height: 0;
|
|
29
|
+
}
|
|
30
|
+
.doc-main.doc-main-files {
|
|
31
|
+
min-height: 0;
|
|
32
|
+
padding: 0;
|
|
33
|
+
}
|
|
34
|
+
.doc-sidebar-right {
|
|
35
|
+
position: sticky;
|
|
36
|
+
top: 0;
|
|
37
|
+
grid-area: right;
|
|
38
|
+
height: 100dvh;
|
|
39
|
+
border-left: 1px solid var(--color-border);
|
|
40
|
+
background: var(--color-bg);
|
|
41
|
+
overflow-y: auto;
|
|
42
|
+
overscroll-behavior: contain;
|
|
43
|
+
padding: 0;
|
|
44
|
+
}
|
|
45
|
+
.doc-sidebar-right-inner {
|
|
46
|
+
display: flex;
|
|
47
|
+
min-height: 0;
|
|
48
|
+
flex-direction: column;
|
|
49
|
+
}
|
|
50
|
+
.doc-toc {
|
|
51
|
+
margin: 0;
|
|
52
|
+
border-top: 1px solid var(--color-border);
|
|
53
|
+
padding: 1rem 1rem 0.75rem;
|
|
54
|
+
max-height: calc(100dvh - var(--graph-preview-height));
|
|
55
|
+
overflow-anchor: none;
|
|
56
|
+
overflow-y: auto;
|
|
57
|
+
overscroll-behavior: contain;
|
|
58
|
+
scrollbar-width: thin;
|
|
59
|
+
}
|
|
60
|
+
.doc-toc .toc-header {
|
|
61
|
+
position: sticky;
|
|
62
|
+
top: 0;
|
|
63
|
+
z-index: 1;
|
|
64
|
+
background: var(--color-bg);
|
|
65
|
+
}
|
|
66
|
+
.doc-toc:where(:not(:has(nav))) {
|
|
67
|
+
display: none;
|
|
68
|
+
}
|
|
69
|
+
.doc-compact-graph,
|
|
70
|
+
.doc-compact-outline {
|
|
71
|
+
display: none;
|
|
72
|
+
}
|
|
73
|
+
.doc-sidebar-content {
|
|
74
|
+
padding: 2rem 1rem 1rem;
|
|
75
|
+
}
|
|
76
|
+
.doc-shell-reader {
|
|
77
|
+
grid-template-columns: minmax(0, 1fr);
|
|
78
|
+
grid-template-areas: 'main';
|
|
79
|
+
}
|
|
80
|
+
.doc-shell-reader .doc-sidebar-left {
|
|
81
|
+
display: none;
|
|
82
|
+
}
|
|
83
|
+
.doc-nav-backdrop {
|
|
84
|
+
display: none;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
@variant max-rail {
|
|
88
|
+
.doc-shell {
|
|
89
|
+
grid-template-columns: 18rem minmax(0, 1fr);
|
|
90
|
+
grid-template-areas: 'left right' 'left main';
|
|
91
|
+
grid-template-rows: auto 1fr;
|
|
92
|
+
}
|
|
93
|
+
.doc-shell-listing {
|
|
94
|
+
grid-template-areas: 'left main';
|
|
95
|
+
}
|
|
96
|
+
.doc-shell-reader {
|
|
97
|
+
grid-template-columns: minmax(0, 1fr);
|
|
98
|
+
grid-template-areas: 'main';
|
|
99
|
+
}
|
|
100
|
+
.doc-main {
|
|
101
|
+
padding-inline: 1.5rem;
|
|
102
|
+
}
|
|
103
|
+
.doc-sidebar-right {
|
|
104
|
+
position: static;
|
|
105
|
+
height: auto;
|
|
106
|
+
border-left: 0;
|
|
107
|
+
padding: 1.5rem 1.5rem 0;
|
|
108
|
+
}
|
|
109
|
+
.doc-sidebar-right-inner {
|
|
110
|
+
max-width: 48rem;
|
|
111
|
+
margin-inline: auto;
|
|
112
|
+
flex-direction: row;
|
|
113
|
+
align-items: start;
|
|
114
|
+
gap: 1rem;
|
|
115
|
+
flex-wrap: wrap;
|
|
116
|
+
}
|
|
117
|
+
.graph-panel {
|
|
118
|
+
display: none;
|
|
119
|
+
}
|
|
120
|
+
.doc-compact-graph,
|
|
121
|
+
.doc-compact-outline {
|
|
122
|
+
display: block;
|
|
123
|
+
}
|
|
124
|
+
.doc-compact-outline {
|
|
125
|
+
padding-block: 0.375rem;
|
|
126
|
+
flex: 1;
|
|
127
|
+
min-width: 10rem;
|
|
128
|
+
}
|
|
129
|
+
.doc-compact-outline nav {
|
|
130
|
+
margin-top: 0.75rem;
|
|
131
|
+
}
|
|
132
|
+
.doc-toc {
|
|
133
|
+
display: none;
|
|
134
|
+
}
|
|
135
|
+
}
|
|
136
|
+
@media (width < 1024px) {
|
|
137
|
+
.doc-shell,
|
|
138
|
+
.doc-shell-listing,
|
|
139
|
+
.doc-shell-reader {
|
|
140
|
+
grid-template-columns: minmax(0, 1fr);
|
|
141
|
+
grid-template-areas: 'mobile-header' 'right' 'main';
|
|
142
|
+
grid-template-rows: auto auto 1fr;
|
|
143
|
+
}
|
|
144
|
+
.doc-shell-listing,
|
|
145
|
+
.doc-shell-reader {
|
|
146
|
+
grid-template-areas: 'mobile-header' 'main';
|
|
147
|
+
grid-template-rows: auto 1fr;
|
|
148
|
+
}
|
|
149
|
+
.doc-mobile-header {
|
|
150
|
+
display: flex;
|
|
151
|
+
}
|
|
152
|
+
.doc-main {
|
|
153
|
+
padding: 1.5rem 1.25rem 2rem;
|
|
154
|
+
}
|
|
155
|
+
.doc-sidebar-left,
|
|
156
|
+
.doc-shell-reader .doc-sidebar-left {
|
|
157
|
+
display: block;
|
|
158
|
+
position: fixed;
|
|
159
|
+
top: 0;
|
|
160
|
+
left: 0;
|
|
161
|
+
z-index: 50;
|
|
162
|
+
width: 17rem;
|
|
163
|
+
max-width: 85vw;
|
|
164
|
+
transform: translateX(-100%);
|
|
165
|
+
transition: transform 200ms;
|
|
166
|
+
}
|
|
167
|
+
.doc-sidebar-left.doc-nav-open {
|
|
168
|
+
transform: translateX(0);
|
|
169
|
+
}
|
|
170
|
+
.doc-nav-backdrop {
|
|
171
|
+
display: block;
|
|
172
|
+
}
|
|
173
|
+
.doc-sidebar-content {
|
|
174
|
+
padding: 1.25rem 1rem;
|
|
175
|
+
}
|
|
176
|
+
.doc-reader-controls {
|
|
177
|
+
display: none;
|
|
178
|
+
}
|
|
179
|
+
.doc-sidebar-right {
|
|
180
|
+
padding-inline: 1.25rem;
|
|
181
|
+
}
|
|
182
|
+
}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function textExportUrl(slug: string, format: 'md' | 'txt' = 'md') {
|
|
2
|
+
// Folder index notes are displayed at the folder URL. Home uses /index.md.
|
|
3
|
+
const route = slug.replace(/\/index$/, '');
|
|
4
|
+
return `/${route.split('/').map(encodeURIComponent).join('/')}.${format}`;
|
|
5
|
+
}
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared types for the doc shell and the prebuild content manifest
|
|
3
|
+
* (`site/build/generated`, emitted by `tooling/compiler.ts`).
|
|
4
|
+
*/
|
|
5
|
+
|
|
6
|
+
/** A node in the sidebar navigation tree (Explorer). */
|
|
7
|
+
export interface NavNode {
|
|
8
|
+
/** Executable worksheet or its file-browser folder, shown in Notes. */
|
|
9
|
+
notebook?: boolean;
|
|
10
|
+
locked?: boolean;
|
|
11
|
+
title: string;
|
|
12
|
+
/** Route if this node is itself a page (folder landing pages, or leaf docs). No trailing slash. */
|
|
13
|
+
route?: string;
|
|
14
|
+
/** Child nodes (sections and pages), already naturally sorted (folders first). */
|
|
15
|
+
children: NavNode[];
|
|
16
|
+
/** Segment key used for sorting/keying within its parent. */
|
|
17
|
+
segment: string;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
/** A flat table-of-contents entry for the right-hand rail. */
|
|
21
|
+
export interface TocEntry {
|
|
22
|
+
id: string;
|
|
23
|
+
text: string;
|
|
24
|
+
/** Heading level (1–6); h1 = 1. */
|
|
25
|
+
level: number;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** Raw TOC entry as emitted by the prebuild (`pages/<slug>.json`). */
|
|
29
|
+
export interface RawTocEntry {
|
|
30
|
+
/** 0-based depth: 0 = h1. */
|
|
31
|
+
depth: number;
|
|
32
|
+
text: string;
|
|
33
|
+
/** github-slugger anchor id. */
|
|
34
|
+
slug: string;
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** Page dates from the prebuild (frontmatter → submodule git log → fs). */
|
|
38
|
+
export interface PageDates {
|
|
39
|
+
created: string;
|
|
40
|
+
modified: string;
|
|
41
|
+
published: string;
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
/**
|
|
45
|
+
* A backlink reference. `slug` is in display form: folder index pages end in
|
|
46
|
+
* `/` (e.g. `sp26-cs537/exams/midterm-2/`), the homepage is `/`.
|
|
47
|
+
*/
|
|
48
|
+
export interface BacklinkRef {
|
|
49
|
+
slug: string;
|
|
50
|
+
title: string;
|
|
51
|
+
}
|
|
52
|
+
|
|
53
|
+
export interface PagePublication {
|
|
54
|
+
public: boolean;
|
|
55
|
+
reason?: string;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
/** Per-page metadata as stored in `content-manifest.json` `pages`. */
|
|
59
|
+
export interface ManifestPage {
|
|
60
|
+
heading?: string;
|
|
61
|
+
author?: import('./metadata').ContentAuthor;
|
|
62
|
+
locked?: boolean;
|
|
63
|
+
license?: import('./content-license').ContentLicense;
|
|
64
|
+
publication: PagePublication;
|
|
65
|
+
/** Canonical slug, e.g. `sp26-cs537/README` or `…/midterm-1/index` (no leading slash). */
|
|
66
|
+
slug: string;
|
|
67
|
+
title: string;
|
|
68
|
+
description: string;
|
|
69
|
+
tags: string[];
|
|
70
|
+
dates: PageDates;
|
|
71
|
+
/** Resolved outgoing link slugs (simple form). */
|
|
72
|
+
links: string[];
|
|
73
|
+
/** Backlink slugs (manifest stores display-form strings). */
|
|
74
|
+
backlinks: string[];
|
|
75
|
+
wordCount: number;
|
|
76
|
+
readingTime: number;
|
|
77
|
+
hasMermaid: boolean;
|
|
78
|
+
relativePath: string;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/** Full page document (`pages/<slug>.json`): manifest meta + rendered HTML. */
|
|
82
|
+
export interface PageDoc extends Omit<ManifestPage, 'backlinks'> {
|
|
83
|
+
backlinks: BacklinkRef[];
|
|
84
|
+
toc: RawTocEntry[];
|
|
85
|
+
html: string;
|
|
86
|
+
markdown?: string;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
/** A folder-tree node from `content-manifest.json` `tree`. */
|
|
90
|
+
export interface TreeNode {
|
|
91
|
+
/** Last path segment (`midterm-1`); root is the site name. */
|
|
92
|
+
name: string;
|
|
93
|
+
/** Full folder slug (`sp26-cs537/exams/midterm-1`); root is ``. */
|
|
94
|
+
slug: string;
|
|
95
|
+
/** Index-page title when the folder has an `index.md`, else the name. */
|
|
96
|
+
title: string;
|
|
97
|
+
children: TreeNode[];
|
|
98
|
+
pages: { slug: string; title: string }[];
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/** The global content manifest. */
|
|
102
|
+
export interface ContentManifest {
|
|
103
|
+
fileCourses?: string[];
|
|
104
|
+
generatedAt: string;
|
|
105
|
+
counts: Record<string, number>;
|
|
106
|
+
pages: Record<string, ManifestPage>;
|
|
107
|
+
/** Every directory slug (with or without its own index page). */
|
|
108
|
+
folders: string[];
|
|
109
|
+
/** Tag → page slugs (case-sensitive tag keys). */
|
|
110
|
+
tags: Record<string, string[]>;
|
|
111
|
+
tree: TreeNode;
|
|
112
|
+
/** Asset paths (slugified, extensionful) copied to static output. */
|
|
113
|
+
assets: string[];
|
|
114
|
+
/** Standalone .html assets, stored extensionless (served via html_handling). */
|
|
115
|
+
htmlAssets: string[];
|
|
116
|
+
graph: {
|
|
117
|
+
nodes: { id: string; title: string; tags: string[] }[];
|
|
118
|
+
links: { source: string; target: string }[];
|
|
119
|
+
};
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
/** One entry in a generated folder-listing page. */
|
|
123
|
+
export interface FolderEntry {
|
|
124
|
+
title: string;
|
|
125
|
+
route: string;
|
|
126
|
+
isFolder: boolean;
|
|
127
|
+
/** ISO modified date (pages only). */
|
|
128
|
+
modified?: string;
|
|
129
|
+
}
|
|
130
|
+
|
|
131
|
+
/** Data for a generated folder-listing page (folders without index.md). */
|
|
132
|
+
export interface FolderListing {
|
|
133
|
+
/** Folder slug, e.g. `sp26-cs537/p1`. */
|
|
134
|
+
folder: string;
|
|
135
|
+
/** Display name (last segment). */
|
|
136
|
+
name: string;
|
|
137
|
+
entries: FolderEntry[];
|
|
138
|
+
/** Total pages anywhere under this folder. */
|
|
139
|
+
pageCount: number;
|
|
140
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import { page } from '$app/state';
|
|
3
|
+
import SEO from '$lib/components/SEO.svelte';
|
|
4
|
+
</script>
|
|
5
|
+
|
|
6
|
+
<SEO title={String(page.status)} noindex />
|
|
7
|
+
|
|
8
|
+
<article class="prose dark:prose-invert max-w-none">
|
|
9
|
+
<h1>{page.status}</h1>
|
|
10
|
+
{#if page.status === 404}
|
|
11
|
+
<p>Either this page is private or doesn't exist.</p>
|
|
12
|
+
{:else}
|
|
13
|
+
<p>{page.error?.message ?? 'Something went wrong.'}</p>
|
|
14
|
+
{/if}
|
|
15
|
+
<p><a href="/">Go back to the homepage</a></p>
|
|
16
|
+
</article>
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { LayoutServerLoad } from './$types';
|
|
2
|
+
import { requestContent } from '$lib/server/runtime-content';
|
|
3
|
+
|
|
4
|
+
export const load: LayoutServerLoad = async ({ platform, url }) => {
|
|
5
|
+
// Track navigation so a stable application build still refreshes content data.
|
|
6
|
+
void url.pathname;
|
|
7
|
+
const content = requestContent(platform);
|
|
8
|
+
const [nav, fileIcons] = await Promise.all([content.nav(), content.icons()]);
|
|
9
|
+
return { nav, fileIcons, edition: content.context.edition };
|
|
10
|
+
};
|
|
@@ -0,0 +1,72 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
import 'katex/dist/katex.min.css';
|
|
3
|
+
import './layout.css';
|
|
4
|
+
import { onMount, setContext, type Snippet } from 'svelte';
|
|
5
|
+
import { dev } from '$app/environment';
|
|
6
|
+
import { onNavigate, invalidateAll } from '$app/navigation';
|
|
7
|
+
import { ModeWatcher } from 'mode-watcher';
|
|
8
|
+
import { site } from '$lib/config';
|
|
9
|
+
import DocShell from '$lib/components/doc/DocShell.svelte';
|
|
10
|
+
import type { LayoutData } from './$types';
|
|
11
|
+
|
|
12
|
+
interface Props {
|
|
13
|
+
children: Snippet;
|
|
14
|
+
data: LayoutData;
|
|
15
|
+
}
|
|
16
|
+
|
|
17
|
+
const { children, data }: Props = $props();
|
|
18
|
+
const nav = $derived(data.nav ?? []);
|
|
19
|
+
setContext('wisconsin-file-icons', () => data.fileIcons);
|
|
20
|
+
|
|
21
|
+
onMount(() => {
|
|
22
|
+
if (dev) return;
|
|
23
|
+
void import('$lib/analytics')
|
|
24
|
+
.then(({ initializeAnalytics }) => initializeAnalytics())
|
|
25
|
+
.catch((error) => console.warn('Failed to initialize analytics', error));
|
|
26
|
+
});
|
|
27
|
+
|
|
28
|
+
if (import.meta.hot) {
|
|
29
|
+
const refreshContent = ({ recovered }: { recovered: boolean }) => {
|
|
30
|
+
if (recovered) document.querySelector('vite-error-overlay')?.remove();
|
|
31
|
+
void invalidateAll();
|
|
32
|
+
};
|
|
33
|
+
import.meta.hot.on('wisconsin:content', refreshContent);
|
|
34
|
+
import.meta.hot.dispose(() => import.meta.hot?.off('wisconsin:content', refreshContent));
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Subtle crossfade between pages via the View Transitions API
|
|
38
|
+
// (https://svelte.dev/blog/view-transitions). Progressive enhancement:
|
|
39
|
+
// no-ops in browsers without document.startViewTransition, and skipped
|
|
40
|
+
// for users who prefer reduced motion. Duration is tuned in foundation.css.
|
|
41
|
+
onNavigate((navigation) => {
|
|
42
|
+
if (
|
|
43
|
+
navigation.from?.route.id?.includes('/files/') &&
|
|
44
|
+
navigation.to?.route.id?.includes('/files/')
|
|
45
|
+
)
|
|
46
|
+
return;
|
|
47
|
+
if (!document.startViewTransition) return;
|
|
48
|
+
if (window.matchMedia('(prefers-reduced-motion: reduce)').matches) return;
|
|
49
|
+
|
|
50
|
+
return new Promise((resolve) => {
|
|
51
|
+
document.startViewTransition(async () => {
|
|
52
|
+
resolve();
|
|
53
|
+
await navigation.complete;
|
|
54
|
+
});
|
|
55
|
+
});
|
|
56
|
+
});
|
|
57
|
+
</script>
|
|
58
|
+
|
|
59
|
+
<svelte:head>
|
|
60
|
+
<link rel="icon" href="/favicon.png" />
|
|
61
|
+
<link
|
|
62
|
+
rel="alternate"
|
|
63
|
+
type="application/rss+xml"
|
|
64
|
+
title={`${site.title} — recent notes`}
|
|
65
|
+
href="/index.xml"
|
|
66
|
+
/>
|
|
67
|
+
</svelte:head>
|
|
68
|
+
<ModeWatcher defaultMode="system" />
|
|
69
|
+
|
|
70
|
+
<DocShell {nav}>
|
|
71
|
+
{@render children()}
|
|
72
|
+
</DocShell>
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
<script lang="ts">
|
|
2
|
+
// Prerendered as 404.html; Workers `assets.not_found_handling: "404-page"`
|
|
3
|
+
// serves it for any URL that matches neither an asset nor a route.
|
|
4
|
+
import SEO from '$lib/components/SEO.svelte';
|
|
5
|
+
</script>
|
|
6
|
+
|
|
7
|
+
<SEO title="404" noindex />
|
|
8
|
+
|
|
9
|
+
<article class="prose dark:prose-invert max-w-none">
|
|
10
|
+
<h1>404</h1>
|
|
11
|
+
<p>Either this page is private or doesn't exist.</p>
|
|
12
|
+
<p><a href="/">Go back to the homepage</a></p>
|
|
13
|
+
</article>
|