Stop the library grid from fighting scroll-up by dropping content-visibility and matching virtual row height to the cards.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -106,15 +106,6 @@ textarea {
|
|||||||
#09090b;
|
#09090b;
|
||||||
}
|
}
|
||||||
|
|
||||||
.library-thumb {
|
|
||||||
content-visibility: auto;
|
|
||||||
contain-intrinsic-size: auto 15rem;
|
|
||||||
}
|
|
||||||
|
|
||||||
.studio-library-card {
|
|
||||||
contain: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.family-nav {
|
.family-nav {
|
||||||
display: flex;
|
display: flex;
|
||||||
height: 2.75rem;
|
height: 2.75rem;
|
||||||
|
|||||||
+21
-8
@@ -136,7 +136,7 @@
|
|||||||
<div
|
<div
|
||||||
v-else
|
v-else
|
||||||
ref="scroller"
|
ref="scroller"
|
||||||
class="mt-3 min-h-[24rem] flex-1 overflow-y-auto"
|
class="mt-3 min-h-[24rem] flex-1 overflow-y-auto overscroll-y-contain [overflow-anchor:none]"
|
||||||
@scroll="onScroll"
|
@scroll="onScroll"
|
||||||
>
|
>
|
||||||
<div :style="{ height: `${gridHeight}px`, position: 'relative' }">
|
<div :style="{ height: `${gridHeight}px`, position: 'relative' }">
|
||||||
@@ -210,7 +210,7 @@
|
|||||||
</section>
|
</section>
|
||||||
|
|
||||||
<aside
|
<aside
|
||||||
class="glass overflow-y-auto p-4 sm:p-5"
|
class="glass overflow-y-auto overscroll-y-contain [overflow-anchor:none] p-4 sm:p-5"
|
||||||
:class="focused
|
:class="focused
|
||||||
? 'fixed inset-0 z-[60] rounded-none lg:static lg:z-auto lg:h-full lg:w-[min(38rem,42vw)] lg:shrink-0 lg:rounded-3xl'
|
? 'fixed inset-0 z-[60] rounded-none lg:static lg:z-auto lg:h-full lg:w-[min(38rem,42vw)] lg:shrink-0 lg:rounded-3xl'
|
||||||
: 'hidden w-full shrink-0 rounded-3xl lg:block lg:h-full lg:w-[22rem]'"
|
: 'hidden w-full shrink-0 rounded-3xl lg:block lg:h-full lg:w-[22rem]'"
|
||||||
@@ -453,8 +453,8 @@ import { clipSettingsRows, stillSettingsRows } from '~/utils/libraryGeneration'
|
|||||||
|
|
||||||
const CARD_MIN = 156
|
const CARD_MIN = 156
|
||||||
const GAP = 10
|
const GAP = 10
|
||||||
const ROW_H = 248
|
const CARD_CAPTION = 50
|
||||||
const BUFFER_ROWS = 3
|
const BUFFER_ROWS = 4
|
||||||
const DRAG_MIME = 'application/x-aigen-library'
|
const DRAG_MIME = 'application/x-aigen-library'
|
||||||
const filterOptions = [
|
const filterOptions = [
|
||||||
{ id: 'all' as const, label: 'All' },
|
{ id: 'all' as const, label: 'All' },
|
||||||
@@ -555,11 +555,16 @@ const emptyLabel = computed(() => {
|
|||||||
return 'Nothing in this folder yet.'
|
return 'Nothing in this folder yet.'
|
||||||
})
|
})
|
||||||
const cols = computed(() => Math.max(2, Math.floor((viewportW.value + GAP) / (CARD_MIN + GAP))))
|
const cols = computed(() => Math.max(2, Math.floor((viewportW.value + GAP) / (CARD_MIN + GAP))))
|
||||||
|
const rowH = computed(() => {
|
||||||
|
const width = Math.max(CARD_MIN, (viewportW.value - GAP * (cols.value - 1)) / cols.value)
|
||||||
|
return Math.round(width * 5 / 4) + CARD_CAPTION
|
||||||
|
})
|
||||||
|
const rowStride = computed(() => rowH.value + GAP)
|
||||||
const rowCount = computed(() => Math.ceil(entries.value.length / cols.value) || 0)
|
const rowCount = computed(() => Math.ceil(entries.value.length / cols.value) || 0)
|
||||||
const gridHeight = computed(() => rowCount.value * ROW_H + Math.max(0, rowCount.value - 1) * GAP)
|
const gridHeight = computed(() => rowCount.value * rowH.value + Math.max(0, rowCount.value - 1) * GAP)
|
||||||
const startRow = computed(() => Math.max(0, Math.floor(scrollTop.value / (ROW_H + GAP)) - BUFFER_ROWS))
|
const startRow = computed(() => Math.max(0, Math.floor(scrollTop.value / rowStride.value) - BUFFER_ROWS))
|
||||||
const visibleRowCount = computed(() => Math.ceil(viewportH.value / (ROW_H + GAP)) + BUFFER_ROWS * 2)
|
const visibleRowCount = computed(() => Math.ceil(viewportH.value / rowStride.value) + BUFFER_ROWS * 2)
|
||||||
const offsetY = computed(() => startRow.value * (ROW_H + GAP))
|
const offsetY = computed(() => startRow.value * rowStride.value)
|
||||||
const visibleEntries = computed(() => {
|
const visibleEntries = computed(() => {
|
||||||
const start = startRow.value * cols.value
|
const start = startRow.value * cols.value
|
||||||
const end = start + visibleRowCount.value * cols.value
|
const end = start + visibleRowCount.value * cols.value
|
||||||
@@ -1100,6 +1105,14 @@ watch([folderId, filter], () => {
|
|||||||
watch(search, () => {
|
watch(search, () => {
|
||||||
if (scroller.value) scroller.value.scrollTop = 0
|
if (scroller.value) scroller.value.scrollTop = 0
|
||||||
})
|
})
|
||||||
|
watch([cols, rowH], ([nextCols, nextRowH], [prevCols, prevRowH]) => {
|
||||||
|
const el = scroller.value
|
||||||
|
if (!el || !prevRowH) return
|
||||||
|
if (nextCols === prevCols && nextRowH === prevRowH) return
|
||||||
|
const index = Math.floor(el.scrollTop / (prevRowH + GAP)) * prevCols
|
||||||
|
el.scrollTop = Math.floor(index / nextCols) * (nextRowH + GAP)
|
||||||
|
scrollTop.value = el.scrollTop
|
||||||
|
})
|
||||||
watch(focusedKey, (key) => {
|
watch(focusedKey, (key) => {
|
||||||
if (!key) {
|
if (!key) {
|
||||||
detailsHidden.value = false
|
detailsHidden.value = false
|
||||||
|
|||||||
Reference in New Issue
Block a user