mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-09-30 15:17:43 -05:00
Replace JS based tier width label solution with subgrid
Main goal is to try to fix the infinite loop bug users are reporting on tier list maker but this also nicely simplifies the code
This commit is contained in:
@@ -1,10 +1,12 @@
|
||||
.container {
|
||||
display: flex;
|
||||
gap: var(--s-1);
|
||||
display: grid;
|
||||
grid-template-columns: subgrid;
|
||||
grid-column: 1 / -1;
|
||||
min-height: 68px;
|
||||
}
|
||||
|
||||
.tierLabel {
|
||||
grid-column: 1;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
justify-content: center;
|
||||
@@ -42,7 +44,7 @@
|
||||
}
|
||||
|
||||
.targetZone {
|
||||
flex: 1;
|
||||
grid-column: 2;
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--s-1-5);
|
||||
@@ -75,6 +77,7 @@
|
||||
}
|
||||
|
||||
.arrowControls {
|
||||
grid-column: 3;
|
||||
display: grid;
|
||||
grid-template-rows: 1fr 1fr;
|
||||
gap: var(--s-1);
|
||||
|
||||
@@ -5,7 +5,6 @@ import {
|
||||
} 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";
|
||||
@@ -37,9 +36,6 @@ export function TierRow({ tier }: TierRowProps) {
|
||||
handleMoveTierDown,
|
||||
showTierHeaders,
|
||||
screenshotMode,
|
||||
tierLabelWidth,
|
||||
registerTierLabelWidth,
|
||||
unregisterTierLabelWidth,
|
||||
} = useTierListState();
|
||||
|
||||
const items = getItemsInTier(tier.id);
|
||||
@@ -47,40 +43,20 @@ export function TierRow({ tier }: TierRowProps) {
|
||||
const { setNodeRef, isOver } = useDroppable({
|
||||
id: tier.id,
|
||||
});
|
||||
const labelRef = useRef<HTMLButtonElement>(null);
|
||||
|
||||
// biome-ignore lint/correctness/useExhaustiveDependencies: tier.name impacts width
|
||||
useLayoutEffect(() => {
|
||||
if (labelRef.current) {
|
||||
// Temporarily remove width constraint to measure natural width
|
||||
const currentWidth = labelRef.current.style.width;
|
||||
labelRef.current.style.width = "auto";
|
||||
const naturalWidth = labelRef.current.scrollWidth;
|
||||
labelRef.current.style.width = currentWidth;
|
||||
registerTierLabelWidth(tier.id, naturalWidth);
|
||||
}
|
||||
}, [tier.id, tier.name, registerTierLabelWidth]);
|
||||
|
||||
const tierIndex = state.tiers.findIndex((t) => t.id === tier.id);
|
||||
const isFirstTier = tierIndex === 0;
|
||||
const isLastTier = tierIndex === state.tiers.length - 1;
|
||||
|
||||
const handleDelete = () => {
|
||||
unregisterTierLabelWidth(tier.id);
|
||||
handleRemoveTier(tier.id);
|
||||
};
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
{showTierHeaders ? (
|
||||
<SendouPopover
|
||||
trigger={
|
||||
<Button
|
||||
ref={labelRef}
|
||||
className={styles.tierLabel}
|
||||
style={{
|
||||
backgroundColor: tier.color,
|
||||
width: tierLabelWidth,
|
||||
}}
|
||||
>
|
||||
<span
|
||||
@@ -135,7 +111,7 @@ export function TierRow({ tier }: TierRowProps) {
|
||||
</div>
|
||||
<div className="stack horizontal justify-end">
|
||||
<SendouButton
|
||||
onPress={handleDelete}
|
||||
onPress={() => handleRemoveTier(tier.id)}
|
||||
variant="minimal-destructive"
|
||||
icon={<Trash />}
|
||||
/>
|
||||
|
||||
@@ -1,14 +1,10 @@
|
||||
import type { ReactNode } from "react";
|
||||
import { createContext, useContext, useRef, useState } from "react";
|
||||
import { createContext, useContext, useState } from "react";
|
||||
import { useTierList } from "../hooks/useTierList";
|
||||
import { DEFAULT_TIER_LABEL_WIDTH } from "../tier-list-maker-constants";
|
||||
|
||||
type TierListContextType = ReturnType<typeof useTierList> & {
|
||||
screenshotMode: boolean;
|
||||
setScreenshotMode: (value: boolean) => void;
|
||||
tierLabelWidth: number;
|
||||
registerTierLabelWidth: (tierId: string, width: number) => void;
|
||||
unregisterTierLabelWidth: (tierId: string) => void;
|
||||
};
|
||||
|
||||
const TierListContext = createContext<TierListContextType | null>(null);
|
||||
@@ -16,28 +12,6 @@ const TierListContext = createContext<TierListContextType | null>(null);
|
||||
export function TierListProvider({ children }: { children: ReactNode }) {
|
||||
const state = useTierList();
|
||||
const [screenshotMode, setScreenshotMode] = useState(false);
|
||||
const [tierLabelWidth, setTierLabelWidth] = useState(
|
||||
DEFAULT_TIER_LABEL_WIDTH,
|
||||
);
|
||||
const widthsRef = useRef<Map<string, number>>(new Map());
|
||||
|
||||
const registerTierLabelWidth = (tierId: string, width: number) => {
|
||||
widthsRef.current.set(tierId, width);
|
||||
const maxWidth = Math.max(...widthsRef.current.values());
|
||||
if (maxWidth !== tierLabelWidth) {
|
||||
setTierLabelWidth(maxWidth);
|
||||
}
|
||||
};
|
||||
|
||||
const unregisterTierLabelWidth = (tierId: string) => {
|
||||
widthsRef.current.delete(tierId);
|
||||
const values = [...widthsRef.current.values()];
|
||||
const maxWidth =
|
||||
values.length > 0 ? Math.max(...values) : DEFAULT_TIER_LABEL_WIDTH;
|
||||
if (maxWidth !== tierLabelWidth) {
|
||||
setTierLabelWidth(maxWidth);
|
||||
}
|
||||
};
|
||||
|
||||
return (
|
||||
<TierListContext.Provider
|
||||
@@ -45,9 +19,6 @@ export function TierListProvider({ children }: { children: ReactNode }) {
|
||||
...state,
|
||||
screenshotMode,
|
||||
setScreenshotMode,
|
||||
tierLabelWidth,
|
||||
registerTierLabelWidth,
|
||||
unregisterTierLabelWidth,
|
||||
}}
|
||||
>
|
||||
{children}
|
||||
|
||||
@@ -8,9 +8,10 @@
|
||||
}
|
||||
|
||||
.tierList {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--s-2);
|
||||
display: grid;
|
||||
grid-template-columns: auto 1fr auto;
|
||||
row-gap: var(--s-2);
|
||||
column-gap: var(--s-1);
|
||||
margin-bottom: var(--s-6);
|
||||
}
|
||||
|
||||
@@ -32,6 +33,7 @@
|
||||
}
|
||||
|
||||
.titleInput {
|
||||
grid-column: 1 / -1;
|
||||
width: 100%;
|
||||
padding: 0 var(--s-2) var(--s-2) var(--s-2);
|
||||
font-size: var(--font-lg);
|
||||
@@ -53,6 +55,7 @@
|
||||
}
|
||||
|
||||
.authorSection {
|
||||
grid-column: 1 / -1;
|
||||
display: flex;
|
||||
flex-direction: row;
|
||||
justify-content: center;
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
import type { TierListMakerTier } from "./tier-list-maker-schemas";
|
||||
|
||||
export const DEFAULT_TIER_LABEL_WIDTH = 68;
|
||||
export const TIER_NAME_MAX_LENGTH = 50;
|
||||
|
||||
export const TIER_NAME_FONT_SIZE_BREAKPOINTS = [
|
||||
|
||||
Reference in New Issue
Block a user