feat: changes of vitepress folder structure and openapi sidebar, including openapi dynamic pages

This commit is contained in:
h+
2025-01-16 23:15:45 +01:00
parent a2885e8d64
commit 79dbc8dffe
10 changed files with 8183 additions and 5453 deletions
+33 -4
View File
@@ -1,6 +1,11 @@
import { fileURLToPath, URL } from 'node:url'
import yaml from 'vite-plugin-yaml'
import { defineConfig } from 'vitepress'
import { useSidebar, useOpenapi } from 'vitepress-openapi'
import spec from '../public/openapi.json' assert { type: 'json' }
const sidebar = useSidebar({ spec, collapsible: true })
// https://vitepress.dev/reference/site-config
export default defineConfig({
lang: 'en-US',
@@ -311,10 +316,34 @@ export default defineConfig({
collapsed: true,
link: '/api-reference/api/overview',
items: [
{
text: 'Overview',
link: '/api-reference/api/overview'
}
...sidebar.generateSidebarGroups({
/**
* Optionally, you can filter paths by a prefix. Default is an empty string.
*/
startsWith: 'operations',
/**
* Optionally, you can specify if the sidebar items are collapsible. Default is true.
*/
collapsible: true,
/**
* Optionally, you can specify a depth for the sidebar items. Default is 6, which is the maximum VitePress sidebar depth.
*/
depth: 6,
/**
* Optionally, you can specify a link prefix for all generated sidebar items. Default is `/operations/`.
*/
linkPrefix: '/api-reference/api/operations/',
/**
* Optionally, you can specify a template for the sidebar items. You can see the default value
* in `sidebarItemTemplate` function in the `useSidebar` composable.
*/
//sidebarItemTemplate: (method: string, path: string): string => `[${method}] ${path}`,
}),
]
}
]
+5 -7
View File
@@ -13,9 +13,8 @@ import "./style.css";
import "./tailwind.postcss";
import "vitepress-openapi/dist/style.css";
// Load the OpenAPI spec
import { load } from 'js-yaml'
import rawSpec from './openapi.yml?raw'
// @ts-ignore
import spec from '../../public/openapi.json' assert { type: 'json' }
// Import components
import Card from "./components/Card.vue";
@@ -35,13 +34,12 @@ export default {
extends: DefaultTheme,
Layout: Landing,
enhanceApp({ app, router, siteData }) {
const spec = load(rawSpec)
const openapi = useOpenapi({
spec,
base: "/docs/api-reference/api/overview/",
label: "API",
base: "/docs/api-reference/api/operations/",
label: "API"
});
// Use theme.enhanceApp with both app and openapi
theme.enhanceApp({ app, openapi });
app.component("Card", Card);
app.component("CardGroup", CardGroup);
File diff suppressed because it is too large Load Diff
+48
View File
@@ -0,0 +1,48 @@
---
aside: false
outline: false
title: API Reference
toc: false
---
<script setup lang="ts">
import { useData } from 'vitepress'
import { useTheme, generateCodeSample } from 'vitepress-openapi'
const { isDark } = useData()
useTheme({
codeSamples: {
langs: [
'bruno',
...useTheme().getCodeSamplesLangs(),
],
availableLanguages: [
{
lang: 'bruno',
label: 'Bruno',
highlighter: 'plaintext',
},
...useTheme().getCodeSamplesAvailableLanguages(),
],
defaultLang: 'bruno',
generator: (lang, request) => {
if (lang === 'bruno') {
return generateBruRequest(request)
}
return generateCodeSample(lang, request)
},
}
})
function generateBruRequest(request) {
// ... existing generateBruRequest code ...
}
</script>
<style>
/* ... existing styles ... */
</style>
<OASpec :isDark="isDark" />
@@ -0,0 +1,62 @@
---
aside: false
outline: false
title: API Operation - {{ $params.operation }}
toc: false
---
<script setup lang="ts">
import { useData } from 'vitepress'
import { useTheme, generateCodeSample } from 'vitepress-openapi'
const { params, isDark } = useData()
const operation = params.value.operation
const themeConfig = {
codeSamples: {
langs: [
'bruno',
...useTheme().getCodeSamplesLangs(),
],
availableLanguages: [
{
lang: 'bruno',
label: 'Bruno',
highlighter: 'plaintext',
},
...useTheme().getCodeSamplesAvailableLanguages(),
],
defaultLang: 'bruno',
generator: (lang, request) => {
if (lang === 'bruno') {
return generateBrunoRequest(request) || ''
}
return generateCodeSample(lang, request) || ''
},
}
}
function generateBrunoRequest(request) {
if (!request) return ''
const { method, url, headers, body } = request
let brunoScript = `${method} ${url}\n`
if (headers && Object.keys(headers).length) {
brunoScript += '\nHeaders\n'
for (const [key, value] of Object.entries(headers)) {
brunoScript += `${key}: ${value}\n`
}
}
if (body) {
brunoScript += '\nBody\n'
brunoScript += typeof body === 'string' ? body : JSON.stringify(body, null, 2)
}
return brunoScript
}
useTheme(themeConfig)
</script>
<OAOperation :operationId="operation" :isDark="isDark" />
@@ -0,0 +1,21 @@
import fs from 'fs'
import spec from '../../../public/openapi.json' assert { type: 'json' }
export default {
async paths() {
// Extract all operationIds
const operations: string[] = []
Object.entries(spec.paths).forEach(([path, pathItem]: [string, Record<string, any>]) => {
Object.entries(pathItem).forEach(([method, operation]: [string, { operationId?: string }]) => {
if (operation?.operationId) {
operations.push(operation.operationId)
}
})
})
// Return the params array
return operations.map(op => ({
params: { operation: op }
}))
}
}
-99
View File
@@ -1,99 +0,0 @@
---
aside: false
outline: false
title: API
toc: false
---
<script setup lang="ts">
import { useData } from 'vitepress'
import { useTheme, generateCodeSample } from 'vitepress-openapi'
const { isDark } = useData()
useTheme({
codeSamples: {
// List of languages to show in Code Samples section.
langs: [
'bruno',
...useTheme().getCodeSamplesLangs(),
],
// List of available languages to select from.
availableLanguages: [
{
lang: 'bruno',
label: 'Bruno',
highlighter: 'plaintext',
},
...useTheme().getCodeSamplesAvailableLanguages(),
],
defaultLang: 'bruno',
generator: (lang, request) => {
if (lang === 'bruno') {
return generateBruRequest(request)
}
return generateCodeSample(lang, request)
},
},
})
function generateBruRequest(request) {
const { url, method, headers, body, query } = request;
const methodLower = method.toLowerCase();
const queryString = query && Object.keys(query).length
? `${url}?${new URLSearchParams(query).toString()}`
: url;
const headersSection = headers && Object.keys(headers).length
? `headers {\n${Object.entries(headers)
.map(([key, value]) => ` ${key}: ${value}`)
.join('\n')}\n}`
: '';
const bodySection = body
? `body {\n ${JSON.stringify(body, null, 2).replace(/\n/g, '\n ')}\n}`
: '';
const bruRequest = `${methodLower} {
url: ${queryString}
}
${headersSection}
${bodySection}
`;
return bruRequest
.trim()
.replace(/\n{2,}/g, '\n\n') // Remove extra newlines
}
</script>
<style>
:deep(.vp-doc a),
:deep([openapi] a),
:deep(a.grid) {
border-bottom: none !important;
text-decoration: none !important;
}
:deep(.vp-doc a:hover),
:deep([openapi] a:hover),
:deep(a.grid:hover) {
color: var(--vp-c-brand-1);
border-bottom: none !important;
text-decoration: none !important;
}
/* Additional specific override for grid links */
:deep(a.grid.items-center) {
border-bottom: none !important;
text-decoration: none !important;
}
</style>
<OASpec :isDark="isDark" />
File diff suppressed because it is too large Load Diff
+1 -1
View File
@@ -25,7 +25,7 @@
"dev": "vitepress dev docs",
"build": "vitepress build docs",
"preview": "vitepress preview docs",
"transform-compose": "tsx docs/.vitepress/data/transform-compose.ts"
"transform-openapi": "tsx scripts/convert-openapi.ts"
},
"dependencies": {
"@vueuse/core": "^12.2.0",
+25
View File
@@ -0,0 +1,25 @@
const yaml = require('js-yaml')
const fs = require('fs')
const path = require('path')
const convertYamlToJson = () => {
try {
// Read the YAML file from the public folder
const yamlPath = path.resolve(__dirname, '../docs/public/openapi.yml')
const yamlContent = fs.readFileSync(yamlPath, 'utf8')
// Parse YAML to JSON
const jsonContent = yaml.load(yamlContent)
// Write JSON to public folder next to the YAML file
const jsonPath = path.resolve(__dirname, '../docs/public/openapi.json')
fs.writeFileSync(jsonPath, JSON.stringify(jsonContent, null, 2))
console.log('Successfully converted YAML to JSON')
console.log(`Output file: ${jsonPath}`)
} catch (error) {
console.error('Error converting YAML to JSON:', error)
}
}
convertYamlToJson()