import { useDroppable } from "@dnd-kit/core"; import { horizontalListSortingStrategy, SortableContext, } from "@dnd-kit/sortable"; import clsx from "clsx"; import { ChevronDown, ChevronUp, Trash } from "lucide-react"; import { useLayoutEffect, useRef } from "react"; import { Button } from "react-aria-components"; import { useTranslation } from "react-i18next"; import { SendouButton } from "~/components/elements/Button"; import { SendouPopover } from "~/components/elements/Popover"; import { useTierListState } from "../contexts/TierListContext"; import { PRESET_COLORS, TIER_NAME_FONT_SIZE_BREAKPOINTS, TIER_NAME_FONT_SIZE_MIN, TIER_NAME_MAX_LENGTH, } from "../tier-list-maker-constants"; import type { TierListMakerTier } from "../tier-list-maker-schemas"; import { tierListItemId } from "../tier-list-maker-utils"; import { DraggableItem } from "./DraggableItem"; import styles from "./TierRow.module.css"; interface TierRowProps { tier: TierListMakerTier; } export function TierRow({ tier }: TierRowProps) { const { state, activeItem, getItemsInTier, handleRemoveTier, handleRenameTier, handleChangeTierColor, handleMoveTierUp, handleMoveTierDown, showTierHeaders, screenshotMode, } = useTierListState(); const items = getItemsInTier(tier.id); const { t } = useTranslation(["tier-list-maker", "common"]); const { setNodeRef, isOver } = useDroppable({ id: tier.id, }); const combinedRef = useLockedHeightWhileDragging({ setNodeRef, isDragging: activeItem !== null, }); const tierIndex = state.tiers.findIndex((t) => t.id === tier.id); const isFirstTier = tierIndex === 0; const isLastTier = tierIndex === state.tiers.length - 1; return (
{showTierHeaders ? ( {tier.name} } >
{t("tier-list-maker:editingTier")}
handleRenameTier(tier.id, e.target.value)} className={styles.nameInput} maxLength={TIER_NAME_MAX_LENGTH} />
{PRESET_COLORS.map((color) => (
handleRemoveTier(tier.id)} variant="minimal-destructive" icon={} />
) : null}
{items.length === 0 && !screenshotMode ? (
{t("tier-list-maker:dropItems")}
) : items.length > 0 ? ( {items.map((item) => ( ))} ) : null}
{!screenshotMode ? (
) : null}
); } function useLockedHeightWhileDragging({ setNodeRef, isDragging, }: { setNodeRef: (node: HTMLElement | null) => void; isDragging: boolean; }) { const ref = useRef(null); const combinedRef = (node: HTMLDivElement | null) => { ref.current = node; setNodeRef(node); }; useLayoutEffect(() => { const el = ref.current; if (!el) return; if (isDragging) { const rect = el.getBoundingClientRect(); const firstItem = el.firstElementChild; const topOffset = firstItem ? firstItem.getBoundingClientRect().top - rect.top : undefined; el.style.height = `${rect.height}px`; el.style.overflow = "hidden"; if (topOffset !== undefined) { el.style.alignContent = "flex-start"; el.style.paddingTop = `${topOffset}px`; } } else { el.style.height = ""; el.style.overflow = ""; el.style.alignContent = ""; el.style.paddingTop = ""; } }, [isDragging]); return combinedRef; } function tierNameFontSize(name: string) { const length = name.length; for (const breakpoint of TIER_NAME_FONT_SIZE_BREAKPOINTS) { if (length <= breakpoint.maxLength) { return breakpoint.fontSize; } } return TIER_NAME_FONT_SIZE_MIN; }