feat(ux): listeden silme geri alınabilir; better-ui skill'i eklendi
- Çekmecede "Listeyi temizle" ve satır çıkarma (düğme ve kaydırma) anında siliyordu, geri dönüş yoktu. Artık 8 sn "Geri al" bildirimi; çıkanlar eski sıralarına döner, arada eklenenler korunur - Çekmece kaydırması sayfaya taşmıyor (overscroll-contain) - .claude/skills/better-ui: Jakub Krehel'in UI cilası skill'i (ui-skills.com); başına DESIGN.md önceliği ve çakışan iki değer notu eklendi Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -12,6 +12,7 @@
|
||||
// sadeleşir; X butonu her durumda kalır.
|
||||
|
||||
import { useState } from "react";
|
||||
import { toast } from "sonner";
|
||||
import Link from "next/link";
|
||||
import { useRouter } from "next/navigation";
|
||||
import { PixelField } from "@/components/pixel-decor";
|
||||
@@ -60,6 +61,7 @@ import {
|
||||
cekmeceAc,
|
||||
cekmeceKapat,
|
||||
cikar,
|
||||
listeOku,
|
||||
temizle,
|
||||
useCekmeceAcik,
|
||||
useManuelListe,
|
||||
@@ -79,6 +81,36 @@ function uniHref(ad: string): string {
|
||||
return `/universite/${turkishSlugify(ad.replace(/\s*\([^)]*\)\s*$/, "").trim())}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Geri alınabilir silme (Vercel arayüz ilkeleri: yıkıcı işlem ya onay ya
|
||||
* geri al penceresi ister; Apple: beklenen işlemde uyarı penceresi açma).
|
||||
* Çıkan tercihler eski sıralarına geri konur; arada eklenenler kaybolmaz.
|
||||
*/
|
||||
function geriAlinabilirCikar(ids: string[], baslik: string) {
|
||||
const onceki = listeOku();
|
||||
const cikanlar = onceki
|
||||
.map((t, sira) => ({ t, sira }))
|
||||
.filter(({ t }) => ids.includes(t.id));
|
||||
if (cikanlar.length === 0) return;
|
||||
if (ids.length === onceki.length) temizle();
|
||||
else for (const id of ids) cikar(id);
|
||||
toast(baslik, {
|
||||
duration: 8000,
|
||||
action: {
|
||||
label: "Geri al",
|
||||
onClick: () => {
|
||||
const simdi = listeOku().filter(
|
||||
(t) => !cikanlar.some((c) => c.t.id === t.id),
|
||||
);
|
||||
for (const { t, sira } of cikanlar) {
|
||||
simdi.splice(Math.min(sira, simdi.length), 0, t);
|
||||
}
|
||||
yenidenSirala(simdi.slice(0, MANUEL_LISTE_MAX));
|
||||
},
|
||||
},
|
||||
});
|
||||
}
|
||||
|
||||
export function ListeCekmecesi() {
|
||||
const router = useRouter();
|
||||
const acik = useCekmeceAcik();
|
||||
@@ -132,7 +164,12 @@ export function ListeCekmecesi() {
|
||||
{liste.length > 0 ? (
|
||||
<button
|
||||
type="button"
|
||||
onClick={temizle}
|
||||
onClick={() =>
|
||||
geriAlinabilirCikar(
|
||||
liste.map((t) => t.id),
|
||||
`Listen temizlendi · ${liste.length} program çıkarıldı`,
|
||||
)
|
||||
}
|
||||
title="Listeyi temizle"
|
||||
className="absolute top-3 left-3 z-10 flex size-9 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-popover text-slate-500 transition-[background-color,transform] duration-150 hover:bg-slate-100 hover:text-slate-800 active:scale-[0.96]"
|
||||
>
|
||||
@@ -201,7 +238,7 @@ export function ListeCekmecesi() {
|
||||
</DrawerHeader>
|
||||
|
||||
<div
|
||||
className="min-h-0 flex-1 overflow-x-hidden overflow-y-auto px-4 py-2"
|
||||
className="min-h-0 flex-1 overflow-x-hidden overflow-y-auto overscroll-contain px-4 py-2"
|
||||
>
|
||||
{liste.length === 0 ? (
|
||||
<div className="relative flex flex-col items-center justify-center gap-2 overflow-hidden px-4 py-16 text-center">
|
||||
@@ -361,7 +398,7 @@ function CekmeceSatiri({
|
||||
info.offset.x > SIL_ESIK ||
|
||||
(info.offset.x > 32 && info.velocity.x > 500)
|
||||
) {
|
||||
cikar(tercih.id);
|
||||
geriAlinabilirCikar([tercih.id], `${tercih.isim} çıkarıldı`);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -450,7 +487,9 @@ function CekmeceSatiri({
|
||||
</span>
|
||||
<button
|
||||
type="button"
|
||||
onClick={() => cikar(tercih.id)}
|
||||
onClick={() =>
|
||||
geriAlinabilirCikar([tercih.id], `${tercih.isim} çıkarıldı`)
|
||||
}
|
||||
onPointerDown={(e) => e.stopPropagation()} // kaydırmayı tetiklemesin
|
||||
className="inline-flex size-11 shrink-0 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white text-slate-500 transition-[background-color,border-color,color,transform] duration-150 hover:border-orange-500 hover:bg-orange-50/60 hover:text-orange-500 active:scale-[0.92]"
|
||||
>
|
||||
|
||||
Reference in New Issue
Block a user