Files
supabase/apps/www/components/Wrapped/AnimatedGridBackground.tsx
+9 a469504f21 Supabase Wrapped 2025 (#41091)
* wip

* wip

* single page

* new sections and polishing up

* reponsive

* nits

* semantic titles

* optimize imgs

* nits

* wup

* hero bubbles

* Update apps/www/components/Wrapped/Pages/SupabaseSelect.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix: Use `amaro` for stripping types in code samples (#41229)

* Fix the error for babel/preset-typescript in docs.

* Unfix the version.

* Try using amaro for type stripping.

* Run prettier after stripping types.

* Fix tests.

---------

Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>

* fix: Fix minor issue in the foreign key selector (#41235)

Change the isPending state to isLoading.

* docs: Remove empty troubleshooting fields (#41236)

* Remove emoty fields

* Fix lock file

* chore: update self-hosted image versions (#41234)

* Feature: show index advisor in table editor (#41166)

* added table advisor query

* updated to include table editor performance

* updated JSON B

* added side panel

* updated query indexes to show highlights context

* show index advisor in table editor

* updated invalidation logic

* added color updates

* added query indexes

* updated query performance type

* updated overflow and title

* put behind flag

* remove gap

* added on close

* Update apps/studio/data/database/table-index-advisor-query.ts

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* updated styling

---------

Co-authored-by: Charis <26616127+charislam@users.noreply.github.com>

* fix: useFlag to update initial check of flag store (#41209)

* fix flag lib

* updated uneeded logic

* updated logic

* remove line

* updated comment

* fix: Hide favourites and share snippets on self-hosted variant (#41227)

* Hide favorite and share actions for self-hosted version.

* Rename the query on save only on platform.

* Simplify useCheckOpenAiKeyQuery.

* Rename with AI now depends if the OPENAI_API_KEY is set.

* Minor fixes.

* Fix the tests to use .skip for skipping tests. Remove extra port params.

* Make the test for favourites work only on platform variant.

* feat(reports): support new database report granularity FE-2221 (#41228)

* handle new granularity

* undo unnecessary type change

* rm console log

* fix: blog auto scroll post app router migration for blog (#41220)

Enhance TOC highlighting and anchor scroll in blog posts

Refactored useActiveAnchors hook to support smooth hash scrolling and improved TOC highlighting based on scroll position. Added options for custom selectors and offset, and updated BlogPostClient to enable scroll-to-anchor and TOC highlight functionality.

* fix: remove flakiness with launch options and default timeouts (#41245)

* attempt to make table editor tests less flaky

* updated race conditions for table editor

* updated playwright config with optimized launch options

* reduce workers

* updated timeouts for tests

* updated config to have a global timeout of 20 seconds

* updated to be visible

* chore: update changelog and image versions file (#41244)

* feat(design-system): improve table docs (#41215)

* docs updates

* docs expansion

* minor docs fix

* improvements

* fix dependencies

* docs expansion

* more table examples

* map over data

* improve copy

* Update apps/design-system/registry/default/example/table-row-link-actions.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* Update apps/design-system/registry/default/example/table-row-link-actions.tsx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fixes

* fix

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* chore(studio): improve table presentation (#41217)

* billing improvements

* wrapper improvements

* border fix

* Nit adjustments

* fixes

* fix aria

* fix loading

* fixes

* fix

---------

Co-authored-by: Joshen Lim <joshenlimek@gmail.com>

* Save opened side bar in local storage, and init on new session (#41224)

* Save opened side bar in local storage, and init on new session

* Fix test

* Fix

* Nit

* docs(design-system): Data Table and Data Grid documentation (#41252)

* basic differentiation

* docs

* data-grid examples

* data-grid-demo

* data-table

* demo

* use existing components

* improvements

* markup

* docs

* remove data table

* lint

* Update apps/design-system/content/docs/ui-patterns/empty-states.mdx

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* fix ref

* use TanStack sorting

* grammar

* dependency

* 📝 Add docstrings to `dnywh/docs/data-table-data-grid` (#41255)

Docstrings generation was requested by @MildTomato.

* https://github.com/supabase/supabase/pull/41252#issuecomment-3640781017

The following files were modified:

* `apps/design-system/registry/default/example/data-grid-demo.tsx`
* `apps/design-system/registry/default/example/data-grid-empty-state.tsx`
* `apps/design-system/registry/default/example/data-table-demo.tsx`

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>

* docs: fix grammatical error in generate-text-embeddings guide (#41187)

* docs: fix grammatical error in generate-text-embeddings guide

* Update generate-text-embeddings.mdx

Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com>

---------

Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com>

* chore: uniform card and panel padding-x (#41237)

* docs: Fix typo in API introduction documentation (#41251)

* chore(billing): regenerate api-types to include vanity subdomain entitlement (#41257)

chore(billing: regenerate api-types to include vanity subdomain entitlement

* Add liam to humans.txt (#41169)

* docs: Add link to restoring backup to new Supabase project (#39108)

Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>

* feat(code-block): add word wrap functionality and controls to code bl… (#39689)

* feat(code-block): add word wrap functionality and controls to code blocks

* feat(code-block): enhance layout of code block with improved line number display and structure

* fix h-full issue

* fix Prettier issue

---------

Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>

* wip

* wip

* single page

* optimize imgs

* revert

* pkg

* update new content

* rm overflow

* new data

* nits

* nits

* og

* border

* fix: improve AnimatedCounter and FloatingStatBubbles/Intro components

- Update AnimatedCounter to correctly reflect value changes in the DOM.
- Add lifetime management for timers in FloatingStatBubbles and FloatingBoxes to prevent memory leaks.
- Ensure cleanup of timers on component unmount for better resource management.

* dbs

* minify images

* text-brand-link on light mode

* fix grid

* max-width on images

* address comments

* fixes

* faster image rotation

* upd og

* new launch

* nitsgs

* last nits

---------

Co-authored-by: coderabbitai[bot] <136622811+coderabbitai[bot]@users.noreply.github.com>
Co-authored-by: Ivan Vasilov <vasilov.ivan@gmail.com>
Co-authored-by: Charis Lam <26616127+charislam@users.noreply.github.com>
Co-authored-by: Chris Chinchilla <chris.ward@supabase.io>
Co-authored-by: Andrey A. <56412611+aantti@users.noreply.github.com>
Co-authored-by: Ali Waseem <waseema393@gmail.com>
Co-authored-by: Jordi Enric <37541088+jordienr@users.noreply.github.com>
Co-authored-by: Jonathan Summers-Muir <MildTomato@users.noreply.github.com>
Co-authored-by: Danny White <3104761+dnywh@users.noreply.github.com>
Co-authored-by: Joshen Lim <joshenlimek@gmail.com>
Co-authored-by: Dinesh Dawonauth <dineshddawo@gmail.com>
Co-authored-by: Chris Chinchilla <chris@chrischinchilla.com>
Co-authored-by: Francesco Sansalvadore <f.sansalvadore@gmail.com>
Co-authored-by: 李子衿 <160584929+hhhez@users.noreply.github.com>
Co-authored-by: Kanishk Dudeja <kanishk@kanishkdudeja.com>
Co-authored-by: lch-supa <liam.hogan@supabase.io>
Co-authored-by: Timothy Lim <tim.lim@supabase.io>
Co-authored-by: Priyanshu Thapliyal <114170980+Priyanshuthapliyal2005@users.noreply.github.com>
2025-12-16 14:49:42 +00:00

233 lines
7.1 KiB
TypeScript

'use client'
import { motion, useInView } from 'framer-motion'
import { useState, useEffect, useCallback, useMemo, useRef } from 'react'
import { Dots, Stripes } from './Visuals'
const STAGGER_DELAY = 0.05
const MOVE_INTERVAL = 2000 // Time between moves in ms
type TileType = 'dots' | 'stripes'
type TileConfig = {
id: number
type: TileType
initialCell: number
}
type ResponsiveRows = {
mobile: number
desktop: number
}
type AnimatedGridBackgroundProps = {
cols: number
rows: number | ResponsiveRows
tiles: Array<{ cell: number; type: TileType }>
initialDelay?: number
}
export function AnimatedGridBackground({
cols,
rows,
tiles,
initialDelay = 0,
}: AnimatedGridBackgroundProps) {
// Detect if we're on mobile (client-side only)
const [isMobile, setIsMobile] = useState(false)
useEffect(() => {
const checkMobile = () => setIsMobile(window.innerWidth < 768)
checkMobile()
window.addEventListener('resize', checkMobile)
return () => window.removeEventListener('resize', checkMobile)
}, [])
// Get the actual row count based on responsive config
const actualRows = typeof rows === 'number' ? rows : isMobile ? rows.mobile : rows.desktop
const totalCells = cols * actualRows
// Convert tiles config to internal format with IDs, filtering out tiles outside bounds
const tileConfigs: TileConfig[] = useMemo(
() =>
tiles
.filter((tile) => tile.cell < totalCells)
.map((tile, index) => ({
id: index,
type: tile.type,
initialCell: tile.cell,
})),
[tiles, totalCells]
)
// Track current positions of all tiles
const [tilePositions, setTilePositions] = useState<Map<number, number>>(new Map())
// Reinitialize tile positions when tileConfigs changes (e.g., on responsive change)
useEffect(() => {
const initial = new Map<number, number>()
tileConfigs.forEach((tile) => {
initial.set(tile.id, tile.initialCell)
})
setTilePositions(initial)
}, [tileConfigs])
// Get adjacent cells (up, down, left, right) that are within bounds
const getAdjacentCells = useCallback(
(cell: number): number[] => {
const row = Math.floor(cell / cols)
const col = cell % cols
const adjacent: number[] = []
// Up
if (row > 0) adjacent.push(cell - cols)
// Down
if (row < actualRows - 1) adjacent.push(cell + cols)
// Left
if (col > 0) adjacent.push(cell - 1)
// Right
if (col < cols - 1) adjacent.push(cell + 1)
return adjacent
},
[cols, actualRows]
)
// Get occupied cells
const getOccupiedCells = useCallback((): Set<number> => {
return new Set(tilePositions.values())
}, [tilePositions])
// Move a random tile to an adjacent empty cell
const moveRandomTile = useCallback(() => {
const occupiedCells = getOccupiedCells()
const tileIds = Array.from(tilePositions.keys())
// Shuffle tile IDs to pick randomly
const shuffledIds = [...tileIds].sort(() => Math.random() - 0.5)
for (const tileId of shuffledIds) {
const currentCell = tilePositions.get(tileId)!
const adjacentCells = getAdjacentCells(currentCell)
// Find empty adjacent cells
const emptyAdjacent = adjacentCells.filter((cell) => !occupiedCells.has(cell))
if (emptyAdjacent.length > 0) {
// Pick a random empty adjacent cell
const targetCell = emptyAdjacent[Math.floor(Math.random() * emptyAdjacent.length)]
setTilePositions((prev) => {
const next = new Map(prev)
next.set(tileId, targetCell)
return next
})
return // Only move one tile per interval
}
}
}, [tilePositions, getAdjacentCells, getOccupiedCells])
// Ref for viewport detection
const containerRef = useRef<HTMLDivElement>(null)
const isInView = useInView(containerRef, { once: true, amount: 0.2 })
// Set up the movement interval (only when in view)
useEffect(() => {
if (!isInView) return
const interval = setInterval(moveRandomTile, MOVE_INTERVAL)
return () => clearInterval(interval)
}, [moveRandomTile, isInView])
// Calculate position offset for animation
const getCellPosition = (cell: number) => {
const row = Math.floor(cell / cols)
const col = cell % cols
return { row, col }
}
// Calculate the CSS transform for a tile based on its current cell vs initial cell
const getTileTransform = (tileId: number, initialCell: number) => {
const currentCell = tilePositions.get(tileId) ?? initialCell
const initial = getCellPosition(initialCell)
const current = getCellPosition(currentCell)
const colDiff = current.col - initial.col
const rowDiff = current.row - initial.row
// Account for 1px border between cells
const xOffset = colDiff * 100
const yOffset = rowDiff * 100
const xBorderOffset = colDiff
const yBorderOffset = rowDiff
return {
x: `calc(${xOffset}% + ${xBorderOffset}px)`,
y: `calc(${yOffset}% + ${yBorderOffset}px)`,
}
}
return (
<div
ref={containerRef}
className={`absolute inset-0 grid h-full [&>*]:border-muted [&>*]:border-r [&>*]:border-b overflow-hidden`}
style={{
gridTemplateColumns: `repeat(${cols}, 1fr)`,
gridTemplateRows: `repeat(${actualRows}, 1fr)`,
}}
>
{Array.from({ length: totalCells }).map((_, cellIndex) => {
const row = Math.floor(cellIndex / cols)
const col = cellIndex % cols
const diagonalIndex = row + col
// Check if this cell is the initial position of any tile
const tile = tileConfigs.find((t) => t.initialCell === cellIndex)
// Remove right border on last column
const isLastCol = col === cols - 1
// Remove bottom border on last row
const isLastRow = row === actualRows - 1
return (
<div
key={cellIndex}
className={`relative ${isLastCol ? '!border-r-0' : ''} ${isLastRow ? '!border-b-0' : ''}`}
>
{tile && (
<motion.div
className="absolute inset-0"
initial={{ opacity: 0, scale: 0.98 }}
animate={
isInView
? {
opacity: 1,
scale: 1,
x: getTileTransform(tile.id, tile.initialCell).x,
y: getTileTransform(tile.id, tile.initialCell).y,
}
: { opacity: 0, scale: 0.98 }
}
transition={{
opacity: {
delay: initialDelay + diagonalIndex * STAGGER_DELAY,
duration: 0.3,
},
scale: {
delay: initialDelay + diagonalIndex * STAGGER_DELAY,
duration: 0.3,
},
x: { type: 'spring', duration: 0.69, bounce: 0.12 },
y: { type: 'spring', duration: 0.69, bounce: 0.12 },
}}
>
{tile.type === 'dots' ? <Dots /> : <Stripes />}
</motion.div>
)}
</div>
)
})}
</div>
)
}