@lupinum/ginko-docs 0.4.0-rc.8 → 0.4.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 +78 -0
- package/LICENSE +1 -1
- package/README.md +206 -54
- package/app/app.config.ts +42 -55
- package/app/assets/docs.css +555 -0
- package/app/components/DocsBanner.vue +29 -0
- package/app/components/DocsExample.vue +43 -0
- package/app/components/DocsFooter.vue +19 -0
- package/app/components/DocsHeader.vue +112 -0
- package/app/components/DocsLanding.vue +55 -0
- package/app/components/DocsLanguage.vue +29 -0
- package/app/components/DocsNavTree.vue +38 -0
- package/app/components/DocsPage.vue +84 -0
- package/app/components/DocsPageActions.vue +47 -0
- package/app/components/DocsPost.vue +58 -0
- package/app/components/DocsSearch.vue +134 -0
- package/app/components/DocsShell.vue +20 -0
- package/app/components/DocsSidebar.vue +18 -0
- package/app/components/DocsTable.vue +11 -0
- package/app/components/DocsThemeToggle.vue +45 -0
- package/app/components/DocsToc.vue +73 -0
- package/app/composables/useDocs.ts +52 -0
- package/app/composables/useDocsBlog.ts +32 -0
- package/app/composables/useDocsCopy.ts +17 -0
- package/app/composables/useDocsPopover.ts +36 -0
- package/app/composables/useDocsSite.ts +10 -0
- package/app/docs-pages/blog.vue +47 -0
- package/app/docs-pages/changelog.vue +27 -0
- package/app/docs-pages/doc.vue +14 -0
- package/app/docs-pages/docs.vue +9 -0
- package/app/docs-pages/index.vue +12 -0
- package/app/docs-pages/post.vue +8 -0
- package/app/error.vue +23 -115
- package/app/layouts/default.vue +25 -7
- package/app/lib/blogTypes.ts +8 -0
- package/app/lib/docsFirst.ts +11 -0
- package/app/lib/docsInit.ts +18 -0
- package/app/lib/docsNav.ts +36 -0
- package/app/lib/docsPage.ts +44 -0
- package/app/lib/markdownComponents.ts +16 -0
- package/app/lib/previewToc.ts +18 -0
- package/dist/config.d.mts +232 -0
- package/dist/config.d.ts +232 -0
- package/dist/config.mjs +114 -0
- package/dist/pages.d.mts +5 -0
- package/dist/pages.d.ts +5 -0
- package/dist/pages.mjs +36 -0
- package/dist/shared/ginko-docs.BwbF7JBR.mjs +4 -0
- package/i18n/de.json +1 -0
- package/i18n/en.json +1 -0
- package/icons/README.md +2 -0
- package/icons/bluesky.svg +1 -0
- package/icons/claude.svg +1 -0
- package/icons/discord.svg +1 -0
- package/icons/github.svg +1 -0
- package/icons/linkedin.svg +1 -0
- package/icons/mastodon.svg +1 -0
- package/icons/openai.svg +1 -0
- package/icons/x.svg +1 -0
- package/icons/youtube.svg +1 -0
- package/nuxt.config.ts +34 -209
- package/package.json +43 -76
- package/public/_docs/fonts/LICENSE +188 -0
- package/public/_docs/fonts/inter-latin-wght-normal.woff2 +0 -0
- package/public/_docs/fonts/jetbrains-mono-latin-400-normal.woff2 +0 -0
- package/public/_docs/fonts/jetbrains-mono-latin-500-normal.woff2 +0 -0
- package/server/feeds/blog-locale.get.ts +9 -0
- package/server/feeds/blog.get.ts +4 -0
- package/server/lib/blogFeed.ts +35 -0
- package/server/lib/rss.ts +57 -0
- package/server/mcp/handler.ts +108 -0
- package/server/routes/__ginko/docs-mcp.ts +35 -0
- package/shared/paths.ts +4 -0
- package/app/app.vue +0 -98
- package/app/assets/css/prose.css +0 -3240
- package/app/assets/css/tailwind.css +0 -394
- package/app/assets/css/theme-palettes.css +0 -309
- package/app/assets/css/theme-presets.css +0 -141
- package/app/components/OgImage/GinkoDocs.satori.vue +0 -238
- package/app/components/content/DocumentPageShell.vue +0 -55
- package/app/components/content/Feedback.vue +0 -102
- package/app/components/content/ImageZoomDialog.vue +0 -84
- package/app/components/content/PageMarkdownCopy.vue +0 -104
- package/app/components/content/imageZoom.ts +0 -25
- package/app/components/mdc/MdcAccordion.vue +0 -67
- package/app/components/mdc/MdcAccordionItem.vue +0 -42
- package/app/components/mdc/MdcApi.vue +0 -159
- package/app/components/mdc/MdcAside.vue +0 -23
- package/app/components/mdc/MdcCallout.vue +0 -61
- package/app/components/mdc/MdcCard.vue +0 -175
- package/app/components/mdc/MdcCards.vue +0 -30
- package/app/components/mdc/MdcCenter.vue +0 -71
- package/app/components/mdc/MdcCodeGroup.vue +0 -197
- package/app/components/mdc/MdcCodeTree.vue +0 -234
- package/app/components/mdc/MdcCollapse.vue +0 -61
- package/app/components/mdc/MdcColumn.vue +0 -70
- package/app/components/mdc/MdcDropcap.vue +0 -84
- package/app/components/mdc/MdcError.vue +0 -23
- package/app/components/mdc/MdcExcerpt.vue +0 -26
- package/app/components/mdc/MdcFigure.vue +0 -85
- package/app/components/mdc/MdcFiles.vue +0 -120
- package/app/components/mdc/MdcIdea.vue +0 -17
- package/app/components/mdc/MdcInfo.vue +0 -17
- package/app/components/mdc/MdcInlineToc.vue +0 -51
- package/app/components/mdc/MdcKbd.vue +0 -10
- package/app/components/mdc/MdcLayout.vue +0 -57
- package/app/components/mdc/MdcNote.vue +0 -17
- package/app/components/mdc/MdcQuiz.vue +0 -241
- package/app/components/mdc/MdcQuizQuestion.vue +0 -221
- package/app/components/mdc/MdcReadMore.vue +0 -70
- package/app/components/mdc/MdcSteps.vue +0 -59
- package/app/components/mdc/MdcSuccess.vue +0 -23
- package/app/components/mdc/MdcTab.vue +0 -17
- package/app/components/mdc/MdcTabs.vue +0 -150
- package/app/components/mdc/MdcTimeline.vue +0 -17
- package/app/components/mdc/MdcTimelineItem.vue +0 -40
- package/app/components/mdc/MdcWarning.vue +0 -23
- package/app/components/mdc/api.utils.ts +0 -132
- package/app/components/mdc/code-tree.utils.ts +0 -22
- package/app/components/mdc/icons.ts +0 -10
- package/app/components/mdc/quiz.utils.ts +0 -38
- package/app/components/prose/ProseA.vue +0 -27
- package/app/components/prose/ProseBlockquote.vue +0 -30
- package/app/components/prose/ProseCode.vue +0 -14
- package/app/components/prose/ProseEm.vue +0 -14
- package/app/components/prose/ProseH1.vue +0 -18
- package/app/components/prose/ProseH2.vue +0 -29
- package/app/components/prose/ProseH3.vue +0 -29
- package/app/components/prose/ProseH4.vue +0 -29
- package/app/components/prose/ProseH5.vue +0 -15
- package/app/components/prose/ProseH6.vue +0 -15
- package/app/components/prose/ProseHr.vue +0 -12
- package/app/components/prose/ProseImg.vue +0 -55
- package/app/components/prose/ProseLi.vue +0 -14
- package/app/components/prose/ProseOl.vue +0 -14
- package/app/components/prose/ProseP.vue +0 -14
- package/app/components/prose/ProsePre.vue +0 -180
- package/app/components/prose/ProseStrong.vue +0 -14
- package/app/components/prose/ProseTable.vue +0 -18
- package/app/components/prose/ProseTbody.vue +0 -14
- package/app/components/prose/ProseTd.vue +0 -14
- package/app/components/prose/ProseTh.vue +0 -14
- package/app/components/prose/ProseThead.vue +0 -14
- package/app/components/prose/ProseTr.vue +0 -14
- package/app/components/prose/ProseUl.vue +0 -14
- package/app/components/site/ModeToggle.vue +0 -81
- package/app/components/site/SiteBanner.vue +0 -97
- package/app/components/site/SiteFooter.vue +0 -90
- package/app/components/site/SiteHeader.vue +0 -371
- package/app/components/site/SiteHeroCode.vue +0 -173
- package/app/components/site/SiteInteractionLayer.vue +0 -42
- package/app/components/site/SiteLocaleSwitcher.vue +0 -190
- package/app/components/site/SiteLogoMark.vue +0 -12
- package/app/components/site/SiteSkipLink.vue +0 -14
- package/app/components/site/SiteSocialLinks.vue +0 -33
- package/app/components/site/header-utils.ts +0 -3
- package/app/components/site/mode-toggle.utils.ts +0 -18
- package/app/components/ui/badge/Badge.vue +0 -28
- package/app/components/ui/badge/index.ts +0 -24
- package/app/components/ui/button/Button.vue +0 -31
- package/app/components/ui/button/index.ts +0 -35
- package/app/components/ui/collapsible/Collapsible.vue +0 -15
- package/app/components/ui/collapsible/CollapsibleContent.vue +0 -25
- package/app/components/ui/collapsible/CollapsibleTrigger.vue +0 -12
- package/app/components/ui/collapsible/index.ts +0 -3
- package/app/components/ui/dropdown-menu/DropdownMenu.vue +0 -15
- package/app/components/ui/dropdown-menu/DropdownMenuContent.vue +0 -50
- package/app/components/ui/dropdown-menu/DropdownMenuItem.vue +0 -41
- package/app/components/ui/dropdown-menu/DropdownMenuRadioGroup.vue +0 -15
- package/app/components/ui/dropdown-menu/DropdownMenuRadioItem.vue +0 -37
- package/app/components/ui/dropdown-menu/DropdownMenuSeparator.vue +0 -23
- package/app/components/ui/dropdown-menu/DropdownMenuTrigger.vue +0 -14
- package/app/components/ui/dropdown-menu/index.ts +0 -7
- package/app/components/ui/kbd/Kbd.vue +0 -23
- package/app/components/ui/kbd/index.ts +0 -21
- package/app/components/ui/scroll-area/ScrollArea.vue +0 -39
- package/app/components/ui/scroll-area/ScrollBar.vue +0 -33
- package/app/components/ui/scroll-area/index.ts +0 -2
- package/app/components/ui/separator/Separator.vue +0 -27
- package/app/components/ui/separator/index.ts +0 -1
- package/app/components/ui/sheet/Sheet.vue +0 -15
- package/app/components/ui/sheet/SheetContent.vue +0 -59
- package/app/components/ui/sheet/SheetDescription.vue +0 -21
- package/app/components/ui/sheet/SheetOverlay.vue +0 -26
- package/app/components/ui/sheet/SheetTitle.vue +0 -21
- package/app/components/ui/sheet/SheetTrigger.vue +0 -12
- package/app/components/ui/sheet/index.ts +0 -5
- package/app/components/ui/tabs/Tabs.vue +0 -24
- package/app/components/ui/tabs/TabsList.vue +0 -26
- package/app/components/ui/tabs/TabsTrigger.vue +0 -28
- package/app/components/ui/tabs/index.ts +0 -3
- package/app/composables/site-navigation.utils.ts +0 -133
- package/app/composables/useCanonicalUrl.ts +0 -9
- package/app/composables/useContentRouteAlternates.ts +0 -35
- package/app/composables/useGinkoAnalytics.ts +0 -52
- package/app/composables/useGinkoDocsConfig.ts +0 -6
- package/app/composables/useGinkoOgImage.ts +0 -20
- package/app/composables/useLocalizedPath.ts +0 -12
- package/app/composables/useLocalizedRouteSwitch.ts +0 -31
- package/app/composables/useMetaKey.ts +0 -18
- package/app/composables/usePageMarkdownActions.ts +0 -79
- package/app/composables/useProseAppearance.ts +0 -24
- package/app/composables/useSchemaJsonLd.ts +0 -25
- package/app/composables/useSiteNavigation.ts +0 -64
- package/app/config/site.utils.ts +0 -36
- package/app/features/docs/components/DocsBreadcrumb.vue +0 -37
- package/app/features/docs/components/DocsContributeLinks.vue +0 -75
- package/app/features/docs/components/DocsMobileToc.vue +0 -108
- package/app/features/docs/components/DocsPageContent.vue +0 -234
- package/app/features/docs/components/DocsPageNav.vue +0 -57
- package/app/features/docs/components/DocsSidebar.vue +0 -145
- package/app/features/docs/components/DocsSidebarDropdown.vue +0 -70
- package/app/features/docs/components/DocsSidebarItem.vue +0 -122
- package/app/features/docs/components/DocsSidebarList.vue +0 -35
- package/app/features/docs/components/DocsSidebarRow.vue +0 -27
- package/app/features/docs/components/DocsSidebarTabs.vue +0 -59
- package/app/features/docs/components/DocsToc.vue +0 -106
- package/app/features/docs/composables/useDocsNavigation.ts +0 -29
- package/app/features/docs/composables/useDocsNavigationData.ts +0 -18
- package/app/features/docs/composables/useRevealActive.ts +0 -58
- package/app/features/docs/composables/useScrollspy.ts +0 -135
- package/app/features/docs/docs-navigation.ts +0 -157
- package/app/features/docs/toc-context.ts +0 -6
- package/app/features/search/command-center.ts +0 -110
- package/app/features/search/components/SiteCommandCenter.vue +0 -359
- package/app/features/search/components/SiteSearchPageHighlight.vue +0 -126
- package/app/features/search/useCommandCenter.ts +0 -292
- package/app/layouts/blog.vue +0 -15
- package/app/layouts/docs.vue +0 -20
- package/app/lib/errors.ts +0 -37
- package/app/lib/schema-org.ts +0 -38
- package/app/pages/blog/[slug].vue +0 -228
- package/app/pages/blog/index.vue +0 -130
- package/app/pages/docs/[...slug].vue +0 -10
- package/app/pages/docs/index.vue +0 -19
- package/app/pages/index.vue +0 -278
- package/app/plugins/ginko-docs-theme.ts +0 -14
- package/app/plugins/ssr-width.ts +0 -6
- package/app/utils/content.ts +0 -67
- package/app/utils/file-icons.ts +0 -90
- package/app/utils/index.ts +0 -7
- package/app/utils/repository.ts +0 -20
- package/components.ts +0 -9
- package/content-collections.ts +0 -89
- package/content.js +0 -200
- package/content.ts +0 -104
- package/i18n/i18n.config.ts +0 -10
- package/i18n/locales.ts +0 -81
- package/i18n/messages/global/banner.ts +0 -8
- package/i18n/messages/global/blog.ts +0 -18
- package/i18n/messages/global/command.ts +0 -49
- package/i18n/messages/global/docs.ts +0 -36
- package/i18n/messages/global/errors.ts +0 -36
- package/i18n/messages/global/feedback.ts +0 -11
- package/i18n/messages/global/index.ts +0 -21
- package/i18n/messages/global/nav.ts +0 -26
- package/i18n/messages/global/site.ts +0 -4
- package/i18n/messages/global/theme.ts +0 -9
- package/i18n/messages/index.ts +0 -20
- package/i18n/messages/localize.ts +0 -35
- package/i18n/routes.ts +0 -33
- package/icon-bundle.ts +0 -116
- package/index.d.ts +0 -37
- package/modules/analytics-boundary.ts +0 -23
- package/modules/feature-routing.ts +0 -68
- package/modules/syntax-highlighting.ts +0 -120
- package/public/fonts/public-sans/LICENSE +0 -93
- package/public/fonts/public-sans/README.md +0 -12
- package/public/fonts/public-sans/public-sans-400-normal-latin.woff +0 -0
- package/public/fonts/public-sans/public-sans-500-normal-latin.woff +0 -0
- package/public/fonts/public-sans/public-sans-600-normal-latin.woff +0 -0
- package/public/fonts/public-sans/public-sans-700-normal-latin.woff +0 -0
- package/runtime/generate-favicons.mjs +0 -124
- package/runtime/server/agent-markdown.ts +0 -19
- package/server/api/_ginko-docs/redirects.get.ts +0 -28
- package/server/mcp/tools/get-page.ts +0 -14
- package/server/mcp/tools/list-pages.ts +0 -10
- package/server/middleware/redirects.ts +0 -22
- package/server/plugins/agent-markdown.ts +0 -6
- package/server/plugins/sitemap-policy.ts +0 -12
- package/server/routes/.well-known/ai-catalog.json.get.ts +0 -10
- package/server/routes/[locale]/blog/rss.xml.get.ts +0 -13
- package/server/routes/blog/rss.xml.get.ts +0 -5
- package/server/routes/mcp/server-card.get.ts +0 -14
- package/server/utils/blog-feed.ts +0 -51
- package/server/utils/feed.ts +0 -70
- package/server/utils/mcp-server-card.ts +0 -45
- package/server/utils/redirects.ts +0 -38
- package/server/utils/redirects.utils.ts +0 -58
- package/server/utils/sitemap.ts +0 -45
- package/shared/route-slugs.ts +0 -5
- package/shared/theme-palettes.ts +0 -37
- package/shared/theme-presets.ts +0 -3
- package/shared/types/app-config.ts +0 -172
- package/shared/types/nuxt-config.ts +0 -14
- package/tags.ts +0 -192
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import { useDocs } from '../composables/useDocs'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Leads to the first docs page of the language. A site without any docs page yet gets a 404 instead: a redirect to
|
|
5
|
+
* `/` would loop, because `/` leads here when the site has no start page.
|
|
6
|
+
*/
|
|
7
|
+
export function toFirstDoc() {
|
|
8
|
+
const first = useDocs().first.value
|
|
9
|
+
if (!first) throw createError({ statusCode: 404, statusMessage: 'No docs page yet: add a Markdown file to content/docs/.' })
|
|
10
|
+
return navigateTo(first, { redirectCode: 302 })
|
|
11
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// Storage keys and the head scripts of the color-mode switch and the banner. Each component adds its own script
|
|
2
|
+
// (useHead with a fixed key, so two toggles on one page add it once), so they also work inside a site's own layout.
|
|
3
|
+
export const COLOR_KEY = 'docs-color-mode'
|
|
4
|
+
export const bannerKey = (id: string) => `docs-banner:${id}`
|
|
5
|
+
|
|
6
|
+
// Runs inline in <head>, before first paint. localStorage can throw (private windows, blocked site data); then the
|
|
7
|
+
// page simply follows the system and shows the banner.
|
|
8
|
+
const guarded = (body: string) => `(function(){try{var d=document.documentElement;${body}}catch(e){}})()`
|
|
9
|
+
|
|
10
|
+
/** Applies the stored light/dark choice (html[data-theme]) before first paint. */
|
|
11
|
+
export function colorInitScript(): string {
|
|
12
|
+
return guarded(`var m=localStorage.getItem(${JSON.stringify(COLOR_KEY)});if(m==='light'||m==='dark')d.setAttribute('data-theme',m);`)
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
/** Marks a dismissed banner (html[data-docs-banner-off]) before first paint, so it does not flash. */
|
|
16
|
+
export function bannerInitScript(id: string): string {
|
|
17
|
+
return guarded(`if(localStorage.getItem(${JSON.stringify(bannerKey(id))})==='1')d.setAttribute('data-docs-banner-off','');`)
|
|
18
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
// Tabs and sections of the side navigation, from the entries' fields. Pure, so the rules have a test.
|
|
2
|
+
import type { NavNode } from '@lupinum/ginko'
|
|
3
|
+
|
|
4
|
+
export interface DocNode extends NavNode {
|
|
5
|
+
section?: string
|
|
6
|
+
badge?: string
|
|
7
|
+
icon?: string
|
|
8
|
+
tab?: string
|
|
9
|
+
children: DocNode[]
|
|
10
|
+
}
|
|
11
|
+
export interface DocTab { title: string; path: string }
|
|
12
|
+
|
|
13
|
+
export interface DocFields { tab?: string; section?: string; badge?: string; icon?: string }
|
|
14
|
+
|
|
15
|
+
/**
|
|
16
|
+
* A root without a tab follows the one before it; a new tab starts without a section; a section runs until the
|
|
17
|
+
* next one. Children always follow their parent's tab and carry no section.
|
|
18
|
+
*/
|
|
19
|
+
export function enrichNav(tree: NavNode[], fieldsOf: (id: string) => DocFields | undefined): DocNode[] {
|
|
20
|
+
let running: string | undefined
|
|
21
|
+
let section: string | undefined
|
|
22
|
+
const enrich = (node: NavNode, tab: string | undefined, root: boolean): DocNode => {
|
|
23
|
+
const data = fieldsOf(node.id ?? '')
|
|
24
|
+
if (root) {
|
|
25
|
+
if (data?.tab && data.tab !== running) section = undefined
|
|
26
|
+
running = data?.tab ?? running
|
|
27
|
+
section = data?.section ?? section
|
|
28
|
+
}
|
|
29
|
+
const own = root ? running : tab
|
|
30
|
+
return {
|
|
31
|
+
...node, tab: own, section: root ? section : undefined, badge: data?.badge, icon: data?.icon,
|
|
32
|
+
children: node.children.map((c) => enrich(c, own, false)),
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
return tree.map((n) => enrich(n, undefined, true))
|
|
36
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
// Small pure helpers of the docs page (edit link, Markdown twin, "open in" links), kept apart for tests.
|
|
2
|
+
|
|
3
|
+
/** Edit link of a page's file. Template placeholders: `{url}`, `{branch}`, `{source}`; default is the GitHub form. */
|
|
4
|
+
export function docsEditUrl(repo: { url: string, branch?: string, editUrl?: string } | undefined, source: string | undefined): string | undefined {
|
|
5
|
+
if (!repo?.url || !source) return undefined
|
|
6
|
+
const values: Record<string, string> = { url: repo.url.replace(/\/+$/, ''), branch: repo.branch ?? 'main', source }
|
|
7
|
+
return (repo.editUrl ?? '{url}/edit/{branch}/{source}').replace(/\{(url|branch|source)\}/g, (_, k: string) => values[k]!)
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
/**
|
|
11
|
+
* Edit link of a page stored on the Ginko platform: its form in the Studio, `<platform>/s/<site>/all/<brick>/<id>`.
|
|
12
|
+
* No platform address (a production build without NUXT_PUBLIC_GINKO_PLATFORM): no link.
|
|
13
|
+
*/
|
|
14
|
+
export function docsStudioUrl(platform: string | undefined, site: string, brick: string, id: string): string | undefined {
|
|
15
|
+
if (!platform) return undefined
|
|
16
|
+
return `${platform.replace(/\/+$/, '')}/s/${[site, 'all', brick, id].map(encodeURIComponent).join('/')}`
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
/**
|
|
20
|
+
* "Report an issue" for a page. Placeholders: `{url}`, `{title}`, `{page}` (the page's address), URL-encoded except
|
|
21
|
+
* `{url}`. GitHub repositories get the GitHub form by default; other hosts need `issueUrl`.
|
|
22
|
+
*/
|
|
23
|
+
export function docsIssueUrl(repo: { url: string, issueUrl?: string } | undefined, title: string, page: string): string | undefined {
|
|
24
|
+
if (!repo?.url) return undefined
|
|
25
|
+
const url = repo.url.replace(/\/+$/, '')
|
|
26
|
+
const template = repo.issueUrl ?? (/^https:\/\/github\.com\//.test(url) ? '{url}/issues/new?title={title}&body={page}' : undefined)
|
|
27
|
+
const values: Record<string, string> = { url, title: encodeURIComponent(title), page: encodeURIComponent(page) }
|
|
28
|
+
return template?.replace(/\{(url|title|page)\}/g, (_, k: string) => values[k]!)
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/** Path of a page's Markdown twin (`/en/docs/x` -> `/en/docs/x.md`, `/` -> `/index.md`). */
|
|
32
|
+
export function docsMarkdownPath(path: string): string {
|
|
33
|
+
const clean = path.replace(/\/+$/, '')
|
|
34
|
+
return `${clean || '/index'}.md`
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
/** A chat the page menu can open the page in (`markdownActions.openIn`). */
|
|
38
|
+
export type DocsAssistant = 'chatgpt' | 'claude'
|
|
39
|
+
|
|
40
|
+
/** Links that open a chat with a prompt pointing at the page's Markdown. */
|
|
41
|
+
export function docsAskLinks(prompt: string): Record<DocsAssistant, string> {
|
|
42
|
+
const q = encodeURIComponent(prompt)
|
|
43
|
+
return { chatgpt: `https://chatgpt.com/?q=${q}`, claude: `https://claude.ai/new?q=${q}` }
|
|
44
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
// Math, mermaid and ```md preview examples for the docs layer. GinkoMarkdown shows their source by default (core stays free of KaTeX);
|
|
2
|
+
// a `components` map wins. Both load lazily, so a page without a formula or a diagram never loads KaTeX or mermaid.
|
|
3
|
+
// Math renders on the server (the HTML holds `.katex`); mermaid renders in the browser.
|
|
4
|
+
import { defineAsyncComponent } from 'vue'
|
|
5
|
+
import DocsExample from '../components/DocsExample.vue'
|
|
6
|
+
import DocsTable from '../components/DocsTable.vue'
|
|
7
|
+
|
|
8
|
+
export const markdownComponents = {
|
|
9
|
+
math: defineAsyncComponent(async () => {
|
|
10
|
+
const [, { Math }] = await Promise.all([import('katex/dist/katex.min.css'), import('@comark/vue/plugins/math')])
|
|
11
|
+
return Math
|
|
12
|
+
}),
|
|
13
|
+
mermaid: defineAsyncComponent(() => import('@comark/vue/plugins/mermaid').then((m) => m.Mermaid)),
|
|
14
|
+
example: DocsExample,
|
|
15
|
+
table: DocsTable,
|
|
16
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
// The table of contents of a ```md preview: ginko-content keeps only the preview's nodes, so an `::inline-toc`
|
|
2
|
+
// inside a preview gets its links from here. Same shape as the page toc: h2 links with their h3 as children.
|
|
3
|
+
import type { MarkdownToc, TocLink } from '@lupinum/ginko'
|
|
4
|
+
|
|
5
|
+
type Node = string | [string, Record<string, unknown>, ...unknown[]]
|
|
6
|
+
const textOf = (node: Node): string => (typeof node === 'string' ? node : (node.slice(2) as Node[]).map(textOf).join(''))
|
|
7
|
+
|
|
8
|
+
export function previewToc(nodes: readonly unknown[]): MarkdownToc {
|
|
9
|
+
const links: TocLink[] = []
|
|
10
|
+
for (const node of nodes as Node[]) {
|
|
11
|
+
if (typeof node === 'string' || (node[0] !== 'h2' && node[0] !== 'h3') || typeof node[1].id !== 'string') continue
|
|
12
|
+
const link: TocLink = { id: node[1].id, depth: node[0] === 'h2' ? 2 : 3, text: textOf(node).trim() }
|
|
13
|
+
const parent = links.at(-1)
|
|
14
|
+
if (link.depth === 3 && parent?.depth === 2) (parent.children ??= []).push(link)
|
|
15
|
+
else links.push(link)
|
|
16
|
+
}
|
|
17
|
+
return { links }
|
|
18
|
+
}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import * as _lupinum_ginko from '@lupinum/ginko';
|
|
2
|
+
import { Locale } from '@lupinum/ginko';
|
|
3
|
+
import * as _lupinum_ginko_internal from '@lupinum/ginko/internal';
|
|
4
|
+
export { components } from '@lupinum/ginko-components/registry';
|
|
5
|
+
|
|
6
|
+
/** The site's locales, main locale first. The same list as `locales` in `defineSite`, as a plain array or a tuple. */
|
|
7
|
+
type Locales = readonly Locale[];
|
|
8
|
+
/** `base`: where the docs live, default `/docs` (e.g. `/handbook` inside a larger site). */
|
|
9
|
+
declare function docsCollection(opts: {
|
|
10
|
+
locales: Locales;
|
|
11
|
+
label?: string;
|
|
12
|
+
max?: number;
|
|
13
|
+
base?: `/${string}`;
|
|
14
|
+
}): _lupinum_ginko.CollectionBrick<{
|
|
15
|
+
readonly title: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
16
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
17
|
+
};
|
|
18
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
19
|
+
readonly optional: true;
|
|
20
|
+
};
|
|
21
|
+
/** Starts a group in the side navigation under this heading; the pages after it belong to it until the next one. */
|
|
22
|
+
readonly section: _lupinum_ginko_internal.TextField & {
|
|
23
|
+
readonly optional: true;
|
|
24
|
+
};
|
|
25
|
+
/** Nests the entry under another doc in the side navigation and the breadcrumbs. */
|
|
26
|
+
readonly parent: _lupinum_ginko_internal.RefField & {
|
|
27
|
+
multiple?: false;
|
|
28
|
+
} & {
|
|
29
|
+
readonly to: "docs";
|
|
30
|
+
readonly optional: true;
|
|
31
|
+
};
|
|
32
|
+
/** Section tab above the side navigation; a page without one follows the tab of the page before it. Children follow their parent. */
|
|
33
|
+
readonly tab: _lupinum_ginko_internal.TextField & {
|
|
34
|
+
readonly optional: true;
|
|
35
|
+
readonly max: 30;
|
|
36
|
+
};
|
|
37
|
+
/** A short label next to the entry in the side navigation, e.g. "New". */
|
|
38
|
+
readonly badge: _lupinum_ginko_internal.TextField & {
|
|
39
|
+
readonly optional: true;
|
|
40
|
+
readonly max: 20;
|
|
41
|
+
};
|
|
42
|
+
/** An icon name such as `lucide:book-open` (any installed Iconify set), shown before the title in the side navigation. */
|
|
43
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
44
|
+
readonly optional: true;
|
|
45
|
+
readonly max: 60;
|
|
46
|
+
readonly translate: false;
|
|
47
|
+
};
|
|
48
|
+
readonly slug: _lupinum_ginko_internal.SlugField & {
|
|
49
|
+
readonly from: "title";
|
|
50
|
+
};
|
|
51
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
52
|
+
readonly profile: "page";
|
|
53
|
+
};
|
|
54
|
+
}, Record<string, `/${string}/[slug]`>>;
|
|
55
|
+
/**
|
|
56
|
+
* The optional start page: one Markdown file `content/home[.<locale>].md`. The frontmatter fills the hero (title,
|
|
57
|
+
* description, install command, up to two links) and the feature grid; the text below the frontmatter follows them and
|
|
58
|
+
* may use every component. Without it, `/` opens the first docs page. Add `home: { <main>: '/', <l>: '/<l>' }` to `pages`.
|
|
59
|
+
*/
|
|
60
|
+
declare function docsHome(): _lupinum_ginko.SingleBrick<{
|
|
61
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
62
|
+
readonly max: 120;
|
|
63
|
+
};
|
|
64
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
65
|
+
readonly optional: true;
|
|
66
|
+
readonly max: 400;
|
|
67
|
+
};
|
|
68
|
+
/** A command shown with a copy button, e.g. `pnpm add @lupinum/ginko`. */
|
|
69
|
+
readonly install: _lupinum_ginko_internal.TextField & {
|
|
70
|
+
readonly optional: true;
|
|
71
|
+
readonly max: 200;
|
|
72
|
+
readonly translate: false;
|
|
73
|
+
};
|
|
74
|
+
/** Buttons under the description; the first one is the main one. */
|
|
75
|
+
readonly links: _lupinum_ginko_internal.ListField<{
|
|
76
|
+
readonly label: _lupinum_ginko_internal.TextField & {
|
|
77
|
+
readonly max: 40;
|
|
78
|
+
};
|
|
79
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
80
|
+
readonly max: 300;
|
|
81
|
+
};
|
|
82
|
+
}> & Omit<{
|
|
83
|
+
readonly itemLabel: "Link";
|
|
84
|
+
readonly fields: {
|
|
85
|
+
readonly label: _lupinum_ginko_internal.TextField & {
|
|
86
|
+
readonly max: 40;
|
|
87
|
+
};
|
|
88
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
89
|
+
readonly max: 300;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
readonly max: 2;
|
|
93
|
+
readonly default: readonly [];
|
|
94
|
+
}, "fields">;
|
|
95
|
+
readonly features: _lupinum_ginko_internal.ListField<{
|
|
96
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
97
|
+
readonly optional: true;
|
|
98
|
+
readonly max: 60;
|
|
99
|
+
readonly translate: false;
|
|
100
|
+
};
|
|
101
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
102
|
+
readonly max: 80;
|
|
103
|
+
};
|
|
104
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
105
|
+
readonly max: 300;
|
|
106
|
+
};
|
|
107
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
108
|
+
readonly optional: true;
|
|
109
|
+
readonly max: 300;
|
|
110
|
+
};
|
|
111
|
+
}> & Omit<{
|
|
112
|
+
readonly itemLabel: "Feature";
|
|
113
|
+
readonly fields: {
|
|
114
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
115
|
+
readonly optional: true;
|
|
116
|
+
readonly max: 60;
|
|
117
|
+
readonly translate: false;
|
|
118
|
+
};
|
|
119
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
120
|
+
readonly max: 80;
|
|
121
|
+
};
|
|
122
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
123
|
+
readonly max: 300;
|
|
124
|
+
};
|
|
125
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
126
|
+
readonly optional: true;
|
|
127
|
+
readonly max: 300;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
readonly max: 12;
|
|
131
|
+
readonly default: readonly [];
|
|
132
|
+
}, "fields">;
|
|
133
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
134
|
+
readonly profile: "page";
|
|
135
|
+
readonly optional: true;
|
|
136
|
+
};
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* The optional blog: `{ posts, authors }`, spread into `bricks` in ginko.config.ts. Posts live at
|
|
140
|
+
* /blog/<slug> (main locale unprefixed, `/<l>/blog/<slug>` otherwise) and come out newest first.
|
|
141
|
+
* Authors have no page; a post names them in `authors`. Files: `content/posts/<n>.<name>[.<locale>].md`
|
|
142
|
+
* and `content/authors/<name>[.<locale>].yml`. Add `blog: blogPages({ locales })` to `pages` as well.
|
|
143
|
+
*/
|
|
144
|
+
declare function blogCollections(opts: {
|
|
145
|
+
locales: Locales;
|
|
146
|
+
max?: number;
|
|
147
|
+
}): {
|
|
148
|
+
posts: _lupinum_ginko.CollectionBrick<{
|
|
149
|
+
readonly title: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
150
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
151
|
+
};
|
|
152
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
153
|
+
readonly optional: true;
|
|
154
|
+
};
|
|
155
|
+
readonly date: _lupinum_ginko_internal.DateField & Omit<_lupinum_ginko_internal.DateField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
156
|
+
default?: string | undefined;
|
|
157
|
+
};
|
|
158
|
+
readonly authors: _lupinum_ginko_internal.RefField & {
|
|
159
|
+
multiple: true;
|
|
160
|
+
} & {
|
|
161
|
+
readonly to: "authors";
|
|
162
|
+
readonly optional: true;
|
|
163
|
+
};
|
|
164
|
+
readonly image: _lupinum_ginko_internal.ImageField & {
|
|
165
|
+
readonly optional: true;
|
|
166
|
+
};
|
|
167
|
+
readonly tags: _lupinum_ginko_internal.ListField<{
|
|
168
|
+
readonly tag: _lupinum_ginko_internal.TextField & {
|
|
169
|
+
readonly max: 40;
|
|
170
|
+
};
|
|
171
|
+
}> & Omit<{
|
|
172
|
+
readonly itemLabel: "Tag";
|
|
173
|
+
readonly fields: {
|
|
174
|
+
readonly tag: _lupinum_ginko_internal.TextField & {
|
|
175
|
+
readonly max: 40;
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
readonly max: 10;
|
|
179
|
+
readonly optional: true;
|
|
180
|
+
}, "fields">;
|
|
181
|
+
readonly slug: _lupinum_ginko_internal.SlugField & {
|
|
182
|
+
readonly from: "title";
|
|
183
|
+
};
|
|
184
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
185
|
+
readonly profile: "page";
|
|
186
|
+
};
|
|
187
|
+
}, Record<string, "/blog/[slug]">>;
|
|
188
|
+
authors: _lupinum_ginko.CollectionBrick<{
|
|
189
|
+
readonly name: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
190
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
191
|
+
};
|
|
192
|
+
readonly role: _lupinum_ginko_internal.TextField & {
|
|
193
|
+
readonly optional: true;
|
|
194
|
+
};
|
|
195
|
+
readonly avatar: _lupinum_ginko_internal.ImageField & {
|
|
196
|
+
readonly optional: true;
|
|
197
|
+
};
|
|
198
|
+
/** Shown as a link on the author's name. */
|
|
199
|
+
readonly url: _lupinum_ginko_internal.TextField & {
|
|
200
|
+
readonly format: "url";
|
|
201
|
+
readonly optional: true;
|
|
202
|
+
};
|
|
203
|
+
}, undefined>;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* The optional changelog: one page at /changelog with one entry per release, newest first. Entries have no
|
|
207
|
+
* page of their own, the page links to each by anchor. Files: `content/changelog/<name>[.<locale>].md`
|
|
208
|
+
* with `version` and `date` in the frontmatter (a dot in the name would read as a language: use `v1-2-0.md`). Add `changelog: changelogPages({ locales })` to `pages` as well.
|
|
209
|
+
*/
|
|
210
|
+
declare function changelogCollection(opts?: {
|
|
211
|
+
max?: number;
|
|
212
|
+
}): _lupinum_ginko.CollectionBrick<{
|
|
213
|
+
readonly version: _lupinum_ginko_internal.TextField & {
|
|
214
|
+
readonly max: 40;
|
|
215
|
+
readonly translate: false;
|
|
216
|
+
};
|
|
217
|
+
readonly date: _lupinum_ginko_internal.DateField & Omit<_lupinum_ginko_internal.DateField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
218
|
+
default?: string | undefined;
|
|
219
|
+
};
|
|
220
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
221
|
+
readonly profile: "page";
|
|
222
|
+
};
|
|
223
|
+
}, undefined>;
|
|
224
|
+
/** The list pages by locale, for `pages` in ginko.config.ts: the sitemap and the static build know them from there. */
|
|
225
|
+
declare const blogPages: (opts: {
|
|
226
|
+
locales: Locales;
|
|
227
|
+
}) => Record<string, "/blog">;
|
|
228
|
+
declare const changelogPages: (opts: {
|
|
229
|
+
locales: Locales;
|
|
230
|
+
}) => Record<string, "/changelog">;
|
|
231
|
+
|
|
232
|
+
export { blogCollections, blogPages, changelogCollection, changelogPages, docsCollection, docsHome };
|
package/dist/config.d.ts
ADDED
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
import * as _lupinum_ginko from '@lupinum/ginko';
|
|
2
|
+
import { Locale } from '@lupinum/ginko';
|
|
3
|
+
import * as _lupinum_ginko_internal from '@lupinum/ginko/internal';
|
|
4
|
+
export { components } from '@lupinum/ginko-components/registry';
|
|
5
|
+
|
|
6
|
+
/** The site's locales, main locale first. The same list as `locales` in `defineSite`, as a plain array or a tuple. */
|
|
7
|
+
type Locales = readonly Locale[];
|
|
8
|
+
/** `base`: where the docs live, default `/docs` (e.g. `/handbook` inside a larger site). */
|
|
9
|
+
declare function docsCollection(opts: {
|
|
10
|
+
locales: Locales;
|
|
11
|
+
label?: string;
|
|
12
|
+
max?: number;
|
|
13
|
+
base?: `/${string}`;
|
|
14
|
+
}): _lupinum_ginko.CollectionBrick<{
|
|
15
|
+
readonly title: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
16
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
17
|
+
};
|
|
18
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
19
|
+
readonly optional: true;
|
|
20
|
+
};
|
|
21
|
+
/** Starts a group in the side navigation under this heading; the pages after it belong to it until the next one. */
|
|
22
|
+
readonly section: _lupinum_ginko_internal.TextField & {
|
|
23
|
+
readonly optional: true;
|
|
24
|
+
};
|
|
25
|
+
/** Nests the entry under another doc in the side navigation and the breadcrumbs. */
|
|
26
|
+
readonly parent: _lupinum_ginko_internal.RefField & {
|
|
27
|
+
multiple?: false;
|
|
28
|
+
} & {
|
|
29
|
+
readonly to: "docs";
|
|
30
|
+
readonly optional: true;
|
|
31
|
+
};
|
|
32
|
+
/** Section tab above the side navigation; a page without one follows the tab of the page before it. Children follow their parent. */
|
|
33
|
+
readonly tab: _lupinum_ginko_internal.TextField & {
|
|
34
|
+
readonly optional: true;
|
|
35
|
+
readonly max: 30;
|
|
36
|
+
};
|
|
37
|
+
/** A short label next to the entry in the side navigation, e.g. "New". */
|
|
38
|
+
readonly badge: _lupinum_ginko_internal.TextField & {
|
|
39
|
+
readonly optional: true;
|
|
40
|
+
readonly max: 20;
|
|
41
|
+
};
|
|
42
|
+
/** An icon name such as `lucide:book-open` (any installed Iconify set), shown before the title in the side navigation. */
|
|
43
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
44
|
+
readonly optional: true;
|
|
45
|
+
readonly max: 60;
|
|
46
|
+
readonly translate: false;
|
|
47
|
+
};
|
|
48
|
+
readonly slug: _lupinum_ginko_internal.SlugField & {
|
|
49
|
+
readonly from: "title";
|
|
50
|
+
};
|
|
51
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
52
|
+
readonly profile: "page";
|
|
53
|
+
};
|
|
54
|
+
}, Record<string, `/${string}/[slug]`>>;
|
|
55
|
+
/**
|
|
56
|
+
* The optional start page: one Markdown file `content/home[.<locale>].md`. The frontmatter fills the hero (title,
|
|
57
|
+
* description, install command, up to two links) and the feature grid; the text below the frontmatter follows them and
|
|
58
|
+
* may use every component. Without it, `/` opens the first docs page. Add `home: { <main>: '/', <l>: '/<l>' }` to `pages`.
|
|
59
|
+
*/
|
|
60
|
+
declare function docsHome(): _lupinum_ginko.SingleBrick<{
|
|
61
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
62
|
+
readonly max: 120;
|
|
63
|
+
};
|
|
64
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
65
|
+
readonly optional: true;
|
|
66
|
+
readonly max: 400;
|
|
67
|
+
};
|
|
68
|
+
/** A command shown with a copy button, e.g. `pnpm add @lupinum/ginko`. */
|
|
69
|
+
readonly install: _lupinum_ginko_internal.TextField & {
|
|
70
|
+
readonly optional: true;
|
|
71
|
+
readonly max: 200;
|
|
72
|
+
readonly translate: false;
|
|
73
|
+
};
|
|
74
|
+
/** Buttons under the description; the first one is the main one. */
|
|
75
|
+
readonly links: _lupinum_ginko_internal.ListField<{
|
|
76
|
+
readonly label: _lupinum_ginko_internal.TextField & {
|
|
77
|
+
readonly max: 40;
|
|
78
|
+
};
|
|
79
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
80
|
+
readonly max: 300;
|
|
81
|
+
};
|
|
82
|
+
}> & Omit<{
|
|
83
|
+
readonly itemLabel: "Link";
|
|
84
|
+
readonly fields: {
|
|
85
|
+
readonly label: _lupinum_ginko_internal.TextField & {
|
|
86
|
+
readonly max: 40;
|
|
87
|
+
};
|
|
88
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
89
|
+
readonly max: 300;
|
|
90
|
+
};
|
|
91
|
+
};
|
|
92
|
+
readonly max: 2;
|
|
93
|
+
readonly default: readonly [];
|
|
94
|
+
}, "fields">;
|
|
95
|
+
readonly features: _lupinum_ginko_internal.ListField<{
|
|
96
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
97
|
+
readonly optional: true;
|
|
98
|
+
readonly max: 60;
|
|
99
|
+
readonly translate: false;
|
|
100
|
+
};
|
|
101
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
102
|
+
readonly max: 80;
|
|
103
|
+
};
|
|
104
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
105
|
+
readonly max: 300;
|
|
106
|
+
};
|
|
107
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
108
|
+
readonly optional: true;
|
|
109
|
+
readonly max: 300;
|
|
110
|
+
};
|
|
111
|
+
}> & Omit<{
|
|
112
|
+
readonly itemLabel: "Feature";
|
|
113
|
+
readonly fields: {
|
|
114
|
+
readonly icon: _lupinum_ginko_internal.TextField & {
|
|
115
|
+
readonly optional: true;
|
|
116
|
+
readonly max: 60;
|
|
117
|
+
readonly translate: false;
|
|
118
|
+
};
|
|
119
|
+
readonly title: _lupinum_ginko_internal.TextField & {
|
|
120
|
+
readonly max: 80;
|
|
121
|
+
};
|
|
122
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
123
|
+
readonly max: 300;
|
|
124
|
+
};
|
|
125
|
+
readonly href: _lupinum_ginko_internal.TextField & {
|
|
126
|
+
readonly optional: true;
|
|
127
|
+
readonly max: 300;
|
|
128
|
+
};
|
|
129
|
+
};
|
|
130
|
+
readonly max: 12;
|
|
131
|
+
readonly default: readonly [];
|
|
132
|
+
}, "fields">;
|
|
133
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
134
|
+
readonly profile: "page";
|
|
135
|
+
readonly optional: true;
|
|
136
|
+
};
|
|
137
|
+
}>;
|
|
138
|
+
/**
|
|
139
|
+
* The optional blog: `{ posts, authors }`, spread into `bricks` in ginko.config.ts. Posts live at
|
|
140
|
+
* /blog/<slug> (main locale unprefixed, `/<l>/blog/<slug>` otherwise) and come out newest first.
|
|
141
|
+
* Authors have no page; a post names them in `authors`. Files: `content/posts/<n>.<name>[.<locale>].md`
|
|
142
|
+
* and `content/authors/<name>[.<locale>].yml`. Add `blog: blogPages({ locales })` to `pages` as well.
|
|
143
|
+
*/
|
|
144
|
+
declare function blogCollections(opts: {
|
|
145
|
+
locales: Locales;
|
|
146
|
+
max?: number;
|
|
147
|
+
}): {
|
|
148
|
+
posts: _lupinum_ginko.CollectionBrick<{
|
|
149
|
+
readonly title: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
150
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
151
|
+
};
|
|
152
|
+
readonly description: _lupinum_ginko_internal.LongTextField & {
|
|
153
|
+
readonly optional: true;
|
|
154
|
+
};
|
|
155
|
+
readonly date: _lupinum_ginko_internal.DateField & Omit<_lupinum_ginko_internal.DateField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
156
|
+
default?: string | undefined;
|
|
157
|
+
};
|
|
158
|
+
readonly authors: _lupinum_ginko_internal.RefField & {
|
|
159
|
+
multiple: true;
|
|
160
|
+
} & {
|
|
161
|
+
readonly to: "authors";
|
|
162
|
+
readonly optional: true;
|
|
163
|
+
};
|
|
164
|
+
readonly image: _lupinum_ginko_internal.ImageField & {
|
|
165
|
+
readonly optional: true;
|
|
166
|
+
};
|
|
167
|
+
readonly tags: _lupinum_ginko_internal.ListField<{
|
|
168
|
+
readonly tag: _lupinum_ginko_internal.TextField & {
|
|
169
|
+
readonly max: 40;
|
|
170
|
+
};
|
|
171
|
+
}> & Omit<{
|
|
172
|
+
readonly itemLabel: "Tag";
|
|
173
|
+
readonly fields: {
|
|
174
|
+
readonly tag: _lupinum_ginko_internal.TextField & {
|
|
175
|
+
readonly max: 40;
|
|
176
|
+
};
|
|
177
|
+
};
|
|
178
|
+
readonly max: 10;
|
|
179
|
+
readonly optional: true;
|
|
180
|
+
}, "fields">;
|
|
181
|
+
readonly slug: _lupinum_ginko_internal.SlugField & {
|
|
182
|
+
readonly from: "title";
|
|
183
|
+
};
|
|
184
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
185
|
+
readonly profile: "page";
|
|
186
|
+
};
|
|
187
|
+
}, Record<string, "/blog/[slug]">>;
|
|
188
|
+
authors: _lupinum_ginko.CollectionBrick<{
|
|
189
|
+
readonly name: _lupinum_ginko_internal.TextField & Omit<_lupinum_ginko_internal.TextField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
190
|
+
default?: (string | Partial<Record<string, string>>) | undefined;
|
|
191
|
+
};
|
|
192
|
+
readonly role: _lupinum_ginko_internal.TextField & {
|
|
193
|
+
readonly optional: true;
|
|
194
|
+
};
|
|
195
|
+
readonly avatar: _lupinum_ginko_internal.ImageField & {
|
|
196
|
+
readonly optional: true;
|
|
197
|
+
};
|
|
198
|
+
/** Shown as a link on the author's name. */
|
|
199
|
+
readonly url: _lupinum_ginko_internal.TextField & {
|
|
200
|
+
readonly format: "url";
|
|
201
|
+
readonly optional: true;
|
|
202
|
+
};
|
|
203
|
+
}, undefined>;
|
|
204
|
+
};
|
|
205
|
+
/**
|
|
206
|
+
* The optional changelog: one page at /changelog with one entry per release, newest first. Entries have no
|
|
207
|
+
* page of their own, the page links to each by anchor. Files: `content/changelog/<name>[.<locale>].md`
|
|
208
|
+
* with `version` and `date` in the frontmatter (a dot in the name would read as a language: use `v1-2-0.md`). Add `changelog: changelogPages({ locales })` to `pages` as well.
|
|
209
|
+
*/
|
|
210
|
+
declare function changelogCollection(opts?: {
|
|
211
|
+
max?: number;
|
|
212
|
+
}): _lupinum_ginko.CollectionBrick<{
|
|
213
|
+
readonly version: _lupinum_ginko_internal.TextField & {
|
|
214
|
+
readonly max: 40;
|
|
215
|
+
readonly translate: false;
|
|
216
|
+
};
|
|
217
|
+
readonly date: _lupinum_ginko_internal.DateField & Omit<_lupinum_ginko_internal.DateField, "type" | "label" | "pos" | "retired" | "default"> & {
|
|
218
|
+
default?: string | undefined;
|
|
219
|
+
};
|
|
220
|
+
readonly body: _lupinum_ginko_internal.MarkdownField & {
|
|
221
|
+
readonly profile: "page";
|
|
222
|
+
};
|
|
223
|
+
}, undefined>;
|
|
224
|
+
/** The list pages by locale, for `pages` in ginko.config.ts: the sitemap and the static build know them from there. */
|
|
225
|
+
declare const blogPages: (opts: {
|
|
226
|
+
locales: Locales;
|
|
227
|
+
}) => Record<string, "/blog">;
|
|
228
|
+
declare const changelogPages: (opts: {
|
|
229
|
+
locales: Locales;
|
|
230
|
+
}) => Record<string, "/changelog">;
|
|
231
|
+
|
|
232
|
+
export { blogCollections, blogPages, changelogCollection, changelogPages, docsCollection, docsHome };
|