@orbytes/astrolab 0.3.0 → 0.4.0-next.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/README.md +109 -64
- package/defaults.mjs +65 -0
- package/dist/core/virtual-module/virtual-routes.js +12 -1
- package/docs/PIN-CONTRACT.md +8 -0
- package/docs/PIN.md +29 -19
- package/index.d.ts +40 -16
- package/index.mjs +32 -10
- package/package.json +6 -2
- package/src/Home.astro +167 -264
- package/src/LabHead.astro +37 -1047
- package/src/chrome/ComponentCard.astro +69 -0
- package/src/chrome/Icon.astro +21 -0
- package/src/chrome/LICENSE-icons +43 -0
- package/src/chrome/Nav.astro +105 -0
- package/src/chrome/Panel.astro +104 -0
- package/src/chrome/Shell.astro +106 -0
- package/src/chrome/Sprite.astro +23 -0
- package/src/chrome/StoryView.astro +251 -0
- package/src/chrome/Tree.astro +83 -0
- package/src/chrome/ViewportControls.astro +98 -0
- package/src/chrome/ViewportStage.astro +32 -0
- package/src/chrome/fonts/OFL.txt +93 -0
- package/src/chrome/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/src/chrome/icons.ts +59 -0
- package/src/chrome/marks-client.ts +102 -0
- package/src/chrome/model.ts +142 -0
- package/src/chrome/pins-data.ts +30 -0
- package/src/chrome/shell-client.ts +372 -0
- package/src/chrome/site-data.ts +230 -0
- package/src/chrome/trees.ts +152 -0
- package/src/chrome/viewport-client.ts +579 -0
- package/src/chrome/views/Assets.astro +110 -0
- package/src/chrome/views/Pages.astro +178 -0
- package/src/chrome/views/Placeholder.astro +37 -0
- package/src/chrome/views/Tasks.astro +107 -0
- package/src/core/LICENSE-astrobook +16 -0
- package/src/core/lib/components/home.astro +4 -2
- package/src/core/lib/pages/story.astro +12 -10
- package/src/core/virtual-module/virtual-routes.ts +20 -4
- package/src/pin/board.mjs +389 -175
- package/src/pin/index.mjs +33 -2
- package/src/pin/toolbar.js +1 -1
- package/src/shell/Browse.astro +106 -353
- package/src/shell/Viewport.astro +22 -1315
- package/src/shell/lab-index.ts +23 -14
- package/src/ui/components/app.astro +5 -7
- package/src/ui/components/theme-script.astro +13 -2
- package/src/ui/lab.css +2152 -370
- package/virtual.d.ts +13 -0
- package/src/shell/CardGrid.astro +0 -297
- package/src/ui/components/build-path.ts +0 -13
- package/src/ui/components/build-tree.ts +0 -108
- package/src/ui/components/collapse-duration.ts +0 -28
- package/src/ui/components/compress-terms.ts +0 -10
- package/src/ui/components/dashboard-layout.astro +0 -39
- package/src/ui/components/home.astro +0 -65
- package/src/ui/components/layout.astro +0 -110
- package/src/ui/components/sidebar-button-fullscreen.astro +0 -38
- package/src/ui/components/sidebar-button-search.astro +0 -23
- package/src/ui/components/sidebar-button-theme.astro +0 -9
- package/src/ui/components/sidebar-button.astro +0 -24
- package/src/ui/components/sidebar-resize-handle.astro +0 -74
- package/src/ui/components/sidebar-search-panel.astro +0 -41
- package/src/ui/components/sidebar-search-script.ts +0 -103
- package/src/ui/components/sidebar-title.astro +0 -17
- package/src/ui/components/sidebar-tree-node.astro +0 -143
- package/src/ui/components/sidebar-tree.astro +0 -84
- package/src/ui/components/sidebar.astro +0 -29
- package/src/ui/components/theme-toggle.astro +0 -63
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/layout.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
//
|
|
5
|
-
// THE DIVERGENCE THAT MATTERS (ruled 2026-09-22): this layout no longer imports
|
|
6
|
-
// `virtual:astrobook/user-css.mjs`. Upstream imported the consumer's stylesheets here, last, "so
|
|
7
|
-
// it can override built-in styles" — which is exactly how the lab's chrome ended up wearing the
|
|
8
|
-
// website's brand. The consumer's CSS now reaches the PREVIEW only, through
|
|
9
|
-
// ./dashboard-layout.astro (the story rendered beside the chrome) and ./preview-layout.astro (the
|
|
10
|
-
// bare story route). This layout is pure chrome and is what the `/lab` home page renders through.
|
|
11
|
-
// Full reasoning: ../lab.css.
|
|
12
|
-
//
|
|
13
|
-
// Other divergences: the UnoCSS utility strings are the `.lab-shell` / `.lab-main` classes in
|
|
14
|
-
// ../lab.css; `astro-theme-toggle`'s ThemeScript is ./theme-script.astro, vendored; and a
|
|
15
|
-
// `<slot name="head" />` was added so a wrapping layout can put the consumer's head and CSS into
|
|
16
|
-
// this document without this file importing either.
|
|
17
|
-
//
|
|
18
|
-
// DOM contracts LabHead.astro depends on, all unchanged: `<html data-active-story>`, the `.dark`
|
|
19
|
-
// class (set by the theme script), `#astrobook-sidebar`, the resize-handle element, and
|
|
20
|
-
// `astro:after-swap` / `astro:page-load` from <ClientRouter>.
|
|
21
|
-
import '../lab.css'
|
|
22
|
-
|
|
23
|
-
import { ClientRouter } from 'astro:transitions'
|
|
24
|
-
|
|
25
|
-
import CustomHead from 'virtual:astrobook/components/head.mjs'
|
|
26
|
-
import config from 'virtual:astrobook/global-config.mjs'
|
|
27
|
-
|
|
28
|
-
import Sidebar from './sidebar.astro'
|
|
29
|
-
import SidebarResizeHandle from './sidebar-resize-handle.astro'
|
|
30
|
-
|
|
31
|
-
interface Props {
|
|
32
|
-
story: string | undefined
|
|
33
|
-
hasSidebar: boolean
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const hasSidebar = Astro.props.hasSidebar ?? true
|
|
37
|
-
const DEFAULT_SIDEBAR_WIDTH = 300
|
|
38
|
-
const DEFAULT_SIDEBAR_RESIZING = false
|
|
39
|
-
---
|
|
40
|
-
|
|
41
|
-
<html
|
|
42
|
-
lang="en"
|
|
43
|
-
class="lab-shell"
|
|
44
|
-
data-astrobook-root
|
|
45
|
-
data-active-story={Astro.props.story ?? ''}
|
|
46
|
-
data-sidebar-width={DEFAULT_SIDEBAR_WIDTH}
|
|
47
|
-
data-sidebar-resizing={DEFAULT_SIDEBAR_RESIZING ? '' : undefined}
|
|
48
|
-
>
|
|
49
|
-
<head>
|
|
50
|
-
<meta charset="utf-8" />
|
|
51
|
-
<meta name="viewport" content="width=device-width" />
|
|
52
|
-
<meta name="generator" content={Astro.generator} />
|
|
53
|
-
<title>{config.title}</title>
|
|
54
|
-
<script>
|
|
55
|
-
import { initThemeMessage } from './theme-message.ts'
|
|
56
|
-
initThemeMessage()
|
|
57
|
-
</script>
|
|
58
|
-
{/* CustomHead is the lab's own head (src/LabHead.astro), and the THEME SCRIPT comes with it.
|
|
59
|
-
Upstream rendered <ThemeScript /> here instead. It moved because the lab's folder pages and
|
|
60
|
-
viewport configurator are their own documents — they mount LabHead and never this layout —
|
|
61
|
-
so a theme script that lived here left `.dark` unset on them. That was invisible while the
|
|
62
|
-
chrome wore the consumer's dark-only tokens; now that the chrome has a light theme and a
|
|
63
|
-
dark one of its own (../lab.css), those pages rendered light while the dashboard rendered
|
|
64
|
-
dark. Measured 2026-09-22 on a real consumer site. One script per document either way:
|
|
65
|
-
LabHead carries it on every chrome page, and the bare story
|
|
66
|
-
page mounts no LabHead and carries its own (./preview-layout.astro). */}
|
|
67
|
-
<CustomHead />
|
|
68
|
-
<slot name="head" />
|
|
69
|
-
<ClientRouter fallback="none" />
|
|
70
|
-
<script is:inline>
|
|
71
|
-
;(() => {
|
|
72
|
-
const STORAGE_KEY = 'astrobook-sidebar-width'
|
|
73
|
-
const restoreWidth = () => {
|
|
74
|
-
const width = parseFloat(localStorage.getItem(STORAGE_KEY) || '')
|
|
75
|
-
if (width) {
|
|
76
|
-
document.documentElement.dataset.sidebarWidth = String(width)
|
|
77
|
-
}
|
|
78
|
-
}
|
|
79
|
-
|
|
80
|
-
restoreWidth()
|
|
81
|
-
document.addEventListener('astro:after-swap', restoreWidth)
|
|
82
|
-
})()
|
|
83
|
-
</script>
|
|
84
|
-
</head>
|
|
85
|
-
<body class="lab-shell">
|
|
86
|
-
{
|
|
87
|
-
hasSidebar && (
|
|
88
|
-
<>
|
|
89
|
-
<div id="astrobook-sidebar" class="lab-chrome">
|
|
90
|
-
<Sidebar story={Astro.props.story} />
|
|
91
|
-
</div>
|
|
92
|
-
<SidebarResizeHandle />
|
|
93
|
-
</>
|
|
94
|
-
)
|
|
95
|
-
}
|
|
96
|
-
{
|
|
97
|
-
/*
|
|
98
|
-
Use `transition:animate="none"` here because we don't want the fade animation
|
|
99
|
-
when switching between stories. Sadly this also removes the animation when toggling the light/dark theme.
|
|
100
|
-
*/
|
|
101
|
-
}
|
|
102
|
-
<main
|
|
103
|
-
class="lab-main"
|
|
104
|
-
transition:name="astrobook-main"
|
|
105
|
-
transition:animate="none"
|
|
106
|
-
>
|
|
107
|
-
<slot />
|
|
108
|
-
</main>
|
|
109
|
-
</body>
|
|
110
|
-
</html>
|
|
@@ -1,38 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-button-fullscreen.astro) —
|
|
3
|
-
// see ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS icon class is an inline SVG (no build step here), and the
|
|
5
|
-
// `import '@astrobook/types'` side-effect line is gone — the ambient declarations it pulled in
|
|
6
|
-
// live in ../../types/virtual.d.ts now.
|
|
7
|
-
import config from 'virtual:astrobook/global-config.mjs'
|
|
8
|
-
|
|
9
|
-
import SidebarButton from './sidebar-button.astro'
|
|
10
|
-
import { buildPath } from './build-path.ts'
|
|
11
|
-
|
|
12
|
-
interface Props {
|
|
13
|
-
story?: string
|
|
14
|
-
}
|
|
15
|
-
---
|
|
16
|
-
|
|
17
|
-
{
|
|
18
|
-
Astro.props.story ? (
|
|
19
|
-
<SidebarButton
|
|
20
|
-
href={buildPath(config.storyBase, Astro.props.story)}
|
|
21
|
-
title="Go full screen"
|
|
22
|
-
>
|
|
23
|
-
<svg
|
|
24
|
-
viewBox="0 0 16 16"
|
|
25
|
-
fill="none"
|
|
26
|
-
stroke="currentColor"
|
|
27
|
-
stroke-width="1.5"
|
|
28
|
-
stroke-linecap="round"
|
|
29
|
-
stroke-linejoin="round"
|
|
30
|
-
aria-hidden="true"
|
|
31
|
-
>
|
|
32
|
-
<path d="M9.5 2.5H13.5V6.5" />
|
|
33
|
-
<path d="M13.5 2.5 8 8" />
|
|
34
|
-
<path d="M12 9.5v3a1 1 0 0 1-1 1H3.5a1 1 0 0 1-1-1V5a1 1 0 0 1 1-1h3" />
|
|
35
|
-
</svg>
|
|
36
|
-
</SidebarButton>
|
|
37
|
-
) : null
|
|
38
|
-
}
|
|
@@ -1,23 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-button-search.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS icon class (`i-fluent-search-16-regular`, which presetIcons turned into
|
|
5
|
-
// a background-image at build time) is an inline SVG — this package has no build step.
|
|
6
|
-
// `id="astrobook-search-toggle"` is a DOM contract: sidebar-search-script.ts binds the panel to
|
|
7
|
-
// it, and LabHead.astro clicks it to open the panel on ⌘K.
|
|
8
|
-
import SidebarButton from './sidebar-button.astro'
|
|
9
|
-
---
|
|
10
|
-
|
|
11
|
-
<SidebarButton id="astrobook-search-toggle" title="Search">
|
|
12
|
-
<svg
|
|
13
|
-
viewBox="0 0 16 16"
|
|
14
|
-
fill="none"
|
|
15
|
-
stroke="currentColor"
|
|
16
|
-
stroke-width="1.5"
|
|
17
|
-
stroke-linecap="round"
|
|
18
|
-
aria-hidden="true"
|
|
19
|
-
>
|
|
20
|
-
<circle cx="7" cy="7" r="4.5"></circle>
|
|
21
|
-
<path d="m10.5 10.5 3 3"></path>
|
|
22
|
-
</svg>
|
|
23
|
-
</SidebarButton>
|
|
@@ -1,9 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-button-theme.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: `astro-theme-toggle`'s Toggle is ./theme-toggle.astro, vendored into this package
|
|
5
|
-
// (why: ./theme-script.astro).
|
|
6
|
-
import Toggle from './theme-toggle.astro'
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<Toggle class="astrobook-sidebar-button lab-focus-ring" />
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-button.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS `astrobook-sidebar-button` shortcut is now a real class in
|
|
5
|
-
// ../lab.css. The CLASS NAME is unchanged on purpose — LabHead.astro creates the collapse, cull,
|
|
6
|
-
// viewport, staging and code buttons in JavaScript and sets exactly this className on each.
|
|
7
|
-
interface Props {
|
|
8
|
-
id?: string
|
|
9
|
-
href?: string
|
|
10
|
-
title: string
|
|
11
|
-
}
|
|
12
|
-
|
|
13
|
-
const Element = Astro.props.href ? 'a' : 'button'
|
|
14
|
-
---
|
|
15
|
-
|
|
16
|
-
<Element
|
|
17
|
-
id={Astro.props.id}
|
|
18
|
-
href={Astro.props.href}
|
|
19
|
-
class:list={['astrobook-sidebar-button', 'lab-focus-ring']}
|
|
20
|
-
title={Astro.props.title}
|
|
21
|
-
>
|
|
22
|
-
<span class="lab-sr-only">{Astro.props.title}</span>
|
|
23
|
-
<slot />
|
|
24
|
-
</Element>
|
|
@@ -1,74 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-resize-handle.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS utility string is a real rule on the `astrobook-sidebar-resize-handle`
|
|
5
|
-
// element selector in ../lab.css. The ELEMENT NAME is unchanged — LabHead.astro's collapse styles
|
|
6
|
-
// hide it by that name.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<astrobook-sidebar-resize-handle role="separator"></astrobook-sidebar-resize-handle>
|
|
10
|
-
|
|
11
|
-
<script>
|
|
12
|
-
const STORAGE_KEY = 'astrobook-sidebar-width'
|
|
13
|
-
const DEFAULT_WIDTH = 300
|
|
14
|
-
let previousWidth = ''
|
|
15
|
-
|
|
16
|
-
function setSidebarWidth(width: number): void {
|
|
17
|
-
const widthString = width.toFixed(0)
|
|
18
|
-
if (widthString === previousWidth) {
|
|
19
|
-
return
|
|
20
|
-
}
|
|
21
|
-
previousWidth = widthString
|
|
22
|
-
document.documentElement.dataset.sidebarWidth = widthString
|
|
23
|
-
localStorage.setItem(STORAGE_KEY, widthString)
|
|
24
|
-
}
|
|
25
|
-
|
|
26
|
-
class AstrobookSidebarResizeHandle extends HTMLElement {
|
|
27
|
-
#handleCapture = (event: PointerEvent) => {
|
|
28
|
-
event.preventDefault()
|
|
29
|
-
this.setPointerCapture(event.pointerId)
|
|
30
|
-
document.documentElement.dataset.sidebarResizing = ''
|
|
31
|
-
|
|
32
|
-
document.body.addEventListener('pointermove', this.#handleMove)
|
|
33
|
-
document.body.addEventListener('pointerup', this.#handleRelease, {
|
|
34
|
-
once: true,
|
|
35
|
-
})
|
|
36
|
-
}
|
|
37
|
-
|
|
38
|
-
#handleRelease = (event?: PointerEvent) => {
|
|
39
|
-
if (event) {
|
|
40
|
-
event.preventDefault()
|
|
41
|
-
this.releasePointerCapture(event.pointerId)
|
|
42
|
-
}
|
|
43
|
-
delete document.documentElement.dataset.sidebarResizing
|
|
44
|
-
document.body.removeEventListener('pointermove', this.#handleMove)
|
|
45
|
-
document.body.removeEventListener('pointerup', this.#handleRelease)
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
#handleMove = (event: PointerEvent) => {
|
|
49
|
-
setSidebarWidth(event.clientX)
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
#handleReset = () => {
|
|
53
|
-
setSidebarWidth(DEFAULT_WIDTH)
|
|
54
|
-
}
|
|
55
|
-
|
|
56
|
-
connectedCallback() {
|
|
57
|
-
this.addEventListener('pointerdown', this.#handleCapture)
|
|
58
|
-
this.addEventListener('dblclick', this.#handleReset)
|
|
59
|
-
}
|
|
60
|
-
|
|
61
|
-
disconnectedCallback() {
|
|
62
|
-
this.removeEventListener('pointerdown', this.#handleCapture)
|
|
63
|
-
this.removeEventListener('dblclick', this.#handleReset)
|
|
64
|
-
this.#handleRelease()
|
|
65
|
-
}
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
if (!customElements.get('astrobook-sidebar-resize-handle')) {
|
|
69
|
-
customElements.define(
|
|
70
|
-
'astrobook-sidebar-resize-handle',
|
|
71
|
-
AstrobookSidebarResizeHandle,
|
|
72
|
-
)
|
|
73
|
-
}
|
|
74
|
-
</script>
|
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-search-panel.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS utility strings and the scoped <style> block are rules in ../lab.css, and
|
|
5
|
-
// the search icon is an inline SVG. The ids are DOM contracts — LabHead.astro and
|
|
6
|
-
// ./sidebar-search-script.ts both bind to them.
|
|
7
|
-
---
|
|
8
|
-
|
|
9
|
-
<div id="astrobook-search-panel">
|
|
10
|
-
<div class="lab-search__row">
|
|
11
|
-
<div class="lab-search__field">
|
|
12
|
-
<svg
|
|
13
|
-
class="lab-search__icon"
|
|
14
|
-
viewBox="0 0 16 16"
|
|
15
|
-
fill="none"
|
|
16
|
-
stroke="currentColor"
|
|
17
|
-
stroke-width="1.5"
|
|
18
|
-
stroke-linecap="round"
|
|
19
|
-
aria-hidden="true"
|
|
20
|
-
>
|
|
21
|
-
<circle cx="7" cy="7" r="4.5"></circle>
|
|
22
|
-
<path d="m10.5 10.5 3 3"></path>
|
|
23
|
-
</svg>
|
|
24
|
-
<input
|
|
25
|
-
id="astrobook-search-input"
|
|
26
|
-
type="text"
|
|
27
|
-
placeholder="Search..."
|
|
28
|
-
aria-label="Search stories"
|
|
29
|
-
/>
|
|
30
|
-
</div>
|
|
31
|
-
</div>
|
|
32
|
-
</div>
|
|
33
|
-
|
|
34
|
-
<script>
|
|
35
|
-
import { initSearch } from './sidebar-search-script.ts'
|
|
36
|
-
|
|
37
|
-
initSearch(document)
|
|
38
|
-
document.addEventListener('astro:before-swap', (event) => {
|
|
39
|
-
initSearch((event as unknown as { newDocument: Document }).newDocument)
|
|
40
|
-
})
|
|
41
|
-
</script>
|
|
@@ -1,103 +0,0 @@
|
|
|
1
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-search-script.ts) — see
|
|
2
|
-
// ../../core/LICENSE-astrobook.
|
|
3
|
-
// Divergence: the relative import carries the .ts extension.
|
|
4
|
-
//
|
|
5
|
-
// Every id below is a DOM contract shared with LabHead.astro, which opens this panel on ⌘K and
|
|
6
|
-
// widens a match by appending lower-cased terms to `data-search-text`. Do not rename them.
|
|
7
|
-
import { compressTerms } from './compress-terms.ts'
|
|
8
|
-
|
|
9
|
-
const TREE_ID = 'astrobook-sidebar-tree'
|
|
10
|
-
const SEARCH_INPUT_ID = 'astrobook-search-input'
|
|
11
|
-
const SEARCH_TOGGLE_ID = 'astrobook-search-toggle'
|
|
12
|
-
const SEARCH_PANEL_ID = 'astrobook-search-panel'
|
|
13
|
-
const STYLE_ID = 'astrobook-search-style'
|
|
14
|
-
const OPEN_KEY = 'astrobook-sidebar-search-open'
|
|
15
|
-
const QUERY_KEY = 'astrobook-sidebar-search-query'
|
|
16
|
-
|
|
17
|
-
function getStyleElement(doc: Document): HTMLStyleElement {
|
|
18
|
-
let styleEl = doc.getElementById(STYLE_ID) as HTMLStyleElement | null
|
|
19
|
-
if (!styleEl) {
|
|
20
|
-
styleEl = doc.createElement('style')
|
|
21
|
-
styleEl.id = STYLE_ID
|
|
22
|
-
doc.head.appendChild(styleEl)
|
|
23
|
-
}
|
|
24
|
-
return styleEl
|
|
25
|
-
}
|
|
26
|
-
|
|
27
|
-
function updateQueryStyle(doc: Document, query: string): void {
|
|
28
|
-
const trimmed = query.trim()
|
|
29
|
-
const el = getStyleElement(doc)
|
|
30
|
-
|
|
31
|
-
if (!trimmed) {
|
|
32
|
-
el.textContent = ''
|
|
33
|
-
return
|
|
34
|
-
}
|
|
35
|
-
|
|
36
|
-
const terms = compressTerms(trimmed.split(/[\s\p{P}]+/u))
|
|
37
|
-
const rules = terms.map((term) => {
|
|
38
|
-
return `#${TREE_ID} [data-search-text]:not([data-search-text*="${CSS.escape(term)}"]) { display: none !important; }`
|
|
39
|
-
})
|
|
40
|
-
el.textContent = rules.join('\n')
|
|
41
|
-
}
|
|
42
|
-
|
|
43
|
-
function saveQuery(query: string): void {
|
|
44
|
-
if (query) {
|
|
45
|
-
sessionStorage.setItem(QUERY_KEY, query)
|
|
46
|
-
} else {
|
|
47
|
-
sessionStorage.removeItem(QUERY_KEY)
|
|
48
|
-
}
|
|
49
|
-
}
|
|
50
|
-
|
|
51
|
-
export function initSearch(doc: Document): void {
|
|
52
|
-
const searchInputElement = doc.getElementById(
|
|
53
|
-
SEARCH_INPUT_ID,
|
|
54
|
-
) as HTMLInputElement | null
|
|
55
|
-
const searchToggleElement = doc.getElementById(SEARCH_TOGGLE_ID)
|
|
56
|
-
const searchPanelElement = doc.getElementById(SEARCH_PANEL_ID)
|
|
57
|
-
if (!searchInputElement || !searchToggleElement || !searchPanelElement) return
|
|
58
|
-
|
|
59
|
-
const searchInput = searchInputElement
|
|
60
|
-
const searchToggle = searchToggleElement
|
|
61
|
-
const searchPanel = searchPanelElement
|
|
62
|
-
|
|
63
|
-
function openPanel(): void {
|
|
64
|
-
searchPanel.setAttribute('data-open', '')
|
|
65
|
-
searchToggle.setAttribute('data-active', '')
|
|
66
|
-
sessionStorage.setItem(OPEN_KEY, '1')
|
|
67
|
-
requestAnimationFrame(() => searchInput.focus())
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function closePanel(): void {
|
|
71
|
-
searchInput.value = ''
|
|
72
|
-
saveQuery('')
|
|
73
|
-
updateQueryStyle(doc, '')
|
|
74
|
-
searchPanel.removeAttribute('data-open')
|
|
75
|
-
searchToggle.removeAttribute('data-active')
|
|
76
|
-
sessionStorage.removeItem(OPEN_KEY)
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function handleInput(): void {
|
|
80
|
-
saveQuery(searchInput.value)
|
|
81
|
-
updateQueryStyle(document, searchInput.value)
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
searchToggle.addEventListener('click', () => {
|
|
85
|
-
if (searchPanel.hasAttribute('data-open')) {
|
|
86
|
-
closePanel()
|
|
87
|
-
} else {
|
|
88
|
-
openPanel()
|
|
89
|
-
}
|
|
90
|
-
})
|
|
91
|
-
|
|
92
|
-
searchInput.addEventListener('input', handleInput)
|
|
93
|
-
|
|
94
|
-
// Restore state from sessionStorage after a page navigation
|
|
95
|
-
const isOpen = sessionStorage.getItem(OPEN_KEY) === '1'
|
|
96
|
-
if (isOpen) {
|
|
97
|
-
const query = sessionStorage.getItem(QUERY_KEY) || ''
|
|
98
|
-
searchPanel.setAttribute('data-open', '')
|
|
99
|
-
searchToggle.setAttribute('data-active', '')
|
|
100
|
-
searchInput.value = query
|
|
101
|
-
updateQueryStyle(doc, query)
|
|
102
|
-
}
|
|
103
|
-
}
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-title.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS utility string is the `.lab-sidebar__title` class in ../lab.css, and the
|
|
5
|
-
// `import '@astrobook/types'` side-effect line is gone (ambient declarations now live in
|
|
6
|
-
// ../../types/virtual.d.ts).
|
|
7
|
-
import config from 'virtual:astrobook/global-config.mjs'
|
|
8
|
-
|
|
9
|
-
import { buildPath } from './build-path.ts'
|
|
10
|
-
---
|
|
11
|
-
|
|
12
|
-
<a
|
|
13
|
-
class:list={['lab-sidebar__title', 'lab-focus-ring']}
|
|
14
|
-
href={buildPath('/', config.astrobookBase)}
|
|
15
|
-
>
|
|
16
|
-
{config.title}
|
|
17
|
-
</a>
|
|
@@ -1,143 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-tree-node.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS utility strings and shortcuts are real classes in ../lab.css, the icons
|
|
5
|
-
// are inline SVGs, and the scoped <style> block moved there with them.
|
|
6
|
-
//
|
|
7
|
-
// EVERY ATTRIBUTE AND STATE CLASS BELOW IS A DOM CONTRACT, shared with LabHead.astro's sidebar
|
|
8
|
-
// decorator and with ./sidebar-search-script.ts — `data-astrobook-collapsible`,
|
|
9
|
-
// `data-id="dir:…"` / `"module:…"`, `data-search-text`, `data-astrobook-story-link`,
|
|
10
|
-
// `data-story-id`, `data-astrobook-chevron`, and the two
|
|
11
|
-
// `astrobook-sidebar-story-link-active|inactive` classes. Do not rename any of them.
|
|
12
|
-
import config from 'virtual:astrobook/global-config.mjs'
|
|
13
|
-
|
|
14
|
-
import type { TreeNode } from './build-tree.ts'
|
|
15
|
-
import { buildPath } from './build-path.ts'
|
|
16
|
-
import { getCollapseDuration } from './collapse-duration.ts'
|
|
17
|
-
|
|
18
|
-
interface Props {
|
|
19
|
-
node: TreeNode
|
|
20
|
-
}
|
|
21
|
-
|
|
22
|
-
const { node } = Astro.props
|
|
23
|
-
|
|
24
|
-
// The inline script in sidebar-tree.astro sets the real active state on the client; the initial
|
|
25
|
-
// state here is always inactive.
|
|
26
|
-
const active = false
|
|
27
|
-
|
|
28
|
-
const collapseDuration = getCollapseDuration(node)
|
|
29
|
-
---
|
|
30
|
-
|
|
31
|
-
{
|
|
32
|
-
node.type === 'directory' && (
|
|
33
|
-
<astrobook-sidebar-node>
|
|
34
|
-
<details
|
|
35
|
-
open
|
|
36
|
-
data-astrobook-collapsible
|
|
37
|
-
data-id={`dir:${node.name}`}
|
|
38
|
-
data-search-text={node.searchText}
|
|
39
|
-
style={`--collapse-duration: ${collapseDuration}ms`}
|
|
40
|
-
>
|
|
41
|
-
<summary
|
|
42
|
-
class:list={[
|
|
43
|
-
'astrobook-sidebar-link',
|
|
44
|
-
'lab-tree-row--group',
|
|
45
|
-
'lab-focus-ring',
|
|
46
|
-
]}
|
|
47
|
-
>
|
|
48
|
-
<svg
|
|
49
|
-
data-astrobook-chevron
|
|
50
|
-
class="lab-tree-icon"
|
|
51
|
-
viewBox="0 0 16 16"
|
|
52
|
-
fill="none"
|
|
53
|
-
stroke="currentColor"
|
|
54
|
-
stroke-width="1.5"
|
|
55
|
-
stroke-linecap="round"
|
|
56
|
-
stroke-linejoin="round"
|
|
57
|
-
aria-hidden="true"
|
|
58
|
-
>
|
|
59
|
-
<path d="m4 6 4 4 4-4" />
|
|
60
|
-
</svg>
|
|
61
|
-
<span>{node.name}</span>
|
|
62
|
-
</summary>
|
|
63
|
-
<div class="lab-tree-children">
|
|
64
|
-
{node.children.map((child) => (
|
|
65
|
-
<Astro.self node={child} />
|
|
66
|
-
))}
|
|
67
|
-
</div>
|
|
68
|
-
</details>
|
|
69
|
-
</astrobook-sidebar-node>
|
|
70
|
-
)
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
{
|
|
74
|
-
node.type === 'module' && (
|
|
75
|
-
<astrobook-sidebar-node>
|
|
76
|
-
<details
|
|
77
|
-
open
|
|
78
|
-
data-astrobook-collapsible
|
|
79
|
-
data-id={`module:${node.id}`}
|
|
80
|
-
data-search-text={node.searchText}
|
|
81
|
-
style={`--collapse-duration: ${collapseDuration}ms`}
|
|
82
|
-
>
|
|
83
|
-
<summary
|
|
84
|
-
class:list={[
|
|
85
|
-
'astrobook-sidebar-link',
|
|
86
|
-
'lab-tree-row--group',
|
|
87
|
-
'lab-focus-ring',
|
|
88
|
-
]}
|
|
89
|
-
>
|
|
90
|
-
<svg
|
|
91
|
-
class="lab-tree-icon"
|
|
92
|
-
viewBox="0 0 16 16"
|
|
93
|
-
fill="none"
|
|
94
|
-
stroke="currentColor"
|
|
95
|
-
stroke-width="1.5"
|
|
96
|
-
stroke-linejoin="round"
|
|
97
|
-
aria-hidden="true"
|
|
98
|
-
>
|
|
99
|
-
<rect x="2.5" y="2.5" width="11" height="11" rx="1.5" />
|
|
100
|
-
<path d="M2.5 6.5h11" />
|
|
101
|
-
</svg>
|
|
102
|
-
<span>{node.name}</span>
|
|
103
|
-
</summary>
|
|
104
|
-
<div class="lab-tree-children">
|
|
105
|
-
{node.children.map((child) => (
|
|
106
|
-
<Astro.self node={child} />
|
|
107
|
-
))}
|
|
108
|
-
</div>
|
|
109
|
-
</details>
|
|
110
|
-
</astrobook-sidebar-node>
|
|
111
|
-
)
|
|
112
|
-
}
|
|
113
|
-
|
|
114
|
-
{
|
|
115
|
-
node.type === 'story' && (
|
|
116
|
-
<a
|
|
117
|
-
href={buildPath(config.dashboardBase, node.id)}
|
|
118
|
-
data-astrobook-story-link
|
|
119
|
-
data-story-id={node.id}
|
|
120
|
-
data-search-text={node.searchText}
|
|
121
|
-
class:list={[
|
|
122
|
-
'astrobook-sidebar-link',
|
|
123
|
-
'lab-focus-ring',
|
|
124
|
-
active
|
|
125
|
-
? 'astrobook-sidebar-story-link-active'
|
|
126
|
-
: 'astrobook-sidebar-story-link-inactive',
|
|
127
|
-
]}
|
|
128
|
-
>
|
|
129
|
-
<svg
|
|
130
|
-
class="lab-tree-icon"
|
|
131
|
-
viewBox="0 0 16 16"
|
|
132
|
-
fill="none"
|
|
133
|
-
stroke="currentColor"
|
|
134
|
-
stroke-width="1.5"
|
|
135
|
-
stroke-linejoin="round"
|
|
136
|
-
aria-hidden="true"
|
|
137
|
-
>
|
|
138
|
-
<path d="M8 2.5 13.5 8 8 13.5 2.5 8z" />
|
|
139
|
-
</svg>
|
|
140
|
-
<span>{node.name}</span>
|
|
141
|
-
</a>
|
|
142
|
-
)
|
|
143
|
-
}
|
|
@@ -1,84 +0,0 @@
|
|
|
1
|
-
---
|
|
2
|
-
// Vendored from astrobook 0.13.3 (packages/ui/src/components/sidebar-tree.astro) — see
|
|
3
|
-
// ../../core/LICENSE-astrobook.
|
|
4
|
-
// Divergence: the UnoCSS utility string is a rule on the `astrobook-sidebar-tree` element
|
|
5
|
-
// selector in ../lab.css, and the two `customElements.define` calls are guarded.
|
|
6
|
-
//
|
|
7
|
-
// `id="astrobook-sidebar-tree"` and `transition:persist` are DOM contracts: LabHead.astro hangs
|
|
8
|
-
// its pills, marks and j/k navigation on this element and relies on it surviving a view
|
|
9
|
-
// transition.
|
|
10
|
-
import modules from 'virtual:astrobook/story-modules.mjs'
|
|
11
|
-
|
|
12
|
-
import { buildTree } from './build-tree.ts'
|
|
13
|
-
import SidebarTreeNode from './sidebar-tree-node.astro'
|
|
14
|
-
|
|
15
|
-
const tree = buildTree(modules)
|
|
16
|
-
---
|
|
17
|
-
|
|
18
|
-
<astrobook-sidebar-tree
|
|
19
|
-
id="astrobook-sidebar-tree"
|
|
20
|
-
transition:persist="astrobook-sidebar-tree"
|
|
21
|
-
>
|
|
22
|
-
{tree.map((node) => <SidebarTreeNode node={node} />)}
|
|
23
|
-
</astrobook-sidebar-tree>
|
|
24
|
-
|
|
25
|
-
<script is:inline>
|
|
26
|
-
{
|
|
27
|
-
class AstrobookSidebarTree extends HTMLElement {
|
|
28
|
-
connectedCallback() {
|
|
29
|
-
const activeStory = document.documentElement.dataset.activeStory || ''
|
|
30
|
-
this.querySelectorAll(
|
|
31
|
-
'a[data-astrobook-story-link][data-story-id]',
|
|
32
|
-
).forEach((link) => {
|
|
33
|
-
const active = link.dataset.storyId === activeStory
|
|
34
|
-
link.classList.toggle('astrobook-sidebar-story-link-active', active)
|
|
35
|
-
link.classList.toggle(
|
|
36
|
-
'astrobook-sidebar-story-link-inactive',
|
|
37
|
-
!active,
|
|
38
|
-
)
|
|
39
|
-
})
|
|
40
|
-
|
|
41
|
-
const SCROLL_KEY = 'astrobook-sidebar-scroll'
|
|
42
|
-
const scrollPosition = parseFloat(
|
|
43
|
-
sessionStorage.getItem(SCROLL_KEY) || '',
|
|
44
|
-
)
|
|
45
|
-
if (scrollPosition) {
|
|
46
|
-
this.scrollTop = scrollPosition
|
|
47
|
-
}
|
|
48
|
-
this.onscrollend = () => {
|
|
49
|
-
sessionStorage.setItem(SCROLL_KEY, String(this.scrollTop))
|
|
50
|
-
}
|
|
51
|
-
}
|
|
52
|
-
}
|
|
53
|
-
if (!customElements.get('astrobook-sidebar-tree')) {
|
|
54
|
-
customElements.define('astrobook-sidebar-tree', AstrobookSidebarTree)
|
|
55
|
-
}
|
|
56
|
-
}
|
|
57
|
-
{
|
|
58
|
-
class AstrobookSidebarNode extends HTMLElement {
|
|
59
|
-
connectedCallback() {
|
|
60
|
-
const details = this.querySelector('details[data-id]')
|
|
61
|
-
if (!details) return
|
|
62
|
-
const id = details.dataset.id
|
|
63
|
-
if (!id) return
|
|
64
|
-
const key = 'astrobook-sidebar-collapse-' + id
|
|
65
|
-
const collapsed = localStorage.getItem(key) === '1'
|
|
66
|
-
|
|
67
|
-
if (collapsed) {
|
|
68
|
-
details.removeAttribute('open')
|
|
69
|
-
}
|
|
70
|
-
|
|
71
|
-
details.addEventListener('toggle', () => {
|
|
72
|
-
if (details.open) {
|
|
73
|
-
localStorage.removeItem(key)
|
|
74
|
-
} else {
|
|
75
|
-
localStorage.setItem(key, '1')
|
|
76
|
-
}
|
|
77
|
-
})
|
|
78
|
-
}
|
|
79
|
-
}
|
|
80
|
-
if (!customElements.get('astrobook-sidebar-node')) {
|
|
81
|
-
customElements.define('astrobook-sidebar-node', AstrobookSidebarNode)
|
|
82
|
-
}
|
|
83
|
-
}
|
|
84
|
-
</script>
|