sourcey 3.5.8 → 3.5.10

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 CHANGED
@@ -1,8 +1,10 @@
1
1
  # Sourcey
2
2
 
3
- > Your API docs shouldn't depend on someone else's SaaS.
3
+ > Docs straight from the source.
4
4
 
5
- Sourcey is an open source documentation platform. Point it at an OpenAPI spec, an MCP server, a Doxygen XML directory, or a Go module; add markdown guides; get a complete docs site. Static HTML you own; no dashboard, no monthly bill, no API calls to render your own documentation. Deploy anywhere.
5
+ Sourcey tells the whole product story. It turns specs, code, rich guides, changelog, roadmap pages, examples, and portable context files from your project into static HTML you can deploy anywhere.
6
+
7
+ No dashboard. No runtime. No API calls to render your own documentation.
6
8
 
7
9
  [![npm](https://img.shields.io/npm/v/sourcey)](https://www.npmjs.com/package/sourcey)
8
10
  [![build](https://img.shields.io/github/actions/workflow/status/sourcey/sourcey/ci.yml?branch=main)](https://github.com/sourcey/sourcey/actions)
@@ -17,17 +19,18 @@ npx sourcey init
17
19
 
18
20
  ![Sourcey](assets/hero-preview.jpg)
19
21
 
20
- **[Live demo](https://cheesestore.github.io/)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/sourcey/sourcey)
22
+ **[Live demo](https://sourcey.com/cheesestore)** · [Documentation](https://sourcey.com/docs) · [GitHub](https://github.com/sourcey/sourcey)
21
23
 
22
24
  ## Features
23
25
 
24
26
  - **OpenAPI 2.0, 3.0, 3.1, and 3.2**: full spec coverage including `QUERY` operations, response summaries, hierarchical tags, `deviceAuthorization` OAuth, `querystring` parameters, and `$self`-aware refs for multi-document APIs
25
27
  - **API reference from OpenAPI**: endpoints, parameters, request/response schemas, auto-generated code samples in 10 languages (cURL, JavaScript, TypeScript, Python, Go, Ruby, Java, PHP, Rust, C#)
26
28
  - **MCP server documentation**: tools, resources, prompts rendered as browsable reference with JSON-RPC, TypeScript, and Python code samples. Color-coded method types, annotation badges, connection config cards
27
- - **Markdown guides with rich components**: steps, cards, accordions, syntax-highlighted code blocks; prose docs alongside your API reference
29
+ - **Rich guides**: markdown pages with steps, cards, accordions, syntax-highlighted code blocks, and prose alongside your API reference
30
+ - **Product story pages**: changelog, roadmap pages, examples, reference material, search, and portable context exports in one source-owned site
28
31
  - **C++ and Doxygen**: feed Doxygen XML output, get modern searchable API docs. No new parser, no four-tool Breathe/Exhale/Sphinx pipeline
29
32
  - **Go and godoc**: native package documentation extracted from Go source via the toolchain. Render Go modules as Sourcey tabs, generate standalone static Go docs sites, or commit `godoc.json` snapshots for JS-only docs hosts. No Doxygen detour
30
- - **llms.txt generation**: auto-generate llms.txt and llms-full.txt alongside your HTML. Docs serve developers and AI agents from one build
33
+ - **Context exports**: auto-generate llms.txt and llms-full.txt alongside your HTML as alternate views of the same documentation graph
31
34
  - **TypeScript config**: `sourcey.config.ts` with `defineConfig()` autocomplete; theme, navbar, CTA buttons, footer
32
35
  - **Theme presets**: default (sidebar + TOC), minimal (single column), api-first (Stripe-style three column); colors, fonts, layout dimensions, and custom CSS on top
33
36
  - **Vite dev server**: SSR hot reload on every component and CSS change; spec and markdown changes trigger instant refresh
@@ -36,50 +39,30 @@ npx sourcey init
36
39
  - **Static HTML output**: no framework runtime, no vendor lock-in. Deploy to GitHub Pages, Vercel, Netlify, S3, anywhere
37
40
  - **Open source**: AGPL-3.0. Self-host, fork, extend. Your docs, your infrastructure
38
41
 
39
- ### Sourcey vs alternatives
40
-
41
- | | Sourcey | Redocly | GitBook | Mintlify | Fern | ReadMe |
42
- |---|---|---|---|---|---|---|
43
- | Open source | Yes | Partial | No | No | No | No |
44
- | Static output | Yes | Yes | No | No | No | No |
45
- | Zero JS shipped | Yes | No | No | No | No | No |
46
- | MCP server docs | Native | No | No | No | No | No |
47
- | Doxygen / C++ docs | Native | No | No | No | No | No |
48
- | godoc / Go docs | Native | No | No | No | No | No |
49
- | Config format | TypeScript | YAML | GUI | JSON | YAML | GUI |
50
- | Local preview | Vite SSR | Local | Hosted | Local | Local | Hosted |
51
- | No account required | Yes | Partial | No | No | No | No |
52
- | Self-hosted | Yes | Yes | No | No | Yes | No |
53
- | Pricing | Free | $10–$24 | $65–$249 | $250+ | $150+ | $79–$3,000+ |
54
-
55
42
  ## Install
56
43
 
57
- ### Sourcey
58
-
59
- ```bash
60
- npm install -g sourcey
61
- npx sourcey init
62
- ```
44
+ ### Sourcey CLI
63
45
 
64
- ### Go docs generator
46
+ The full Sourcey binary handles OpenAPI, Doxygen, godoc, MCP, and Markdown sources.
65
47
 
66
- ```bash
67
- go install github.com/sourcey/sourcey/go/sourcey-godoc/cmd/sourcey-godoc@latest
68
- ```
48
+ | Path | Command | Requires |
49
+ |----------|----------------------------------------------------|-------------------|
50
+ | npm | `npm install -g sourcey` | Node 20+ |
51
+ | Homebrew | `brew tap sourcey/tap && brew install sourcey` | macOS / Linuxbrew |
52
+ | Docker | `docker run -v "$PWD":/docs sourcey/sourcey` | Docker |
53
+ | Nix | `nix run github:sourcey/sourcey` | Nix (flakes) |
69
54
 
70
- ### Homebrew (Go docs generator)
55
+ Then `sourcey init` to scaffold a new project, or `sourcey build` against an existing one. See [docs/install.md](docs/install.md) for full Docker invocations (`init` / `dev` / `build`), the `--host` flag for containerized dev, Linuxbrew notes, and Nix profile install.
71
56
 
72
- ```bash
73
- brew tap sourcey/tap
74
- brew install sourcey-godoc
75
- ```
57
+ ### Standalone Go docs generator
76
58
 
77
- ### Scoop (Go docs generator)
59
+ For Go-only consumers without a JavaScript toolchain, `sourcey-godoc` ships as a separate native binary. It produces static Go docs sites or portable `godoc.json` snapshots.
78
60
 
79
- ```powershell
80
- scoop bucket add sourcey https://github.com/sourcey/scoop-bucket
81
- scoop install sourcey-godoc
82
- ```
61
+ | Path | Command |
62
+ |----------|---------|
63
+ | Go | `go install github.com/sourcey/sourcey/go/sourcey-godoc/cmd/sourcey-godoc@latest` |
64
+ | Homebrew | `brew install sourcey/tap/sourcey-godoc` |
65
+ | Scoop | `scoop bucket add sourcey https://github.com/sourcey/scoop-bucket && scoop install sourcey-godoc` |
83
66
 
84
67
  ## Quick start
85
68
 
@@ -4,7 +4,176 @@
4
4
  // backdrop click, nav link click, Escape (native dialog behavior).
5
5
  // Dropdown toggles list visibility for tab selection.
6
6
  (function () {
7
+ function storageGet(key) {
8
+ try {
9
+ return window.sessionStorage.getItem(key);
10
+ } catch {
11
+ return null;
12
+ }
13
+ }
14
+
15
+ function storageSet(key, value) {
16
+ try {
17
+ window.sessionStorage.setItem(key, value);
18
+ } catch {
19
+ // Ignore blocked storage. Sidebar navigation still works normally.
20
+ }
21
+ }
22
+
23
+ function storageRemove(key) {
24
+ try {
25
+ window.sessionStorage.removeItem(key);
26
+ } catch {
27
+ // Ignore blocked storage. Sidebar navigation still works normally.
28
+ }
29
+ }
30
+
31
+ function normalizePath(pathname) {
32
+ var clean = (pathname || '/').replace(/\/+$/, '') || '/';
33
+ clean = clean.replace(/\/index(?:\.html)?$/, '') || '/';
34
+ clean = clean.replace(/\.html$/, '');
35
+ return clean || '/';
36
+ }
37
+
38
+ function commonPath(paths) {
39
+ if (!paths.length) return null;
40
+ var parts = paths.map(function (path) {
41
+ return normalizePath(path).split('/').filter(Boolean);
42
+ });
43
+ var common = [];
44
+
45
+ for (var i = 0; i < parts[0].length; i++) {
46
+ var part = parts[0][i];
47
+ var allMatch = parts.every(function (segments) {
48
+ return segments[i] === part;
49
+ });
50
+ if (!allMatch) break;
51
+ common.push(part);
52
+ }
53
+
54
+ return '/' + common.join('/');
55
+ }
56
+
57
+ function navScope(nav) {
58
+ var paths = [];
59
+ nav.querySelectorAll('a.nav-link[href]').forEach(function (link) {
60
+ var href = link.getAttribute('href');
61
+ if (!href || href.startsWith('#')) return;
62
+
63
+ try {
64
+ var url = new URL(href, window.location.href);
65
+ if (url.origin === window.location.origin) {
66
+ paths.push(url.pathname);
67
+ }
68
+ } catch {
69
+ // Ignore malformed hrefs.
70
+ }
71
+ });
72
+
73
+ return commonPath(paths);
74
+ }
75
+
76
+ function searchIndexScope() {
77
+ var meta = document.querySelector('meta[name="sourcey-search"]');
78
+ var content = meta && meta.getAttribute('content');
79
+ if (!content) return null;
80
+
81
+ try {
82
+ var url = new URL(content, window.location.href);
83
+ if (url.origin === window.location.origin) {
84
+ return normalizePath(url.pathname.replace(/\/search-index\.json$/, ''));
85
+ }
86
+ } catch {
87
+ // Ignore malformed metadata.
88
+ }
89
+
90
+ return null;
91
+ }
92
+
93
+ function sidebarStorageKey(scroller, nav) {
94
+ var tab = scroller.getAttribute('data-sourcey-sidebar-tab') || 'default';
95
+ var scope = navScope(nav) || searchIndexScope() || normalizePath(window.location.pathname);
96
+ return 'sourcey:sidebar-scroll:v1:' + window.location.origin + scope + ':' + tab;
97
+ }
98
+
99
+ function clampSidebarScroll(scroller, top) {
100
+ var max = Math.max(0, scroller.scrollHeight - scroller.clientHeight);
101
+ return Math.max(0, Math.min(top, max));
102
+ }
103
+
104
+ function saveSidebarScroll(scroller, key) {
105
+ storageSet(key, String(Math.round(scroller.scrollTop || 0)));
106
+ }
107
+
108
+ function restoreSidebarScroll(scroller, key) {
109
+ var raw = storageGet(key);
110
+ if (raw === null) return false;
111
+ storageRemove(key);
112
+
113
+ var top = Number(raw);
114
+ if (!Number.isFinite(top) || top <= 0) return false;
115
+
116
+ function apply() {
117
+ scroller.scrollTop = clampSidebarScroll(scroller, top);
118
+ }
119
+
120
+ apply();
121
+ requestAnimationFrame(apply);
122
+ return true;
123
+ }
124
+
125
+ function revealActiveSidebarLink(nav) {
126
+ var active = nav.querySelector('.nav-link.active');
127
+ if (!active) return;
128
+ requestAnimationFrame(function () {
129
+ active.scrollIntoView({ block: 'nearest', behavior: 'auto' });
130
+ });
131
+ }
132
+
133
+ function shouldSaveForNavigation(e, link) {
134
+ if (!link || e.defaultPrevented) return false;
135
+ if (e.button !== undefined && e.button !== 0) return false;
136
+ if (e.metaKey || e.ctrlKey || e.shiftKey || e.altKey) return false;
137
+ if (link.hasAttribute('download')) return false;
138
+
139
+ var target = link.getAttribute('target');
140
+ if (target && target.toLowerCase() !== '_self') return false;
141
+
142
+ var href = link.getAttribute('href');
143
+ if (!href || href.startsWith('#')) return false;
144
+
145
+ try {
146
+ var url = new URL(href, window.location.href);
147
+ if (url.origin !== window.location.origin) return false;
148
+ if (url.pathname === window.location.pathname && url.search === window.location.search && url.hash) {
149
+ return false;
150
+ }
151
+ return url.protocol === 'http:' || url.protocol === 'https:';
152
+ } catch {
153
+ return false;
154
+ }
155
+ }
156
+
157
+ function initDesktopSidebarScroll() {
158
+ var scroller = document.querySelector('[data-sourcey-sidebar-scroll]');
159
+ var nav = document.getElementById('nav');
160
+ if (!scroller || !nav) return;
161
+
162
+ var key = sidebarStorageKey(scroller, nav);
163
+ var restored = restoreSidebarScroll(scroller, key);
164
+ if (!restored) revealActiveSidebarLink(nav);
165
+
166
+ nav.addEventListener('click', function (e) {
167
+ var link = e.target.closest('a[href]');
168
+ if (shouldSaveForNavigation(e, link)) {
169
+ saveSidebarScroll(scroller, key);
170
+ }
171
+ });
172
+ }
173
+
7
174
  function init() {
175
+ initDesktopSidebarScroll();
176
+
8
177
  var dialog = document.getElementById('mobile-nav');
9
178
  var openBtns = document.querySelectorAll('[data-drawer-slide]');
10
179
  if (!dialog) return;
@@ -1 +1 @@
1
- {"version":3,"file":"ChangelogPage.d.ts","sourceRoot":"","sources":["../../../src/components/changelog/ChangelogPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAGxF,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,gCAyBlE"}
1
+ {"version":3,"file":"ChangelogPage.d.ts","sourceRoot":"","sources":["../../../src/components/changelog/ChangelogPage.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,aAAa,IAAI,iBAAiB,EAAE,MAAM,+BAA+B,CAAC;AAIxF,wBAAgB,aAAa,CAAC,EAAE,IAAI,EAAE,EAAE;IAAE,IAAI,EAAE,iBAAiB,CAAA;CAAE,gCA4BlE"}
@@ -1,8 +1,9 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "preact/jsx-runtime";
2
+ import { renderMarkdownInline } from "../../utils/markdown.js";
2
3
  import { VersionCard } from "./VersionCard.js";
3
4
  export function ChangelogPage({ page }) {
4
5
  const versions = page.permalinkVersionId
5
6
  ? page.changelog.versions.filter((version) => version.id === page.permalinkVersionId)
6
7
  : page.changelog.versions;
7
- return (_jsxs("div", { class: "sourcey-changelog-page", children: [_jsxs("header", { class: "sourcey-changelog-header", children: [_jsx("div", { class: "mt-0.5 space-y-2.5", children: _jsx("h1", { class: "text-2xl sm:text-3xl text-[rgb(var(--color-gray-900))] tracking-tight dark:text-[rgb(var(--color-gray-200))] font-bold", style: "overflow-wrap: anywhere", children: page.title }) }), page.description && (_jsx("p", { class: "sourcey-changelog-description", children: page.description }))] }), _jsx("div", { class: "sourcey-changelog-list", children: versions.map((version) => (_jsx(VersionCard, { version: version }, version.id))) })] }));
8
+ return (_jsxs("div", { class: "sourcey-changelog-page", children: [_jsxs("header", { class: "sourcey-changelog-header", children: [_jsx("div", { class: "mt-0.5 space-y-2.5", children: _jsx("h1", { class: "text-2xl sm:text-3xl text-[rgb(var(--color-gray-900))] tracking-tight dark:text-[rgb(var(--color-gray-200))] font-bold", style: "overflow-wrap: anywhere", children: page.title }) }), page.description && (_jsx("p", { class: "sourcey-changelog-description", dangerouslySetInnerHTML: { __html: renderMarkdownInline(page.description) } }))] }), _jsx("div", { class: "sourcey-changelog-list", children: versions.map((version) => (_jsx(VersionCard, { version: version }, version.id))) })] }));
8
9
  }
@@ -1 +1 @@
1
- {"version":3,"file":"VersionCard.d.ts","sourceRoot":"","sources":["../../../src/components/changelog/VersionCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAoBtE,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,aAAa,GACd,EAAE;IACD,OAAO,EAAE,0BAA0B,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,gCAuCA"}
1
+ {"version":3,"file":"VersionCard.d.ts","sourceRoot":"","sources":["../../../src/components/changelog/VersionCard.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,0BAA0B,EAAE,MAAM,qBAAqB,CAAC;AAoBtE,wBAAgB,WAAW,CAAC,EAC1B,OAAO,EACP,aAAa,GACd,EAAE;IACD,OAAO,EAAE,0BAA0B,CAAC;IACpC,aAAa,CAAC,EAAE,MAAM,CAAC;CACxB,gCA4CA"}
@@ -21,5 +21,7 @@ export function VersionCard({ version, permalinkHref, }) {
21
21
  const href = permalinkHref ?? `#${version.id}`;
22
22
  const label = version.version ?? "Unreleased";
23
23
  const formattedDate = formatDate(version.date);
24
- return (_jsxs("article", { id: version.id, class: `sourcey-changelog-version${version.version ? "" : " sourcey-changelog-version-unreleased"}`, children: [_jsxs("header", { class: "sourcey-changelog-version-header", children: [_jsxs("div", { class: "sourcey-changelog-version-heading", children: [_jsx("a", { href: href, class: "sourcey-changelog-version-link", children: label }), version.yanked && _jsx("span", { class: "sourcey-changelog-pill sourcey-changelog-pill-yanked", children: "YANKED" }), version.prerelease && _jsx("span", { class: "sourcey-changelog-pill sourcey-changelog-pill-pre", children: "pre" })] }), _jsxs("div", { class: "sourcey-changelog-version-meta", children: [formattedDate && _jsx("time", { dateTime: version.date ?? undefined, children: formattedDate }), version.compareUrl && (_jsx("a", { href: version.compareUrl, target: "_blank", rel: "noopener noreferrer", class: "sourcey-changelog-compare-link", children: "Compare" }))] })] }), version.summary && _jsx(Markdown, { content: version.summary, class: "sourcey-changelog-summary" }), _jsx("div", { class: "sourcey-changelog-sections", children: version.sections.map((section) => (_jsxs("section", { class: "sourcey-changelog-section", children: [_jsx("div", { class: "sourcey-changelog-section-header", children: _jsx(TypeBadge, { type: section.type, label: section.label }) }), _jsx(EntryList, { entries: section.entries })] }, `${version.id}-${section.label}`))) })] }));
24
+ const isUnreleased = !version.version;
25
+ const hasMeta = isUnreleased || formattedDate || version.compareUrl;
26
+ return (_jsxs("article", { id: version.id, class: `sourcey-changelog-version${isUnreleased ? " sourcey-changelog-version-unreleased" : ""}`, children: [_jsxs("header", { class: "sourcey-changelog-version-header", children: [_jsxs("div", { class: "sourcey-changelog-version-heading", children: [_jsx("a", { href: href, class: "sourcey-changelog-version-link", children: label }), version.yanked && _jsx("span", { class: "sourcey-changelog-pill sourcey-changelog-pill-yanked", children: "YANKED" }), version.prerelease && _jsx("span", { class: "sourcey-changelog-pill sourcey-changelog-pill-pre", children: "pre" })] }), hasMeta && (_jsxs("div", { class: "sourcey-changelog-version-meta", children: [isUnreleased && _jsx("span", { class: "sourcey-changelog-pill sourcey-changelog-pill-next", children: "Next release" }), formattedDate && _jsx("time", { dateTime: version.date ?? undefined, children: formattedDate }), version.compareUrl && (_jsx("a", { href: version.compareUrl, target: "_blank", rel: "noopener noreferrer", class: "sourcey-changelog-compare-link", children: "Compare" }))] }))] }), version.summary && _jsx(Markdown, { content: version.summary, class: "sourcey-changelog-summary" }), _jsx("div", { class: "sourcey-changelog-sections", children: version.sections.map((section) => (_jsxs("section", { class: "sourcey-changelog-section", children: [_jsx("div", { class: "sourcey-changelog-section-header", children: _jsx(TypeBadge, { type: section.type, label: section.label }) }), _jsx(EntryList, { entries: section.entries })] }, `${version.id}-${section.label}`))) })] }));
25
27
  }
@@ -1 +1 @@
1
- {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Sidebar.tsx"],"names":[],"mappings":"AA+FA;;GAEG;AACH,wBAAgB,OAAO,wCAuGtB"}
1
+ {"version":3,"file":"Sidebar.d.ts","sourceRoot":"","sources":["../../../src/components/layout/Sidebar.tsx"],"names":[],"mappings":"AA+FA;;GAEG;AACH,wBAAgB,OAAO,wCA2GtB"}
@@ -58,7 +58,7 @@ export function Sidebar() {
58
58
  const primaryAction = site.navbar.primary;
59
59
  const groups = activeTab.groups;
60
60
  const logoHref = site.logo?.href ?? `${base}${nav.tabs[0]?.href ?? ""}`;
61
- return (_jsxs(_Fragment, { children: [_jsx("div", { id: "sidebar", class: "z-20 hidden lg:block fixed bottom-0 right-auto w-[18rem]", style: "top: var(--header-height)", children: _jsx("div", { class: "absolute inset-0 z-10 overflow-auto pr-8 pb-10", children: _jsxs("div", { class: "relative text-sm leading-6", children: [_jsx("div", { class: "sticky top-0 h-8 z-10 bg-gradient-to-b from-[rgb(var(--color-background-light))] dark:from-[rgb(var(--color-background-dark))]" }), _jsx("nav", { id: "nav", role: "navigation", children: _jsx(NavGroups, { groups: groups, activePageSlug: nav.activePageSlug, base: base }) })] }) }) }), _jsxs("dialog", { id: "mobile-nav", class: "mobile-nav-dialog", children: [site.logo?.light && (_jsx("div", { class: "px-4 py-4 border-b border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-gray-800)/0.5)] shrink-0", children: _jsx(Logo, { href: logoHref, logo: site.logo, height: "h-6" }) })), nav.tabs.length > 1 && (_jsx("div", { class: "pt-5 px-4 shrink-0", children: _jsxs("div", { class: "drawer-dropdown", children: [_jsxs("button", { id: "drawer-group-toggle", type: "button", class: "drawer-dropdown-trigger", "aria-expanded": "false", children: [_jsx("span", { class: "drawer-dropdown-label", children: activeTab.label }), _jsx(DropdownChevron, {})] }), _jsx("ul", { id: "drawer-group-list", class: "drawer-dropdown-list", style: "display:none", children: nav.tabs.map((tab) => (_jsx("li", { children: _jsx("a", { href: `${base}${tab.href}`, class: `drawer-dropdown-item${tab.slug === nav.activeTabSlug ? " active" : ""}`, children: tab.label }) }, tab.slug))) })] }) })), _jsx("nav", { class: "pt-5 pb-3 px-4 flex-1 overflow-y-auto", children: _jsx(NavGroups, { groups: groups, activePageSlug: nav.activePageSlug, base: base }) }), (links.length > 0 || primaryAction) && (_jsx("div", { class: "px-4 py-3 border-t border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-gray-800)/0.5)] shrink-0", children: _jsxs("ul", { class: "space-y-3", children: [links.map((link) => {
61
+ return (_jsxs(_Fragment, { children: [_jsx("div", { id: "sidebar", class: "z-20 hidden lg:block fixed bottom-0 right-auto w-[18rem]", style: "top: var(--header-height)", children: _jsx("div", { class: "absolute inset-0 z-10 overflow-auto pr-8 pb-10", "data-sourcey-sidebar-scroll": true, "data-sourcey-sidebar-tab": nav.activeTabSlug || "default", children: _jsxs("div", { class: "relative text-sm leading-6", children: [_jsx("div", { class: "sticky top-0 h-8 z-10 bg-gradient-to-b from-[rgb(var(--color-background-light))] dark:from-[rgb(var(--color-background-dark))]" }), _jsx("nav", { id: "nav", role: "navigation", children: _jsx(NavGroups, { groups: groups, activePageSlug: nav.activePageSlug, base: base }) })] }) }) }), _jsxs("dialog", { id: "mobile-nav", class: "mobile-nav-dialog", children: [site.logo?.light && (_jsx("div", { class: "px-4 py-4 border-b border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-gray-800)/0.5)] shrink-0", children: _jsx(Logo, { href: logoHref, logo: site.logo, height: "h-6" }) })), nav.tabs.length > 1 && (_jsx("div", { class: "pt-5 px-4 shrink-0", children: _jsxs("div", { class: "drawer-dropdown", children: [_jsxs("button", { id: "drawer-group-toggle", type: "button", class: "drawer-dropdown-trigger", "aria-expanded": "false", children: [_jsx("span", { class: "drawer-dropdown-label", children: activeTab.label }), _jsx(DropdownChevron, {})] }), _jsx("ul", { id: "drawer-group-list", class: "drawer-dropdown-list", style: "display:none", children: nav.tabs.map((tab) => (_jsx("li", { children: _jsx("a", { href: `${base}${tab.href}`, class: `drawer-dropdown-item${tab.slug === nav.activeTabSlug ? " active" : ""}`, children: tab.label }) }, tab.slug))) })] }) })), _jsx("nav", { class: "pt-5 pb-3 px-4 flex-1 overflow-y-auto", children: _jsx(NavGroups, { groups: groups, activePageSlug: nav.activePageSlug, base: base }) }), (links.length > 0 || primaryAction) && (_jsx("div", { class: "px-4 py-3 border-t border-[rgb(var(--color-gray-200)/0.7)] dark:border-[rgb(var(--color-gray-800)/0.5)] shrink-0", children: _jsxs("ul", { class: "space-y-3", children: [links.map((link) => {
62
62
  const label = link.label ?? socialLabels[link.type] ?? link.href;
63
63
  return (_jsx("li", { children: _jsxs("a", { href: link.href, target: "_blank", rel: "noopener noreferrer", class: "flex items-center gap-2.5 text-[rgb(var(--color-gray-600))] hover:text-[rgb(var(--color-gray-900))] dark:text-[rgb(var(--color-gray-400))] dark:hover:text-[rgb(var(--color-gray-200))]", children: [link.type !== "link" && _jsx(SocialIcon, { type: link.type }), _jsx("span", { children: label })] }) }, link.href));
64
64
  }), primaryAction && (_jsx("li", { children: _jsxs("a", { href: primaryAction.href, target: "_blank", class: "group relative flex items-center justify-center px-4 py-2 text-sm font-medium", children: [_jsx("span", { class: "absolute inset-0 bg-[rgb(var(--color-primary-dark))] rounded-lg group-hover:opacity-90" }), _jsx("span", { class: "z-10 text-white", children: primaryAction.label })] }) }))] }) }))] })] }));
@@ -1 +1 @@
1
- {"version":3,"file":"changelog-normalizer.d.ts","sourceRoot":"","sources":["../../src/core/changelog-normalizer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAMV,mBAAmB,EAIpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuDD,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,mBAAmB,CA4HrB"}
1
+ {"version":3,"file":"changelog-normalizer.d.ts","sourceRoot":"","sources":["../../src/core/changelog-normalizer.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAMV,mBAAmB,EAIpB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,yBAAyB;IACxC,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB;AAuDD,wBAAgB,kBAAkB,CAChC,QAAQ,EAAE,MAAM,EAChB,OAAO,GAAE,yBAA8B,GACtC,mBAAmB,CA8HrB"}
@@ -36,6 +36,7 @@ export function normalizeChangelog(markdown, options = {}) {
36
36
  const descriptionParts = [];
37
37
  const rawBlocks = [];
38
38
  let currentBlock = null;
39
+ let seenFirstVersionHeading = false;
39
40
  for (const token of tokens) {
40
41
  if (token.type === "heading") {
41
42
  const heading = token;
@@ -48,6 +49,7 @@ export function normalizeChangelog(markdown, options = {}) {
48
49
  if (currentBlock)
49
50
  rawBlocks.push(currentBlock);
50
51
  currentBlock = null;
52
+ seenFirstVersionHeading = true;
51
53
  const parsed = parseVersionHeading(text);
52
54
  if (!parsed) {
53
55
  diagnostics.push({
@@ -72,7 +74,7 @@ export function normalizeChangelog(markdown, options = {}) {
72
74
  if (currentBlock) {
73
75
  appendTokenToVersion(token, currentBlock, diagnostics, options.repoUrl);
74
76
  }
75
- else if (!options.description && shouldContributeToDescription(token)) {
77
+ else if (!options.description && !seenFirstVersionHeading && shouldContributeToDescription(token)) {
76
78
  descriptionParts.push(token.raw);
77
79
  }
78
80
  }
@@ -882,12 +882,46 @@ h1[id], h2[id], h3[id], h4[id], h5[id], h6[id] {
882
882
  font-size: 1.05rem;
883
883
  line-height: 1.7;
884
884
  color: rgb(var(--color-gray-600));
885
+ max-width: 65ch;
886
+ text-wrap: pretty;
885
887
  }
886
888
 
887
889
  .dark #sourcey .sourcey-changelog-description {
888
890
  color: rgb(var(--color-gray-400));
889
891
  }
890
892
 
893
+ #sourcey .sourcey-changelog-description a {
894
+ color: rgb(var(--color-primary-ink));
895
+ text-decoration: none;
896
+ border-bottom: 1px solid rgb(var(--color-primary-ink) / 0.3);
897
+ }
898
+
899
+ #sourcey .sourcey-changelog-description a:hover {
900
+ border-bottom-color: rgb(var(--color-primary-ink));
901
+ }
902
+
903
+ .dark #sourcey .sourcey-changelog-description a {
904
+ color: rgb(var(--color-primary-light));
905
+ border-bottom-color: rgb(var(--color-primary-light) / 0.3);
906
+ }
907
+
908
+ .dark #sourcey .sourcey-changelog-description a:hover {
909
+ border-bottom-color: rgb(var(--color-primary-light));
910
+ }
911
+
912
+ #sourcey .sourcey-changelog-description code {
913
+ font-size: 0.92em;
914
+ padding: 0.05rem 0.3rem;
915
+ border-radius: 0.25rem;
916
+ background: rgb(var(--color-gray-100));
917
+ color: rgb(var(--color-gray-800));
918
+ }
919
+
920
+ .dark #sourcey .sourcey-changelog-description code {
921
+ background: rgb(255 255 255 / 0.08);
922
+ color: rgb(var(--color-gray-200));
923
+ }
924
+
891
925
  #sourcey .sourcey-changelog-list {
892
926
  display: flex;
893
927
  flex-direction: column;
@@ -907,7 +941,16 @@ h1[id], h2[id], h3[id], h4[id], h5[id], h6[id] {
907
941
  }
908
942
 
909
943
  #sourcey .sourcey-changelog-version-unreleased {
910
- border-style: dashed;
944
+ border-color: rgb(var(--color-primary) / 0.18);
945
+ border-left: 3px solid rgb(var(--color-primary));
946
+ padding-left: calc(1.25rem - 2px);
947
+ background: linear-gradient(180deg, rgb(var(--color-primary) / 0.04), rgb(var(--color-primary) / 0.015));
948
+ }
949
+
950
+ .dark #sourcey .sourcey-changelog-version-unreleased {
951
+ border-color: rgb(var(--color-primary-light) / 0.22);
952
+ border-left-color: rgb(var(--color-primary-light));
953
+ background: linear-gradient(180deg, rgb(var(--color-primary-light) / 0.06), rgb(var(--color-primary-light) / 0.02));
911
954
  }
912
955
 
913
956
  #sourcey .sourcey-changelog-version-header {
@@ -1001,6 +1044,19 @@ h1[id], h2[id], h3[id], h4[id], h5[id], h6[id] {
1001
1044
  color: rgb(var(--color-gray-300));
1002
1045
  }
1003
1046
 
1047
+ #sourcey .sourcey-changelog-pill-next {
1048
+ background: rgb(var(--color-primary) / 0.1);
1049
+ color: rgb(var(--color-primary-ink));
1050
+ text-transform: uppercase;
1051
+ letter-spacing: 0.06em;
1052
+ font-size: 0.68rem;
1053
+ }
1054
+
1055
+ .dark #sourcey .sourcey-changelog-pill-next {
1056
+ background: rgb(var(--color-primary-light) / 0.14);
1057
+ color: rgb(var(--color-primary-light));
1058
+ }
1059
+
1004
1060
  #sourcey .sourcey-changelog-summary {
1005
1061
  margin-bottom: 1rem;
1006
1062
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "sourcey",
3
- "version": "3.5.8",
3
+ "version": "3.5.10",
4
4
  "description": "Precision documentation from OpenAPI, MCP, Doxygen, godoc, and Markdown. Static HTML you own.",
5
5
  "type": "module",
6
6
  "engines": {
@@ -45,7 +45,7 @@
45
45
  "jiti": "^2.6.1",
46
46
  "js-yaml": "^4.1.0",
47
47
  "marked": "^15.0.0",
48
- "mcp-parser": "^0.2.0",
48
+ "mcp-parser": "^0.4.0",
49
49
  "moxygen": "^2.1.1",
50
50
  "preact": "^10.28.4",
51
51
  "preact-render-to-string": "^6.6.6",