Fix mobile league settings: prevent sports scroll and remove completion checkmarks

- Add overflow-hidden to sport label text span so flex truncation is properly contained
- Add min-w-0 to SettingsSection header inner flex item to prevent title/description overflow
- Remove completion check marks from mobile grid nav buttons (league settings has no completion concept)
- Remove "X of Y set" counter from mobile nav header
- Remove isComplete field from SettingsGridSection type and all data

https://claude.ai/code/session_01T7iTb9YZLuWJFtKV753tdB
This commit is contained in:
Claude 2026-05-07 03:55:13 +00:00
parent d342f1ad25
commit c50386ed4c
No known key found for this signature in database
4 changed files with 13 additions and 26 deletions

View file

@ -1,6 +1,6 @@
import type { ComponentType } from "react"; import type { ComponentType } from "react";
import type { LucideProps } from "lucide-react"; import type { LucideProps } from "lucide-react";
import { ArrowLeft, Check } from "lucide-react"; import { ArrowLeft } from "lucide-react";
import { cn } from "~/lib/utils"; import { cn } from "~/lib/utils";
type SettingsNavSection = { type SettingsNavSection = {
@ -11,28 +11,22 @@ type SettingsNavSection = {
export type SettingsGridSection = SettingsNavSection & { export type SettingsGridSection = SettingsNavSection & {
icon: ComponentType<LucideProps>; icon: ComponentType<LucideProps>;
subtitle: string; subtitle: string;
isComplete: boolean;
isDanger?: boolean; isDanger?: boolean;
}; };
export function SettingsMobileGridNav({ export function SettingsMobileGridNav({
sections, sections,
completedCount,
onSectionChange, onSectionChange,
}: { }: {
sections: readonly SettingsGridSection[]; sections: readonly SettingsGridSection[];
completedCount: number;
onSectionChange: (sectionId: string) => void; onSectionChange: (sectionId: string) => void;
}) { }) {
return ( return (
<div className="mb-5 lg:hidden"> <div className="mb-5 lg:hidden">
<div className="mb-3 flex items-center justify-between"> <div className="mb-3">
<p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground"> <p className="text-xs font-semibold uppercase tracking-wide text-muted-foreground">
Manage Manage
</p> </p>
<p className="text-xs text-muted-foreground">
{completedCount} of {sections.length} set
</p>
</div> </div>
<div className="grid grid-cols-2 gap-3"> <div className="grid grid-cols-2 gap-3">
{sections.map((section) => ( {sections.map((section) => (
@ -41,15 +35,10 @@ export function SettingsMobileGridNav({
type="button" type="button"
onClick={() => onSectionChange(section.id)} onClick={() => onSectionChange(section.id)}
className={cn( className={cn(
"relative flex cursor-pointer flex-col gap-3 rounded-xl border bg-card p-4 text-left transition-colors hover:border-primary/40 active:scale-[0.98]", "flex cursor-pointer flex-col gap-3 rounded-xl border bg-card p-4 text-left transition-colors hover:border-primary/40 active:scale-[0.98]",
section.isDanger && "border-destructive/40" section.isDanger && "border-destructive/40"
)} )}
> >
{section.isComplete && (
<div className="absolute right-3 top-3 flex h-5 w-5 items-center justify-center rounded-full bg-primary text-primary-foreground">
<Check className="h-3 w-3" strokeWidth={3} />
</div>
)}
<div <div
className={cn( className={cn(
"flex h-10 w-10 items-center justify-center rounded-lg", "flex h-10 w-10 items-center justify-center rounded-lg",

View file

@ -50,7 +50,7 @@ export function SettingsSection({
<div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between"> <div className="flex flex-col gap-3 sm:flex-row sm:items-start sm:justify-between">
<div className="flex items-start gap-3"> <div className="flex items-start gap-3">
<GradientIcon icon={icon} className="mt-1 h-6 w-6 shrink-0" /> <GradientIcon icon={icon} className="mt-1 h-6 w-6 shrink-0" />
<div> <div className="min-w-0">
<h2 className="text-2xl font-bold tracking-tight sm:text-3xl">{title}</h2> <h2 className="text-2xl font-bold tracking-tight sm:text-3xl">{title}</h2>
<p className="mt-2 max-w-2xl text-sm text-muted-foreground">{description}</p> <p className="mt-2 max-w-2xl text-sm text-muted-foreground">{description}</p>
</div> </div>

View file

@ -72,7 +72,7 @@ export function SportsSection({
disabled={!canEditSports} disabled={!canEditSports}
/> />
<SportIcon sport={ss.sport} /> <SportIcon sport={ss.sport} />
<span className="min-w-0 flex-1"> <span className="min-w-0 flex-1 overflow-hidden">
<span className="block truncate font-medium"> <span className="block truncate font-medium">
{ss.sport.slug === BRACKT_SLUG ? "Brackt" : `${ss.sport.name} - ${ss.name} (${ss.year})`} {ss.sport.slug === BRACKT_SLUG ? "Brackt" : `${ss.sport.name} - ${ss.name} (${ss.year})`}
</span> </span>

View file

@ -307,16 +307,15 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
}; };
const sectionGridData: SettingsGridSection[] = [ const sectionGridData: SettingsGridSection[] = [
{ id: "league-basics", label: "League Basics", icon: Shield, subtitle: "Name, teams, join", isComplete: true }, { id: "league-basics", label: "League Basics", icon: Shield, subtitle: "Name, teams, join" },
{ id: "draft-setup", label: "Draft Settings", icon: Swords, subtitle: "Format, timing, rounds", isComplete: !!(draftDate && draftTime) }, { id: "draft-setup", label: "Draft Settings", icon: Swords, subtitle: "Format, timing, rounds" },
{ id: "draft-order", label: "Draft Order", icon: ListOrdered, subtitle: "Pick order, randomize", isComplete: draftOrderSet }, { id: "draft-order", label: "Draft Order", icon: ListOrdered, subtitle: "Pick order, randomize" },
{ id: "sports", label: "Sports", icon: Trophy, subtitle: `${selectedSports.size} season${selectedSports.size !== 1 ? "s" : ""} selected`, isComplete: selectedSports.size > 0 }, { id: "sports", label: "Sports", icon: Trophy, subtitle: `${selectedSports.size} season${selectedSports.size !== 1 ? "s" : ""} selected` },
{ id: "scoring", label: "Scoring", icon: TrendingUp, subtitle: "Place values, ties", isComplete: true }, { id: "scoring", label: "Scoring", icon: TrendingUp, subtitle: "Place values, ties" },
{ id: "notifications", label: "Notifications", icon: Bell, subtitle: "Discord alerts", isComplete: !!league.discordWebhookUrl }, { id: "notifications", label: "Notifications", icon: Bell, subtitle: "Discord alerts" },
{ id: "people", label: "People", icon: Users, subtitle: `${teamsWithOwners} of ${teamCountValue} teams`, isComplete: false }, { id: "people", label: "People", icon: Users, subtitle: `${teamsWithOwners} of ${teamCountValue} teams` },
{ id: "history-danger", label: "History & Danger", icon: AlertTriangle, subtitle: "Audit log, dissolve", isComplete: false, isDanger: true }, { id: "history-danger", label: "History & Danger", icon: AlertTriangle, subtitle: "Audit log, dissolve", isDanger: true },
]; ];
const completedSectionCount = sectionGridData.filter((s) => s.isComplete).length;
return ( return (
<div className="container mx-auto max-w-5xl px-4 py-6 sm:py-8"> <div className="container mx-auto max-w-5xl px-4 py-6 sm:py-8">
@ -328,7 +327,6 @@ export default function LeagueSettings({ loaderData, actionData }: Route.Compone
<div className="lg:hidden"> <div className="lg:hidden">
<SettingsMobileGridNav <SettingsMobileGridNav
sections={sectionGridData} sections={sectionGridData}
completedCount={completedSectionCount}
onSectionChange={(id) => handleSectionChange(id as SettingsSectionId, { mobile: true })} onSectionChange={(id) => handleSectionChange(id as SettingsSectionId, { mobile: true })}
/> />
</div> </div>