diff options
| author | Sho Sakuma <me@m1sk9.dev> | 2026-04-05 02:08:18 +0900 |
|---|---|---|
| committer | Sho Sakuma <me@m1sk9.dev> | 2026-04-05 02:08:18 +0900 |
| commit | 50fac99f6b9627186f97b036eef9f0cbe0aa37cb (patch) | |
| tree | 15c59026581e59796a644017548f173e23d8434a /website/.vitepress | |
| parent | 579ca7f5bf01187e1f758cadfb4eda652fd5a4c3 (diff) | |
| download | LunaticChat-50fac99f6b9627186f97b036eef9f0cbe0aa37cb.tar.gz LunaticChat-50fac99f6b9627186f97b036eef9f0cbe0aa37cb.tar.bz2 LunaticChat-50fac99f6b9627186f97b036eef9f0cbe0aa37cb.zip | |
fix(website): fetch download data dynamically on client side
Replace the VitePress build-time data loader with a client-side
composable so the download page always shows the latest GitHub
release without requiring a site redeploy.
Co-Authored-By: Claude <noreply@anthropic.com>
Diffstat (limited to 'website/.vitepress')
| -rw-r--r-- | website/.vitepress/theme/components/DownloadCard.vue | 32 | ||||
| -rw-r--r-- | website/.vitepress/theme/components/download.data.ts | 105 | ||||
| -rw-r--r-- | website/.vitepress/theme/components/useDownloadData.ts | 104 |
3 files changed, 134 insertions, 107 deletions
diff --git a/website/.vitepress/theme/components/DownloadCard.vue b/website/.vitepress/theme/components/DownloadCard.vue index 019a8f8..a61cff6 100644 --- a/website/.vitepress/theme/components/DownloadCard.vue +++ b/website/.vitepress/theme/components/DownloadCard.vue @@ -1,10 +1,11 @@ <script setup lang="ts"> import { computed } from 'vue'; import { useData } from 'vitepress'; -import { data } from './download.data'; +import { useDownloadData } from './useDownloadData'; const { lang } = useData(); const isEn = computed(() => lang.value === 'en-US'); +const { data, loading, error } = useDownloadData(); const t = computed(() => isEn.value @@ -93,7 +94,15 @@ function formatDate(dateStr: string | null): string { <p><a :href="isEn ? '/en/docs/features/velocity#protocol-version' : '/docs/features/velocity#プロトコルバージョン'">{{ t.compatLink }}</a></p> </div> - <div class="download-grid"> + <div v-if="loading" class="download-loading"> + <p>{{ isEn ? 'Loading releases...' : 'リリース情報を取得中...' }}</p> + </div> + + <div v-else-if="error" class="download-error"> + <p>{{ isEn ? 'Failed to load release information. Please check ' : 'リリース情報の取得に失敗しました.' }}<a href="https://github.com/m1sk9/LunaticChat/releases" target="_blank" rel="noopener">GitHub Releases</a>{{ isEn ? ' directly.' : ' を直接ご確認ください.' }}</p> + </div> + + <div v-else class="download-grid"> <!-- Paper / Folia --> <div class="download-card"> <div class="download-card-header"> @@ -377,4 +386,23 @@ function formatDate(dateStr: string | null): string { .download-ci { margin: 16px 0; } + +.download-loading { + text-align: center; + padding: 48px 0; + color: var(--vp-c-text-2); +} + +.download-error { + border: 1px solid var(--vp-c-danger-soft); + background: var(--vp-c-danger-soft); + border-radius: 8px; + padding: 16px 20px; + margin: 24px 0; +} + +.download-error a { + color: var(--vp-c-brand-1); + text-decoration: underline; +} </style> diff --git a/website/.vitepress/theme/components/download.data.ts b/website/.vitepress/theme/components/download.data.ts deleted file mode 100644 index 11e0489..0000000 --- a/website/.vitepress/theme/components/download.data.ts +++ /dev/null @@ -1,105 +0,0 @@ -const REPO = 'm1sk9/LunaticChat'; - -interface ReleaseAsset { - name: string; - size: number; - browser_download_url: string; -} - -interface GitHubRelease { - tag_name: string; - published_at: string; - html_url: string; - assets: ReleaseAsset[]; -} - -interface PlatformRelease { - version: string; - publishedAt: string; - releaseUrl: string; - downloadUrl: string | null; - fileName: string | null; - fileSize: number | null; -} - -interface CIBuild { - url: string; -} - -export interface DownloadData { - paper: PlatformRelease | null; - velocity: PlatformRelease | null; - ci: CIBuild; -} - -async function fetchLatestRelease( - tagPrefix: string, -): Promise<GitHubRelease | null> { - const res = await fetch( - `https://api.github.com/repos/${REPO}/releases?per_page=20`, - ); - if (!res.ok) return null; - - const releases: GitHubRelease[] = await res.json(); - return ( - releases.find( - (r) => - r.tag_name.startsWith(tagPrefix) || r.tag_name.startsWith('v'), - ) ?? null - ); -} - -function parsePlatformRelease( - release: GitHubRelease | null, - jarPattern: RegExp, -): PlatformRelease | null { - if (!release) return null; - - const asset = release.assets.find((a) => jarPattern.test(a.name)); - const version = release.tag_name.replace(/^(paper\/|velocity\/)?v/, ''); - - return { - version, - publishedAt: release.published_at, - releaseUrl: release.html_url, - downloadUrl: asset?.browser_download_url ?? null, - fileName: asset?.name ?? null, - fileSize: asset?.size ?? null, - }; -} - -export default { - async load(): Promise<DownloadData> { - // Fetch all recent releases and find the latest for each platform - const res = await fetch( - `https://api.github.com/repos/${REPO}/releases?per_page=30`, - ); - const releases: GitHubRelease[] = res.ok ? await res.json() : []; - - // Find latest Paper release (paper/v* or v*) - const paperRelease = - releases.find((r) => r.tag_name.startsWith('paper/v')) ?? - releases.find((r) => /^v\d/.test(r.tag_name)) ?? - null; - - // Find latest Velocity release (velocity/v* or v*) - const velocityRelease = - releases.find((r) => r.tag_name.startsWith('velocity/v')) ?? - releases.find((r) => /^v\d/.test(r.tag_name)) ?? - null; - - return { - paper: parsePlatformRelease( - paperRelease, - /^LunaticChat-[\d.]+\.jar$/, - ), - velocity: parsePlatformRelease( - velocityRelease, - /^LunaticChat-[\d.]+-velocity\.jar$/, - ), - ci: { - url: `https://github.com/${REPO}/actions/workflows/ci.yaml?query=branch%3Amain`, - }, - }; - }, -}; diff --git a/website/.vitepress/theme/components/useDownloadData.ts b/website/.vitepress/theme/components/useDownloadData.ts new file mode 100644 index 0000000..0c9e7e0 --- /dev/null +++ b/website/.vitepress/theme/components/useDownloadData.ts @@ -0,0 +1,104 @@ +import { ref, onMounted } from 'vue'; + +const REPO = 'm1sk9/LunaticChat'; + +interface ReleaseAsset { + name: string; + size: number; + browser_download_url: string; +} + +interface GitHubRelease { + tag_name: string; + published_at: string; + html_url: string; + assets: ReleaseAsset[]; +} + +export interface PlatformRelease { + version: string; + publishedAt: string; + releaseUrl: string; + downloadUrl: string | null; + fileName: string | null; + fileSize: number | null; +} + +export interface DownloadData { + paper: PlatformRelease | null; + velocity: PlatformRelease | null; + ci: { url: string }; +} + +function parsePlatformRelease( + release: GitHubRelease | null, + jarPattern: RegExp, +): PlatformRelease | null { + if (!release) return null; + + const asset = release.assets.find((a) => jarPattern.test(a.name)); + const version = release.tag_name.replace(/^(paper\/|velocity\/)?v/, ''); + + return { + version, + publishedAt: release.published_at, + releaseUrl: release.html_url, + downloadUrl: asset?.browser_download_url ?? null, + fileName: asset?.name ?? null, + fileSize: asset?.size ?? null, + }; +} + +export function useDownloadData() { + const data = ref<DownloadData>({ + paper: null, + velocity: null, + ci: { + url: `https://github.com/${REPO}/actions/workflows/ci.yaml?query=branch%3Amain`, + }, + }); + const loading = ref(true); + const error = ref(false); + + onMounted(async () => { + try { + const res = await fetch( + `https://api.github.com/repos/${REPO}/releases?per_page=30`, + ); + if (!res.ok) { + error.value = true; + return; + } + + const releases: GitHubRelease[] = await res.json(); + + const paperRelease = + releases.find((r) => r.tag_name.startsWith('paper/v')) ?? + releases.find((r) => /^v\d/.test(r.tag_name)) ?? + null; + + const velocityRelease = + releases.find((r) => r.tag_name.startsWith('velocity/v')) ?? + releases.find((r) => /^v\d/.test(r.tag_name)) ?? + null; + + data.value = { + paper: parsePlatformRelease( + paperRelease, + /^LunaticChat-[\d.]+\.jar$/, + ), + velocity: parsePlatformRelease( + velocityRelease, + /^LunaticChat-[\d.]+-velocity\.jar$/, + ), + ci: data.value.ci, + }; + } catch { + error.value = true; + } finally { + loading.value = false; + } + }); + + return { data, loading, error }; +} |
