@feathersdev/websites 0.0.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (76) hide show
  1. package/app/assets/icons/feathers.svg +12 -0
  2. package/app/assets/icons/pinion.svg +3 -0
  3. package/app/assets/icons/talon.svg +3 -0
  4. package/app/components/CodePreview.vue +139 -0
  5. package/app/components/CodeSnippet.vue +119 -0
  6. package/app/components/Discord.vue +33 -0
  7. package/app/components/DocsPage.vue +11 -0
  8. package/app/components/DocsSearch.vue +62 -0
  9. package/app/components/DocsSearchModal.vue +831 -0
  10. package/app/components/DocsSidebar.vue +43 -0
  11. package/app/components/DocsTiles.vue +121 -0
  12. package/app/components/FooterMain.vue +46 -0
  13. package/app/components/HeroProduct.vue +148 -0
  14. package/app/components/MoonSurface.vue +1599 -0
  15. package/app/components/NewsletterSubscribe.vue +21 -0
  16. package/app/components/SidebarMenuSection.vue +45 -0
  17. package/app/components/TableOfContents.vue +221 -0
  18. package/app/components/ThemeToggle.vue +10 -0
  19. package/app/components/Titles.vue +39 -0
  20. package/app/components/TocTree.vue +49 -0
  21. package/app/components/content/BlueskyEmbed.vue +92 -0
  22. package/app/components/content/CodeWrapper.vue +10 -0
  23. package/app/components/content/ProseA.vue +19 -0
  24. package/app/components/content/ProseAlert.vue +11 -0
  25. package/app/components/content/ProseBlockquote.vue +11 -0
  26. package/app/components/content/ProseEm.vue +5 -0
  27. package/app/components/content/ProseH1.vue +17 -0
  28. package/app/components/content/ProseH2.vue +17 -0
  29. package/app/components/content/ProseH3.vue +17 -0
  30. package/app/components/content/ProseH4.vue +17 -0
  31. package/app/components/content/ProseH5.vue +17 -0
  32. package/app/components/content/ProseH6.vue +17 -0
  33. package/app/components/content/ProseHr.vue +3 -0
  34. package/app/components/content/ProseImg.vue +37 -0
  35. package/app/components/content/ProseLi.vue +3 -0
  36. package/app/components/content/ProseOl.vue +5 -0
  37. package/app/components/content/ProseP.vue +3 -0
  38. package/app/components/content/ProsePre.vue +49 -0
  39. package/app/components/content/ProsePre2.vue +69 -0
  40. package/app/components/content/ProseScript.vue +37 -0
  41. package/app/components/content/ProseStrong.vue +5 -0
  42. package/app/components/content/ProseTable.vue +7 -0
  43. package/app/components/content/ProseTbody.vue +5 -0
  44. package/app/components/content/ProseTd.vue +5 -0
  45. package/app/components/content/ProseTh.vue +5 -0
  46. package/app/components/content/ProseThead.vue +5 -0
  47. package/app/components/content/ProseTr.vue +5 -0
  48. package/app/components/content/ProseUl.vue +5 -0
  49. package/app/composables/useGlobalSearch.ts +22 -0
  50. package/app/composables/useTheme.ts +17 -0
  51. package/app/layouts/default.vue +46 -0
  52. package/app/layouts/docs.vue +62 -0
  53. package/app/layouts/page.vue +11 -0
  54. package/app/pages/help.vue +19 -0
  55. package/app/pages/privacy.vue +30 -0
  56. package/app/pages/tos.vue +28 -0
  57. package/content/pages/privacy.md +152 -0
  58. package/content/pages/tos.md +133 -0
  59. package/content/products/1-auth.yaml +13 -0
  60. package/content/products/2-feathers.yaml +13 -0
  61. package/content/products/3-pinion.yaml +13 -0
  62. package/content/products/4-daisyui-kit.yaml +14 -0
  63. package/content/products/lofi.yaml +14 -0
  64. package/content.config.ts +36 -0
  65. package/nuxt.config.ts +102 -0
  66. package/package.json +33 -0
  67. package/public/img/bird-comms.png +0 -0
  68. package/public/img/bird-yellow.svg +125 -0
  69. package/public/img/logo-auth-white.svg +22 -0
  70. package/public/img/logos/feathersdev-white.svg +24 -0
  71. package/public/img/logos/talon-auth-white.svg +19 -0
  72. package/public/img/planet-yellow.svg +31 -0
  73. package/public/img/rock-lg.svg +6 -0
  74. package/public/img/rock-md.svg +6 -0
  75. package/public/img/top_background.svg +56 -0
  76. package/vitest.config.ts +7 -0
