@lupinum/ginko-docs 0.4.0 → 0.5.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/CHANGELOG.md +63 -0
- package/README.md +111 -16
- package/app/app.config.ts +2 -0
- package/app/assets/docs.css +79 -15
- package/app/components/DocsBanner.vue +1 -1
- package/app/components/DocsExample.vue +1 -1
- package/app/components/DocsHeader.vue +7 -6
- package/app/components/DocsIcon.vue +12 -0
- package/app/components/DocsLanding.vue +8 -5
- package/app/components/DocsLanguage.vue +18 -7
- package/app/components/DocsNavSheet.vue +37 -0
- package/app/components/DocsNavTree.vue +2 -2
- package/app/components/DocsPage.vue +16 -12
- package/app/components/DocsPageActions.vue +5 -5
- package/app/components/DocsPageEnd.ts +12 -0
- package/app/components/DocsPost.vue +11 -11
- package/app/components/DocsSearch.vue +7 -5
- package/app/components/DocsShell.vue +19 -3
- package/app/components/DocsSidebar.vue +2 -1
- package/app/components/DocsSidebarEnd.ts +4 -0
- package/app/components/DocsThemeToggle.vue +3 -3
- package/app/components/DocsToc.vue +2 -2
- package/app/composables/useDocs.ts +3 -2
- package/app/composables/useDocsBlog.ts +8 -7
- package/app/composables/useDocsFrame.ts +11 -0
- package/app/composables/useDocsSite.ts +24 -3
- package/app/docs-pages/blog.vue +12 -4
- package/app/docs-pages/changelog.vue +13 -5
- package/app/docs-pages/doc.vue +3 -1
- package/app/error.vue +16 -1
- package/app/layouts/default.vue +4 -0
- package/app/lib/docsPage.ts +40 -0
- package/app/lib/markdownComponents.ts +1 -2
- package/dist/config.d.mts +28 -8
- package/dist/config.d.ts +28 -8
- package/dist/config.mjs +16 -47
- package/dist/icons.d.mts +38 -0
- package/dist/icons.d.ts +38 -0
- package/dist/icons.mjs +175 -0
- package/dist/pages.mjs +56 -24
- package/i18n/de.json +1 -1
- package/i18n/en.json +1 -1
- package/i18n/fr.json +1 -0
- package/nuxt.config.ts +2 -17
- package/package.json +11 -10
- package/server/lib/blogFeed.ts +1 -1
- package/shared/layerRoutes.ts +66 -0
- package/dist/shared/ginko-docs.BwbF7JBR.mjs +0 -4
- package/server/lib/rss.ts +0 -57
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,68 @@
|
|
|
1
1
|
# @lupinum/ginko-docs
|
|
2
2
|
|
|
3
|
+
## 0.5.0
|
|
4
|
+
|
|
5
|
+
### Minor Changes
|
|
6
|
+
|
|
7
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add public ways to customize the docs: `<DocsShell>` for a site's own pages in the docs frame, the override points `DocsPageEnd` and `DocsSidebarEnd`, and `docs: { search: false }`.
|
|
8
|
+
|
|
9
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add a docs frame for sites that embed the docs in their own layout: no framed panel, the search above the navigation, a phone bar with the navigation as a sheet, and `--docs-gutter` to line the docs up with the site's container.
|
|
10
|
+
|
|
11
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add `homePages({ locales })` to `@lupinum/ginko-docs/config`: the start page by locale, with the main locale at `/`.
|
|
12
|
+
|
|
13
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Change the docs layer to draw icons itself instead of with @nuxt/icon: pages outside the docs no longer download an icon library (about 16 KB gzip less on every page of a site that embeds the docs), and docs pages load only the icons they use. Icon names work as before (any installed Iconify set). The build finds them in your Markdown front matter and component attributes (not in prose or code blocks), in YAML and JSON content, in `app.config.ts` and in your own `app/` components (`<Icon name="lucide:x" />`); it reads all locales and ignores commented-out code. A name built at runtime (a variable) is not found, so write it once as a literal; a name that is not installed logs one build warning with its file. A site's own `@nuxt/icon` still wins over the layer's `Icon`. Remove the `icon` options from your nuxt.config if you set any. The icon hints in the editor now say "needs a global Icon component".
|
|
14
|
+
|
|
15
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add route links outside Markdown: the start page's buttons and cards, `nav`, `footer.links` and `banner.href` take `$docs.<page>` and `$page.<key>`, which lead to the page in the reader's language.
|
|
16
|
+
|
|
17
|
+
- [#24](https://github.com/lupinum-dev/ginko/pull/24) [`c28d1e3`](https://github.com/lupinum-dev/ginko/commit/c28d1e3e4ba1e558f8c71d7b69961f7474a221d1) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add `source: 'platform'` to docsCollection, docsHome, blogCollections and changelogCollection, so docs content can be edited in Ginko Studio; the default stays `'files'`.
|
|
18
|
+
|
|
19
|
+
### Patch Changes
|
|
20
|
+
|
|
21
|
+
- [#21](https://github.com/lupinum-dev/ginko/pull/21) [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add `breadcrumbJsonLd(steps, siteUrl)` to `@lupinum/ginko`: a JSON-LD BreadcrumbList from steps with `title` and `path`, such as the nodes of `useGinkoBreadcrumbs` (templates/_features/site/app/composables/usePageSeo.ts uses it).
|
|
22
|
+
|
|
23
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix the 404 page's main-language link ignoring the site's i18n strategy, and name the language in the reader's language
|
|
24
|
+
|
|
25
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix the focus ring of the default theme in light mode: emerald-700 instead of emerald-500, 5.5:1 against the page instead of 2.5:1.
|
|
26
|
+
|
|
27
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix layout shift on first load of a docs page: the standalone layout preloads Inter, so text no longer re-wraps when the font arrives.
|
|
28
|
+
|
|
29
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add French texts to the docs layer.
|
|
30
|
+
|
|
31
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix the "not translated" note in the language menu: screen readers read it in the page's language. An empty changelog now says where to add releases.
|
|
32
|
+
|
|
33
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix English fallback text on translated docs pages being read in the page language, and add a link to the main-language page on a docs 404 under another language
|
|
34
|
+
|
|
35
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add CollectionPage JSON-LD and a description to the changelog page, and CollectionPage JSON-LD to the blog list.
|
|
36
|
+
|
|
37
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix tables with three columns on phones narrower than 360 px: the last column keeps its width and the table scrolls, instead of showing a few letters per line.
|
|
38
|
+
|
|
39
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix docs tables, the home feature list and the install box on phones.
|
|
40
|
+
|
|
41
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Change the phone header and menu of the docs layer: the light/dark button stays in the header, and the menu lists the languages as links at its top, one tap each.
|
|
42
|
+
|
|
43
|
+
- [#21](https://github.com/lupinum-dev/ginko/pull/21) [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Change the JSON-LD of a blog post from Article to BlogPosting, built by `postJsonLd` of `@lupinum/ginko/basics`, with the post's tags as keywords.
|
|
44
|
+
|
|
45
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix route links outside Markdown (nav, footer, banner, start page): they lead to the main-language page when the current language has no such doc, instead of a raw `$docs…` address.
|
|
46
|
+
|
|
47
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix the docs layer adding a second blog, blog feed or changelog at /blog and /changelog to a site that has its own: it now adds them only at the address of your posts and changelog and only when you have no page there.
|
|
48
|
+
|
|
49
|
+
A changelog page needs `changelog: changelogPages({ locales })` in `pages` (or a `route` on the changelog brick); without an address the build warns once and the layer adds no changelog. The layer now decides after all of your pages are known, so a page that the page-paths module moves to `/blog` also counts as yours, and its links to the blog and changelog follow the addresses you configured.
|
|
50
|
+
|
|
51
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix short tables in the docs ending before the edge of their frame: the rows and the header now fill it.
|
|
52
|
+
|
|
53
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add a note to the language menu for a language that has no version of the page: "Not translated: opens the start page".
|
|
54
|
+
|
|
55
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Fix wide tables, long titles and the previous and next links making docs pages scroll or squeeze text on phones
|
|
56
|
+
|
|
57
|
+
- [#21](https://github.com/lupinum-dev/ginko/pull/21) [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Change Markdown refs in page state to carry no table of contents: read `toc` from the loaded text, `(await useGinkoMarkdown(() => entry.value.data.body)).value?.toc`.
|
|
58
|
+
|
|
59
|
+
- [#23](https://github.com/lupinum-dev/ginko/pull/23) [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7) Thanks [@Mat4m0](https://github.com/Mat4m0)! - Add `releaseAnchor(version)` to `@lupinum/ginko/basics`: the anchor of a release on a changelog page (`4.6.0` → `v4-6-0`). The changelog page of `@lupinum/ginko-docs` and the changelog feature of the templates (templates/_features/changelog/app/composables/useChangelog.ts, server/middleware/changelog-feed.ts) use it, so both keep the same public addresses.
|
|
60
|
+
- Updated dependencies [[`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`c28d1e3`](https://github.com/lupinum-dev/ginko/commit/c28d1e3e4ba1e558f8c71d7b69961f7474a221d1), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`7b165c2`](https://github.com/lupinum-dev/ginko/commit/7b165c25e17ed2f4fb50e8054febf618a6af10d7), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991), [`80f93a4`](https://github.com/lupinum-dev/ginko/commit/80f93a4f6bd171e1146b929913254039becdd991)]:
|
|
61
|
+
- @lupinum/ginko@0.5.0
|
|
62
|
+
- @lupinum/ginko-components@0.5.0
|
|
63
|
+
- @lupinum/ginko-content@0.5.0
|
|
64
|
+
- @lupinum/ginko-i18n@0.5.0
|
|
65
|
+
|
|
3
66
|
## 0.4.0
|
|
4
67
|
|
|
5
68
|
### Minor Changes
|
package/README.md
CHANGED
|
@@ -15,7 +15,7 @@ npm install @lupinum/ginko @lupinum/ginko-content @lupinum/ginko-i18n @lupinum/g
|
|
|
15
15
|
```ts
|
|
16
16
|
// ginko.config.ts
|
|
17
17
|
import { defineSite } from '@lupinum/ginko'
|
|
18
|
-
import { components, docsCollection } from '@lupinum/ginko-docs/config'
|
|
18
|
+
import { components, docsCollection, homePages } from '@lupinum/ginko-docs/config'
|
|
19
19
|
|
|
20
20
|
const locales = ['en', 'de'] as const
|
|
21
21
|
|
|
@@ -26,15 +26,22 @@ export default defineSite({
|
|
|
26
26
|
timeZone: 'Europe/Vienna',
|
|
27
27
|
locales,
|
|
28
28
|
currency: 'EUR',
|
|
29
|
-
pages: { home: {
|
|
29
|
+
pages: { home: homePages({ locales }) }, // the start page is the page `home`
|
|
30
30
|
components, // the Markdown components: ::callout, ::tabs, ::steps …
|
|
31
31
|
bricks: { docs: docsCollection({ locales }) },
|
|
32
32
|
})
|
|
33
33
|
```
|
|
34
34
|
|
|
35
|
-
`docsCollection`, `blogCollections`, `blogPages` and `changelogPages` take one options object. `locales` is the same list as
|
|
35
|
+
`docsCollection`, `blogCollections`, `homePages`, `blogPages` and `changelogPages` take one options object. `locales` is the same list as
|
|
36
36
|
in `defineSite` (the layer accepts any `readonly string[]`; `defineSite` itself needs the tuple, hence `as const`).
|
|
37
37
|
|
|
38
|
+
The bricks read Markdown files from `content/`. To edit them in Ginko Studio instead, pass `source: 'platform'` to
|
|
39
|
+
`docsCollection`, `docsHome`, `blogCollections` or `changelogCollection` (each brick on its own; the default is
|
|
40
|
+
`'files'`). The pages, their Markdown twins and `read_doc` work the same with either source, and a page from the
|
|
41
|
+
platform links "Edit this page" to its form in the Studio. Two things are built from files only: the search index
|
|
42
|
+
(the search box and `search_docs`) finds no page that lives on the platform, and an icon named only in Studio content
|
|
43
|
+
is not bundled (name it once in a file the icon scan reads, see "Icons").
|
|
44
|
+
|
|
38
45
|
`components` is the registry of `@lupinum/ginko-components` (a dependency of the layer, re-exported here). With it, Ginko checks every component tag and prop in the
|
|
39
46
|
pages; a site can add its own components next to it (see "Inside an existing site").
|
|
40
47
|
|
|
@@ -56,7 +63,10 @@ export default defineNuxtConfig({ extends: ['@lupinum/ginko-docs'], modules: ['@
|
|
|
56
63
|
## Configure
|
|
57
64
|
|
|
58
65
|
Options go in the site's `app.config.ts`. All are optional. Internal paths in `nav`, `footer.links` and `banner.href`
|
|
59
|
-
follow the reader's language (`/guide` becomes `/de/guide`); absolute URLs stay as written.
|
|
66
|
+
follow the reader's language (`/guide` becomes `/de/guide`); absolute URLs stay as written. A route link names the page
|
|
67
|
+
instead of its address, as in Markdown: `$docs.<page>` (a docs page by its file name, such as `$docs.webhooks`, or its
|
|
68
|
+
slug) and `$page.<key>` (a page of `pages` in `ginko.config.ts`, such as `$page.changelog`), with an optional `#anchor`.
|
|
69
|
+
It leads to the page in the reader's language, also when a translation has another slug.
|
|
60
70
|
|
|
61
71
|
```ts
|
|
62
72
|
export default defineAppConfig({
|
|
@@ -108,8 +118,26 @@ Each docs page's frontmatter can set, besides `title` and `description`:
|
|
|
108
118
|
| `icon` | An Iconify name, e.g. `lucide:rocket`, before the title in the navigation. Main locale only. |
|
|
109
119
|
| `badge` | A short label after the title, e.g. "New". |
|
|
110
120
|
|
|
111
|
-
Icons
|
|
112
|
-
|
|
121
|
+
### Icons
|
|
122
|
+
|
|
123
|
+
The layer draws icons itself (no `@nuxt/icon`, no icon API call, no icon library in the browser). At build time it reads
|
|
124
|
+
exactly the icons your site names from the installed `@iconify-json/<set>` packages (`lucide` is installed with the
|
|
125
|
+
layer; add others with `pnpm add -D @iconify-json/<set>`) and bundles them in one small map that only docs pages load.
|
|
126
|
+
|
|
127
|
+
The build scans, in all locales:
|
|
128
|
+
|
|
129
|
+
- the front matter of your Markdown files, the attributes of Markdown components (`::card{icon="lucide:rocket"}`) and the
|
|
130
|
+
`---` block inside a component; prose and code blocks are not read;
|
|
131
|
+
- YAML and JSON content files and `app.config.ts` (`icon:` values and `social`);
|
|
132
|
+
- the layer's own components and your site's `app/**/*.vue` files (`<Icon name="lucide:x" />`, `icon="..."`, or a bound
|
|
133
|
+
literal `:name="'lucide:x'"`). Commented-out code is ignored; other `.ts` files than `app.config.ts` are not read.
|
|
134
|
+
|
|
135
|
+
A name is `set:name`; a bare name such as `book-open` means Lucide. The `i-set-name` form is not supported. Names built at
|
|
136
|
+
runtime (a variable, a template string) are not found; write the name once as a literal somewhere in the places above. A
|
|
137
|
+
name the build cannot find logs one warning with its file and renders nothing.
|
|
138
|
+
|
|
139
|
+
The layer registers a global `Icon` component that the Markdown components (card, tabs, callout) use. If your site installs
|
|
140
|
+
`@nuxt/icon` itself, yours wins (the layer's has a lower priority).
|
|
113
141
|
|
|
114
142
|
### Start page (optional)
|
|
115
143
|
|
|
@@ -129,6 +157,9 @@ features:
|
|
|
129
157
|
---
|
|
130
158
|
```
|
|
131
159
|
|
|
160
|
+
`href` takes a path as written, an absolute URL, or a route link (`$docs.introduction`, `$page.changelog`) that follows
|
|
161
|
+
the reader's language, so the translations (`home.<locale>.md`) can use the same links.
|
|
162
|
+
|
|
132
163
|
Add `home: docsHome()` to `bricks`. Without it, `/` leads to the first docs page. A site's own `pages/index.vue` wins.
|
|
133
164
|
|
|
134
165
|
### Look and colours
|
|
@@ -170,17 +201,24 @@ bricks: { docs: docsCollection({ locales, base: '/handbook' }), /* … */ },
|
|
|
170
201
|
components: { ...components, /* the site's own components; same name wins */ },
|
|
171
202
|
```
|
|
172
203
|
|
|
173
|
-
- **Only the docs pages are added.** The layer registers its pages from the bricks
|
|
174
|
-
`docsCollection` (default `/docs`),
|
|
175
|
-
|
|
204
|
+
- **Only the docs pages are added.** The layer registers its pages from the bricks, after all pages of the site are
|
|
205
|
+
known: the docs at the `base` of `docsCollection` (default `/docs`), the blog (with its RSS feed) at the route of
|
|
206
|
+
the `posts` brick and the changelog at the route of the `changelog` brick (or `pages.changelog`), and `/` only when
|
|
207
|
+
the site has no start page of its own. A page the site defines itself at one of these addresses always wins, also
|
|
208
|
+
when the page-paths module gives it that address (a page file `news.vue` that answers at `/blog`). Then the layer
|
|
209
|
+
adds no page and no feed there, and its header and post links point to the site's page.
|
|
176
210
|
- **The site's frame stays.** The header, footer and page background are the layer's `layouts/default.vue`. When
|
|
177
211
|
the site has its own `layouts/default.vue`, that one is used and the docs (navigation, page, table of contents)
|
|
178
|
-
sit inside it
|
|
212
|
+
sit inside it, without the layer's framed panel, on the site's background. The search sits above the navigation.
|
|
213
|
+
On phones a bar under the site's header holds a "Contents" button (the navigation as a sheet), the search and the
|
|
214
|
+
"On this page" menu, so the docs need no header of their own.
|
|
179
215
|
- **Nothing leaks.** Every rule is under a `docs-` class; the page background, font and `color-scheme` are only set
|
|
180
216
|
by the layer's own frame. The search, the language menu and the light/dark switch are components
|
|
181
217
|
(`<DocsSearch />`, `<DocsLanguage />`, `<DocsThemeToggle />`) the site can put into its own header; the switch sets
|
|
182
218
|
`data-theme` on `<html>`, so it fits a site that themes with that attribute. `<DocsThemeToggle segmented />` is the
|
|
183
|
-
three-way Auto/Light/Dark switch
|
|
219
|
+
three-way Auto/Light/Dark switch and `<DocsLanguage list />` the languages as a row of links (the phone menu uses
|
|
220
|
+
both). A language without a version of the page says so ("Not translated: opens the start page"). These three,
|
|
221
|
+
`<DocsShell>` and the override points under [Customize](#customize) are the public components. The other `Docs*`
|
|
184
222
|
components, the `useDocs*` composables and the files in `app/lib` are internal and can change in any release.
|
|
185
223
|
- **Error page:** the layer's `error.vue` shows a not-found page inside the site's layout, with links home and to
|
|
186
224
|
the docs. A site with its own `error.vue` keeps it.
|
|
@@ -190,10 +228,11 @@ components: { ...components, /* the site's own components; same name wins */ },
|
|
|
190
228
|
- **Title:** pages get the title `Page · Site name` from Ginko (`seo.titleTemplate` in `defineSite`). A
|
|
191
229
|
`titleTemplate` in `app.head` or from nuxt-seo-utils does not apply to them, so the name is never added twice.
|
|
192
230
|
- **Styling:** map the site's design tokens to the token names above (leave out the ones the site already defines
|
|
193
|
-
under the same name, often `--font-sans` and `--font-mono`).
|
|
194
|
-
- `--docs-max`: the width of the site's content container, so the
|
|
195
|
-
|
|
196
|
-
|
|
231
|
+
under the same name, often `--font-sans` and `--font-mono`). Three layout tokens line the docs up with the site:
|
|
232
|
+
- `--docs-max` and `--docs-gutter`: the width and the side padding of the site's content container, so the search
|
|
233
|
+
and the navigation start where the header's logo does.
|
|
234
|
+
- `--docs-top`: the space the sidebar, the phone bar and the table of contents keep from the top of the window when
|
|
235
|
+
they stick, and the scroll offset of headings. With a sticky header, its height; with one that scrolls away, 0.
|
|
197
236
|
|
|
198
237
|
```css
|
|
199
238
|
:root {
|
|
@@ -205,10 +244,65 @@ components: { ...components, /* the site's own components; same name wins */ },
|
|
|
205
244
|
--primary: var(--color-brand);
|
|
206
245
|
--radius: 0.75rem;
|
|
207
246
|
--docs-max: 82.5rem;
|
|
208
|
-
--docs-
|
|
247
|
+
--docs-gutter: 1.5rem;
|
|
248
|
+
--docs-top: 4.5rem; /* sticky header 4.5rem high; 0 for one that scrolls away */
|
|
209
249
|
}
|
|
210
250
|
```
|
|
211
251
|
|
|
252
|
+
Headings use the site's own heading styles; the layer sets no font on them.
|
|
253
|
+
|
|
254
|
+
## Customize
|
|
255
|
+
|
|
256
|
+
Everything here is public and stays stable between releases.
|
|
257
|
+
|
|
258
|
+
**Tokens.** The colour tokens are listed under [Look and colours](#look-and-colours). The layout tokens:
|
|
259
|
+
|
|
260
|
+
| Token | Default | What it sets |
|
|
261
|
+
| --- | --- | --- |
|
|
262
|
+
| `--docs-max` | `90rem` | Width of the docs, gutters included |
|
|
263
|
+
| `--docs-gutter` | `1rem` | Space between the window edge and the docs |
|
|
264
|
+
| `--docs-top` | `0px` (standalone: the header) | Height of what sticks above the docs |
|
|
265
|
+
| `--docs-sidebar` | `17rem` | Width of the navigation |
|
|
266
|
+
| `--docs-toc` | `13.5rem` | Width of "On this page" beside the text (from 80rem window width) |
|
|
267
|
+
| `--docs-measure` | `38rem` | Reading width of running text |
|
|
268
|
+
| `--docs-h1` | `clamp(1.75rem, …, 2.25rem)` | Size of page titles |
|
|
269
|
+
| `--docs-header` | `4rem` | Height of the standalone header |
|
|
270
|
+
|
|
271
|
+
**Override points.** The layer ships empty components that a site replaces with its own file of the same name in
|
|
272
|
+
`app/components/`:
|
|
273
|
+
|
|
274
|
+
- `DocsPageEnd` (prop `doc`, the page's entry): after the text of every page, before "Edit this page" and the pager.
|
|
275
|
+
For a support box or a call to action.
|
|
276
|
+
- `DocsSidebarEnd`: below the navigation, in the sidebar and in the phone menu. For a few links or a contact line.
|
|
277
|
+
|
|
278
|
+
**Own pages in the docs frame.** `<DocsShell>` is the docs body (navigation, search, the phone bar) with a default slot
|
|
279
|
+
for the page and a `bar` slot for controls in the phone bar. A help center's start page, for example:
|
|
280
|
+
|
|
281
|
+
```vue
|
|
282
|
+
<!-- app/pages/help/index.vue; the docs live at /help (docsCollection({ locales, base: '/help' })) -->
|
|
283
|
+
<script setup lang="ts">
|
|
284
|
+
const docs = useGinko('docs')
|
|
285
|
+
</script>
|
|
286
|
+
|
|
287
|
+
<template>
|
|
288
|
+
<DocsShell>
|
|
289
|
+
<h1>How can we help?</h1>
|
|
290
|
+
<ul>
|
|
291
|
+
<li v-for="item in docs.items" :key="item.id"><NuxtLink :to="item.url">{{ item.data.title }}</NuxtLink></li>
|
|
292
|
+
</ul>
|
|
293
|
+
</DocsShell>
|
|
294
|
+
</template>
|
|
295
|
+
```
|
|
296
|
+
|
|
297
|
+
The layer then adds no page of its own at that address.
|
|
298
|
+
|
|
299
|
+
**Search.** `docs: { search: false }` in app.config leaves out the built-in search (header, sidebar and phone bar), for
|
|
300
|
+
a site that puts `<DocsSearch />` into its own header.
|
|
301
|
+
|
|
302
|
+
**Texts.** Every text of the layer is a `docs.*` message, and the site's own i18n wins per key. A help center, for
|
|
303
|
+
example, words the search for itself in `i18n/en.json`: `{ "docs": { "searchPlaceholder": "Search help…" } }`. The
|
|
304
|
+
layer brings English, German and French.
|
|
305
|
+
|
|
212
306
|
## Blog and changelog (optional)
|
|
213
307
|
|
|
214
308
|
A site opts in by adding the collections to `ginko.config.ts`. The layer then adds the pages and the header links;
|
|
@@ -229,6 +323,7 @@ export default defineSite({
|
|
|
229
323
|
- **Authors** (`content/authors/<name>[.<locale>].yml`) have `name`, `role`, `avatar` and `url`. A post names them by id: `authors: [authors/jane]`. Authors have no page.
|
|
230
324
|
- A post page writes Article JSON-LD with the author names, `datePublished` from `date` and `dateModified` from the entry's `updatedAt`.
|
|
231
325
|
- **RSS:** `/blog/rss.xml` and `/<l>/blog/rss.xml`, RSS 2.0 with title and description (not the full text) and absolute links. It reads the build-time file bundle, so it works for file blogs only. `nuxt generate` writes it: the blog page sends the feed path in the `x-nitro-prerender` header, because Nitro's crawler does not follow `.xml` links.
|
|
326
|
+
- **Addresses:** the blog list is the parent of the `posts` route (`/blog/[slug]` gives `/blog`; `blogCollections` uses `/blog`). The changelog page is at the route of the `changelog` brick, else at `pages.changelog` (`changelogPages({ locales })`, `/changelog`). A changelog brick with neither gets no page, and the build warns once. A site that has its own page at an address keeps it; the layer then adds nothing there.
|
|
232
327
|
- **Changelog:** `changelogCollection()` (options: `max`) is one collection with `version`, `date` and Markdown text per release (`content/changelog/v1-2-0.md`; no dots in the file name, a dot reads as a language). The page `/changelog` shows all releases newest first, each with an anchor (`#v1-2-0`). It is a collection, not a docs page, so the date orders it and it has its own link in the header.
|
|
233
328
|
|
|
234
329
|
The Ginko docs themselves are built this way: [sites/docs](https://github.com/lupinum-dev/ginko/tree/main/sites/docs).
|
package/app/app.config.ts
CHANGED
|
@@ -32,6 +32,8 @@ export interface DocsConfig {
|
|
|
32
32
|
}
|
|
33
33
|
/** "Copy page" (default true) and the chats the page menu can open it in (default both, `[]` for none). */
|
|
34
34
|
markdownActions?: { copy?: boolean, openIn?: DocsAssistant[] }
|
|
35
|
+
/** `false` leaves out the built-in search (header, sidebar, phone bar), for a site with <DocsSearch /> in its own header. */
|
|
36
|
+
search?: boolean
|
|
35
37
|
/** Footer. Link texts: messages `docs.footer.<id>`. `attribution` (default true) adds "Built with Ginko". */
|
|
36
38
|
footer?: { links?: { id: string, href: string }[], attribution?: boolean }
|
|
37
39
|
}
|
package/app/assets/docs.css
CHANGED
|
@@ -26,7 +26,7 @@
|
|
|
26
26
|
--input: light-dark(#d4d4d8, #52525b);
|
|
27
27
|
--primary: light-dark(#047857, #34d399);
|
|
28
28
|
--primary-foreground: light-dark(#ffffff, #09090b);
|
|
29
|
-
--ring: light-dark(#
|
|
29
|
+
--ring: light-dark(#047857, #34d399);
|
|
30
30
|
--success: light-dark(#157a39, #4ade80);
|
|
31
31
|
--warning: light-dark(#985807, #fbbf24);
|
|
32
32
|
--info: light-dark(#1d4ed8, #60a5fa);
|
|
@@ -43,6 +43,8 @@
|
|
|
43
43
|
--docs-sidebar: 17rem;
|
|
44
44
|
--docs-toc: 13.5rem;
|
|
45
45
|
--docs-max: 90rem;
|
|
46
|
+
/* Space between the window edge and the docs: the site's container padding when the docs sit in its layout. */
|
|
47
|
+
--docs-gutter: 1rem;
|
|
46
48
|
/* One page-title size for docs, blog, changelog and 404. */
|
|
47
49
|
--docs-h1: clamp(1.75rem, 1.4rem + 1vw, 2.25rem);
|
|
48
50
|
/* Height of the phone bar above the page; 0 where the bar is hidden. Anchors scroll below both. */
|
|
@@ -195,7 +197,7 @@
|
|
|
195
197
|
/* ---------- Docs shell: sidebar, phone bar, content ---------- */
|
|
196
198
|
|
|
197
199
|
/* The navigation sits on the page background; the page is a framed panel. */
|
|
198
|
-
.docs-shell { display: grid; grid-template-columns: var(--docs-sidebar) minmax(0, 1fr); gap: 0.75rem; max-width: var(--docs-max); margin: 0 auto; padding: 0
|
|
200
|
+
.docs-shell { display: grid; grid-template-columns: var(--docs-sidebar) minmax(0, 1fr); gap: 0.75rem; box-sizing: border-box; max-width: var(--docs-max); margin: 0 auto; padding: 0 var(--docs-gutter) 1rem; }
|
|
199
201
|
.docs-sidebar { position: sticky; top: var(--docs-top); align-self: start; max-height: calc(100dvh - var(--docs-top)); overflow-y: auto; overscroll-behavior: contain; padding: 1rem 0.5rem 3rem 0.25rem; scrollbar-width: none; }
|
|
200
202
|
.docs-content { min-width: 0; padding: 2rem 2.25rem 4.5rem 3.5rem; border: 1px solid var(--border); border-radius: var(--docs-r-panel); background: var(--card); }
|
|
201
203
|
.docs-bar { display: none; }
|
|
@@ -239,8 +241,11 @@
|
|
|
239
241
|
.docs-menu-links a:hover { background: color-mix(in oklab, var(--foreground) 9%, var(--muted)); }
|
|
240
242
|
.docs-menu-links a[aria-current] { font-weight: 700; }
|
|
241
243
|
.docs-menu-foot { display: flex; flex: none; align-items: center; justify-content: space-between; gap: 0.75rem; margin-top: auto; padding: 0.75rem 1rem 1.75rem; border-top: 1px solid var(--border); }
|
|
242
|
-
|
|
243
|
-
.docs-
|
|
244
|
+
/* The languages at the top of the phone menu: one link each, named in its own language. */
|
|
245
|
+
.docs-lang-list { display: flex; flex: none; flex-wrap: wrap; gap: 0.5rem; padding: 0.75rem 1rem; border-bottom: 1px solid var(--border); }
|
|
246
|
+
.docs-lang-list a { display: inline-flex; flex-direction: column; justify-content: center; min-height: 2.75rem; padding: 0.25rem 0.875rem; border-radius: var(--docs-r-control); background: var(--muted); color: var(--foreground); font-size: 0.9375rem; font-weight: 500; line-height: 1.25; text-decoration: none; }
|
|
247
|
+
.docs-lang-list a[aria-current] { box-shadow: inset 0 0 0 1px var(--foreground); font-weight: 700; }
|
|
248
|
+
.docs-lang-list small { display: block; color: var(--muted-foreground); font-size: 0.75rem; font-weight: 400; }
|
|
244
249
|
.docs-segmented { display: inline-flex; gap: 4px; padding: 3px; border-radius: calc(var(--docs-r-control) + 2px); background: var(--muted); }
|
|
245
250
|
.docs-segmented button { height: 1.875rem; padding: 0 0.75rem; border: 0; border-radius: var(--docs-r-control); background: none; color: var(--muted-foreground); font: 500 0.8125rem/1 var(--font-sans); cursor: pointer; }
|
|
246
251
|
.docs-segmented button[aria-pressed='true'] { background: light-dark(var(--card), var(--muted)); color: var(--foreground); box-shadow: 0 1px 2px rgb(0 0 0 / 0.08); }
|
|
@@ -272,26 +277,30 @@
|
|
|
272
277
|
.docs-page-foot { display: flex; flex-wrap: wrap; align-items: center; justify-content: space-between; gap: 0.5rem 1.5rem; margin-top: 3.5rem; color: var(--muted-foreground); font-size: 0.8125rem; }
|
|
273
278
|
.docs-page-foot a { display: inline-flex; align-items: center; gap: 0.375rem; color: var(--muted-foreground); text-decoration: none; }
|
|
274
279
|
.docs-page-foot a:hover { color: var(--foreground); }
|
|
275
|
-
.docs-pager { display: grid; grid-template-columns:
|
|
276
|
-
.docs-pager a { display: flex; flex-direction: column; gap: 0.1875rem; padding: 0.875rem 1rem 0.9375rem; border: 1px solid var(--border); border-radius: var(--docs-r-box); color: var(--foreground); font-size: 0.9375rem; font-weight: 600; text-decoration: none; transition: border-color 0.15s, background-color 0.15s; }
|
|
280
|
+
.docs-pager { display: grid; grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 0.75rem; margin-top: 1rem; }
|
|
281
|
+
.docs-pager a { display: flex; flex-direction: column; gap: 0.1875rem; padding: 0.875rem 1rem 0.9375rem; border: 1px solid var(--border); border-radius: var(--docs-r-box); color: var(--foreground); font-size: 0.9375rem; font-weight: 600; text-decoration: none; overflow-wrap: anywhere; hyphens: auto; transition: border-color 0.15s, background-color 0.15s; }
|
|
277
282
|
.docs-pager a:hover { background: color-mix(in oklab, var(--muted) 60%, transparent); }
|
|
278
283
|
.docs-pager small { display: inline-flex; align-items: center; gap: 0.375rem; color: var(--muted-foreground); font-size: 0.78125rem; font-weight: 500; }
|
|
279
284
|
.docs-pager .is-next { grid-column: 2; align-items: flex-end; text-align: right; }
|
|
280
285
|
|
|
286
|
+
/* Headings outside .docs-prose have no wrap rule of their own. `anywhere` (not break-word) because the blog head is a flex container and needs the smaller min-content. */
|
|
287
|
+
:where(.docs-page-head, .docs-hero, .docs-blog, .docs-error) h1, .docs-posts h2, .docs-prose :is(h1, h2, h3, h4) { hyphens: auto; overflow-wrap: anywhere; }
|
|
288
|
+
|
|
281
289
|
/* Table of contents: a rail on wide screens, a menu in the phone bar */
|
|
282
290
|
.docs-toc { position: sticky; top: calc(var(--docs-top) + 2rem); align-self: start; max-height: calc(100dvh - var(--docs-top) - 4rem); overflow-y: auto; scrollbar-width: none; font-size: 0.8125rem; }
|
|
283
291
|
.docs-toc-title { display: flex; align-items: center; gap: 0.5rem; margin: 0 0 0.625rem; color: var(--foreground); font-size: 0.78125rem; font-weight: 600; }
|
|
284
292
|
.docs-toc-title .docs-icon { color: var(--muted-foreground); font-size: 0.875rem; }
|
|
285
293
|
.docs-toc-list { margin: 0; padding: 0; list-style: none; border-left: 1px solid var(--border); }
|
|
286
|
-
.docs-toc-list a { display: block; margin-left: -1px; padding: 0.3125rem 0 0.3125rem 0.875rem; border-left: 2px solid transparent; color: var(--muted-foreground); line-height: 1.4; text-decoration: none; transition: color 0.15s, border-color 0.15s; }
|
|
294
|
+
.docs-toc-list a { display: block; margin-left: -1px; padding: 0.3125rem 0 0.3125rem 0.875rem; border-left: 2px solid transparent; color: var(--muted-foreground); line-height: 1.4; text-decoration: none; overflow-wrap: break-word; hyphens: auto; transition: color 0.15s, border-color 0.15s; }
|
|
287
295
|
.docs-toc-list a.is-sub { padding-left: 1.625rem; }
|
|
288
296
|
.docs-toc-list a:hover { color: var(--foreground); }
|
|
289
297
|
.docs-toc-list a[aria-current] { border-left-color: var(--primary); color: var(--foreground); font-weight: 500; }
|
|
290
298
|
.docs-toc-more { display: flex; flex-direction: column; gap: 0.125rem; margin-top: 1.125rem; padding-top: 0.875rem; border-top: 1px solid var(--border); }
|
|
291
299
|
.docs-toc-more a, .docs-toc-more button { display: inline-flex; align-items: center; gap: 0.5rem; padding: 0.25rem 0; border: 0; background: none; color: var(--muted-foreground); font: inherit; text-decoration: none; cursor: pointer; }
|
|
292
300
|
.docs-toc-more a:hover, .docs-toc-more button:hover { color: var(--foreground); }
|
|
293
|
-
.docs-toc-menu { position: relative; }
|
|
294
|
-
.docs-toc-menu > button
|
|
301
|
+
.docs-toc-menu { position: relative; min-width: 0; max-width: 100%; }
|
|
302
|
+
.docs-toc-menu > button > span { min-width: 0; overflow: hidden; text-overflow: ellipsis; white-space: nowrap; }
|
|
303
|
+
.docs-toc-menu > button { display: inline-flex; align-items: center; gap: 0.375rem; height: 2rem; padding: 0 0.5rem; border: 0; border-radius: calc(var(--radius) - 2px); background: none; color: var(--muted-foreground); font: 500 0.8125rem/1 var(--font-sans); cursor: pointer; max-width: 100%;}
|
|
295
304
|
.docs-toc-menu > button:hover { color: var(--foreground); }
|
|
296
305
|
.docs-toc-menu > button[aria-expanded='true'] .docs-icon { transform: rotate(180deg); }
|
|
297
306
|
.docs-toc-menu .docs-popover { right: 0; top: calc(100% + 0.25rem); width: min(20rem, calc(100vw - 2rem)); max-height: 60dvh; overflow-y: auto; padding: 0.75rem 0.75rem 0.75rem 0.5rem; }
|
|
@@ -328,12 +337,26 @@
|
|
|
328
337
|
.docs-prose hr { margin: 2.5rem 0; border: 0; border-top: 1px solid var(--border); }
|
|
329
338
|
.docs-prose blockquote { padding-left: 1rem; border-left: 2px solid var(--border); color: var(--muted-foreground); }
|
|
330
339
|
.docs-prose img { max-width: 100%; height: auto; border-radius: var(--radius); }
|
|
331
|
-
|
|
332
|
-
.docs-prose table {
|
|
340
|
+
/* The edge shadows are the scroll cue: the "local" covers hide them at the ends, so a shadow shows only on a side with more to scroll to. */
|
|
341
|
+
.docs-prose .docs-table {
|
|
342
|
+
width: 100%; max-width: 100%; overflow-x: auto; border: 1px solid var(--border); border-radius: var(--docs-r-box);
|
|
343
|
+
background:
|
|
344
|
+
linear-gradient(to right, var(--card), var(--card)) left center / 1.5rem 100% no-repeat local,
|
|
345
|
+
linear-gradient(to left, var(--card), var(--card)) right center / 1.5rem 100% no-repeat local,
|
|
346
|
+
linear-gradient(to right, color-mix(in oklab, var(--foreground) 14%, transparent), transparent) left center / 0.75rem 100% no-repeat scroll,
|
|
347
|
+
linear-gradient(to left, color-mix(in oklab, var(--foreground) 14%, transparent), transparent) right center / 0.75rem 100% no-repeat scroll;
|
|
348
|
+
}
|
|
349
|
+
/* At least as wide as its frame, so a short table's rows and header reach the frame's edge. */
|
|
350
|
+
.docs-prose table { min-width: 100%; border-collapse: separate; border-spacing: 0; margin: 0; font-size: 0.875rem; line-height: 1.5; font-variant-numeric: tabular-nums; }
|
|
333
351
|
.docs-prose :where(th, td) { padding: 0.6875rem 0.875rem; border-bottom: 1px solid var(--border); text-align: left; vertical-align: top; }
|
|
334
352
|
.docs-prose tr:last-child > td { border-bottom: 0; }
|
|
335
353
|
.docs-prose th { background: var(--sidebar); color: var(--muted-foreground); font-size: 0.78125rem; font-weight: 600; white-space: nowrap; }
|
|
336
|
-
.docs-prose td code { white-space:
|
|
354
|
+
.docs-prose td code { white-space: normal; overflow-wrap: normal; }
|
|
355
|
+
.docs-prose td:first-child code { white-space: nowrap; }
|
|
356
|
+
/* Only the last column of a table with 4+ columns needs room; in narrower tables it would force a scroll on phones. */
|
|
357
|
+
.docs-prose table:has(th:nth-child(4)) td:last-child { min-width: 14rem; }
|
|
358
|
+
/* Below 360 px a 3-column table squeezes its last column to a few letters; there it scrolls too. */
|
|
359
|
+
@media (max-width: 22.5rem) { .docs-prose table:has(th:nth-child(3)) td:last-child { min-width: 10rem; } }
|
|
337
360
|
|
|
338
361
|
/* Code blocks: one bordered panel with the file name or tabs on a lighter head (ginko-components draws an inset). */
|
|
339
362
|
:where(.docs-prose, .docs-landing) :is(.ginko-code, .ginko-code-group, .ginko-code-tree):not([data-bare]) { padding: 0; overflow: hidden; border: 1px solid var(--docs-code-line); border-radius: var(--docs-r-box); }
|
|
@@ -403,7 +426,7 @@
|
|
|
403
426
|
.docs-hero p { max-width: 40rem; margin: 1.5rem auto 0; color: var(--muted-foreground); font-size: 1.1875rem; line-height: 1.6; text-wrap: pretty; }
|
|
404
427
|
.docs-hero-links { display: flex; flex-wrap: wrap; justify-content: center; gap: 0.625rem; margin-top: 2.25rem; }
|
|
405
428
|
.docs-install { display: inline-flex; align-items: center; gap: 0.625rem; max-width: 100%; height: 2.625rem; margin-top: 1rem; padding: 0 0.3125rem 0 0.875rem; border: 1px solid var(--border); border-radius: var(--docs-r-control); background: var(--card); font: 500 0.84375rem/1 var(--font-mono); }
|
|
406
|
-
.docs-install code { font: inherit; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
|
|
429
|
+
.docs-install code { min-width: 0; font: inherit; overflow-x: auto; white-space: nowrap; scrollbar-width: none; }
|
|
407
430
|
.docs-install code::before { content: '$ '; color: var(--muted-foreground); }
|
|
408
431
|
.docs-features { display: grid; grid-template-columns: repeat(3, minmax(0, 1fr)); gap: 2.75rem 3rem; margin: 6.5rem 0 0; padding: 0; list-style: none; }
|
|
409
432
|
.docs-feature { position: relative; display: grid; align-content: start; gap: 0.5rem; padding-top: 1.375rem; border-top: 1px solid var(--border); }
|
|
@@ -512,7 +535,7 @@ html[data-docs-banner-off] .docs-banner { display: none; }
|
|
|
512
535
|
.docs-sidebar { display: none; }
|
|
513
536
|
.docs-content { padding: 0 1.5rem 4rem; border: 0; border-radius: 0; background: none; }
|
|
514
537
|
.docs-bar { justify-content: flex-end; margin: 0 -1.5rem; padding: 0 0.75rem 0 1rem; border-block: 1px solid var(--border); border-radius: 0; background: color-mix(in oklab, var(--background) 92%, transparent); }
|
|
515
|
-
.docs-nav-links, .docs-header-end > :not(.docs-search-trigger, .docs-header-menu) { display: none; }
|
|
538
|
+
.docs-nav-links, .docs-header-end > :not(.docs-search-trigger, .docs-theme-toggle, .docs-header-menu) { display: none; }
|
|
516
539
|
.docs-header-menu { display: inline-grid; }
|
|
517
540
|
.docs-header-inner { padding: 0 0.5rem 0 1rem; }
|
|
518
541
|
.docs-search-trigger { width: 2.25rem; padding: 0; justify-content: center; border-color: transparent; background: none; }
|
|
@@ -527,10 +550,14 @@ html[data-docs-banner-off] .docs-banner { display: none; }
|
|
|
527
550
|
.docs-bar { margin: 0 -1rem; padding: 0 0.5rem; }
|
|
528
551
|
.docs-page-head { grid-template-columns: minmax(0, 1fr); }
|
|
529
552
|
.docs-page-head .docs-actions { grid-column: 1; grid-row: auto; margin-top: 0.75rem; }
|
|
530
|
-
.docs-pager { grid-template-columns: 1fr; }
|
|
553
|
+
.docs-pager { grid-template-columns: minmax(0, 1fr); }
|
|
531
554
|
.docs-pager .is-next { grid-column: 1; }
|
|
532
555
|
.docs-landing-inner { padding: 3rem 1rem 4rem; }
|
|
533
556
|
.docs-features { margin-top: 3.5rem; }
|
|
557
|
+
.docs-landing-body { margin-top: 3.5rem; }
|
|
558
|
+
.docs-feature:has(.docs-feature-icon) { grid-template-columns: auto minmax(0, 1fr); column-gap: 0.75rem; align-items: center; }
|
|
559
|
+
.docs-feature-icon { margin-bottom: 0; }
|
|
560
|
+
.docs-feature > p { grid-column: 1 / -1; }
|
|
534
561
|
.docs-blog-panel { padding: 1.5rem 1rem 3rem; border: 0; background: none; }
|
|
535
562
|
.docs-posts { margin-inline: 0; }
|
|
536
563
|
.docs-posts li { grid-template-columns: minmax(0, 1fr); gap: 0.5rem; padding-inline: 0; }
|
|
@@ -541,6 +568,38 @@ html[data-docs-banner-off] .docs-banner { display: none; }
|
|
|
541
568
|
}
|
|
542
569
|
|
|
543
570
|
/* Touch screens: small controls keep their look but get a 44px hit area. */
|
|
571
|
+
/* ---------- Embedded: the docs inside a site's own layout (no html.docs-standalone) ----------
|
|
572
|
+
No framed panel: the page sits on the site's background, and the shell lines up with the site's container through
|
|
573
|
+
--docs-max and --docs-gutter. The search sits above the navigation; on phones the bar always shows, with the
|
|
574
|
+
navigation button and the search on the start side and the table of contents on the end side. */
|
|
575
|
+
:root:not(.docs-standalone) .docs-shell { gap: 3rem; padding-bottom: 0; }
|
|
576
|
+
:root:not(.docs-standalone) .docs-sidebar { padding: 2rem 0 3rem; }
|
|
577
|
+
:root:not(.docs-standalone) .docs-content { padding: 2rem 0 4.5rem; border: 0; border-radius: 0; background: none; }
|
|
578
|
+
.docs-sidebar-search { margin: 0 0 1.25rem; }
|
|
579
|
+
.docs-sidebar-search .docs-search-trigger { width: 100%; }
|
|
580
|
+
.docs-bar-start { display: none; }
|
|
581
|
+
.docs-bar-nav { display: inline-flex; align-items: center; gap: 0.5rem; height: 2.75rem; padding: 0 0.5rem; border: 0; background: none; color: var(--foreground); font: 500 0.875rem/1 var(--font-sans); cursor: pointer; }
|
|
582
|
+
.docs-bar-nav .docs-icon { font-size: 1.125rem; color: var(--muted-foreground); }
|
|
583
|
+
.docs-nav-sheet { inset-block: 0; inset-inline: 0 auto; width: min(20rem, calc(100vw - 3rem)); max-width: none; height: 100dvh; max-height: none; margin: 0; padding: 0; border: 0; border-inline-end: 1px solid var(--border); background: var(--background); color: var(--foreground); font-family: var(--font-sans); animation: docs-menu-in 0.15s ease-out; }
|
|
584
|
+
.docs-nav-sheet[open] { display: flex; flex-direction: column; }
|
|
585
|
+
.docs-nav-sheet::backdrop { background: rgb(0 0 0 / 0.4); }
|
|
586
|
+
.docs-nav-sheet-head { display: flex; flex: none; align-items: center; justify-content: space-between; height: 3.5rem; padding: 0 0.5rem 0 1rem; border-bottom: 1px solid var(--border); }
|
|
587
|
+
.docs-nav-sheet-head p { margin: 0; font-weight: 600; }
|
|
588
|
+
.docs-nav-sheet-body { flex: 1; min-height: 0; overflow-y: auto; overscroll-behavior: contain; padding: 0.75rem 0.5rem 2rem; }
|
|
589
|
+
.docs-nav-sheet-body .docs-nav-item > a { min-height: 2.75rem; }
|
|
590
|
+
@media (prefers-reduced-motion: reduce) { .docs-nav-sheet { animation: none; } }
|
|
591
|
+
@media (max-width: 79.99rem) {
|
|
592
|
+
:root:not(.docs-standalone) .docs-content { padding-top: 0; }
|
|
593
|
+
:root:not(.docs-standalone) .docs-bar { margin: 0; padding: 0; border-radius: 0; background: color-mix(in oklab, var(--background) 92%, transparent); }
|
|
594
|
+
}
|
|
595
|
+
@media (max-width: 63.99rem) {
|
|
596
|
+
:root:not(.docs-standalone) .docs-shell { padding: 0 var(--docs-gutter); }
|
|
597
|
+
:root:not(.docs-standalone) .docs-content { padding: 0 0 4rem; }
|
|
598
|
+
/* No top border: the site's header above has one. */
|
|
599
|
+
:root:not(.docs-standalone) .docs-bar { display: flex; justify-content: space-between; margin: 0 calc(-1 * var(--docs-gutter)); padding: 0 max(0px, calc(var(--docs-gutter) - 0.5rem)); border-top: 0; }
|
|
600
|
+
.docs-bar-start { display: flex; align-items: center; gap: 0.25rem; }
|
|
601
|
+
}
|
|
602
|
+
|
|
544
603
|
@media (pointer: coarse) {
|
|
545
604
|
:where(.docs-icon-button, .ginko-code-copy, .ginko-code-tab, .docs-toc-menu > button, .docs-example .ginko-tabs-tab) { position: relative; }
|
|
546
605
|
:where(.docs-icon-button, .ginko-code-copy, .ginko-code-tab, .docs-toc-menu > button, .docs-example .ginko-tabs-tab)::after { content: ''; position: absolute; inset: -7px; }
|
|
@@ -552,4 +611,9 @@ html[data-docs-banner-off] .docs-banner { display: none; }
|
|
|
552
611
|
.docs-blog { padding-inline: 0; }
|
|
553
612
|
.docs-hero p { font-size: 1.0625rem; }
|
|
554
613
|
}
|
|
614
|
+
/* 320px: both hero buttons fill the row. */
|
|
615
|
+
@media (max-width: 23.99rem) {
|
|
616
|
+
.docs-hero-links { flex-direction: column; }
|
|
617
|
+
.docs-hero-links > .docs-button { width: 100%; justify-content: center; }
|
|
618
|
+
}
|
|
555
619
|
.ginko-excerpt-source { font-family: var(--font-sans); }
|
|
@@ -24,6 +24,6 @@ function dismiss() {
|
|
|
24
24
|
<NuxtLink v-if="href" :to="siteHref(href)">{{ text(`docs.banner.${id}`) }}</NuxtLink>
|
|
25
25
|
<template v-else>{{ text(`docs.banner.${id}`) }}</template>
|
|
26
26
|
</p>
|
|
27
|
-
<button type="button" class="docs-icon-button" :aria-label="t('docs.bannerClose')" @click="dismiss"><
|
|
27
|
+
<button type="button" class="docs-icon-button" :aria-label="t('docs.bannerClose')" @click="dismiss"><DocsIcon name="lucide:x" class="docs-icon" /></button>
|
|
28
28
|
</div>
|
|
29
29
|
</template>
|
|
@@ -36,7 +36,7 @@ onBeforeUnmount(() => clearTimeout(timer))
|
|
|
36
36
|
</Tab>
|
|
37
37
|
</Tabs>
|
|
38
38
|
<button type="button" class="ginko-code-copy docs-example-copy" :aria-label="tc('code.copy')" @click="copy">
|
|
39
|
-
<
|
|
39
|
+
<DocsIcon :name="copied ? 'lucide:check' : 'lucide:copy'" class="docs-icon" />
|
|
40
40
|
<span class="ginko-code-status" aria-live="polite">{{ copied ? tc('code.copied') : '' }}</span>
|
|
41
41
|
</button>
|
|
42
42
|
</div>
|
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
<script setup lang="ts">
|
|
2
2
|
// The standalone header: brand, the site's sections (Docs, Blog, Changelog and the site's own links), search,
|
|
3
|
-
// language, light/dark and social links. On phones the menu button opens one full-screen menu: the
|
|
4
|
-
// navigation (on docs pages), the site links and social
|
|
3
|
+
// language, light/dark and social links. On phones the menu button opens one full-screen menu: the
|
|
4
|
+
// languages as links at its top, the docs navigation (on docs pages), the site links and social links, and the
|
|
5
|
+
// Auto/Light/Dark switch. The light/dark button stays in the header on phones too.
|
|
5
6
|
const { t, localePath } = useI18n()
|
|
6
7
|
const cfg = useAppConfig().docs ?? {}
|
|
7
8
|
const title = cfg.title ?? useGinkoSite().name
|
|
@@ -71,14 +72,14 @@ onBeforeUnmount(() => {
|
|
|
71
72
|
<NuxtLink v-for="l in links" :key="l.key" :to="l.to" :aria-current="l.active ? 'page' : undefined">{{ l.label }}</NuxtLink>
|
|
72
73
|
</nav>
|
|
73
74
|
<div class="docs-header-end">
|
|
74
|
-
<DocsSearch />
|
|
75
|
+
<DocsSearch v-if="cfg.search !== false" />
|
|
75
76
|
<DocsLanguage />
|
|
76
77
|
<DocsThemeToggle />
|
|
77
78
|
<template v-if="cfg.social?.length">
|
|
78
79
|
<span class="docs-header-sep" aria-hidden="true" />
|
|
79
80
|
<div class="docs-social">
|
|
80
81
|
<a v-for="s in cfg.social" :key="s.href" class="docs-icon-button" :href="s.href" target="_blank" rel="noopener" :aria-label="s.label" :title="s.label">
|
|
81
|
-
<
|
|
82
|
+
<DocsIcon :name="s.icon" class="docs-icon" />
|
|
82
83
|
</a>
|
|
83
84
|
</div>
|
|
84
85
|
</template>
|
|
@@ -86,13 +87,14 @@ onBeforeUnmount(() => {
|
|
|
86
87
|
ref="button" type="button" class="docs-icon-button docs-header-menu" :aria-expanded="menu" aria-controls="docs-menu"
|
|
87
88
|
:aria-label="menu ? t('docs.close') : t('docs.siteMenu')" @click="menu = !menu"
|
|
88
89
|
>
|
|
89
|
-
<
|
|
90
|
+
<DocsIcon :name="menu ? 'lucide:x' : 'lucide:menu'" class="docs-icon" />
|
|
90
91
|
</button>
|
|
91
92
|
</div>
|
|
92
93
|
</div>
|
|
93
94
|
<!-- Teleported: the header's backdrop blur would otherwise make it the containing block of the fixed menu. -->
|
|
94
95
|
<Teleport to="body">
|
|
95
96
|
<div v-if="menu" id="docs-menu" ref="panel" class="docs-menu" role="dialog" tabindex="-1" :aria-label="t('docs.siteMenu')">
|
|
97
|
+
<DocsLanguage list />
|
|
96
98
|
<div v-if="inDocs" class="docs-menu-scroll">
|
|
97
99
|
<DocsSidebar />
|
|
98
100
|
</div>
|
|
@@ -103,7 +105,6 @@ onBeforeUnmount(() => {
|
|
|
103
105
|
</nav>
|
|
104
106
|
</div>
|
|
105
107
|
<div class="docs-menu-foot">
|
|
106
|
-
<DocsLanguage />
|
|
107
108
|
<DocsThemeToggle segmented />
|
|
108
109
|
</div>
|
|
109
110
|
</div>
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
<script setup lang="ts">
|
|
2
|
+
// One icon from the build-time map (modules/icons.ts). A bare name is a Lucide icon; an unknown name renders nothing.
|
|
3
|
+
import { computed } from 'vue'
|
|
4
|
+
import icons from '#docs-icons'
|
|
5
|
+
|
|
6
|
+
const props = defineProps<{ name: string }>()
|
|
7
|
+
const icon = computed(() => icons[props.name.includes(':') ? props.name : `lucide:${props.name}`])
|
|
8
|
+
</script>
|
|
9
|
+
|
|
10
|
+
<template>
|
|
11
|
+
<svg v-if="icon" xmlns="http://www.w3.org/2000/svg" width="1em" height="1em" :viewBox="icon[1]" aria-hidden="true" v-html="icon[0]" />
|
|
12
|
+
</template>
|