mirror of
https://github.com/supabase/supabase.git
synced 2026-10-11 20:35:07 +03:00
+9







![coderabbitai[bot]](/assets/img/avatar_default.png)
a469504f21
* 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>
233 lines
7.1 KiB
TypeScript
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>
|
|
)
|
|
}
|