Files
Compass/web/hooks/use-column-count.ts
MartinBraquet a5c4969d48 Introduce new components and utilities: ProfileAvatar, ShareCTAButton, custom video extensions, and responsive hooks.
- Added `ProfileAvatar` for consistent avatar rendering across profiles, with fallback initials and gradient backgrounds.
- Created `ShareCTAButton` for sharing links with native sharing support and clipboard fallback.
- Integrated custom `tiptap` video extension (`tiptap-video`) for video support in rich text editing.
- Introduced `useColumnCount` for responsive column count management in dynamic masonry layouts.
- Enhanced onboarding flow with refined "Share My Profile" feature using the new share button.
- Updated styles and layout in filtered profiles and onboarding screens for better consistency and responsiveness.
2026-07-27 00:51:20 +02:00

47 lines
1.6 KiB
TypeScript

import {clamp} from 'lodash'
import {RefObject, useEffect, useLayoutEffect, useState} from 'react'
/** Layout effect on the client so the first paint already has the right column count. */
const useIsomorphicLayoutEffect = typeof window === 'undefined' ? useEffect : useLayoutEffect
export type ColumnCountOptions = {
/** Narrowest a card may get before dropping a column. Drives the reading measure. */
minCardWidth: number
maxColumns: number
/** Gap between columns, so the fit accounts for it. */
gap?: number
}
/**
* Column count for JS-driven masonry layouts, measured from the container rather than the
* viewport — the people page has a sidebar and an optional docked filter panel, so the same
* viewport width can leave very different amounts of room for cards.
*/
export function useColumnCount(
containerRef: RefObject<HTMLElement | null>,
options: ColumnCountOptions,
) {
const {minCardWidth, maxColumns, gap = 16} = options
const [columnCount, setColumnCount] = useState(1)
useIsomorphicLayoutEffect(() => {
const el = containerRef.current
if (!el) return
const measure = () => {
const width = el.clientWidth
if (!width) return
// n columns fit when (width - gap * (n - 1)) / n >= minCardWidth.
const fits = Math.floor((width + gap) / (minCardWidth + gap))
setColumnCount(clamp(fits, 1, maxColumns))
}
measure()
const observer = new ResizeObserver(measure)
observer.observe(el)
return () => observer.disconnect()
}, [containerRef, minCardWidth, maxColumns, gap])
return columnCount
}