Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 1 addition & 2 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -15,5 +15,4 @@ openapi.json
# Changelog maintained in apps/docs/src/data/changelog.ts only
**/CHANGELOG.md

webi-bot.js
.vite-ssg-temp
webi-bot.js
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ The docs site is a custom Vue app that pulls API docs from the SDK via a custom
# Dev server — http://localhost:3333
pnpm run docs:dev

# Generate docs JSON + build static site
# Generate docs JSON + build the site
pnpm run docs:build

# Preview the production build
Expand Down
5 changes: 2 additions & 3 deletions apps/docs/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
"type": "module",
"scripts": {
"dev": "vite --port 3333",
"build": "vue-tsc -b && vite-ssg build",
"build": "vue-tsc -b && vite build",
"preview": "vite preview --port 3333",
"lint": "eslint src --max-warnings 0 --ext .ts,.tsx,.vue --config ../../eslint.config.js",
"lint:fix": "eslint src --fix --ext .ts,.tsx,.vue --config ../../eslint.config.js"
Expand All @@ -23,11 +23,10 @@
"@types/prismjs": "^1.26.0",
"@unhead/vue": "^2.1.4",
"@vercel/functions": "^3.4.2",
"@vitejs/plugin-vue": "^5.0.0",
"@vitejs/plugin-vue": "^6.0.4",
"beasties": "^0.4.1",
"typescript": "^5.6.0",
"vite": "^5.0.0",
"vite-ssg": "^28.3.0",
"vue-tsc": "^2.0.0"
}
}
2 changes: 1 addition & 1 deletion apps/docs/public/docs/latest/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"meta": {
"generator": "fluxer-docgen",
"version": "1",
"date": 1771464068532
"date": 1771466540218
},
"package": "@fluxerjs/core",
"version": "1.1.8",
Expand Down
2 changes: 1 addition & 1 deletion apps/docs/public/docs/v1.1.8/main.json
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
"meta": {
"generator": "fluxer-docgen",
"version": "1",
"date": 1771464068532
"date": 1771466540218
},
"package": "@fluxerjs/core",
"version": "1.1.8",
Expand Down
3 changes: 2 additions & 1 deletion apps/docs/src/components/SponsorBanner.vue
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,8 @@
aria-label="Sponsor Fluxer.js on GitHub Sponsors">
<span class="sponsor-heart" aria-hidden="true">♥</span>
<span class="sponsor-text">
<strong>Support Fluxer.js</strong> — Sponsor or donate on GitHub to help keep the project going
<strong>Support Fluxer.js</strong> — Sponsor or donate on GitHub to help keep the project
going
</span>
<span class="sponsor-cta">Sponsor →</span>
</a>
Expand Down
54 changes: 14 additions & 40 deletions apps/docs/src/main.ts
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import { ViteSSG } from 'vite-ssg';
import { createApp } from 'vue';
import { createRouter, createWebHistory } from 'vue-router';
import { createPinia } from 'pinia';
import App from './App.vue';
import { routes } from './router';
Expand All @@ -9,45 +10,18 @@ import 'prismjs/components/prism-javascript';
import 'prismjs/components/prism-bash';
import 'prismjs/components/prism-typescript';

export const createApp = ViteSSG(
App,
{ routes: routes as import('vue-router').RouteRecordRaw[] },
({ app, router, initialState, isClient }) => {
const pinia = createPinia();
app.use(pinia);
const app = createApp(App);
const pinia = createPinia();
const router = createRouter({
history: createWebHistory(import.meta.env.BASE_URL || '/'),
routes: routes as import('vue-router').RouteRecordRaw[],
});

if (import.meta.env.SSR) {
initialState.pinia = pinia.state.value;
} else {
pinia.state.value = initialState.pinia ?? {};
}
app.use(pinia);
app.use(router);

router.beforeEach(async (to) => {
if (import.meta.env.SSR) {
const version = to.params.version as string | undefined;
if (version) {
const { useDocsStore } = await import('./stores/docs');
const { useGuidesStore } = await import('./stores/guides');
const { useVersionStore } = await import('./stores/version');
const docsStore = useDocsStore(pinia);
const guidesStore = useGuidesStore(pinia);
const versionStore = useVersionStore(pinia);
router.afterEach(() => {
queueMicrotask(() => Prism.highlightAll());
});

await versionStore.loadVersions();
versionStore.setVersion(version);

const key = version === 'latest' ? 'latest' : version;
if (to.path.includes('/docs')) await docsStore.loadDocs(key);
if (to.path.includes('/guides')) await guidesStore.loadGuides(key);

initialState.pinia = pinia.state.value;
}
}
});

router.afterEach(() => {
if (!isClient) return;
queueMicrotask(() => Prism.highlightAll());
});
},
);
app.mount('#app');
107 changes: 57 additions & 50 deletions apps/docs/src/router.ts
Original file line number Diff line number Diff line change
Expand Up @@ -12,54 +12,61 @@ import ApiReferenceLayout from './pages/ApiReferenceLayout.vue';
import ApiReferencePage from './pages/ApiReferencePage.vue';

