Skip to content

Commit 2a4a4e8

Browse files
committed
chore: clean up mock changelog
1 parent cdc2b3e commit 2a4a4e8

1 file changed

Lines changed: 40 additions & 299 deletions

File tree

app/pages/package/[[org]]/[name]/versions.vue

Lines changed: 40 additions & 299 deletions
Original file line numberDiff line numberDiff line change
@@ -74,207 +74,9 @@ const versionHistory: PackageVersionInfo[] = [
7474
{ version: '1.0.28', time: '2016-12-15T10:00:00Z', hasProvenance: false },
7575
]
7676
77-
// Changelog markdown strings keyed by version.
78-
// In production these would be pre-rendered HTML from the server
79-
// (e.g. GitHub release body or CHANGELOG.md, parsed like README).
77+
// TODO: Replace with pre-rendered HTML from the server
8078
const mockChangelogs: Record<string, string> = {
81-
'3.5.0-beta.3': `### Bug Fixes
82-
83-
- Fixed \`v-model\` not triggering update when used with custom modifier on the same component
84-
- Resolved hydration mismatch for \`<Suspense>\` with async setup components
85-
86-
### Performance
87-
88-
- Reduced scheduler flush cost for large component trees with many watchers`,
89-
90-
'3.5.0-rc.1': `## Vue 3.5 RC
91-
92-
The API is now stable. This release candidate is intended for final testing before the stable release.
93-
94-
### New Features
95-
96-
- \`useTemplateRef()\` — reactive ref bound to a template element by string key
97-
- \`useId()\` — SSR-safe unique ID generation for accessibility attributes
98-
- Deferred \`<Suspense>\` — suspense boundary no longer blocks parent tree rendering
99-
100-
### Breaking Changes
101-
102-
> **Note:** These only affect experimental APIs that were previously behind flags.
103-
104-
- Removed \`v-memo\` on component root nodes — use it on inner elements instead
105-
- \`defineModel()\` local mutation now requires explicit \`local\` option
106-
107-
**Full Changelog**: [v3.4.21...v3.5.0-rc.1](https://github.com/vuejs/core/compare/v3.4.21...v3.5.0-rc.1)`,
108-
109-
'3.4.21': `### Bug Fixes
110-
111-
- Fixed \`<KeepAlive>\` failing to restore scroll position on re-activation (#10156)
112-
- Corrected \`shallowReadonly\` not preserving array identity on nested access
113-
- Fixed compiler warning for \`v-bind\` shorthand used on \`<slot>\` elements
114-
115-
**Full Changelog**: [v3.4.20...v3.4.21](https://github.com/vuejs/core/compare/v3.4.20...v3.4.21)`,
116-
117-
'3.4.0': `## Vue 3.4 — "Slam Dunk"
118-
119-
### New Features
120-
121-
- **Reactivity transform removed** — the experimental \`$ref\` sugar has been dropped; use \`ref()\` directly
122-
- **\`v-bind\` shorthand** — \`:foo\` can now be written as just \`:foo\` when binding a same-name prop
123-
- **\`defineModel()\` stable** — two-way binding macro is now stable and no longer requires opt-in
124-
- **Parser rewrite** — the template compiler's parser is 2× faster and produces better error messages
125-
126-
### Breaking Changes
127-
128-
- \`app.config.compilerOptions.isCustomElement\` now receives the full element tag with namespace prefix
129-
- \`@vue/reactivity\` no longer exports \`deferredComputed\` — use \`computed\` with a scheduler instead
130-
131-
\`\`\`ts
132-
// Before
133-
const double = deferredComputed(() => count.value * 2)
134-
135-
// After
136-
const double = computed(() => count.value * 2, { scheduler: queueMicrotask })
137-
\`\`\`
138-
139-
**Full Changelog**: [v3.3.13...v3.4.0](https://github.com/vuejs/core/compare/v3.3.13...v3.4.0)`,
140-
141-
'3.0.0': `## Vue 3.0 — "One Piece"
142-
143-
The first stable release of Vue 3. Rebuilt from the ground up with the Composition API, TypeScript, and a new reactivity system.
144-
145-
### Highlights
146-
147-
- **Composition API** — \`setup()\`, \`ref()\`, \`reactive()\`, \`computed()\`, \`watch()\`
148-
- **Fragments** — components can now have multiple root nodes
149-
- **Teleport** — render content in a different part of the DOM
150-
- **Suspense** — coordinate async dependency resolution in component trees
151-
- **Improved TypeScript support** — full type inference for component props and emits
152-
- **Tree-shakeable** — global APIs are now ES module exports
153-
154-
### Migration
155-
156-
Vue 3 is not backwards compatible with Vue 2. See the [Migration Guide](https://v3-migration.vuejs.org/) for a full list of breaking changes.
157-
158-
**Full Changelog**: [github.com/vuejs/core](https://github.com/vuejs/core/blob/main/CHANGELOG.md)`,
159-
}
160-
161-
// ─── Markdown rendering ───────────────────────────────────────────────────────
162-
// Minimal block-level markdown parser for changelog content.
163-
// Handles headings, lists, paragraphs, blockquotes, and inline formatting.
164-
// In production this would be replaced by server-rendered HTML (like README).
165-
166-
function parseInline(text: string): string {
167-
return text
168-
.replace(/&/g, '&amp;')
169-
.replace(/</g, '&lt;')
170-
.replace(/>/g, '&gt;')
171-
.replace(/\*\*(.+?)\*\*/g, '<strong>$1</strong>')
172-
.replace(/`([^`]+)`/g, '<code>$1</code>')
173-
.replace(
174-
/\[([^\]]+)\]\((https?:[^)]+)\)/g,
175-
'<a href="$2" target="_blank" rel="nofollow noreferrer noopener">$1</a>',
176-
)
177-
}
178-
179-
function parseChangelogMarkdown(markdown: string): string {
180-
const lines = markdown.split('\n')
181-
const out: string[] = []
182-
let inList = false
183-
let inBlockquote = false
184-
let inCodeBlock = false
185-
let codeLang = ''
186-
let codeLines: string[] = []
187-
188-
const flushList = () => {
189-
if (inList) {
190-
out.push('</ul>')
191-
inList = false
192-
}
193-
}
194-
const flushBlockquote = () => {
195-
if (inBlockquote) {
196-
out.push('</blockquote>')
197-
inBlockquote = false
198-
}
199-
}
200-
201-
for (const line of lines) {
202-
// Code block fence
203-
if (line.startsWith('```')) {
204-
if (inCodeBlock) {
205-
out.push(
206-
`<pre><code${codeLang ? ` class="language-${codeLang}"` : ''}>${codeLines.map(l => l.replace(/&/g, '&amp;').replace(/</g, '&lt;').replace(/>/g, '&gt;')).join('\n')}</code></pre>`,
207-
)
208-
inCodeBlock = false
209-
codeLines = []
210-
codeLang = ''
211-
} else {
212-
flushList()
213-
flushBlockquote()
214-
inCodeBlock = true
215-
codeLang = line.slice(3).trim()
216-
}
217-
continue
218-
}
219-
if (inCodeBlock) {
220-
codeLines.push(line)
221-
continue
222-
}
223-
224-
const trimmed = line.trim()
225-
226-
// Blank line
227-
if (!trimmed) {
228-
flushList()
229-
flushBlockquote()
230-
continue
231-
}
232-
233-
// Blockquote
234-
if (trimmed.startsWith('> ')) {
235-
flushList()
236-
if (!inBlockquote) {
237-
out.push('<blockquote>')
238-
inBlockquote = true
239-
}
240-
out.push(`<p>${parseInline(trimmed.slice(2))}</p>`)
241-
continue
242-
}
243-
flushBlockquote()
244-
245-
// Headings
246-
const h2 = trimmed.match(/^## (.+)/)
247-
const h3 = trimmed.match(/^### (.+)/)
248-
if (h2) {
249-
flushList()
250-
out.push(`<h2>${parseInline(h2[1]!)}</h2>`)
251-
continue
252-
}
253-
if (h3) {
254-
flushList()
255-
out.push(`<h3>${parseInline(h3[1]!)}</h3>`)
256-
continue
257-
}
258-
259-
// List item
260-
const li = trimmed.match(/^[-*] (.+)/)
261-
if (li) {
262-
if (!inList) {
263-
out.push('<ul>')
264-
inList = true
265-
}
266-
out.push(`<li>${parseInline(li[1]!)}</li>`)
267-
continue
268-
}
269-
270-
// Paragraph
271-
flushList()
272-
out.push(`<p>${parseInline(trimmed)}</p>`)
273-
}
274-
275-
flushList()
276-
flushBlockquote()
277-
return out.join('\n')
79+
'3.5.0-beta.3': 'Hello world',
27880
}
27981
28082
// ─── Derived data ─────────────────────────────────────────────────────────────
@@ -301,15 +103,14 @@ function getVersionTime(version: string): string | undefined {
301103
302104
const selectedChangelogVersion = ref<string | null>(null)
303105
304-
const selectedChangelogHtml = computed(() => {
106+
const selectedChangelogContent = computed(() => {
305107
if (!selectedChangelogVersion.value) return ''
306-
const raw = mockChangelogs[selectedChangelogVersion.value]
307-
return raw ? parseChangelogMarkdown(raw) : ''
108+
return mockChangelogs[selectedChangelogVersion.value] ?? ''
308109
})
309110
310-
function toggleChangelog(version: string) {
311-
selectedChangelogVersion.value = selectedChangelogVersion.value === version ? null : version
312-
}
111+
// function toggleChangelog(version: string) {
112+
// selectedChangelogVersion.value = selectedChangelogVersion.value === version ? null : version
113+
// }
313114
314115
// ─── Jump to version ──────────────────────────────────────────────────────────
315116
@@ -416,7 +217,7 @@ watch(jumpVersion, () => {
416217
<!-- Right: date + provenance -->
417218
<div class="flex flex-col items-end gap-1.5 shrink-0 relative z-10">
418219
<ProvenanceBadge
419-
v-if="versionHistory.find(v => v.version === tagRows[0].version)?.hasProvenance"
220+
v-if="versionHistory.find(v => v.version === tagRows?.[0]?.version)?.hasProvenance"
420221
:package-name="packageName"
421222
:version="tagRows[0].version"
422223
compact
@@ -545,6 +346,32 @@ watch(jumpVersion, () => {
545346

546347
<!-- Right side -->
547348
<div class="flex items-center gap-2 shrink-0 relative z-10">
349+
<!-- Changelog toggle button -->
350+
<!-- TODO(atriiy): changelog would be implemented later -->
351+
<!-- <button
352+
v-if="v.hasChangelog"
353+
type="button"
354+
class="flex items-center gap-1.5 text-xs px-2 py-1 rounded border transition-colors focus-visible:outline-accent/70"
355+
:class="
356+
selectedChangelogVersion === v.version
357+
? 'border-accent/50 bg-accent/8 text-accent'
358+
: 'border-border text-fg-subtle hover:text-fg hover:border-border-hover'
359+
"
360+
:aria-expanded="selectedChangelogVersion === v.version"
361+
:aria-label="`Toggle changelog for v${v.version}`"
362+
@click.stop="toggleChangelog(v.version)"
363+
>
364+
<span class="i-lucide:scroll-text w-3.5 h-3.5 shrink-0" aria-hidden="true" />
365+
<span class="hidden sm:inline">Changelog</span>
366+
</button> -->
367+
368+
<!-- Divider -->
369+
<span
370+
v-if="v.hasChangelog"
371+
class="w-px h-3.5 bg-border shrink-0 hidden sm:block"
372+
aria-hidden="true"
373+
/>
374+
548375
<!-- Metadata: date + provenance -->
549376
<DateTime
550377
v-if="v.time"
@@ -561,31 +388,6 @@ watch(jumpVersion, () => {
561388
compact
562389
:linked="false"
563390
/>
564-
565-
<!-- Divider -->
566-
<span
567-
v-if="v.hasChangelog"
568-
class="w-px h-3.5 bg-border shrink-0 hidden sm:block"
569-
aria-hidden="true"
570-
/>
571-
572-
<!-- Changelog toggle button -->
573-
<button
574-
v-if="v.hasChangelog"
575-
type="button"
576-
class="flex items-center gap-1.5 text-xs px-2 py-1 rounded border transition-colors focus-visible:outline-accent/70"
577-
:class="
578-
selectedChangelogVersion === v.version
579-
? 'border-accent/50 bg-accent/8 text-accent'
580-
: 'border-border text-fg-subtle hover:text-fg hover:border-border-hover'
581-
"
582-
:aria-expanded="selectedChangelogVersion === v.version"
583-
:aria-label="`Toggle changelog for v${v.version}`"
584-
@click.stop="toggleChangelog(v.version)"
585-
>
586-
<span class="i-lucide:scroll-text w-3.5 h-3.5 shrink-0" aria-hidden="true" />
587-
<span class="hidden sm:inline">Changelog</span>
588-
</button>
589391
</div>
590392
</div>
591393

@@ -598,10 +400,9 @@ watch(jumpVersion, () => {
598400
"
599401
>
600402
<div class="overflow-hidden">
601-
<div
602-
class="changelog-body border-t border-border px-4 py-3 text-sm"
603-
v-html="selectedChangelogVersion === v.version ? selectedChangelogHtml : ''"
604-
/>
403+
<div class="changelog-body border-t border-border px-4 py-3 text-sm">
404+
{{ selectedChangelogVersion === v.version ? selectedChangelogContent : '' }}
405+
</div>
605406
</div>
606407
</div>
607408
</div>
@@ -641,8 +442,9 @@ watch(jumpVersion, () => {
641442
<!-- Panel body — scrollable for long content -->
642443
<div
643444
class="changelog-body overflow-y-auto max-h-[calc(100vh-12rem)] px-4 py-3 text-sm"
644-
v-html="selectedChangelogHtml"
645-
/>
445+
>
446+
{{ selectedChangelogContent }}
447+
</div>
646448
</div>
647449
</div>
648450
</div>
@@ -660,65 +462,4 @@ watch(jumpVersion, () => {
660462
overflow-wrap: break-word;
661463
word-break: break-word;
662464
}
663-
664-
.changelog-body :deep(h2) {
665-
@apply font-mono font-medium text-fg text-base mt-4 mb-2 pb-1.5 border-b border-border;
666-
}
667-
.changelog-body :deep(h2:first-child) {
668-
@apply mt-0;
669-
}
670-
.changelog-body :deep(h3) {
671-
@apply font-mono font-medium text-fg text-sm mt-3 mb-1.5;
672-
}
673-
.changelog-body :deep(h3:first-child) {
674-
@apply mt-0;
675-
}
676-
677-
.changelog-body :deep(p) {
678-
@apply mb-2 last:mb-0;
679-
}
680-
681-
.changelog-body :deep(ul) {
682-
@apply mb-2 ps-4 space-y-1 last:mb-0;
683-
list-style-type: disc;
684-
}
685-
.changelog-body :deep(li::marker) {
686-
color: var(--border-hover);
687-
}
688-
689-
.changelog-body :deep(blockquote) {
690-
@apply border-s-2 border-border ps-3 my-2 text-fg-subtle italic;
691-
}
692-
693-
.changelog-body :deep(code) {
694-
@apply font-mono text-xs;
695-
font-size: 0.8em;
696-
background: var(--bg-muted);
697-
padding: 0.15em 0.35em;
698-
border-radius: 3px;
699-
border: 1px solid var(--border);
700-
}
701-
702-
.changelog-body :deep(pre) {
703-
@apply rounded-md border border-border overflow-x-auto p-3 my-2;
704-
background: var(--bg-subtle);
705-
}
706-
.changelog-body :deep(pre code) {
707-
background: transparent;
708-
border: none;
709-
padding: 0;
710-
font-size: 0.8rem;
711-
color: var(--fg);
712-
}
713-
714-
.changelog-body :deep(a) {
715-
@apply underline underline-offset-2 decoration-1 decoration-fg/30 transition-colors duration-150;
716-
}
717-
.changelog-body :deep(a:hover) {
718-
@apply decoration-accent text-accent;
719-
}
720-
721-
.changelog-body :deep(strong) {
722-
@apply font-semibold text-fg;
723-
}
724465
</style>

0 commit comments

Comments
 (0)