@openlaboratory/open-doc 0.1.0
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 +91 -0
- package/app/.astro/collections/docs.schema.json +24 -0
- package/app/.astro/content-assets.mjs +1 -0
- package/app/.astro/content-modules.mjs +4 -0
- package/app/.astro/content.d.ts +218 -0
- package/app/.astro/data-store.json +1 -0
- package/app/.astro/settings.json +5 -0
- package/app/.astro/types.d.ts +2 -0
- package/app/astro.config.mjs +43 -0
- package/app/node_modules/.astro/data-store.json +1 -0
- package/app/node_modules/.vite/deps/@astrojs_react_client__js.js +163 -0
- package/app/node_modules/.vite/deps/@astrojs_react_client__js.js.map +7 -0
- package/app/node_modules/.vite/deps/_metadata.json +67 -0
- package/app/node_modules/.vite/deps/astro___aria-query.js +6776 -0
- package/app/node_modules/.vite/deps/astro___aria-query.js.map +7 -0
- package/app/node_modules/.vite/deps/astro___axobject-query.js +3754 -0
- package/app/node_modules/.vite/deps/astro___axobject-query.js.map +7 -0
- package/app/node_modules/.vite/deps/astro___cssesc.js +99 -0
- package/app/node_modules/.vite/deps/astro___cssesc.js.map +7 -0
- package/app/node_modules/.vite/deps/chunk-55ZOATU5.js +305 -0
- package/app/node_modules/.vite/deps/chunk-55ZOATU5.js.map +7 -0
- package/app/node_modules/.vite/deps/chunk-5WRI5ZAA.js +30 -0
- package/app/node_modules/.vite/deps/chunk-5WRI5ZAA.js.map +7 -0
- package/app/node_modules/.vite/deps/chunk-FEZZJEG2.js +6935 -0
- package/app/node_modules/.vite/deps/chunk-FEZZJEG2.js.map +7 -0
- package/app/node_modules/.vite/deps/package.json +3 -0
- package/app/node_modules/.vite/deps/react-dom.js +6 -0
- package/app/node_modules/.vite/deps/react-dom.js.map +7 -0
- package/app/node_modules/.vite/deps/react.js +5 -0
- package/app/node_modules/.vite/deps/react.js.map +7 -0
- package/app/node_modules/.vite/deps/react_jsx-dev-runtime.js +39 -0
- package/app/node_modules/.vite/deps/react_jsx-dev-runtime.js.map +7 -0
- package/app/node_modules/.vite/deps/react_jsx-runtime.js +57 -0
- package/app/node_modules/.vite/deps/react_jsx-runtime.js.map +7 -0
- package/app/src/components/DocsMobileNav.tsx +124 -0
- package/app/src/components/DocsSearch.tsx +315 -0
- package/app/src/components/DocsSidebar.astro +46 -0
- package/app/src/components/DocsTableOfContents.tsx +92 -0
- package/app/src/components/Navbar.astro +39 -0
- package/app/src/components/SocialIcon.astro +54 -0
- package/app/src/components/ThemeToggle.tsx +62 -0
- package/app/src/content.config.ts +17 -0
- package/app/src/env.d.ts +7 -0
- package/app/src/integrations/open-doc-config.mjs +65 -0
- package/app/src/layouts/DocsLayout.astro +369 -0
- package/app/src/lib/config.ts +36 -0
- package/app/src/lib/navigation.ts +68 -0
- package/app/src/lib/withBase.ts +11 -0
- package/app/src/pages/404.astro +24 -0
- package/app/src/pages/[...slug].astro +34 -0
- package/app/src/pages/index.astro +107 -0
- package/app/src/styles/global.css +324 -0
- package/app/tailwind.config.mjs +53 -0
- package/app/tsconfig.json +11 -0
- package/bin/open-doc.js +2 -0
- package/dist/chunk-BRUM67K7.js +30 -0
- package/dist/cli.d.ts +2 -0
- package/dist/cli.js +268 -0
- package/dist/index.d.ts +116 -0
- package/dist/index.js +8 -0
- package/package.json +77 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { useEffect, useRef, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
interface Heading {
|
|
4
|
+
depth: number
|
|
5
|
+
slug: string
|
|
6
|
+
text: string
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
interface Props {
|
|
10
|
+
headings: Heading[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
/** Right-hand "On this page" list with scroll-spy via IntersectionObserver. */
|
|
14
|
+
export function DocsTableOfContents({ headings }: Props) {
|
|
15
|
+
const [activeId, setActiveId] = useState('')
|
|
16
|
+
const navRef = useRef<HTMLElement>(null)
|
|
17
|
+
const filtered = headings.filter((h) => h.depth === 2 || h.depth === 3)
|
|
18
|
+
|
|
19
|
+
useEffect(() => {
|
|
20
|
+
if (filtered.length === 0) return
|
|
21
|
+
|
|
22
|
+
const observer = new IntersectionObserver(
|
|
23
|
+
(entries) => {
|
|
24
|
+
for (const entry of entries) {
|
|
25
|
+
if (entry.isIntersecting) {
|
|
26
|
+
setActiveId(entry.target.id)
|
|
27
|
+
break
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
},
|
|
31
|
+
{ rootMargin: '-80px 0px -70% 0px', threshold: 0 },
|
|
32
|
+
)
|
|
33
|
+
|
|
34
|
+
filtered.forEach(({ slug }) => {
|
|
35
|
+
const el = document.getElementById(slug)
|
|
36
|
+
if (el) observer.observe(el)
|
|
37
|
+
})
|
|
38
|
+
|
|
39
|
+
// The bottom rootMargin means the last heading may never "activate"; force it
|
|
40
|
+
// active once the page is scrolled to the bottom.
|
|
41
|
+
const onScroll = () => {
|
|
42
|
+
if (window.innerHeight + window.scrollY >= document.documentElement.scrollHeight - 2) {
|
|
43
|
+
setActiveId(filtered[filtered.length - 1].slug)
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
window.addEventListener('scroll', onScroll, { passive: true })
|
|
47
|
+
|
|
48
|
+
return () => {
|
|
49
|
+
observer.disconnect()
|
|
50
|
+
window.removeEventListener('scroll', onScroll)
|
|
51
|
+
}
|
|
52
|
+
}, [filtered])
|
|
53
|
+
|
|
54
|
+
// Keep the active item visible within the (scrollable) TOC.
|
|
55
|
+
useEffect(() => {
|
|
56
|
+
if (!activeId || !navRef.current) return
|
|
57
|
+
const link = navRef.current.querySelector(`a[href="#${CSS.escape(activeId)}"]`)
|
|
58
|
+
link?.scrollIntoView({ block: 'nearest' })
|
|
59
|
+
}, [activeId])
|
|
60
|
+
|
|
61
|
+
if (filtered.length === 0) return null
|
|
62
|
+
|
|
63
|
+
return (
|
|
64
|
+
<nav ref={navRef} aria-label="On this page">
|
|
65
|
+
<p className="mb-3 text-[11px] font-semibold uppercase tracking-widest text-foreground/40">
|
|
66
|
+
On this page
|
|
67
|
+
</p>
|
|
68
|
+
<ul className="flex flex-col gap-0.5">
|
|
69
|
+
{filtered.map((heading) => {
|
|
70
|
+
const isActive = activeId === heading.slug
|
|
71
|
+
return (
|
|
72
|
+
<li key={heading.slug}>
|
|
73
|
+
<a
|
|
74
|
+
href={`#${heading.slug}`}
|
|
75
|
+
aria-current={isActive ? 'location' : undefined}
|
|
76
|
+
className={[
|
|
77
|
+
'block rounded py-1 text-sm leading-snug transition-colors',
|
|
78
|
+
heading.depth === 3 ? 'pl-3' : '',
|
|
79
|
+
isActive
|
|
80
|
+
? 'font-medium text-foreground'
|
|
81
|
+
: 'text-foreground/50 hover:text-foreground/80',
|
|
82
|
+
].join(' ')}
|
|
83
|
+
>
|
|
84
|
+
{heading.text}
|
|
85
|
+
</a>
|
|
86
|
+
</li>
|
|
87
|
+
)
|
|
88
|
+
})}
|
|
89
|
+
</ul>
|
|
90
|
+
</nav>
|
|
91
|
+
)
|
|
92
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
---
|
|
2
|
+
import config from 'virtual:open-doc-config'
|
|
3
|
+
import { withBase } from '../lib/withBase'
|
|
4
|
+
import { ThemeToggle } from './ThemeToggle'
|
|
5
|
+
import SocialIcon from './SocialIcon.astro'
|
|
6
|
+
|
|
7
|
+
const { logo, title, social, themeToggle } = config
|
|
8
|
+
---
|
|
9
|
+
|
|
10
|
+
<header
|
|
11
|
+
class="sticky top-0 z-40 h-[57px] border-b border-foreground/[0.08] bg-surface-sidebar/80 backdrop-blur supports-[backdrop-filter]:bg-surface-sidebar/70"
|
|
12
|
+
>
|
|
13
|
+
<div class="flex h-full items-center justify-between gap-4 px-4 sm:px-6">
|
|
14
|
+
<a
|
|
15
|
+
href={withBase(logo.href)}
|
|
16
|
+
class="flex items-center gap-2.5 text-foreground/90 transition-colors hover:text-foreground"
|
|
17
|
+
>
|
|
18
|
+
{logo.src && <img src={withBase(logo.src)} alt={title} class="h-6 w-auto" />}
|
|
19
|
+
{logo.text && <span class="text-sm font-semibold tracking-tight">{logo.text}</span>}
|
|
20
|
+
</a>
|
|
21
|
+
|
|
22
|
+
<div class="flex items-center gap-1">
|
|
23
|
+
{
|
|
24
|
+
social.map((item) => (
|
|
25
|
+
<a
|
|
26
|
+
href={item.href}
|
|
27
|
+
target="_blank"
|
|
28
|
+
rel="noopener noreferrer"
|
|
29
|
+
class="flex h-8 w-8 items-center justify-center rounded-md text-foreground/55 transition-colors hover:bg-foreground/[0.06] hover:text-foreground/90"
|
|
30
|
+
aria-label={item.label ?? item.icon ?? 'Link'}
|
|
31
|
+
>
|
|
32
|
+
<SocialIcon name={item.icon} />
|
|
33
|
+
</a>
|
|
34
|
+
))
|
|
35
|
+
}
|
|
36
|
+
{themeToggle && <ThemeToggle client:load />}
|
|
37
|
+
</div>
|
|
38
|
+
</div>
|
|
39
|
+
</header>
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
---
|
|
2
|
+
// Renders a brand glyph for a social link. Falls back to a generic link icon.
|
|
3
|
+
interface Props {
|
|
4
|
+
name?: string
|
|
5
|
+
class?: string
|
|
6
|
+
}
|
|
7
|
+
const { name, class: className = 'h-[18px] w-[18px]' } = Astro.props
|
|
8
|
+
|
|
9
|
+
// Brand glyphs (single-path, 24x24, fill=currentColor).
|
|
10
|
+
const brands: Record<string, string> = {
|
|
11
|
+
github:
|
|
12
|
+
'M12 .297c-6.63 0-12 5.373-12 12 0 5.303 3.438 9.8 8.205 11.385.6.113.82-.258.82-.577 0-.285-.01-1.04-.015-2.04-3.338.724-4.042-1.61-4.042-1.61-.546-1.387-1.333-1.757-1.333-1.757-1.089-.745.083-.729.083-.729 1.205.084 1.839 1.237 1.839 1.237 1.07 1.834 2.807 1.304 3.492.997.107-.775.418-1.305.762-1.604-2.665-.305-5.467-1.334-5.467-5.931 0-1.311.469-2.381 1.236-3.221-.124-.303-.535-1.524.117-3.176 0 0 1.008-.322 3.301 1.23A11.509 11.509 0 0112 5.803c1.02.005 2.047.138 3.006.404 2.291-1.552 3.297-1.23 3.297-1.23.653 1.653.242 2.874.118 3.176.77.84 1.235 1.911 1.235 3.221 0 4.609-2.807 5.624-5.479 5.921.43.372.823 1.102.823 2.222 0 1.606-.014 2.898-.014 3.293 0 .322.216.694.825.576C20.565 22.092 24 17.592 24 12.297c0-6.627-5.373-12-12-12',
|
|
13
|
+
x: 'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z',
|
|
14
|
+
twitter:
|
|
15
|
+
'M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z',
|
|
16
|
+
discord:
|
|
17
|
+
'M20.317 4.369a19.791 19.791 0 00-4.885-1.515.074.074 0 00-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 00-5.487 0 12.64 12.64 0 00-.617-1.25.077.077 0 00-.079-.037A19.736 19.736 0 003.677 4.37a.07.07 0 00-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 00.031.057 19.9 19.9 0 005.993 3.03.078.078 0 00.084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 00-.041-.106 13.107 13.107 0 01-1.872-.892.077.077 0 01-.008-.128c.126-.094.252-.192.371-.291a.074.074 0 01.077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 01.078.009c.12.099.245.198.372.292a.077.077 0 01-.006.127c-.598.35-1.22.645-1.873.892a.077.077 0 00-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 00.084.028 19.839 19.839 0 006.002-3.03.077.077 0 00.032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 00-.031-.03zM8.02 15.331c-1.183 0-2.157-1.086-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.332-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.086-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.332-.946 2.418-2.157 2.418z',
|
|
18
|
+
linkedin:
|
|
19
|
+
'M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 01-2.063-2.065 2.064 2.064 0 112.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z',
|
|
20
|
+
youtube:
|
|
21
|
+
'M23.498 6.186a3.016 3.016 0 00-2.122-2.136C19.505 3.545 12 3.545 12 3.545s-7.505 0-9.377.505A3.017 3.017 0 00.502 6.186C0 8.07 0 12 0 12s0 3.93.502 5.814a3.016 3.016 0 002.122 2.136c1.871.505 9.376.505 9.376.505s7.505 0 9.377-.505a3.015 3.015 0 002.122-2.136C24 15.93 24 12 24 12s0-3.93-.502-5.814zM9.545 15.568V8.432L15.818 12l-6.273 3.568z',
|
|
22
|
+
mastodon:
|
|
23
|
+
'M23.268 5.313c-.35-2.578-2.617-4.61-5.304-5.004C17.51.242 15.792 0 11.813 0h-.03c-3.98 0-4.835.242-5.288.309C3.882.692 1.496 2.518.917 5.127.64 6.412.61 7.837.661 9.143c.073 1.874.088 3.745.26 5.611.118 1.24.325 2.47.62 3.68.55 2.237 2.777 4.098 4.96 4.857 2.336.792 4.849.923 7.256.38.265-.061.527-.132.786-.213.585-.184 1.27-.39 1.774-.753a.057.057 0 00.023-.043v-1.809a.052.052 0 00-.02-.041.053.053 0 00-.046-.01 20.282 20.282 0 01-4.709.545c-2.73 0-3.463-1.284-3.674-1.818a5.593 5.593 0 01-.319-1.433.053.053 0 01.066-.054c1.517.363 3.072.546 4.632.546.376 0 .75 0 1.125-.01 1.57-.044 3.224-.124 4.768-.422.038-.008.077-.015.11-.024 2.435-.464 4.753-1.92 4.989-5.604.008-.145.03-1.52.03-1.67.002-.512.167-3.63-.024-5.545zm-3.748 9.195h-2.561V8.29c0-1.309-.55-1.976-1.67-1.976-1.23 0-1.846.79-1.846 2.35v3.403h-2.546V8.663c0-1.56-.617-2.35-1.848-2.35-1.112 0-1.668.668-1.67 1.977v6.218H4.822V8.102c0-1.31.337-2.35 1.011-3.12.696-.77 1.608-1.164 2.74-1.164 1.311 0 2.302.5 2.962 1.498l.638 1.06.638-1.06c.66-.999 1.65-1.498 2.96-1.498 1.13 0 2.043.395 2.74 1.164.675.77 1.012 1.81 1.012 3.12z',
|
|
24
|
+
slack:
|
|
25
|
+
'M5.042 15.165a2.528 2.528 0 01-2.52 2.523A2.528 2.528 0 010 15.165a2.527 2.527 0 012.522-2.52h2.52v2.52zm1.271 0a2.527 2.527 0 012.521-2.52 2.527 2.527 0 012.521 2.52v6.313A2.528 2.528 0 018.834 24a2.528 2.528 0 01-2.521-2.522v-6.313zM8.834 5.042a2.528 2.528 0 01-2.521-2.52A2.528 2.528 0 018.834 0a2.528 2.528 0 012.521 2.522v2.52H8.834zm0 1.271a2.528 2.528 0 012.521 2.521 2.528 2.528 0 01-2.521 2.521H2.522A2.528 2.528 0 010 8.834a2.528 2.528 0 012.522-2.521h6.312zm10.122 2.521a2.528 2.528 0 012.522-2.521A2.528 2.528 0 0124 8.834a2.528 2.528 0 01-2.522 2.521h-2.522V8.834zm-1.268 0a2.528 2.528 0 01-2.523 2.521 2.527 2.527 0 01-2.52-2.521V2.522A2.527 2.527 0 0115.165 0a2.528 2.528 0 012.523 2.522v6.312zm-2.523 10.122a2.528 2.528 0 012.523 2.522A2.528 2.528 0 0115.165 24a2.527 2.527 0 01-2.52-2.522v-2.522h2.52zm0-1.268a2.527 2.527 0 01-2.52-2.523 2.526 2.526 0 012.52-2.52h6.313A2.527 2.527 0 0124 15.165a2.528 2.528 0 01-2.522 2.523h-6.313z',
|
|
26
|
+
bluesky:
|
|
27
|
+
'M12 10.8c-1.087-2.114-4.046-6.053-6.798-7.995C2.566.944 1.561 1.266.902 1.565.139 1.908 0 3.08 0 3.768c0 .69.378 5.65.624 6.479.815 2.736 3.713 3.66 6.383 3.364.136-.02.275-.039.415-.056-.138.022-.276.04-.415.056-3.912.58-7.387 2.005-2.83 7.078 5.013 5.19 6.87-1.113 7.823-4.308.953 3.195 2.05 9.271 7.733 4.308 4.267-4.308 1.172-6.498-2.74-7.078a8.741 8.741 0 01-.415-.056c.14.017.279.036.415.056 2.67.297 5.568-.628 6.383-3.364.246-.828.624-5.789.624-6.479 0-.688-.139-1.86-.902-2.203-.659-.299-1.664-.621-4.3 1.24C16.046 4.748 13.087 8.687 12 10.8z',
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
const path = (name && brands[name]) || null
|
|
31
|
+
---
|
|
32
|
+
|
|
33
|
+
{
|
|
34
|
+
path ? (
|
|
35
|
+
<svg class={className} viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
|
|
36
|
+
<path d={path} />
|
|
37
|
+
</svg>
|
|
38
|
+
) : (
|
|
39
|
+
<svg
|
|
40
|
+
class={className}
|
|
41
|
+
viewBox="0 0 24 24"
|
|
42
|
+
fill="none"
|
|
43
|
+
stroke="currentColor"
|
|
44
|
+
stroke-width="2"
|
|
45
|
+
aria-hidden="true"
|
|
46
|
+
>
|
|
47
|
+
<path
|
|
48
|
+
stroke-linecap="round"
|
|
49
|
+
stroke-linejoin="round"
|
|
50
|
+
d="M13.19 8.688a4.5 4.5 0 011.242 7.244l-4.5 4.5a4.5 4.5 0 01-6.364-6.364l1.757-1.757m13.35-.622l1.757-1.757a4.5 4.5 0 00-6.364-6.364l-4.5 4.5a4.5 4.5 0 001.242 7.244"
|
|
51
|
+
/>
|
|
52
|
+
</svg>
|
|
53
|
+
)
|
|
54
|
+
}
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
import { useEffect, useState } from 'react'
|
|
2
|
+
|
|
3
|
+
const STORAGE_KEY = 'open-doc-theme'
|
|
4
|
+
|
|
5
|
+
/** Header button that toggles the `.dark` class and persists the choice. */
|
|
6
|
+
export function ThemeToggle() {
|
|
7
|
+
const [isDark, setIsDark] = useState(true)
|
|
8
|
+
|
|
9
|
+
useEffect(() => {
|
|
10
|
+
setIsDark(document.documentElement.classList.contains('dark'))
|
|
11
|
+
}, [])
|
|
12
|
+
|
|
13
|
+
const toggle = () => {
|
|
14
|
+
const next = !isDark
|
|
15
|
+
setIsDark(next)
|
|
16
|
+
document.documentElement.classList.toggle('dark', next)
|
|
17
|
+
try {
|
|
18
|
+
localStorage.setItem(STORAGE_KEY, next ? 'dark' : 'light')
|
|
19
|
+
} catch {
|
|
20
|
+
/* storage unavailable — ignore */
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
return (
|
|
25
|
+
<button
|
|
26
|
+
type="button"
|
|
27
|
+
onClick={toggle}
|
|
28
|
+
className="flex h-8 w-8 items-center justify-center rounded-md text-foreground/55 transition-colors hover:bg-foreground/[0.06] hover:text-foreground/90"
|
|
29
|
+
aria-label={isDark ? 'Switch to light theme' : 'Switch to dark theme'}
|
|
30
|
+
>
|
|
31
|
+
{isDark ? (
|
|
32
|
+
<svg
|
|
33
|
+
className="h-[18px] w-[18px]"
|
|
34
|
+
fill="none"
|
|
35
|
+
viewBox="0 0 24 24"
|
|
36
|
+
stroke="currentColor"
|
|
37
|
+
strokeWidth={2}
|
|
38
|
+
>
|
|
39
|
+
<path
|
|
40
|
+
strokeLinecap="round"
|
|
41
|
+
strokeLinejoin="round"
|
|
42
|
+
d="M21.752 15.002A9.718 9.718 0 0118 15.75c-5.385 0-9.75-4.365-9.75-9.75 0-1.33.266-2.597.748-3.752A9.753 9.753 0 003 11.25C3 16.635 7.365 21 12.75 21a9.753 9.753 0 009.002-5.998z"
|
|
43
|
+
/>
|
|
44
|
+
</svg>
|
|
45
|
+
) : (
|
|
46
|
+
<svg
|
|
47
|
+
className="h-[18px] w-[18px]"
|
|
48
|
+
fill="none"
|
|
49
|
+
viewBox="0 0 24 24"
|
|
50
|
+
stroke="currentColor"
|
|
51
|
+
strokeWidth={2}
|
|
52
|
+
>
|
|
53
|
+
<path
|
|
54
|
+
strokeLinecap="round"
|
|
55
|
+
strokeLinejoin="round"
|
|
56
|
+
d="M12 3v2.25m6.364.386l-1.591 1.591M21 12h-2.25m-.386 6.364l-1.591-1.591M12 18.75V21m-4.773-4.227l-1.591 1.591M5.25 12H3m4.227-4.773L5.636 5.636M15.75 12a3.75 3.75 0 11-7.5 0 3.75 3.75 0 017.5 0z"
|
|
57
|
+
/>
|
|
58
|
+
</svg>
|
|
59
|
+
)}
|
|
60
|
+
</button>
|
|
61
|
+
)
|
|
62
|
+
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { defineCollection, z } from 'astro:content'
|
|
2
|
+
import { glob } from 'astro/loaders'
|
|
3
|
+
|
|
4
|
+
// The CLI sets OPEN_DOC_CONTENT_DIR to the consumer's content directory.
|
|
5
|
+
const base = process.env.OPEN_DOC_CONTENT_DIR ?? './content'
|
|
6
|
+
|
|
7
|
+
const docs = defineCollection({
|
|
8
|
+
// Underscore-prefixed files/folders (e.g. _components) are ignored as pages,
|
|
9
|
+
// so they can hold partials & components imported by your MDX.
|
|
10
|
+
loader: glob({ pattern: ['**/*.{md,mdx}', '!**/_*', '!**/_*/**'], base }),
|
|
11
|
+
schema: z.object({
|
|
12
|
+
title: z.string(),
|
|
13
|
+
description: z.string().optional(),
|
|
14
|
+
}),
|
|
15
|
+
})
|
|
16
|
+
|
|
17
|
+
export const collections = { docs }
|
package/app/src/env.d.ts
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Internal Astro integration that wires the consumer's project into the bundled
|
|
3
|
+
* app:
|
|
4
|
+
* • exposes the resolved config as the `virtual:open-doc-config` module
|
|
5
|
+
* • aliases `@docs` to the consumer's content directory
|
|
6
|
+
* • allows Vite to read files from the (external) content + public dirs
|
|
7
|
+
*
|
|
8
|
+
* The resolved config is passed from the CLI via OPEN_DOC_CONFIG_JSON.
|
|
9
|
+
*
|
|
10
|
+
* @param {{ contentDir?: string, publicDir?: string }} options
|
|
11
|
+
* @returns {import('astro').AstroIntegration}
|
|
12
|
+
*/
|
|
13
|
+
export function openDocConfig({ contentDir, publicDir } = {}) {
|
|
14
|
+
const configJson = process.env.OPEN_DOC_CONFIG_JSON || '{}'
|
|
15
|
+
const allow = [contentDir, publicDir].filter(Boolean)
|
|
16
|
+
|
|
17
|
+
return {
|
|
18
|
+
name: 'open-doc:config',
|
|
19
|
+
hooks: {
|
|
20
|
+
'astro:config:setup': ({ command, updateConfig }) => {
|
|
21
|
+
// For `build`, bundle open-doc's runtime deps into the SSR output so the
|
|
22
|
+
// build is self-contained under every package manager (their files live
|
|
23
|
+
// in open-doc's node_modules, not the consumer's). In `dev` they must
|
|
24
|
+
// stay external — bundling CommonJS React breaks the dev SSR runtime.
|
|
25
|
+
const noExternal =
|
|
26
|
+
command === 'build' ? ['fuse.js', 'react', 'react-dom', '@astrojs/react'] : []
|
|
27
|
+
|
|
28
|
+
updateConfig({
|
|
29
|
+
vite: {
|
|
30
|
+
plugins: [virtualConfigPlugin(configJson)],
|
|
31
|
+
resolve: {
|
|
32
|
+
alias: contentDir ? { '@docs': contentDir } : {},
|
|
33
|
+
// One React instance, even if a consumer installs their own for MDX.
|
|
34
|
+
dedupe: ['react', 'react-dom'],
|
|
35
|
+
},
|
|
36
|
+
ssr: { noExternal },
|
|
37
|
+
// Merged additively with Vite's defaults by Astro's config merge.
|
|
38
|
+
server: { fs: { allow } },
|
|
39
|
+
},
|
|
40
|
+
})
|
|
41
|
+
},
|
|
42
|
+
},
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Emits the resolved config object as a virtual ES module so any `.astro` /
|
|
48
|
+
* `.tsx` component can `import config from 'virtual:open-doc-config'`.
|
|
49
|
+
*
|
|
50
|
+
* @param {string} json
|
|
51
|
+
* @returns {import('vite').Plugin}
|
|
52
|
+
*/
|
|
53
|
+
function virtualConfigPlugin(json) {
|
|
54
|
+
const id = 'virtual:open-doc-config'
|
|
55
|
+
const resolvedId = '\0' + id
|
|
56
|
+
return {
|
|
57
|
+
name: 'open-doc:virtual-config',
|
|
58
|
+
resolveId(source) {
|
|
59
|
+
if (source === id) return resolvedId
|
|
60
|
+
},
|
|
61
|
+
load(thisId) {
|
|
62
|
+
if (thisId === resolvedId) return `export default ${json}`
|
|
63
|
+
},
|
|
64
|
+
}
|
|
65
|
+
}
|