import type { Ref } from 'vue' import { useWindowSize } from '@vueuse/core' // Spiegelt das Upload-Grid aus index.vue: // grid-cols-4 sm:6 md:8 lg:12, auto-rows 6.5rem / sm:7rem / lg:7.5rem, gap-2 const PAGINATION_RESERVE_PX = 76 // Pagination (~36px) + mt-4 + Bottom-Padding const FALLBACK_TOP_PX = 150 // SSR-Schätzung: Header + Padding + Filterzeile interface PageSizeOptions { // [base, sm (>=640px), lg (>=1024px)] — Zeilenhöhe in rem ohne Grid-Gap rowHeights?: [number, number, number] // Abstand zwischen Anker-Unterkante und Grid-Oberkante in px (mb-* der Zeile) gapBelowAnchorPx?: number } export function usePageSize(anchor: Ref, options: PageSizeOptions = {}) { const { rowHeights = [6.5, 7, 7.5], gapBelowAnchorPx = 8 } = options const { width, height } = useWindowSize() const cols = computed(() => { const w = Number.isFinite(width.value) ? width.value : 1280 return w >= 1024 ? 12 : w >= 768 ? 8 : w >= 640 ? 6 : 4 }) // Zell-Budget: Wie viele 1x1-Zellen passen ohne Scrollen in den Viewport. // Die Grid-Oberkante wird am DOM-Element (Filterzeile) gemessen statt // Header/Padding zu schätzen. const cells = computed(() => { const w = Number.isFinite(width.value) ? width.value : 1280 const h = Number.isFinite(height.value) ? height.value : 800 const rem = import.meta.client ? Number.parseFloat(getComputedStyle(document.documentElement).fontSize) || 16 : 16 const rowH = (w >= 1024 ? rowHeights[2] : w >= 640 ? rowHeights[1] : rowHeights[0]) * rem + 8 // + grid gap const top = (anchor.value?.getBoundingClientRect().bottom ?? FALLBACK_TOP_PX) + gapBelowAnchorPx const rows = Math.max(1, Math.floor((h - top - PAGINATION_RESERVE_PX) / rowH)) return cols.value * rows }) return { cells, cols } }