vitepress-theme-oai 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md ADDED
@@ -0,0 +1,50 @@
1
+ # vitepress-theme-oai
2
+
3
+ Installable VitePress theme extracted from the Motion documentation.
4
+
5
+ ## Install
6
+
7
+ ```sh
8
+ npm install vitepress-theme-oai vitepress vue
9
+ ```
10
+
11
+ The theme includes:
12
+
13
+ - the VitePress default theme extension used by the Motion docs
14
+ - Motion/OAI typography, navigation, sidebar, document, table, code, Mermaid, and home-page styles
15
+ - a global `NextSteps` component
16
+ - the `aside-outline-after` Copy page action
17
+
18
+ ## Use The Theme
19
+
20
+ Create or update `.vitepress/theme/index.ts` in your VitePress project:
21
+
22
+ ```ts
23
+ export { default } from 'vitepress-theme-oai'
24
+ ```
25
+
26
+ Then keep the package inside Vite's SSR transform pipeline from `.vitepress/config.mts`:
27
+
28
+ ```ts
29
+ import { defineConfig } from 'vitepress'
30
+
31
+ export default defineConfig({
32
+ vite: {
33
+ ssr: {
34
+ noExternal: ['vitepress-theme-oai']
35
+ }
36
+ }
37
+ })
38
+ ```
39
+
40
+ ## Mermaid
41
+
42
+ The theme contains Mermaid CSS fixes, but it does not install or configure a Mermaid Markdown plugin. If your docs use Mermaid diagrams, keep using your preferred VitePress Mermaid integration.
43
+
44
+ ## Develop
45
+
46
+ ```sh
47
+ npm install
48
+ npm run docs:dev
49
+ npm run docs:build
50
+ ```
package/package.json ADDED
@@ -0,0 +1,32 @@
1
+ {
2
+ "name": "vitepress-theme-oai",
3
+ "version": "0.1.0",
4
+ "description": "Installable VitePress theme extracted from the Motion documentation.",
5
+ "type": "module",
6
+ "files": [
7
+ "theme",
8
+ "README.md"
9
+ ],
10
+ "exports": {
11
+ ".": {
12
+ "import": "./theme/index.js"
13
+ },
14
+ "./style.css": "./theme/style.css",
15
+ "./components/*": "./theme/components/*",
16
+ "./theme/*": "./theme/*"
17
+ },
18
+ "scripts": {
19
+ "docs:dev": "vitepress dev docs",
20
+ "docs:build": "vitepress build docs",
21
+ "docs:preview": "vitepress preview docs"
22
+ },
23
+ "peerDependencies": {
24
+ "vitepress": "^2.0.0-alpha.12",
25
+ "vue": "^3.5.20"
26
+ },
27
+ "devDependencies": {
28
+ "vitepress": "^2.0.0-alpha.12",
29
+ "vue": "^3.5.20"
30
+ },
31
+ "license": "AGPL-3.0-only"
32
+ }
@@ -0,0 +1,54 @@
1
+ <script setup lang="ts">
2
+ import { useData } from 'vitepress'
3
+
4
+ const { page } = useData()
5
+
6
+ const markdownPages = import.meta.glob('/**/*.md', {
7
+ query: '?raw',
8
+ import: 'default'
9
+ })
10
+
11
+ function markdownLoader(relativePath: string) {
12
+ const normalizedPath = relativePath.replace(/\\/g, '/').replace(/^\/+/, '')
13
+ const candidates = [
14
+ `/${normalizedPath}`,
15
+ `/docs/${normalizedPath}`,
16
+ ]
17
+
18
+ return candidates
19
+ .map(candidate => markdownPages[candidate])
20
+ .find(loader => typeof loader === 'function')
21
+ }
22
+
23
+ async function copyPage() {
24
+ try {
25
+ const loader = markdownLoader(page.value.relativePath)
26
+ const markdown = typeof loader === 'function' ? await loader() : null
27
+
28
+ if (typeof markdown === 'string') {
29
+ await navigator.clipboard.writeText(markdown)
30
+ return
31
+ }
32
+
33
+ await navigator.clipboard.writeText(window.location.href)
34
+ } catch {}
35
+ }
36
+ </script>
37
+
38
+ <template>
39
+ <div class="motion-aside-actions">
40
+ <button
41
+ class="motion-aside-action"
42
+ type="button"
43
+ @click="copyPage"
44
+ >
45
+ <svg viewBox="0 0 16 16" aria-hidden="true">
46
+ <path
47
+ fill="currentColor"
48
+ d="M10.5 1.5a2 2 0 0 1 2 2V9h-1.5V3.5a.5.5 0 0 0-.5-.5H5V1.5zm-5 4a2 2 0 0 0-2 2v5a2 2 0 0 0 2 2h5a2 2 0 0 0 2-2v-5a2 2 0 0 0-2-2zm0 1.5h5a.5.5 0 0 1 .5.5v5a.5.5 0 0 1-.5.5h-5a.5.5 0 0 1-.5-.5v-5a.5.5 0 0 1 .5-.5"
49
+ />
50
+ </svg>
51
+ <span>Copy page</span>
52
+ </button>
53
+ </div>
54
+ </template>
@@ -0,0 +1,64 @@
1
+ <script setup lang="ts">
2
+ type NextStepIcon =
3
+ | 'bolt'
4
+ | 'box'
5
+ | 'book'
6
+ | 'code'
7
+ | 'network'
8
+ | 'play'
9
+ | 'tool'
10
+
11
+ interface NextStepItem {
12
+ title: string
13
+ description: string
14
+ href: string
15
+ icon?: NextStepIcon
16
+ }
17
+
18
+ defineProps<{
19
+ items: NextStepItem[]
20
+ }>()
21
+
22
+ const iconPaths: Record<NextStepIcon, string> = {
23
+ bolt: 'M15.24 3.486v.002l-1.056 4.517h5.823c1.726 0 2.596 2.021 1.518 3.3l-.002.003-9.308 10.965-.002.002c-1.397 1.656-3.922.223-3.454-1.76v-.003l1.057-4.517H3.993c-1.726 0-2.596-2.021-1.519-3.3l.003-.003 9.308-10.965.002-.002c1.397-1.656 3.922-.223 3.454 1.76Zm-1.95-.444-1.34 5.735a.998.998 0 0 0 .973 1.226h7.074a.04.04 0 0 1 .003.01.045.045 0 0 1-.004.005l-9.287 10.94 1.341-5.735a.998.998 0 0 0-.973-1.226H4.003a.041.041 0 0 1-.003-.01l.004-.005 9.287-10.94Z',
24
+ box: 'M12.5 3.444a1 1 0 0 0-1 0l-6.253 3.61 6.768 3.807 6.955-3.682-6.47-3.735Zm7.16 5.632L13 12.602v7.666l6.16-3.556a1 1 0 0 0 .5-.867V9.076ZM11 20.268v-7.683L4.34 8.839v7.006a1 1 0 0 0 .5.867L11 20.268Zm-.5-18.557a3 3 0 0 1 3 0l6.66 3.846a3 3 0 0 1 1.5 2.598v7.69a3 3 0 0 1-1.5 2.598L13.5 22.29a3 3 0 0 1-3 0l-6.66-3.846a3 3 0 0 1-1.5-2.598v-7.69a3 3 0 0 1 1.5-2.598L10.5 1.71Z',
25
+ book: 'M5 4a3 3 0 0 1 3-3h10a1 1 0 0 1 1 1v17a1 1 0 0 1-1 1H8a1 1 0 1 0 0 2h10a1 1 0 1 1 0 2H8a3 3 0 0 1-3-3V4Zm3-1a1 1 0 0 0-1 1v14.17A2.98 2.98 0 0 1 8 18h9V3H8Zm2 4a1 1 0 0 1 1-1h4a1 1 0 1 1 0 2h-4a1 1 0 0 1-1-1Z',
26
+ code: 'M14.447 7.106a1 1 0 0 1 .447 1.341l-4 8a1 1 0 1 1-1.788-.894l4-8a1 1 0 0 1 1.341-.447ZM6.6 7.2a1 1 0 0 1 .2 1.4L4.25 12l2.55 3.4a1 1 0 0 1-1.6 1.2l-3-4a1 1 0 0 1 0-1.2l3-4a1 1 0 0 1 1.4-.2Zm10.8 0a1 1 0 0 1 1.4.2l3 4a1 1 0 0 1 0 1.2l-3 4a1 1 0 0 1-1.6-1.2l2.55-3.4-2.55-3.4a1 1 0 0 1 .2-1.4Z',
27
+ network: 'M6 4a3 3 0 1 1 2.83 4H8v2.5h8V8h-.83a3.001 3.001 0 1 1 0-2H17a1 1 0 0 1 1 1v4.5a1 1 0 0 1-1 1h-4v3.67a3.001 3.001 0 1 1-2 0V12.5H7a1 1 0 0 1-1-1V8h-.17A3.001 3.001 0 0 1 6 4Zm0 2a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm12 0a1 1 0 1 0 0-2 1 1 0 0 0 0 2Zm-6 15a1 1 0 1 0 0-2 1 1 0 0 0 0 2Z',
28
+ play: 'M5 4.9c0-1.65 1.79-2.68 3.22-1.86l10.31 5.95c1.43.83 1.43 2.89 0 3.72L8.22 18.66C6.79 19.49 5 18.46 5 16.81V4.9Zm2.2-.13a.15.15 0 0 0-.2.13v11.91c0 .12.13.2.24.14l10.3-5.96a.16.16 0 0 0 0-.27L7.2 4.77Z',
29
+ tool: 'M20.4 5.6a5.5 5.5 0 0 1-6.97 6.97l-7.22 7.22a2.5 2.5 0 1 1-3.54-3.54l7.22-7.22A5.5 5.5 0 0 1 16.86 2.1a1 1 0 0 1 .36 1.64l-2.5 2.5 3.03 3.03 2.5-2.5a1 1 0 0 1 1.64.36Zm-2.94 5.02a3.5 3.5 0 0 0 2.27-1.5l-1.27 1.27a1 1 0 0 1-1.42 0l-4.44-4.44a1 1 0 0 1 0-1.42l1.27-1.27a3.5 3.5 0 0 0-2.28 5.55 1 1 0 0 1-.1 1.25l-7.4 7.4a.5.5 0 1 0 .7.7l7.4-7.4a1 1 0 0 1 1.25-.1 3.5 3.5 0 0 0 2.04.16Z'
30
+ }
31
+
32
+ const chevronPath =
33
+ 'M9.293 7.293a1 1 0 0 1 1.414 0l4 4a1 1 0 0 1 0 1.414l-4 4a1 1 0 0 1-1.414-1.414L12.586 12 9.293 8.707a1 1 0 0 1 0-1.414Z'
34
+
35
+ function iconPath(icon: NextStepIcon | undefined) {
36
+ return iconPaths[icon ?? 'book']
37
+ }
38
+ </script>
39
+
40
+ <template>
41
+ <div class="motion-next-steps not-prose">
42
+ <a
43
+ v-for="item in items"
44
+ :key="item.href"
45
+ class="motion-next-step"
46
+ :href="item.href"
47
+ >
48
+ <span class="motion-next-step-icon" aria-hidden="true">
49
+ <svg viewBox="0 0 24 24" fill="currentColor">
50
+ <path fill-rule="evenodd" clip-rule="evenodd" :d="iconPath(item.icon)" />
51
+ </svg>
52
+ </span>
53
+ <span class="motion-next-step-body">
54
+ <span class="motion-next-step-title">
55
+ <span>{{ item.title }}</span>
56
+ <svg class="motion-next-step-chevron" viewBox="0 0 24 24" fill="currentColor" aria-hidden="true">
57
+ <path fill-rule="evenodd" clip-rule="evenodd" :d="chevronPath" />
58
+ </svg>
59
+ </span>
60
+ <span class="motion-next-step-description">{{ item.description }}</span>
61
+ </span>
62
+ </a>
63
+ </div>
64
+ </template>
package/theme/index.js ADDED
@@ -0,0 +1,17 @@
1
+ // https://vitepress.dev/guide/custom-theme
2
+ import DefaultTheme from 'vitepress/theme'
3
+ import { h } from 'vue'
4
+ import AsideActions from './components/AsideActions.vue'
5
+ import NextSteps from './components/NextSteps.vue'
6
+ import './style.css'
7
+
8
+ export default {
9
+ extends: DefaultTheme,
10
+ enhanceApp({ app }) {
11
+ app.component('NextSteps', NextSteps)
12
+ },
13
+ Layout: () =>
14
+ h(DefaultTheme.Layout, null, {
15
+ 'aside-outline-after': () => h(AsideActions)
16
+ })
17
+ }