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:
parent
d342f1ad25
commit
c50386ed4c
4 changed files with 13 additions and 26 deletions
|
|
@ -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",
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
|
|
@ -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>
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue