Aggiunge sottosezioni a swipe su Squadra e Classifica.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -0,0 +1,119 @@
|
|||||||
|
import { useEffect, useRef, useState, type ReactNode } from "react";
|
||||||
|
import { AnimatePresence, motion, useReducedMotion } from "motion/react";
|
||||||
|
import { cn } from "@/lib/utils";
|
||||||
|
import { molla, proietta } from "@/lib/molla";
|
||||||
|
|
||||||
|
export type VoceSottosezione = {
|
||||||
|
id: string;
|
||||||
|
label: string;
|
||||||
|
contenuto: ReactNode;
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Barra di sottosezioni in un'unica fila scorrevole (swipe orizzontale) e
|
||||||
|
* pannello che mostra una sola sezione alla volta, cambiabile anche con
|
||||||
|
* swipe sul contenuto.
|
||||||
|
*/
|
||||||
|
export function BarraSottosezioni({
|
||||||
|
voci,
|
||||||
|
defaultId,
|
||||||
|
}: {
|
||||||
|
voci: VoceSottosezione[];
|
||||||
|
defaultId?: string;
|
||||||
|
}) {
|
||||||
|
const [attiva, setAttiva] = useState(defaultId ?? voci[0]?.id ?? "");
|
||||||
|
const direzione = useRef(0);
|
||||||
|
const tabRefs = useRef<Record<string, HTMLButtonElement | null>>({});
|
||||||
|
const ridotto = useReducedMotion();
|
||||||
|
const indice = Math.max(
|
||||||
|
0,
|
||||||
|
voci.findIndex((v) => v.id === attiva),
|
||||||
|
);
|
||||||
|
const voce = voci[indice] ?? voci[0];
|
||||||
|
|
||||||
|
useEffect(() => {
|
||||||
|
tabRefs.current[attiva]?.scrollIntoView({
|
||||||
|
behavior: ridotto ? "auto" : "smooth",
|
||||||
|
inline: "center",
|
||||||
|
block: "nearest",
|
||||||
|
});
|
||||||
|
}, [attiva, ridotto]);
|
||||||
|
|
||||||
|
function vaiA(nuovo: number) {
|
||||||
|
if (nuovo < 0 || nuovo >= voci.length) return;
|
||||||
|
const target = voci[nuovo];
|
||||||
|
if (!target || target.id === attiva) return;
|
||||||
|
direzione.current = nuovo > indice ? 1 : -1;
|
||||||
|
setAttiva(target.id);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!voce) return null;
|
||||||
|
|
||||||
|
return (
|
||||||
|
<div>
|
||||||
|
<div className="border-b border-border bg-background/80 pt-3 backdrop-blur-md">
|
||||||
|
<div
|
||||||
|
role="tablist"
|
||||||
|
aria-label="Sottosezioni"
|
||||||
|
className="-mx-0 flex snap-x snap-mandatory gap-1.5 overflow-x-auto px-5 pb-3 [scrollbar-width:none] [&::-webkit-scrollbar]:hidden"
|
||||||
|
>
|
||||||
|
{voci.map((v) => {
|
||||||
|
const selezionata = v.id === attiva;
|
||||||
|
return (
|
||||||
|
<button
|
||||||
|
key={v.id}
|
||||||
|
ref={(el) => {
|
||||||
|
tabRefs.current[v.id] = el;
|
||||||
|
}}
|
||||||
|
type="button"
|
||||||
|
role="tab"
|
||||||
|
aria-selected={selezionata}
|
||||||
|
onClick={() => {
|
||||||
|
const i = voci.findIndex((x) => x.id === v.id);
|
||||||
|
vaiA(i);
|
||||||
|
}}
|
||||||
|
className={cn(
|
||||||
|
"snap-center shrink-0 rounded-full px-3.5 py-2 text-xs font-bold uppercase tracking-wide transition-colors",
|
||||||
|
"min-h-11 touch-manipulation whitespace-nowrap",
|
||||||
|
selezionata
|
||||||
|
? "bg-accent text-accent-foreground shadow-pop"
|
||||||
|
: "bg-secondary text-muted-foreground",
|
||||||
|
)}
|
||||||
|
>
|
||||||
|
{v.label}
|
||||||
|
</button>
|
||||||
|
);
|
||||||
|
})}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="relative overflow-hidden">
|
||||||
|
<AnimatePresence initial={false} mode="popLayout" custom={direzione.current}>
|
||||||
|
<motion.div
|
||||||
|
key={voce.id}
|
||||||
|
role="tabpanel"
|
||||||
|
aria-label={voce.label}
|
||||||
|
custom={direzione.current}
|
||||||
|
drag="x"
|
||||||
|
dragConstraints={{ left: 0, right: 0 }}
|
||||||
|
dragElastic={0.18}
|
||||||
|
dragMomentum={false}
|
||||||
|
onDragEnd={(_, info) => {
|
||||||
|
const arrivo = info.offset.x + proietta(info.velocity.x);
|
||||||
|
if (arrivo < -60) vaiA(indice + 1);
|
||||||
|
else if (arrivo > 60) vaiA(indice - 1);
|
||||||
|
}}
|
||||||
|
initial={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione.current * 40 }}
|
||||||
|
animate={{ opacity: 1, x: 0 }}
|
||||||
|
exit={ridotto ? { opacity: 0 } : { opacity: 0, x: direzione.current * -40 }}
|
||||||
|
transition={ridotto ? { duration: 0.15 } : molla.foglio}
|
||||||
|
className="touch-pan-y px-5 py-4"
|
||||||
|
>
|
||||||
|
<h2 className="mb-3 font-display-sm text-lg uppercase">{voce.label}</h2>
|
||||||
|
{voce.contenuto}
|
||||||
|
</motion.div>
|
||||||
|
</AnimatePresence>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
+27
-18
@@ -2,11 +2,11 @@ import { createFileRoute, Link } from "@tanstack/react-router";
|
|||||||
import { ChevronRight, RefreshCw } from "lucide-react";
|
import { ChevronRight, RefreshCw } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { formatData } from "@/lib/crapp-data";
|
import { formatData } from "@/lib/crapp-data";
|
||||||
import { PageHeader, Section, SezioneTendina } from "@/components/crapp/ui-bits";
|
import { PageHeader } from "@/components/crapp/ui-bits";
|
||||||
|
import { BarraSottosezioni } from "@/components/crapp/BarraSottosezioni";
|
||||||
import { useScoutMatches } from "@/lib/scout-store";
|
import { useScoutMatches } from "@/lib/scout-store";
|
||||||
import { useCsi } from "@/lib/csi";
|
import { useCsi } from "@/lib/csi";
|
||||||
import { isNostraSquadra, matchDaPartitaCsi, partiteGiocate } from "@/lib/csi-core";
|
import { isNostraSquadra, matchDaPartitaCsi, partiteGiocate } from "@/lib/csi-core";
|
||||||
import { ScoutEntry } from "@/components/crapp/ScoutEntry";
|
|
||||||
import { useVotiMvp, vincitoriMvp } from "@/lib/mvp-voti";
|
import { useVotiMvp, vincitoriMvp } from "@/lib/mvp-voti";
|
||||||
import { useEventi } from "@/lib/eventi";
|
import { useEventi } from "@/lib/eventi";
|
||||||
|
|
||||||
@@ -69,19 +69,20 @@ function Classifica() {
|
|||||||
sottotitolo={csi ? `${csi.girone} · CSI Bologna` : "CSI Bologna"}
|
sottotitolo={csi ? `${csi.girone} · CSI Bologna` : "CSI Bologna"}
|
||||||
/>
|
/>
|
||||||
|
|
||||||
<div className="px-5 pt-4">
|
<BarraSottosezioni
|
||||||
<div className="flex items-center gap-2 rounded-2xl bg-secondary px-3 py-2 text-xs text-muted-foreground">
|
defaultId="classifica"
|
||||||
|
voci={[
|
||||||
|
{
|
||||||
|
id: "classifica",
|
||||||
|
label: "Classifica",
|
||||||
|
contenuto: (
|
||||||
|
<>
|
||||||
|
<div className="mb-3 flex items-center gap-2 rounded-2xl bg-secondary px-3 py-2 text-xs text-muted-foreground">
|
||||||
<RefreshCw className="h-3.5 w-3.5 text-accent" />
|
<RefreshCw className="h-3.5 w-3.5 text-accent" />
|
||||||
{csi
|
{csi
|
||||||
? `Dati CSI aggiornati ${formatAggiornamento(csi.aggiornato)}`
|
? `Dati CSI aggiornati ${formatAggiornamento(csi.aggiornato)}`
|
||||||
: "Dati CSI in arrivo"}
|
: "Dati CSI in arrivo"}
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2">
|
|
||||||
<ScoutEntry variante="compatto" />
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<Section titolo="Classifica">
|
|
||||||
<div className="overflow-hidden rounded-3xl bg-card shadow-card">
|
<div className="overflow-hidden rounded-3xl bg-card shadow-card">
|
||||||
<div className="grid grid-cols-[2rem_minmax(0,1fr)_2rem_2.5rem_2.5rem] gap-2 border-b border-border px-3 py-2 text-xs font-bold uppercase text-muted-foreground">
|
<div className="grid grid-cols-[2rem_minmax(0,1fr)_2rem_2.5rem_2.5rem] gap-2 border-b border-border px-3 py-2 text-xs font-bold uppercase text-muted-foreground">
|
||||||
<span>#</span>
|
<span>#</span>
|
||||||
@@ -111,7 +112,9 @@ function Classifica() {
|
|||||||
<span className={cn("truncate", noi ? "font-bold" : "font-medium")}>
|
<span className={cn("truncate", noi ? "font-bold" : "font-medium")}>
|
||||||
{r.squadra}
|
{r.squadra}
|
||||||
</span>
|
</span>
|
||||||
<span className="text-center text-xs text-muted-foreground">{r.giocate}</span>
|
<span className="text-center text-xs text-muted-foreground">
|
||||||
|
{r.giocate}
|
||||||
|
</span>
|
||||||
<span className="text-center text-xs tabular-nums text-muted-foreground">
|
<span className="text-center text-xs tabular-nums text-muted-foreground">
|
||||||
{r.setFatti}:{r.setSubiti}
|
{r.setFatti}:{r.setSubiti}
|
||||||
</span>
|
</span>
|
||||||
@@ -121,12 +124,16 @@ function Classifica() {
|
|||||||
})
|
})
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
</>
|
||||||
|
),
|
||||||
<SezioneTendina titolo="Storico match">
|
},
|
||||||
{tuttiMatch.length === 0 ? (
|
{
|
||||||
|
id: "storico",
|
||||||
|
label: "Storico partite",
|
||||||
|
contenuto:
|
||||||
|
tuttiMatch.length === 0 ? (
|
||||||
<p className="rounded-3xl bg-card p-4 text-center text-xs text-muted-foreground shadow-card">
|
<p className="rounded-3xl bg-card p-4 text-center text-xs text-muted-foreground shadow-card">
|
||||||
Nessun match disponibile.
|
Nessuna partita disponibile.
|
||||||
</p>
|
</p>
|
||||||
) : (
|
) : (
|
||||||
<div className="space-y-3">
|
<div className="space-y-3">
|
||||||
@@ -193,8 +200,10 @@ function Classifica() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
)}
|
),
|
||||||
</SezioneTendina>
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
+84
-31
@@ -2,7 +2,8 @@ import { useState } from "react";
|
|||||||
import { createFileRoute } from "@tanstack/react-router";
|
import { createFileRoute } from "@tanstack/react-router";
|
||||||
import { Cake, ChevronDown, Crown } from "lucide-react";
|
import { Cake, ChevronDown, Crown } from "lucide-react";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
import { PageHeader, Section, SezioneTendina } from "@/components/crapp/ui-bits";
|
import { PageHeader } from "@/components/crapp/ui-bits";
|
||||||
|
import { BarraSottosezioni } from "@/components/crapp/BarraSottosezioni";
|
||||||
import { Avatar } from "@/components/crapp/Avatar";
|
import { Avatar } from "@/components/crapp/Avatar";
|
||||||
import { formatData } from "@/lib/crapp-data";
|
import { formatData } from "@/lib/crapp-data";
|
||||||
import { microcopyObiettivo, progressoObiettivo } from "@/lib/obiettivi";
|
import { microcopyObiettivo, progressoObiettivo } from "@/lib/obiettivi";
|
||||||
@@ -99,7 +100,13 @@ function Squadra() {
|
|||||||
<>
|
<>
|
||||||
<PageHeader titolo="Squadra" sottotitolo={`${rosa.length} giocatori · Stagione 2026/27`} />
|
<PageHeader titolo="Squadra" sottotitolo={`${rosa.length} giocatori · Stagione 2026/27`} />
|
||||||
|
|
||||||
<Section titolo="Rosa">
|
<BarraSottosezioni
|
||||||
|
defaultId="rosa"
|
||||||
|
voci={[
|
||||||
|
{
|
||||||
|
id: "rosa",
|
||||||
|
label: "Rosa",
|
||||||
|
contenuto: (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{rosa.map((g) => {
|
{rosa.map((g) => {
|
||||||
const stati = badgeGiocatore(g);
|
const stati = badgeGiocatore(g);
|
||||||
@@ -122,7 +129,9 @@ function Squadra() {
|
|||||||
className="h-11 w-11 text-lg"
|
className="h-11 w-11 text-lg"
|
||||||
/>
|
/>
|
||||||
<span className="min-w-0 flex-1">
|
<span className="min-w-0 flex-1">
|
||||||
<span className="block truncate text-sm font-bold leading-tight">{g.nome}</span>
|
<span className="block truncate text-sm font-bold leading-tight">
|
||||||
|
{g.nome}
|
||||||
|
</span>
|
||||||
<span className="mt-1 flex items-center gap-2">
|
<span className="mt-1 flex items-center gap-2">
|
||||||
<RuoloBadge ruolo={g.ruolo} />
|
<RuoloBadge ruolo={g.ruolo} />
|
||||||
<span className="text-xs text-muted-foreground">
|
<span className="text-xs text-muted-foreground">
|
||||||
@@ -187,7 +196,8 @@ function Squadra() {
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
<p className="mt-4 text-xs font-bold uppercase tracking-wide text-muted-foreground">
|
<p className="mt-4 text-xs font-bold uppercase tracking-wide text-muted-foreground">
|
||||||
Badge sbloccati · {collezioneBadge(g).ottenuti}/{collezioneBadge(g).totali}
|
Badge sbloccati · {collezioneBadge(g).ottenuti}/
|
||||||
|
{collezioneBadge(g).totali}
|
||||||
</p>
|
</p>
|
||||||
{sbloccati.length === 0 ? (
|
{sbloccati.length === 0 ? (
|
||||||
<p className="mt-2 rounded-2xl bg-secondary/50 p-3 text-xs text-muted-foreground">
|
<p className="mt-2 rounded-2xl bg-secondary/50 p-3 text-xs text-muted-foreground">
|
||||||
@@ -200,16 +210,25 @@ function Squadra() {
|
|||||||
const meta = gradoMeta[b.grado!];
|
const meta = gradoMeta[b.grado!];
|
||||||
return (
|
return (
|
||||||
<BadgeDrawer key={b.def.id} def={b.def} stato={b}>
|
<BadgeDrawer key={b.def.id} def={b.def} stato={b}>
|
||||||
<div className={cn("rounded-2xl p-2.5 ring-1", meta.bg, meta.ring)}>
|
<div
|
||||||
|
className={cn("rounded-2xl p-2.5 ring-1", meta.bg, meta.ring)}
|
||||||
|
>
|
||||||
<Icon className={cn("h-4 w-4", meta.text)} />
|
<Icon className={cn("h-4 w-4", meta.text)} />
|
||||||
<p className="mt-1 text-xs font-bold leading-tight">{b.def.nome}</p>
|
<p className="mt-1 text-xs font-bold leading-tight">
|
||||||
|
{b.def.nome}
|
||||||
|
</p>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{b.valore} {b.def.unita}
|
{b.valore} {b.def.unita}
|
||||||
{b.prossimaSoglia
|
{b.prossimaSoglia
|
||||||
? ` · ${b.prossimaSoglia} per ${gradoMeta[b.prossimo!].label.toLowerCase()}`
|
? ` · ${b.prossimaSoglia} per ${gradoMeta[b.prossimo!].label.toLowerCase()}`
|
||||||
: ""}
|
: ""}
|
||||||
</p>
|
</p>
|
||||||
<p className={cn("mt-1.5 text-xs font-bold uppercase", meta.text)}>
|
<p
|
||||||
|
className={cn(
|
||||||
|
"mt-1.5 text-xs font-bold uppercase",
|
||||||
|
meta.text,
|
||||||
|
)}
|
||||||
|
>
|
||||||
{meta.label}
|
{meta.label}
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
@@ -224,9 +243,12 @@ function Squadra() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
),
|
||||||
|
},
|
||||||
<Section titolo="Statistiche di squadra">
|
{
|
||||||
|
id: "stats",
|
||||||
|
label: "Statistiche",
|
||||||
|
contenuto: (
|
||||||
<div className="grid grid-cols-3 gap-2">
|
<div className="grid grid-cols-3 gap-2">
|
||||||
<StatTile valore={`${mediaPresenze}%`} label="Media presenze" />
|
<StatTile valore={`${mediaPresenze}%`} label="Media presenze" />
|
||||||
<StatTile valore={matchGiocati} label="Match giocati" />
|
<StatTile valore={matchGiocati} label="Match giocati" />
|
||||||
@@ -235,9 +257,13 @@ function Squadra() {
|
|||||||
<StatTile valore={team.ace} label="Ace squadra" />
|
<StatTile valore={team.ace} label="Ace squadra" />
|
||||||
<StatTile valore={team.muri} label="Muri squadra" />
|
<StatTile valore={team.muri} label="Muri squadra" />
|
||||||
</div>
|
</div>
|
||||||
</Section>
|
),
|
||||||
|
},
|
||||||
<SezioneTendina titolo="Classifica giocatori">
|
{
|
||||||
|
id: "classifica-giocatori",
|
||||||
|
label: "Classifica",
|
||||||
|
contenuto: (
|
||||||
|
<>
|
||||||
<div className="mb-3 flex flex-nowrap gap-1.5">
|
<div className="mb-3 flex flex-nowrap gap-1.5">
|
||||||
{criteri.map((c) => (
|
{criteri.map((c) => (
|
||||||
<button
|
<button
|
||||||
@@ -267,7 +293,9 @@ function Squadra() {
|
|||||||
<div className="min-w-0">
|
<div className="min-w-0">
|
||||||
<p className="truncate text-sm font-bold">
|
<p className="truncate text-sm font-bold">
|
||||||
{g.nome}
|
{g.nome}
|
||||||
{i === 0 ? <Crown className="ml-1 inline h-3.5 w-3.5 text-warning" /> : null}
|
{i === 0 ? (
|
||||||
|
<Crown className="ml-1 inline h-3.5 w-3.5 text-warning" />
|
||||||
|
) : null}
|
||||||
</p>
|
</p>
|
||||||
<p className="truncate text-xs text-muted-foreground">
|
<p className="truncate text-xs text-muted-foreground">
|
||||||
#{g.numero} · {g.ruolo} · {g.streak} presenze consecutive
|
#{g.numero} · {g.ruolo} · {g.streak} presenze consecutive
|
||||||
@@ -286,11 +314,14 @@ function Squadra() {
|
|||||||
</div>
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</SezioneTendina>
|
</>
|
||||||
|
),
|
||||||
<SezioneTendina
|
},
|
||||||
titolo="Obiettivi di squadra"
|
{
|
||||||
anteprima={
|
id: "obiettivi",
|
||||||
|
label: "Obiettivi",
|
||||||
|
contenuto: (
|
||||||
|
<>
|
||||||
<div className="mb-3 rounded-3xl bg-hero p-4 text-primary-foreground shadow-card">
|
<div className="mb-3 rounded-3xl bg-hero p-4 text-primary-foreground shadow-card">
|
||||||
<div className="flex items-end justify-between gap-3">
|
<div className="flex items-end justify-between gap-3">
|
||||||
<div>
|
<div>
|
||||||
@@ -305,10 +336,11 @@ function Squadra() {
|
|||||||
{completati}/{obiettivi.length} completati
|
{completati}/{obiettivi.length} completati
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<Barra percentuale={mediaObiettivi} trackClassName="mt-3 bg-primary-foreground/15" />
|
<Barra
|
||||||
|
percentuale={mediaObiettivi}
|
||||||
|
trackClassName="mt-3 bg-primary-foreground/15"
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
}
|
|
||||||
>
|
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{obiettivi.map((o, i) => {
|
{obiettivi.map((o, i) => {
|
||||||
const pct = progressoObiettivo(o);
|
const pct = progressoObiettivo(o);
|
||||||
@@ -319,7 +351,11 @@ function Squadra() {
|
|||||||
indice={i}
|
indice={i}
|
||||||
className={cn(
|
className={cn(
|
||||||
"premi rounded-3xl bg-card p-4 shadow-card ring-1",
|
"premi rounded-3xl bg-card p-4 shadow-card ring-1",
|
||||||
fatto ? "ring-success/40" : pct >= 90 ? "ring-accent/40" : "ring-transparent",
|
fatto
|
||||||
|
? "ring-success/40"
|
||||||
|
: pct >= 90
|
||||||
|
? "ring-accent/40"
|
||||||
|
: "ring-transparent",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<div className="flex items-start gap-2">
|
<div className="flex items-start gap-2">
|
||||||
@@ -344,15 +380,21 @@ function Squadra() {
|
|||||||
{o.valore}/{o.target} {o.unita} · {pct}%
|
{o.valore}/{o.target} {o.unita} · {pct}%
|
||||||
{o.scadenza ? ` · entro il ${formatData(o.scadenza)}` : ""}
|
{o.scadenza ? ` · entro il ${formatData(o.scadenza)}` : ""}
|
||||||
</p>
|
</p>
|
||||||
<p className="mt-1 text-xs font-semibold text-accent">{microcopyObiettivo(o)}</p>
|
<p className="mt-1 text-xs font-semibold text-accent">
|
||||||
|
{microcopyObiettivo(o)}
|
||||||
|
</p>
|
||||||
<p className="mt-0.5 text-xs text-muted-foreground">{o.impatto}</p>
|
<p className="mt-0.5 text-xs text-muted-foreground">{o.impatto}</p>
|
||||||
</Reveal>
|
</Reveal>
|
||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</SezioneTendina>
|
</>
|
||||||
|
),
|
||||||
<SezioneTendina titolo="Badge sbloccabili">
|
},
|
||||||
|
{
|
||||||
|
id: "badge",
|
||||||
|
label: "Badge",
|
||||||
|
contenuto: (
|
||||||
<div className="space-y-2">
|
<div className="space-y-2">
|
||||||
{badgeDefs.map((b) => {
|
{badgeDefs.map((b) => {
|
||||||
const Icon = b.icon;
|
const Icon = b.icon;
|
||||||
@@ -362,7 +404,9 @@ function Squadra() {
|
|||||||
<div className="flex items-center gap-2">
|
<div className="flex items-center gap-2">
|
||||||
<Icon className="h-5 w-5 text-accent" />
|
<Icon className="h-5 w-5 text-accent" />
|
||||||
<p className="text-sm font-bold leading-tight">{b.nome}</p>
|
<p className="text-sm font-bold leading-tight">{b.nome}</p>
|
||||||
<p className="ml-auto text-xs text-muted-foreground">{descrizioneSoglie(b)}</p>
|
<p className="ml-auto text-xs text-muted-foreground">
|
||||||
|
{descrizioneSoglie(b)}
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="mt-2 grid grid-cols-3 gap-1.5">
|
<div className="mt-2 grid grid-cols-3 gap-1.5">
|
||||||
{gradiOrdine.map((grado) => {
|
{gradiOrdine.map((grado) => {
|
||||||
@@ -376,12 +420,18 @@ function Squadra() {
|
|||||||
return (
|
return (
|
||||||
<div
|
<div
|
||||||
key={grado}
|
key={grado}
|
||||||
className={cn("rounded-2xl p-2 text-center ring-1", meta.bg, meta.ring)}
|
className={cn(
|
||||||
|
"rounded-2xl p-2 text-center ring-1",
|
||||||
|
meta.bg,
|
||||||
|
meta.ring,
|
||||||
|
)}
|
||||||
>
|
>
|
||||||
<p className={cn("text-xs font-bold uppercase", meta.text)}>
|
<p className={cn("text-xs font-bold uppercase", meta.text)}>
|
||||||
{meta.label}
|
{meta.label}
|
||||||
</p>
|
</p>
|
||||||
<p className="font-display text-lg leading-none">{b.soglie[grado]}</p>
|
<p className="font-display text-lg leading-none">
|
||||||
|
{b.soglie[grado]}
|
||||||
|
</p>
|
||||||
<p className="text-xs text-muted-foreground">
|
<p className="text-xs text-muted-foreground">
|
||||||
{quanti}/{rosa.length}
|
{quanti}/{rosa.length}
|
||||||
</p>
|
</p>
|
||||||
@@ -394,7 +444,10 @@ function Squadra() {
|
|||||||
);
|
);
|
||||||
})}
|
})}
|
||||||
</div>
|
</div>
|
||||||
</SezioneTendina>
|
),
|
||||||
|
},
|
||||||
|
]}
|
||||||
|
/>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user