feat(ux): sihirbaz adımları adlandı; Emil Kowalski ilkeleriyle hareket inceltmesi
- Adım göstergesi: Alan · Şehir · Öncelik; dolum transform ile soldan, güçlü ease-out 300 ms; adım değişimi ekran okuyucuya duyurulur - Çekmecede "Listen tamam" satırı @starting-style ile küçük giriş (scale 0.95 + opaklık); hareketi azalt'ta yalnız opaklık - Dilim sekmesindeki kayan hapta sekme kaldırıldı (bounce 0, 0.35 sn) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -150,7 +150,9 @@ export function ListeCekmecesi() {
|
||||
{/* Durum ekran okuyucuya da duyurulur (WCAG 4.1.3) */}
|
||||
<p role="status" className="mt-1 px-10 text-center text-sm text-slate-500">
|
||||
{liste.length === MANUEL_LISTE_MAX ? (
|
||||
<span className="inline-flex items-center gap-1.5 font-semibold text-primary">
|
||||
// Nadir, hak edilmiş an: küçük giriş (Emil: scale 0.95 + opaklık,
|
||||
// güçlü ease-out, <300 ms). Hareketi azalt'ta yalnız opaklık.
|
||||
<span className="inline-flex items-center gap-1.5 font-semibold text-primary transition-[opacity,transform] duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] starting:scale-95 starting:opacity-0 motion-reduce:starting:scale-100">
|
||||
<Check className="size-4" aria-hidden />
|
||||
Listen tamam · {liste.length} / {MANUEL_LISTE_MAX}
|
||||
</span>
|
||||
|
||||
@@ -215,7 +215,7 @@ export function ProgramTablosu({
|
||||
transition={
|
||||
hareketAzalt
|
||||
? { duration: 0 }
|
||||
: { type: "spring", duration: 0.4, bounce: 0.15 }
|
||||
: { type: "spring", duration: 0.35, bounce: 0 }
|
||||
}
|
||||
aria-hidden
|
||||
/>
|
||||
|
||||
@@ -56,6 +56,8 @@ export function Cip({
|
||||
);
|
||||
}
|
||||
|
||||
const ADIM_ADLARI = ["Alan", "Şehir", "Öncelik"] as const;
|
||||
|
||||
// Haritada karşılığı olan iller (KKTC/yurtdışı kampüsler çip olarak kalır)
|
||||
const HARITA_ILLERI = new Set(cities.map((c) => normalizeIlAdi(c.name)));
|
||||
|
||||
@@ -237,22 +239,40 @@ export function SihirbazAdimlar({
|
||||
|
||||
return (
|
||||
<div className="flex flex-col gap-5">
|
||||
<div className="flex items-center gap-1.5">
|
||||
{[0, 1, 2].map((i) => (
|
||||
{/* Adım göstergesi (DESIGN.md §10): üç parçalı çubuk + adların
|
||||
kendisi; öğrenci nerede olduğunu ve ne kaldığını görür. Değişim
|
||||
ekran okuyucuya duyurulur (WCAG 4.1.3). */}
|
||||
<div>
|
||||
<ol className="grid grid-cols-3 gap-2" aria-label="Sihirbaz adımları">
|
||||
{ADIM_ADLARI.map((ad, i) => (
|
||||
<li key={ad} className="flex flex-col gap-1.5">
|
||||
{/* Dolum transform ile (yalnız transform/opaklık canlandırılır);
|
||||
soldan dolar, güçlü ease-out 300 ms. */}
|
||||
<span className="h-1.5 overflow-hidden rounded-full bg-slate-200" aria-hidden>
|
||||
<span
|
||||
key={i}
|
||||
className={
|
||||
i === adim
|
||||
? "h-1.5 w-6 rounded-full bg-primary transition-[width,background-color] duration-200 ease-out"
|
||||
: i < adim
|
||||
? "h-1.5 w-3 rounded-full bg-primary/50 transition-[width,background-color] duration-200 ease-out"
|
||||
: "h-1.5 w-1.5 rounded-full bg-slate-200 transition-[width,background-color] duration-200 ease-out"
|
||||
}
|
||||
className={`block h-full origin-left rounded-full bg-primary transition-transform duration-300 ease-[cubic-bezier(0.23,1,0.32,1)] motion-reduce:transition-none ${
|
||||
i <= adim ? "scale-x-100" : "scale-x-0"
|
||||
}`}
|
||||
/>
|
||||
))}
|
||||
<span className="ml-2 text-sm font-medium text-slate-500">
|
||||
Adım {adim + 1}/3
|
||||
</span>
|
||||
<span
|
||||
className={`text-sm ${
|
||||
i === adim
|
||||
? "font-semibold text-slate-900"
|
||||
: i < adim
|
||||
? "font-medium text-slate-600"
|
||||
: "text-slate-400"
|
||||
}`}
|
||||
aria-current={i === adim ? "step" : undefined}
|
||||
>
|
||||
{ad}
|
||||
</span>
|
||||
</li>
|
||||
))}
|
||||
</ol>
|
||||
<p role="status" className="sr-only">
|
||||
Adım {adim + 1} / 3: {ADIM_ADLARI[adim]}
|
||||
</p>
|
||||
</div>
|
||||
|
||||
<TransitionPanel
|
||||
|
||||
Reference in New Issue
Block a user