Skip to content

Commit 4a816e7

Browse files
committed
fix: fix virtual window rendering issue
1 parent 7aa08d5 commit 4a816e7

1 file changed

Lines changed: 139 additions & 127 deletions

File tree

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

Lines changed: 139 additions & 127 deletions
Original file line numberDiff line numberDiff line change
@@ -156,21 +156,27 @@ const filteredGroups = computed(() => {
156156
// ─── Flat list for virtual rendering ──────────────────────────────────────────
157157
158158
type FlatItem =
159-
| { type: 'header'; groupKey: string; label: string; versions: string[] }
160-
| { type: 'version'; version: string; groupKey: string }
159+
| { type: 'header'; key: string; groupKey: string; label: string; versions: string[] }
160+
| { type: 'version'; key: string; version: string; groupKey: string }
161161
162162
const flatItems = computed<FlatItem[]>(() => {
163163
const items: FlatItem[] = []
164164
for (const group of filteredGroups.value) {
165165
items.push({
166166
type: 'header',
167+
key: `header:${group.groupKey}`,
167168
groupKey: group.groupKey,
168169
label: group.label,
169170
versions: group.versions,
170171
})
171172
if (expandedGroups.value.has(group.groupKey) || isFilterActive.value) {
172173
for (const version of group.versions) {
173-
items.push({ type: 'version', version, groupKey: group.groupKey })
174+
items.push({
175+
type: 'version',
176+
key: `version:${version}`,
177+
version,
178+
groupKey: group.groupKey,
179+
})
174180
}
175181
}
176182
}
@@ -351,141 +357,147 @@ const selectedChangelogContent = computed(() => {
351357
<ClientOnly>
352358
<WindowVirtualizer :data="flatItems">
353359
<template #default="{ item, index }">
354-
<!-- ── Group header ── -->
355-
<button
356-
v-if="item.type === 'header'"
357-
type="button"
358-
class="flex items-center gap-3 px-4 py-2.5 w-full text-start hover:bg-bg-subtle transition-colors"
359-
:class="index < flatItems.length - 1 ? 'border-b border-border' : ''"
360-
:aria-expanded="expandedGroups.has(item.groupKey)"
361-
:aria-label="`${expandedGroups.has(item.groupKey) ? 'Collapse' : 'Expand'} ${item.label}`"
362-
@click="toggleGroup(item.groupKey)"
363-
>
364-
<span class="w-4 h-4 flex items-center justify-center text-fg-subtle shrink-0">
365-
<span
366-
v-if="loadingGroup === item.groupKey"
367-
class="i-svg-spinners:ring-resize w-3 h-3"
368-
aria-hidden="true"
369-
/>
370-
<span
371-
v-else
372-
class="i-lucide:chevron-right w-3 h-3 transition-transform duration-200 rtl-flip"
373-
:class="expandedGroups.has(item.groupKey) ? 'rotate-90' : ''"
374-
aria-hidden="true"
375-
/>
376-
</span>
377-
<span class="font-mono text-sm font-medium">{{ item.label }}</span>
378-
<span class="text-xs text-fg-subtle">({{ item.versions.length }})</span>
379-
<span class="ms-auto flex items-center gap-3 shrink-0">
380-
<span class="font-mono text-xs text-fg-muted" dir="ltr">{{
381-
item.versions[0]
382-
}}</span>
383-
<DateTime
384-
v-if="getVersionTime(item.versions[0])"
385-
:datetime="getVersionTime(item.versions[0])!"
386-
class="text-xs text-fg-subtle hidden sm:block"
387-
year="numeric"
388-
month="short"
389-
day="numeric"
390-
/>
391-
</span>
392-
</button>
393-
394-
<!-- ── Version row ── -->
395-
<div
396-
v-else
397-
class="transition-colors"
398-
:class="[
399-
index < flatItems.length - 1 ? 'border-b border-border' : '',
400-
selectedChangelogVersion === item.version ? 'bg-bg-subtle' : '',
401-
]"
402-
>
403-
<div
404-
class="flex items-center gap-3 px-4 ps-11 py-2.5 group relative"
405-
:class="selectedChangelogVersion === item.version ? '' : 'hover:bg-bg-subtle'"
360+
<div :key="item.key">
361+
<!-- ── Group header ── -->
362+
<button
363+
v-if="item.type === 'header'"
364+
type="button"
365+
class="flex items-center gap-3 px-4 py-2.5 w-full text-start hover:bg-bg-subtle transition-colors"
366+
:class="index < flatItems.length - 1 ? 'border-b border-border' : ''"
367+
:aria-expanded="expandedGroups.has(item.groupKey)"
368+
:aria-label="`${expandedGroups.has(item.groupKey) ? 'Collapse' : 'Expand'} ${item.label}`"
369+
@click="toggleGroup(item.groupKey)"
406370
>
407-
<!-- Version + badges -->
408-
<div class="flex-1 min-w-0 flex items-center gap-2 flex-wrap">
409-
<LinkBase
410-
:to="packageRoute(packageName, item.version)"
411-
:prefetch="false"
412-
class="font-mono text-sm after:absolute after:inset-0 after:content-['']"
413-
:class="
414-
fullVersionMap?.get(item.version)?.deprecated
415-
? 'text-red-700 dark:text-red-400'
416-
: ''
417-
"
418-
:classicon="
419-
fullVersionMap?.get(item.version)?.deprecated
420-
? 'i-lucide:octagon-alert'
421-
: undefined
422-
"
423-
dir="ltr"
424-
>
425-
{{ item.version }}
426-
</LinkBase>
427-
<div
428-
v-if="versionToTagsMap.get(item.version)?.length"
429-
class="flex items-center gap-1 flex-wrap relative z-10"
430-
>
431-
<span
432-
v-for="tag in versionToTagsMap.get(item.version)"
433-
:key="tag"
434-
class="text-4xs font-semibold uppercase tracking-wide"
435-
:class="tag === 'latest' ? 'text-accent' : 'text-fg-subtle'"
436-
>
437-
{{ tag }}
438-
</span>
439-
</div>
371+
<span
372+
class="w-4 h-4 flex items-center justify-center text-fg-subtle shrink-0"
373+
>
440374
<span
441-
v-if="fullVersionMap?.get(item.version)?.deprecated"
442-
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded relative z-10"
443-
:title="fullVersionMap.get(item.version)!.deprecated"
444-
>
445-
deprecated
446-
</span>
447-
</div>
448-
449-
<!-- Right side -->
450-
<div class="flex items-center gap-2 shrink-0 relative z-10">
451-
<!-- TODO(atriiy): changelog would be implemented later -->
452-
453-
<!-- Metadata: date + provenance -->
375+
v-if="loadingGroup === item.groupKey"
376+
class="i-svg-spinners:ring-resize w-3 h-3"
377+
aria-hidden="true"
378+
/>
379+
<span
380+
v-else
381+
class="i-lucide:chevron-right w-3 h-3 transition-transform duration-200 rtl-flip"
382+
:class="expandedGroups.has(item.groupKey) ? 'rotate-90' : ''"
383+
aria-hidden="true"
384+
/>
385+
</span>
386+
<span class="font-mono text-sm font-medium">{{ item.label }}</span>
387+
<span class="text-xs text-fg-subtle">({{ item.versions.length }})</span>
388+
<span class="ms-auto flex items-center gap-3 shrink-0">
389+
<span class="font-mono text-xs text-fg-muted" dir="ltr">{{
390+
item.versions[0]
391+
}}</span>
454392
<DateTime
455-
v-if="getVersionTime(item.version)"
456-
:datetime="getVersionTime(item.version)!"
393+
v-if="getVersionTime(item.versions[0])"
394+
:datetime="getVersionTime(item.versions[0])!"
457395
class="text-xs text-fg-subtle hidden sm:block"
458396
year="numeric"
459397
month="short"
460398
day="numeric"
461399
/>
462-
<ProvenanceBadge
463-
v-if="fullVersionMap?.get(item.version)?.hasProvenance"
464-
:package-name="packageName"
465-
:version="item.version"
466-
compact
467-
:linked="false"
468-
/>
469-
</div>
470-
</div>
400+
</span>
401+
</button>
471402

472-
<!-- Mobile inline changelog (below the row, sm and up uses side panel) -->
403+
<!-- ── Version row ── -->
473404
<div
474-
v-if="item.version in mockChangelogs"
475-
class="grid sm:hidden transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none"
476-
:class="
477-
selectedChangelogVersion === item.version
478-
? 'grid-rows-[1fr]'
479-
: 'grid-rows-[0fr]'
480-
"
405+
v-else
406+
class="transition-colors"
407+
:class="[
408+
index < flatItems.length - 1 ? 'border-b border-border' : '',
409+
selectedChangelogVersion === item.version ? 'bg-bg-subtle' : '',
410+
]"
481411
>
482-
<div class="overflow-hidden">
483-
<div class="changelog-body border-t border-border px-4 py-3 text-sm">
484-
{{
485-
selectedChangelogVersion === item.version
486-
? selectedChangelogContent
487-
: ''
488-
}}
412+
<div
413+
class="flex items-center gap-3 px-4 ps-11 py-2.5 group relative"
414+
:class="
415+
selectedChangelogVersion === item.version ? '' : 'hover:bg-bg-subtle'
416+
"
417+
>
418+
<!-- Version + badges -->
419+
<div class="flex-1 min-w-0 flex items-center gap-2 flex-wrap">
420+
<LinkBase
421+
:to="packageRoute(packageName, item.version)"
422+
:prefetch="false"
423+
class="font-mono text-sm after:absolute after:inset-0 after:content-['']"
424+
:class="
425+
fullVersionMap?.get(item.version)?.deprecated
426+
? 'text-red-700 dark:text-red-400'
427+
: ''
428+
"
429+
:classicon="
430+
fullVersionMap?.get(item.version)?.deprecated
431+
? 'i-lucide:octagon-alert'
432+
: undefined
433+
"
434+
dir="ltr"
435+
>
436+
{{ item.version }}
437+
</LinkBase>
438+
<div
439+
v-if="versionToTagsMap.get(item.version)?.length"
440+
class="flex items-center gap-1 flex-wrap relative z-10"
441+
>
442+
<span
443+
v-for="tag in versionToTagsMap.get(item.version)"
444+
:key="tag"
445+
class="text-4xs font-semibold uppercase tracking-wide"
446+
:class="tag === 'latest' ? 'text-accent' : 'text-fg-subtle'"
447+
>
448+
{{ tag }}
449+
</span>
450+
</div>
451+
<span
452+
v-if="fullVersionMap?.get(item.version)?.deprecated"
453+
class="text-3xs font-medium text-red-700 dark:text-red-400 bg-red-100 dark:bg-red-900/30 px-1.5 py-0.5 rounded relative z-10"
454+
:title="fullVersionMap.get(item.version)!.deprecated"
455+
>
456+
deprecated
457+
</span>
458+
</div>
459+
460+
<!-- Right side -->
461+
<div class="flex items-center gap-2 shrink-0 relative z-10">
462+
<!-- TODO(atriiy): changelog would be implemented later -->
463+
464+
<!-- Metadata: date + provenance -->
465+
<DateTime
466+
v-if="getVersionTime(item.version)"
467+
:datetime="getVersionTime(item.version)!"
468+
class="text-xs text-fg-subtle hidden sm:block"
469+
year="numeric"
470+
month="short"
471+
day="numeric"
472+
/>
473+
<ProvenanceBadge
474+
v-if="fullVersionMap?.get(item.version)?.hasProvenance"
475+
:package-name="packageName"
476+
:version="item.version"
477+
compact
478+
:linked="false"
479+
/>
480+
</div>
481+
</div>
482+
483+
<!-- Mobile inline changelog (below the row, sm and up uses side panel) -->
484+
<div
485+
v-if="item.version in mockChangelogs"
486+
class="grid sm:hidden transition-[grid-template-rows] duration-200 ease-out motion-reduce:transition-none"
487+
:class="
488+
selectedChangelogVersion === item.version
489+
? 'grid-rows-[1fr]'
490+
: 'grid-rows-[0fr]'
491+
"
492+
>
493+
<div class="overflow-hidden">
494+
<div class="changelog-body border-t border-border px-4 py-3 text-sm">
495+
{{
496+
selectedChangelogVersion === item.version
497+
? selectedChangelogContent
498+
: ''
499+
}}
500+
</div>
489501
</div>
490502
</div>
491503
</div>

0 commit comments

Comments
 (0)