@@ -0,0 +1,21 @@
1
+ <template>
2
+ <div>
3
+ <Titles title="Subscribe to our Newsletter" description="Get new Feathers content as it becomes available." />
4
+
5
+ <form
6
+ action="https://buttondown.email/api/emails/embed-subscribe/feathers"
7
+ method="post"
8
+ target="popupwindow"
9
+ onsubmit="window.open('https://buttondown.email/feathers', 'popupwindow')"
10
+ class="embeddable-buttondown-form flex flex-col"
11
+ >
12
+ <Join class="join-vertical md:join-horizontal mt-8">
13
+ <Label xl join floating input class="bg-white/10 py-3 px-3 w-full">
14
+ <Text>Enter your email</Text>
15
+ <Input id="bd-email" type="email" name="email" placeholder="Enter your email" />
16
+ </Label>
17
+ <Button join primary type="submit" value="Subscribe" name="Submit" size="xl"> Subscribe </Button>
18
+ </Join>
19
+ </form>
20
+ </div>
21
+ </template>
@@ -0,0 +1,45 @@
1
+ <script setup lang="ts">
2
+ import type { MenuItem } from '../../content.config.schema'
3
+
4
+ defineProps<{
5
+ section?: MenuItem
6
+ }>()
7
+ </script>
8
+
9
+ <template>
10
+ <Menu class="w-full">
11
+ <li v-if="!section?.noDivider" class="mx-0" />
12
+ <MenuTitle v-if="section && !section.path" class="flex flex-row items-center gap-3">
13
+ <Icon v-if="section.icon" :name="section.icon" :class="section.iconClasses" />
14
+ {{ section.title }}
15
+ </MenuTitle>
16
+
17
+ <template v-for="link in section?.children" :key="link.title">
18
+ <!-- Menu item with children - render submenu -->
19
+ <MenuItem v-if="link.children">
20
+ <MenuExpand :close-on-click-outside="false">
21
+ <MenuExpandToggle class="flex flex-row items-center">
22
+ <Icon v-if="link.icon" :name="link.icon" class="w-5 h-5 mr-1" />
23
+ <Text class="grow">
24
+ {{ link.title }}
25
+ </Text>
26
+ <Badge v-if="link.meta?.new" sm accent class="ml-2"> new </Badge>
27
+ </MenuExpandToggle>
28
+ <!-- Recursively render child menu -->
29
+ <SidebarMenuSection :children="link.children" :no-divider="true" />
30
+ </MenuExpand>
31
+ </MenuItem>
32
+
33
+ <!-- Regular menu item without children -->
34
+ <MenuItem v-else>
35
+ <NuxtLink :to="link.path" exact-active-class="menu-active" class="flex flex-row items-center">
36
+ <Icon v-if="link.icon" :name="link.icon" class="w-5 h-5 mr-1" />
37
+ <Text class="grow">
38
+ {{ link.title }}
39
+ </Text>
40
+ <Badge v-if="link.meta?.new" sm accent class="ml-2"> new </Badge>
41
+ </NuxtLink>
42
+ </MenuItem>
43
+ </template>
44
+ </Menu>
45
+ </template>
@@ -0,0 +1,221 @@
1
+ <script setup lang="ts">
2
+ import TocTree from './TocTree.vue'
3
+
4
+ const pageRoute = useRoute()
5
+
6
+ // Interface for our TOC structure
7
+ interface TocLink {
8
+ id: string
9
+ text: string
10
+ level: number
11
+ children: TocLink[]
12
+ }
13
+
14
+ // Create a reactive reference for our TOC links
15
+ const tocLinks = ref<TocLink[]>([])
16
+ const pageTitle = ref('Table of Contents')
17
+
18
+ // Function to scan the page for headings and build the TOC
19
+ function scanHeadings() {
20
+ // Wait for the DOM to be ready
21
+ if (typeof document === 'undefined') {
22
+ return
23
+ }
24
+
25
+ // Find all headings (h1-h6) with IDs
26
+ const headings = document.querySelectorAll('h1[id], h2[id], h3[id], h4[id], h5[id], h6[id]')
27
+ const links: TocLink[] = []
28
+
29
+ // Get the page title from the first h1
30
+ const h1 = document.querySelector('h1')
31
+ if (h1) {
32
+ pageTitle.value = h1.textContent || 'Table of Contents'
33
+ }
34
+
35
+ // If no headings found, it might mean content hasn't loaded yet
36
+ // But also check if we have at least an h1 to ensure page content exists
37
+ if (headings.length === 0 && !h1) {
38
+ return
39
+ }
40
+
41
+ // Process each heading
42
+ headings.forEach((heading) => {
43
+ // Skip the first h1 as it's the page title
44
+ if (heading.tagName === 'H1' && heading === h1) {
45
+ return
46
+ }
47
+
48
+ const id = heading.id
49
+ const level = Number.parseInt(heading.tagName.substring(1), 10)
50
+
51
+ // Create a TOC link
52
+ const link: TocLink = { id, text: heading.textContent || '', level, children: [] }
53
+ links.push(link)
54
+ })
55
+
56
+ // Build a robust hierarchical structure in a single pass
57
+ const hierarchicalLinks: TocLink[] = []
58
+ const parents: TocLink[] = []
59
+
60
+ for (const link of links) {
61
+ // Always ensure children is initialized
62
+ if (!('children' in link) || !Array.isArray(link.children)) {
63
+ (link as TocLink).children = []
64
+ }
65
+ // Find the last parent of lower level
66
+ while (parents.length > 0 && parents[parents.length - 1]!.level >= link.level) {
67
+ parents.pop()
68
+ }
69
+ if (parents.length === 0) {
70
+ hierarchicalLinks.push(link)
71
+ }
72
+ else {
73
+ parents[parents.length - 1]!.children.push(link)
74
+ }
75
+ parents.push(link)
76
+ }
77
+ tocLinks.value = hierarchicalLinks
78
+ }
79
+
80
+ // Check if we're in the browser
81
+ let observer: MutationObserver | null = null
82
+
83
+ onMounted(() => {
84
+ // Initial scan with a small delay to ensure content is rendered
85
+ setTimeout(() => {
86
+ scanHeadings()
87
+ }, 100)
88
+
89
+ // Re-scan when route changes (for SPA navigation)
90
+ watch(() => pageRoute.path, () => {
91
+ // Clear current TOC immediately when route changes
92
+ tocLinks.value = []
93
+ pageTitle.value = 'Table of Contents'
94
+
95
+ // Use multiple strategies to ensure content is fully loaded
96
+ nextTick(() => {
97
+ // First attempt after nextTick
98
+ scanHeadings()
99
+
100
+ // Second attempt with a delay to handle slow rendering
101
+ setTimeout(() => {
102
+ scanHeadings()
103
+ }, 200)
104
+
105
+ // Third attempt with a longer delay as fallback
106
+ setTimeout(() => {
107
+ scanHeadings()
108
+ }, 500)
109
+ })
110
+ })
111
+
112
+ // Also watch for hash changes to update active states
113
+ watch(() => pageRoute.hash, () => {
114
+ // No need to rescan, just update active states
115
+ })
116
+
117
+ // Watch for DOM mutations affecting headings
118
+ observer = new MutationObserver((mutations) => {
119
+ let shouldRescan = false
120
+ for (const mutation of mutations) {
121
+ if (
122
+ Array.from(mutation.addedNodes).some(isHeadingNode)
123
+ || Array.from(mutation.removedNodes).some(isHeadingNode)
124
+ || (mutation.type === 'attributes' && isHeadingNode(mutation.target))
125
+ ) {
126
+ shouldRescan = true
127
+ break
128
+ }
129
+ }
130
+ if (shouldRescan) {
131
+ // Add a small delay to allow DOM to stabilize
132
+ setTimeout(() => {
133
+ scanHeadings()
134
+ }, 50)
135
+ }
136
+ })
137
+ observer.observe(document.body, {
138
+ childList: true,
139
+ subtree: true,
140
+ attributes: true,
141
+ attributeFilter: ['id'],
142
+ })
143
+ })
144
+
145
+ onBeforeUnmount(() => {
146
+ if (observer) {
147
+ observer.disconnect()
148
+ observer = null
149
+ }
150
+ })
151
+
152
+ function isHeadingNode(node: Node | EventTarget): boolean {
153
+ if (!(node instanceof HTMLElement)) {
154
+ return false
155
+ }
156
+ return /^H[1-6]$/.test(node.tagName)
157
+ }
158
+
159
+ function checkActive(hash: string) {
160
+ return pageRoute.hash === hash ? 'active' : null
161
+ }
162
+
163
+ function toTop() {
164
+ window.scrollTo({
165
+ top: 0,
166
+ behavior: 'smooth',
167
+ })
168
+ setTimeout(() => {
169
+ window.location.hash = ''
170
+ }, 600)
171
+ }
172
+
173
+ function toBottom() {
174
+ window.scrollTo({
175
+ top: document.body.scrollHeight,
176
+ behavior: 'smooth',
177
+ })
178
+ }
179
+
180
+ function scrollToHeading(id: string) {
181
+ const el = document.getElementById(id)
182
+ if (el) {
183
+ el.scrollIntoView({ behavior: 'smooth', block: 'start' })
184
+ // Update the hash after the scroll
185
+ history.replaceState(null, '', `#${id}`)
186
+ }
187
+ }
188
+ </script>
189
+
190
+ <template>
191
+ <Flex col>
192
+ <Menu v-if="tocLinks.length" class="md:menu-sm xl:menu-md w-full">
193
+ <NuxtLink href="#" custom>
194
+ <template #default="{ route }">
195
+ <MenuItem class="text-base-content cursor-pointer">
196
+ <a
197
+ class="flex flex-row items-center justify-between font-semibold bg-neutral/30"
198
+ :class="checkActive(route?.hash || '')" @click="toTop"
199
+ >
200
+ {{ pageTitle }}
201
+ <Icon name="feather:arrow-up" class="text-base" />
202
+ </a>
203
+ </MenuItem>
204
+ </template>
205
+ </NuxtLink>
206
+
207
+ <TocTree
208
+ :links="tocLinks"
209
+ :check-active="checkActive"
210
+ :scroll-to-heading="scrollToHeading"
211
+ />
212
+
213
+ <MenuItem>
214
+ <a class="flex flex-row items-center justify-between hover:bg-accent/25 mt-6" @click="toBottom">
215
+ scroll to bottom
216
+ <Icon name="feather:arrow-down" class="text-base" />
217
+ </a>
218
+ </MenuItem>
219
+ </Menu>
220
+ </Flex>
221
+ </template>
@@ -0,0 +1,10 @@
1
+ <script setup lang="ts">
2
+ const { isDark, toggleTheme } = useTheme()
3
+ </script>
4
+
5
+ <template>
6
+ <Button ghost circle aria-label="Toggle theme" @click="toggleTheme">
7
+ <Icon v-if="isDark" name="heroicons:moon" size="24" />
8
+ <Icon v-else name="heroicons:sun" size="24" />
9
+ </Button>
10
+ </template>
@@ -0,0 +1,39 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ superTitle?: string
4
+ title: string,
5
+ subTitle?: string
6
+ description?: string
7
+ }>()
8
+
9
+ const slots = defineSlots<{
10
+ superTitle?: string
11
+ title: string,
12
+ subTitle?: string
13
+ description?: string
14
+ }>()
15
+ </script>
16
+
17
+ <template>
18
+ <Flex col items-center class="gap-4">
19
+ <slot v-if="slots.superTitle" name="superTitle" />
20
+ <Text v-if="superTitle && !slots.superTitle" center size="md" class="text-balance md:text-lg">
21
+ {{ superTitle }}
22
+ </Text>
23
+
24
+ <slot v-if="slots.title" name="title" />
25
+ <Text v-if="title && !slots.title" center size="4xl" class="text-balance md:text-5xl">
26
+ {{ title }}
27
+ </Text>
28
+
29
+ <slot v-if="slots.subTitle" name="subTitle" />
30
+ <Text v-if="subTitle && !slots.subTitle" center size="md" class="text-balance md:text-lg">
31
+ {{ subTitle }}
32
+ </Text>
33
+
34
+ <slot v-if="slots.description" name="description" />
35
+ <Text v-if="description && !slots.description" center size="md" class="text-balance md:text-lg">
36
+ {{ description }}
37
+ </Text>
38
+ </Flex>
39
+ </template>
@@ -0,0 +1,49 @@
1
+ <script setup lang="ts">
2
+ import type { PropType } from 'vue'
3
+
4
+ interface TocLink {
5
+ id: string
6
+ text: string
7
+ level: number
8
+ children: TocLink[]
9
+ }
10
+
11
+ defineProps({
12
+ links: {
13
+ type: Array as PropType<TocLink[]>,
14
+ required: true
15
+ },
16
+ checkActive: {
17
+ type: Function as PropType<(hash: string) => string | null>,
18
+ required: true
19
+ },
20
+ scrollToHeading: {
21
+ type: Function as PropType<(id: string) => void>,
22
+ required: true
23
+ }
24
+ })
25
+ </script>
26
+
27
+ <template>
28
+ <Menu v-if="links && links.length" class="w-full">
29
+ <MenuItem v-for="link in links" :key="link.id">
30
+ <NuxtLink :href="`#${link.id}`" custom>
31
+ <template #default="{ route }">
32
+ <a
33
+ class="block px-2 py-1 text-base-content hover:bg-accent/10 rounded cursor-pointer"
34
+ :class="checkActive(route?.hash || '')"
35
+ @click.prevent="scrollToHeading(link.id)"
36
+ >
37
+ {{ link.text }}
38
+ </a>
39
+ </template>
40
+ </NuxtLink>
41
+ <TocTree
42
+ v-if="link.children && link.children.length"
43
+ :links="link.children"
44
+ :check-active="checkActive"
45
+ :scroll-to-heading="scrollToHeading"
46
+ />
47
+ </MenuItem>
48
+ </Menu>
49
+ </template>
@@ -0,0 +1,92 @@
1
+ <script setup lang="ts">
2
+ interface Props {
3
+ uri: string
4
+ cid: string
5
+ }
6
+
7
+ const props = defineProps<Props>()
8
+ const embedContainer = ref<HTMLElement | null>(null)
9
+
10
+ // Extract the post URL from the AT URI
11
+ // Format: at://did:plc:xxx/app.bsky.feed.post/postId
12
+ const getPostUrl = () => {
13
+ const parts = props.uri.split('/')
14
+ const did = parts[2]
15
+ const postId = parts[parts.length - 1]
16
+ return `https://bsky.app/profile/${did}/post/${postId}`
17
+ }
18
+
19
+ const postUrl = getPostUrl()
20
+
21
+ onMounted(() => {
22
+ // Load the Bluesky embed script
23
+ const scriptId = 'bluesky-embed-script'
24
+
25
+ const initializeEmbed = () => {
26
+ // Wait a bit longer and check multiple times
27
+ let attempts = 0
28
+ const maxAttempts = 10
29
+
30
+ const checkAndScan = () => {
31
+ attempts++
32
+
33
+ if ((window as any).bluesky?.scan) {
34
+ console.log('Bluesky scan function found, triggering...')
35
+ ;(window as any).bluesky.scan()
36
+ } else if (attempts < maxAttempts) {
37
+ console.log(`Waiting for Bluesky script... attempt ${attempts}`)
38
+ setTimeout(checkAndScan, 200)
39
+ } else {
40
+ console.error('Bluesky embed script did not load properly')
41
+ }
42
+ }
43
+
44
+ setTimeout(checkAndScan, 100)
45
+ }
46
+
47
+ if (!document.getElementById(scriptId)) {
48
+ const script = document.createElement('script')
49
+ script.id = scriptId
50
+ script.src = 'https://embed.bsky.app/static/embed.js'
51
+ script.async = true
52
+ script.charset = 'utf-8'
53
+
54
+ script.onload = () => {
55
+ console.log('Bluesky embed script loaded')
56
+ initializeEmbed()
57
+ }
58
+
59
+ script.onerror = () => {
60
+ console.error('Failed to load Bluesky embed script')
61
+ }
62
+
63
+ document.head.appendChild(script)
64
+ } else {
65
+ initializeEmbed()
66
+ }
67
+ })
68
+ </script>
69
+
70
+ <template>
71
+ <ClientOnly>
72
+ <div class="bluesky-embed-wrapper my-6 rounded-lg" ref="embedContainer">
73
+ <blockquote
74
+ class="bluesky-embed"
75
+ :data-bluesky-uri="uri"
76
+ :data-bluesky-cid="cid"
77
+ data-bluesky-embed-color-mode="dark"
78
+ >
79
+ <p lang="en">
80
+ Loading Bluesky post...
81
+ <a :href="postUrl" target="_blank" rel="noopener noreferrer">View on Bluesky</a>
82
+ </p>
83
+ </blockquote>
84
+ </div>
85
+ </ClientOnly>
86
+ </template>
87
+
88
+ <style scoped>
89
+ .bluesky-embed-wrapper :deep(iframe) {
90
+ border-radius: 0.7rem !important;
91
+ }
92
+ </style>
@@ -0,0 +1,10 @@
1
+ <template>
2
+ <Collapse arrow toggle class="mb-8 rounded-b-xl rounded-t-none bg-base-200 p-0">
3
+ <CollapseTitle class="text-lg font-medium">
4
+ Code Example
5
+ </CollapseTitle>
6
+ <CollapseContent class="overflow-hidden">
7
+ <slot />
8
+ </CollapseContent>
9
+ </Collapse>
10
+ </template>
@@ -0,0 +1,19 @@
1
+ <script setup lang="ts">
2
+ defineProps({
3
+ href: {
4
+ type: String,
5
+ default: '',
6
+ },
7
+ target: {
8
+ type: String,
9
+ default: undefined,
10
+ required: false,
11
+ },
12
+ })
13
+ </script>
14
+
15
+ <template>
16
+ <NuxtLink :href="href" :target="target" class="daisy-link link-primary">
17
+ <slot />
18
+ </NuxtLink>
19
+ </template>
@@ -0,0 +1,11 @@
1
+ <script setup lang="ts">
2
+ defineProps<{
3
+ type: string
4
+ }>()
5
+ </script>
6
+
7
+ <template>
8
+ <Alert class="not-prose" v-bind="$props">
9
+ <slot />
10
+ </Alert>
11
+ </template>
@@ -0,0 +1,11 @@
1
+ <template>
2
+ <Alert>
3
+ <slot />
4
+ </Alert>
5
+ </template>
6
+
7
+ <style>
8
+ .alert p {
9
+ margin: 0;
10
+ }
11
+ </style>
@@ -0,0 +1,5 @@
1
+ <template>
2
+ <em>
3
+ <slot />
4
+ </em>
5
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h1)))
8
+ </script>
9
+
10
+ <template>
11
+ <h1 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h1>
17
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h2)))
8
+ </script>
9
+
10
+ <template>
11
+ <h2 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h2>
17
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h3)))
8
+ </script>
9
+
10
+ <template>
11
+ <h3 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h3>
17
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h4)))
8
+ </script>
9
+
10
+ <template>
11
+ <h4 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h4>
17
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h5)))
8
+ </script>
9
+
10
+ <template>
11
+ <h5 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h5>
17
+ </template>
@@ -0,0 +1,17 @@
1
+ <script setup lang="ts">
2
+ import { computed, useRuntimeConfig } from '#imports';
3
+
4
+ const props = defineProps<{ id?: string }>()
5
+
6
+ const { headings } = useRuntimeConfig().public.mdc
7
+ const generate = computed(() => props.id && ((typeof headings?.anchorLinks === 'boolean' && headings?.anchorLinks === true) || (typeof headings?.anchorLinks === 'object' && headings?.anchorLinks?.h6)))
8
+ </script>
9
+
10
+ <template>
11
+ <h6 :id="props.id">
12
+ <a v-if="id || generate" :href="`#${props.id}`">
13
+ <slot />
14
+ </a>
15
+ <slot v-else />
16
+ </h6>
17
+ </template>
@@ -0,0 +1,3 @@
1
+ <template>
2
+ <hr>
3
+ </template>