export const routes = [
{ path: '/', name: 'home', component: Home },
{ path: '/changelog', name: 'changelog', component: Changelog },
{ path: '/guides', redirect: '/v/latest/guides' },
{ path: '/docs', redirect: '/v/latest/docs' },
{ path: '/api', redirect: '/v/latest/api' },
{ path: '/v/:version/changelog', redirect: '/changelog' },
{
path: '/v/:version',
component: VersionLayout,
children: [
{ path: '', redirect: ((to: { params: { version?: string } }) => `/v/${to.params.version}/guides`) as import('vue-router').RouteRecordRedirectOption },
{
path: 'guides',
component: GuidesLayout,
children: [
{ path: '', name: 'guides', component: GuidesIndex },
{ path: ':slug', name: 'guide', component: GuidePage },
],
},
{
path: 'docs',
component: DocsLayout,
children: [
{
path: '',
name: 'docs',
redirect: ((to: { params: Record<string, string | string[] | undefined> }) => ({ name: 'classes', params: { ...to.params } })) as import('vue-router').RouteRecordRedirectOption,
},
{
path: 'classes',
{ path: '/', name: 'home', component: Home },
{ path: '/changelog', name: 'changelog', component: Changelog },
{ path: '/guides', redirect: '/v/latest/guides' },
{ path: '/docs', redirect: '/v/latest/docs' },
{ path: '/api', redirect: '/v/latest/api' },
{ path: '/v/:version/changelog', redirect: '/changelog' },
{
path: '/v/:version',
component: VersionLayout,
children: [
{
path: '',
redirect: ((to: { params: { version?: string } }) =>
`/v/${to.params.version}/guides`) as import('vue-router').RouteRecordRedirectOption,
},
{
path: 'guides',
component: GuidesLayout,
children: [
{ path: '', name: 'guides', component: GuidesIndex },
{ path: ':slug', name: 'guide', component: GuidePage },
],
},
{
path: 'docs',
component: DocsLayout,
children: [
{
path: '',
name: 'docs',
redirect: ((to: { params: Record<string, string | string[] | undefined> }) => ({
name: 'classes',
component: () => import('./pages/ClassesList.vue'),
},
{ path: 'classes/:class', name: 'class', component: ClassPage },
{
path: 'typedefs',
name: 'typedefs',
component: () => import('./pages/TypedefsList.vue'),
},
{ path: 'typedefs/:typedef', name: 'typedef', component: TypedefPage },
],
},
{
path: 'api',
component: ApiReferenceLayout,
children: [{ path: '', name: 'api', component: ApiReferencePage }],
},
],
},
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound },
];
params: { ...to.params },
})) as import('vue-router').RouteRecordRedirectOption,
},
{
path: 'classes',
name: 'classes',
component: () => import('./pages/ClassesList.vue'),
},
{ path: 'classes/:class', name: 'class', component: ClassPage },
{
path: 'typedefs',
name: 'typedefs',
component: () => import('./pages/TypedefsList.vue'),
},
{ path: 'typedefs/:typedef', name: 'typedef', component: TypedefPage },
],
},
{
path: 'api',
component: ApiReferenceLayout,
children: [{ path: '', name: 'api', component: ApiReferencePage }],
},
],
},
{ path: '/:pathMatch(.*)*', name: 'not-found', component: NotFound },
];
23 changes: 6 additions & 17 deletions apps/docs/src/stores/docs.ts
Original file line number Diff line number Diff line change
Expand Up @@ -15,30 +15,19 @@ export const useDocsStore = defineStore('docs', () => {

/**
* Load docs for a specific version. Uses versioned path: docs/{version}/main.json
* During SSG: reads from disk. On client: fetches.
*/
async function loadDocs(versionKey: DocsVersionKey) {
if (docsData.value && loadedVersion.value === versionKey) return;
loading.value = true;
error.value = null;
try {
const versionPath = versionKey === 'latest' ? 'latest' : `v${versionKey}`;

if (import.meta.env.SSR) {
const { readFileSync } = await import('fs');
const { resolve } = await import('path');
const path = resolve(process.cwd(), 'public/docs', versionPath, 'main.json');
const data = JSON.parse(readFileSync(path, 'utf-8')) as DocOutput;
docsData.value = data;
loadedVersion.value = versionKey;
} else {
const url = `/docs/${versionPath}/main.json`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed to load docs: ${res.status}`);
const data = (await res.json()) as DocOutput;
docsData.value = data;
loadedVersion.value = versionKey;
}
const url = `/docs/${versionPath}/main.json`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed to load docs: ${res.status}`);
const data = (await res.json()) as DocOutput;
docsData.value = data;
loadedVersion.value = versionKey;
} catch (e) {
error.value = e instanceof Error ? e.message : String(e);
throw e;
Expand Down
19 changes: 5 additions & 14 deletions apps/docs/src/stores/guides.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,20 +21,11 @@ export const useGuidesStore = defineStore('guides', () => {
error.value = null;
try {
const versionPath = versionKey === 'latest' ? 'latest' : `v${versionKey}`;

if (import.meta.env.SSR) {
const { readFileSync } = await import('fs');
const { resolve } = await import('path');
const path = resolve(process.cwd(), 'public/docs', versionPath, 'guides.json');
guidesData.value = JSON.parse(readFileSync(path, 'utf-8')) as Guide[];
loadedVersion.value = versionKey;
} else {
const url = `/docs/${versionPath}/guides.json`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed to load guides: ${res.status}`);
guidesData.value = (await res.json()) as Guide[];
loadedVersion.value = versionKey;
}
const url = `/docs/${versionPath}/guides.json`;
const res = await fetch(url);
if (!res.ok) throw new Error(`Failed to load guides: ${res.status}`);
guidesData.value = (await res.json()) as Guide[];
loadedVersion.value = versionKey;
} catch (e) {
// Fallback to static guides if json not yet generated (e.g. dev before docs:build)
guidesData.value = null;
Expand Down
35 changes: 12 additions & 23 deletions apps/docs/src/stores/version.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,31 +31,20 @@ export const useVersionStore = defineStore('version', () => {
async function loadVersions() {
if (versionsLoaded.value) return;
try {
if (import.meta.env.SSR) {
const { readFileSync } = await import('fs');
const { resolve } = await import('path');
const path = resolve(process.cwd(), 'public/docs/versions.json');
const data = JSON.parse(readFileSync(path, 'utf-8')) as VersionsManifest;
availableVersions.value = data.versions ?? [];
latestVersion.value = data.latest ?? data.versions?.[0] ?? '1.0.7';
versionsLoaded.value = true;
} else {
const res = await fetch('/docs/versions.json');
if (!res.ok) throw new Error('Failed to load versions');
const data = (await res.json()) as VersionsManifest;
availableVersions.value = data.versions ?? [];
latestVersion.value = data.latest ?? data.versions?.[0] ?? '1.0.7';
versionsLoaded.value = true;
const res = await fetch('/docs/versions.json');
if (!res.ok) throw new Error('Failed to load versions');
const data = (await res.json()) as VersionsManifest;
availableVersions.value = data.versions ?? [];
latestVersion.value = data.latest ?? data.versions?.[0] ?? '1.0.7';
versionsLoaded.value = true;

// Restore saved preference (client only)
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved && (saved === 'latest' || availableVersions.value.includes(saved))) {
currentVersion.value = saved;
}
} catch {
/* ignore */
try {
const saved = localStorage.getItem(STORAGE_KEY);
if (saved && (saved === 'latest' || availableVersions.value.includes(saved))) {
currentVersion.value = saved;
}
} catch {
/* ignore */
}
} catch {
// Fallback when versions.json doesn't exist (e.g. dev before first generate)
Expand Down
7 changes: 0 additions & 7 deletions apps/docs/vite.config.d.ts

This file was deleted.

Loading