diff --git a/app/components/AbilitiesSelector.tsx b/app/components/AbilitiesSelector.tsx index 041366d11..7105ea58f 100644 --- a/app/components/AbilitiesSelector.tsx +++ b/app/components/AbilitiesSelector.tsx @@ -176,28 +176,21 @@ function addAbility({ ) as BuildAbilitiesTupleWithUnknown; if (atRowIndex !== undefined && atAbilityIndex !== undefined) { - // Attempt to place the ability at a specific slot since we - // were given an atRowIndex and atAbilityIndex if (canPlaceAbilityAtSlot(atRowIndex, atAbilityIndex, ability)) { - // Assign this ability to the slot abilitiesClone[atRowIndex][atAbilityIndex] = ability.name; } } else { - // Loop through all slots and attempt to place this ability - // in the first empty one + // place in the first empty valid slot for (const [rowIndex, row] of abilitiesClone.entries()) { for (const [abilityIndex, oldAbility] of row.entries()) { if (oldAbility !== "UNKNOWN") { - // Skip any filled slots in this loop until we arrive at an empty one. continue; } if (!canPlaceAbilityAtSlot(rowIndex, abilityIndex, ability)) { - // This ability isn't valid for this slot continue; } - // Assign this ability to the slot abilitiesClone[rowIndex][abilityIndex] = ability.name; return abilitiesClone; @@ -205,6 +198,5 @@ function addAbility({ } } - // no-op if no available slots return abilitiesClone; } diff --git a/app/components/Ability.tsx b/app/components/Ability.tsx index 7f997487f..7a37edfa4 100644 --- a/app/components/Ability.tsx +++ b/app/components/Ability.tsx @@ -47,7 +47,6 @@ export function Ability({ const readonly = typeof onClick === "undefined" || ability === "UNKNOWN"; // Force "UNKNOWN" ability icons to be readonly - // Render an ability as a button only if it is meant to be draggable (i.e., not readonly) const AbilityTag = readonly ? "div" : "button"; const altText = diff --git a/app/components/ActionButton.tsx b/app/components/ActionButton.tsx index dbe76c341..2ab2acae1 100644 --- a/app/components/ActionButton.tsx +++ b/app/components/ActionButton.tsx @@ -14,16 +14,15 @@ interface ActionButtonBaseProps< TSchema extends AnySchema, TAction extends ActionsOf, > extends Omit { - /** Action schema of the route the button submits to. Only used for typing `action` and `fields`. */ + /** Route's action schema, only used for typing `action` and `fields`. */ schema: TSchema; - /** `_action` to submit, narrowed to the literals of the schema. */ action: TAction; - /** Route to submit to. Defaults to the current route. */ + /** Defaults to the current route. */ formAction?: string; formClassName?: string; - /** Fetcher to submit with, e.g. to share submitting state between buttons. Defaults to own fetcher. */ + /** e.g. to share submitting state between buttons */ fetcher?: FetcherWithComponents; - /** When set, submits only after the user confirms via a dialog. */ + /** submits only after the user confirms via a dialog */ confirm?: { dialogHeading: string; description?: React.ReactNode; diff --git a/app/components/BuildCard.tsx b/app/components/BuildCard.tsx index 124b4d598..d0bc6fec0 100644 --- a/app/components/BuildCard.tsx +++ b/app/components/BuildCard.tsx @@ -65,7 +65,7 @@ interface BuildProps { Partial< Pick >; - /** Set to false when the page context already shows the owner (e.g. their own builds page) */ + /** false when the page already shows the owner (e.g. their own builds page) */ showOwner?: boolean; canEdit?: boolean; } diff --git a/app/components/Catcher.tsx b/app/components/Catcher.tsx index 9ad37bebe..10cead5ca 100644 --- a/app/components/Catcher.tsx +++ b/app/components/Catcher.tsx @@ -29,7 +29,7 @@ export function Catcher() { window.scrollTo(0, 0); }, []); - // refresh user data to make sure it's up to date (e.g. cookie might have been removed, let's show the prompt to log back in) + // refresh user data so e.g. a removed cookie shows the prompt to log back in const hasRevalidated = React.useRef(false); React.useEffect(() => { if (!isRouteErrorResponse(error) || error.status !== 401) return; @@ -144,10 +144,7 @@ export function Catcher() { } } -/** - * A client side navigation to an URL matching no route never reaches the server, so the - * redirects (normally resolved by `redirectsMiddleware`) are checked here as well. - */ +/** Client side navigation to an unmatched URL never reaches the server, so `redirectsMiddleware`'s redirects are checked here too. */ function PageNotFound() { const location = useLocation(); const navigate = useNavigate(); diff --git a/app/components/Chart.tsx b/app/components/Chart.tsx index f192b26b0..fd049159f 100644 --- a/app/components/Chart.tsx +++ b/app/components/Chart.tsx @@ -49,14 +49,14 @@ export default function Chart({ xTicksLimit?: number; yTicksLimit?: number; xAbilityLimit?: number; - /** Marks current positions on the curve, each at ability point `x` and stat value `y` (e.g. one per build being compared). */ + /** Markers on the curve at ability point `x` / stat value `y`, e.g. one per build compared. */ highlight?: Array<{ x: number; y: number }>; - /** When true, draws dashed guide lines from the hovered point to the x- and y-axes. */ + /** dashed guide lines from the hovered point to both axes */ crosshair?: boolean; }) { const isHydrated = useHydrated(); - // Ref to the Chart.js instance, allows proper cleanup between renders to prevent "Canvas is already in use" errors + // cleanup between renders prevents "Canvas is already in use" errors const chartRef = useRef | null>(null); const chartId = React.useId(); // Chart.js re-fires the external tooltip on every redraw; track the last value to skip redundant state updates @@ -74,22 +74,19 @@ export default function Chart({ header: string; } | null>(null); - // Format dates in the tooltip header using the user's locale const { formatter: headerFormatter } = useDateTimeFormat({ weekday: "short", day: "numeric", month: "numeric", }); - // Format dates on the xAxis const { formatter: scaleFormatter } = useDateTimeFormat({ day: "numeric", month: "numeric", }); - // Get the chart colors from CSS variables const colors = useThemeColors({ - // bright "high" variants for the curve lines so they stay legible on the dark chart + // "high" variants for the curve lines so they stay legible on the dark chart accentHigh: "--color-text-accent", infoHigh: "--color-info-high", secondHigh: "--color-second-high", @@ -110,13 +107,12 @@ export default function Chart({ [colors.border, colors.borderHigh, colors.text], ); - // Make a color list to use inside ChartData for the borderColor and the external tooltip const colorList = React.useMemo( () => [colors.accentHigh, colors.infoHigh, colors.secondHigh], [colors.accentHigh, colors.infoHigh, colors.secondHigh], ); - // Distinct accent/secondary pair so the highlight markers (e.g. build 1 vs build 2) stay tellable apart in both themes + // distinct pair so highlight markers (e.g. build 1 vs build 2) stay apart in both themes const markerColors = React.useMemo( () => [colors.accentLow, colors.secondLow], [colors.accentLow, colors.secondLow], @@ -169,7 +165,6 @@ export default function Chart({ [options, datasetColors, highlight, markerColors, colors.text], ); - // Draws dashed guide lines from the hovered point to the y-axis (left) and x-axis (bottom) const crosshairPlugin = React.useMemo( () => ({ id: "crosshair", diff --git a/app/components/EmptyState.tsx b/app/components/EmptyState.tsx index 2ed9a3a24..52beace7c 100644 --- a/app/components/EmptyState.tsx +++ b/app/components/EmptyState.tsx @@ -9,7 +9,7 @@ interface EmptyStateProps { children: React.ReactNode; } -/** Renders the message shown by a page or tab that has no content, with the feature's nav icon above it. */ +/** Message for a page or tab with no content, with the feature's nav icon above it. */ export function EmptyState({ navItem, children }: EmptyStateProps) { return (
diff --git a/app/components/FormWithConfirm.tsx b/app/components/FormWithConfirm.tsx index bc06fa3bb..cc0dbb038 100644 --- a/app/components/FormWithConfirm.tsx +++ b/app/components/FormWithConfirm.tsx @@ -37,17 +37,17 @@ export function FormWithConfirm({ )[]; children?: React.ReactElement; dialogHeading: string; - /** Optional explanatory text shown below the heading in the confirm dialog */ + /** shown below the heading in the confirm dialog */ description?: React.ReactNode; submitButtonText?: string; action?: string; submitButtonTestId?: string; submitButtonVariant?: SendouButtonProps["variant"]; fetcher?: FetcherWithComponents; - /** Controls the dialog open state. When provided, no child trigger is needed. */ + /** controlled open state, no child trigger needed */ isOpen?: boolean; onOpenChange?: (isOpen: boolean) => void; - /** Confirming runs this callback instead of submitting a form (client only action) */ + /** runs instead of submitting a form (client only action) */ onConfirm?: () => void; }) { const componentsFetcher = useFetcher(); diff --git a/app/components/GameTimeline.tsx b/app/components/GameTimeline.tsx index 152e11217..5d4238079 100644 --- a/app/components/GameTimeline.tsx +++ b/app/components/GameTimeline.tsx @@ -1,11 +1,7 @@ /** - * A game's two scanned-timeline charts stacked on one shared time axis and - * plot width: per-player status bands above the objective-counter chart. - * Hovering scrubs over both — a dotted cursor line spans the charts and a - * readout next to the cursor shows the moment's elapsed time, match clock, - * scores, penalties, who was in control, who was splatted and who had their - * special ready. The chart's own tooltip is turned off in favor of the - * readout. + * A game's two scanned-timeline charts (player status bands above the objective-counter chart) + * on one shared time axis. Hovering scrubs both: a cursor line spans the charts and a readout + * shows the moment's state, replacing the chart's own tooltip. */ import clsx from "clsx"; import { memo, useRef, useState } from "react"; diff --git a/app/components/LocaleTime.tsx b/app/components/LocaleTime.tsx index 67514e95b..df95f99e2 100644 --- a/app/components/LocaleTime.tsx +++ b/app/components/LocaleTime.tsx @@ -3,24 +3,18 @@ import { useDateTimeFormat } from "~/hooks/intl/useDateTimeFormat"; import { databaseTimestampToDate } from "~/utils/dates"; interface LocaleTimeProps { - /** The date to render. Accepts a `Date` or a database timestamp (number), which is converted via `databaseTimestampToDate`. */ + /** `Date` or database timestamp */ date: Date | number; - /** Formatting options forwarded to `Intl.DateTimeFormat`. Combined with the user's locale and hour cycle preferences. */ options: Intl.DateTimeFormatOptions; - /** Optional extra class names appended to the rendered `