From 691a22d1eb89f325efa19067f756f4329ee2a061 Mon Sep 17 00:00:00 2001 From: JP Swinski Date: Wed, 10 Jun 2026 11:08:30 +0000 Subject: [PATCH] combined the release notes from SlideRule Releases and Web Client Releases onto one tab called Release Notes on the Landing page --- web-client/src/views/LandingView.vue | 66 +++++++++------------------- 1 file changed, 21 insertions(+), 45 deletions(-) diff --git a/web-client/src/views/LandingView.vue b/web-client/src/views/LandingView.vue index e76e8445..bac5d513 100644 --- a/web-client/src/views/LandingView.vue +++ b/web-client/src/views/LandingView.vue @@ -15,7 +15,7 @@ function stripFrontmatter(md: string): string { const aboutHtml = DOMPurify.sanitize(marked(stripFrontmatter(aboutRaw)) as string) const contactHtml = DOMPurify.sanitize(marked(stripFrontmatter(contactRaw)) as string) -const tabOptions = ['About', 'Contact', 'SlideRule Releases', 'Web Client Releases'] +const tabOptions = ['About', 'Contact', 'Release Notes'] const selectedTab = ref('About') const panelHtml = computed(() => { @@ -30,11 +30,6 @@ const panelHtml = computed(() => { }) // --- Release Notes --- -// -// Two release-note sources share the list/detail UI below: -// - 'remote' = the SlideRule platform notes scraped from the docs site -// - 'local' = this repo's web-client notes, bundled at build time (see the -// import.meta.glob of src/assets/content/release-notes/*.md) const RELEASE_NOTES_INDEX_URL = DOCS.releaseNotes.index const RELEASE_NOTES_BASE_URL = DOCS.releaseNotes.base @@ -53,11 +48,7 @@ const releaseHtml = ref('') const releaseLoading = ref(false) const releaseError = ref('') -const releaseMode = computed<'remote' | 'local' | null>(() => { - if (selectedTab.value === 'SlideRule Releases') return 'remote' - if (selectedTab.value === 'Web Client Releases') return 'local' - return null -}) +const showReleaseNotes = computed(() => selectedTab.value === 'Release Notes') // --- Local web-client release notes (bundled markdown) --- @@ -67,24 +58,6 @@ const localNoteModules = import.meta.glob('@/assets/content/release-notes/*.md', eager: true }) as Record -function versionKey(v: string): number[] { - return v - .replace(/^v/, '') - .split('.') - .map((n) => parseInt(n, 10) || 0) -} - -// Sort newest-first by semantic version (v4.5.10 after v4.5.2). -function compareVersionDesc(a: string, b: string): number { - const av = versionKey(a) - const bv = versionKey(b) - for (let i = 0; i < Math.max(av.length, bv.length); i++) { - const diff = (bv[i] ?? 0) - (av[i] ?? 0) - if (diff !== 0) return diff - } - return 0 -} - const localReleaseNotes = computed(() => { const notes = Object.entries(localNoteModules).map(([path, raw]) => { const version = path.split('/').pop()?.replace(/\.md$/, '') ?? '' @@ -97,33 +70,38 @@ const localReleaseNotes = computed(() => { const bullet = body.match(/^\s*[-*]\s+(.+)$/m) const snippet = bullet?.[1] ?? '' const html = DOMPurify.sanitize(marked(body) as string) - return { title, date, url: DOCS.webClient.tags + version, snippet, html } + return { + title: 'Web Client - ' + title, + date, + url: DOCS.webClient.tags + version, + snippet, + html + } }) - return notes.sort((a, b) => compareVersionDesc(a.title, b.title) || b.date.localeCompare(a.date)) + return notes.sort((a, b) => b.date.localeCompare(a.date)) }) const currentNotes = computed(() => { - if (releaseMode.value === 'local') return localReleaseNotes.value - if (releaseMode.value === 'remote') return releaseNotes.value - return [] + if (!showReleaseNotes.value) return [] + const combined = [...releaseNotes.value, ...localReleaseNotes.value] + return combined.sort((a, b) => b.date.localeCompare(a.date)) }) const externalLink = computed(() => { if (!selectedRelease.value) return '' - return releaseMode.value === 'local' + return selectedRelease.value.html ? selectedRelease.value.url : RELEASE_NOTES_BASE_URL + selectedRelease.value.url }) const externalLinkLabel = computed(() => - releaseMode.value === 'local' ? 'View on GitHub ↗' : 'View on docs site ↗' + selectedRelease.value?.html ? 'View on GitHub ↗' : 'View on docs site ↗' ) function openRelease(note: ReleaseNote) { - if (releaseMode.value === 'local') { - // Local notes are already rendered — no network fetch needed. + if (note.html) { selectedRelease.value = note - releaseHtml.value = note.html ?? '' + releaseHtml.value = note.html } else { void fetchRelease(note) } @@ -146,7 +124,7 @@ async function fetchReleaseNotesIndex() { // Matches "Release v5.4.x", "Release v5.4.1", "Web Client Release v4.5.0", etc. const match = text.match(/^(?:Web Client )?Release v[\d.x]+$/) if (match) { - notes.push({ date: '', title: text, url: href }) + notes.push({ date: '', title: 'Server - ' + text, url: href }) } }) releaseNotes.value = notes @@ -237,12 +215,10 @@ onMounted(() => { }) watch(selectedTab, (tab) => { - // Reset the detail view whenever the tab changes; only the remote source needs - // an on-switch fetch (local notes are bundled and rendered eagerly). selectedRelease.value = null releaseHtml.value = '' releaseError.value = '' - if (tab === 'SlideRule Releases') { + if (tab === 'Release Notes') { void fetchReleaseNotesIndex() } }) @@ -261,7 +237,7 @@ watch(selectedTab, (tab) => { -
+
@@ -270,7 +246,7 @@ watch(selectedTab, (tab) => {
- +
Loading...
{{ releaseError }}