import { useWindowSize } from '@vueuse/core' import { computed, onMounted, ref } from 'vue' import type { Sizes } from '@/constants/layout' import { Breakpoints } from '@/constants/layout' type SizeValue = Sizes | number type BreakpointName = 'mobile' | 'tablet' | 'largeTablet' | 'desktop' | 'large' const NAMED_BREAKPOINTS: Record = { mobile: Breakpoints.MOBILE, tablet: Breakpoints.TABLET, largeTablet: Breakpoints.LARGE_TABLET, desktop: Breakpoints.DESKTOP, large: Breakpoints.LARGE, } export type DynamicSizeConfig = { default: SizeValue } & Partial> const resolveThreshold = (key: string): number => { if (key in NAMED_BREAKPOINTS) { return NAMED_BREAKPOINTS[key as BreakpointName] } return Number(key) } const resolveSize = (width: number, config: DynamicSizeConfig): SizeValue => { const { default: defaultValue, ...breakpoints } = config let match: SizeValue | undefined let matchThreshold = -1 for (const [key, value] of Object.entries(breakpoints)) { const threshold = resolveThreshold(key) if (width <= threshold && threshold > matchThreshold) { match = value matchThreshold = threshold } } return match ?? defaultValue } export const useDynamicSize = (config: DynamicSizeConfig) => { if (import.meta.env.SSR) return config.default const isMounted = ref(false) onMounted(() => (isMounted.value = true)) const { width: windowWidth } = useWindowSize() return computed(() => { if (!isMounted.value) return config.default return resolveSize(windowWidth.value, config) }) }