feat(ui): Arc bileşenleri, landing bölümleri ve bildirim yığını
Sonner/vaul yerine kendi bildirim yığını ve alt sayfa; çip grubu, kart destesi, kaydırma eylemi, yazı dönüşümü, bölme tutamacı; landing'e program duvarı, süzülen haplar ve veri akışı; yaylar tek dosyada (lib/hareket.ts). Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This commit is contained in:
@@ -11,7 +11,7 @@ import { useEffect, useMemo, useState } from "react";
|
||||
import { ArrowLeft, ArrowRight, Search, X } from "lucide-react";
|
||||
import { useReducedMotion } from "motion/react";
|
||||
import useMeasure from "react-use-measure";
|
||||
import { toast } from "sonner";
|
||||
import { toast } from "@/components/ui/bildirim";
|
||||
import { cities } from "turkey-map-react/lib/data";
|
||||
import { TransitionPanel } from "@/components/core/transition-panel";
|
||||
import { Button } from "@/components/ui/button";
|
||||
@@ -23,47 +23,8 @@ import { trBaslikDuzeni } from "@/lib/slug";
|
||||
import type { SihirbazFacetleri } from "@/types/yokatlas";
|
||||
import { ONCELIKLER, UNIVERSITE_TIPI_ETIKET, type SihirbazSecimleri, type UniversiteTipi } from "@/features/sihirbaz/sihirbaz-sabitler";
|
||||
import { OZEL_DURUMLAR, OZEL_DURUM_ETIKET, type OzelDurum } from "@/lib/ozel-durum";
|
||||
|
||||
export function Cip({
|
||||
secili,
|
||||
onClick,
|
||||
children,
|
||||
kucuk = false,
|
||||
ton = "notr",
|
||||
className = "",
|
||||
}: {
|
||||
secili: boolean;
|
||||
onClick: () => void;
|
||||
children: React.ReactNode;
|
||||
kucuk?: boolean;
|
||||
/**
|
||||
* bilgi: özel kontenjan durumu çipi (DESIGN.md §4.21) — pasif hâli bilgi
|
||||
* mavisi tonunda (§2 `primary` rolü), seçili hâli nötr çiple aynı.
|
||||
*/
|
||||
ton?: "notr" | "bilgi";
|
||||
className?: string;
|
||||
}) {
|
||||
// Şişko ve sade (DESIGN.md §1.1): çip 44 px dokunma hedefi; il
|
||||
// çipleri (kucuk) çok sayıda olduğu için 40 px. Hover §2.1 tek turuncu.
|
||||
const boyut = kucuk ? "h-10 px-3.5 text-sm" : "h-11 px-4 text-sm";
|
||||
const temel = `inline-flex cursor-pointer items-center rounded-full border font-semibold transition-[background-color,border-color,color,transform] duration-150 active:scale-[0.97] ${boyut} ${className}`;
|
||||
const pasif =
|
||||
ton === "bilgi"
|
||||
? "border-primary/30 bg-primary/10 text-primary hover:border-orange-500 hover:bg-orange-50/60 hover:text-orange-500"
|
||||
: "border-slate-200 bg-card text-slate-700 hover:border-orange-500 hover:bg-orange-50/60 hover:text-orange-500";
|
||||
return (
|
||||
<button
|
||||
type="button"
|
||||
onClick={onClick}
|
||||
aria-pressed={secili}
|
||||
className={
|
||||
secili ? `${temel} border-primary bg-primary text-white` : `${temel} ${pasif}`
|
||||
}
|
||||
>
|
||||
{children}
|
||||
</button>
|
||||
);
|
||||
}
|
||||
// Seçim çipi tek kaynaktan (DESIGN.md §4.24): seçilince tik büyür, yazı kayar.
|
||||
import { CipGrubu, SecimCipi as Cip } from "@/components/ui/cip-grubu";
|
||||
|
||||
const ADIM_ADLARI = ["Alan", "Şehir", "Öncelik"] as const;
|
||||
|
||||
@@ -337,7 +298,7 @@ export function SihirbazAdimlar({
|
||||
<p className="mt-1 text-sm text-slate-500">
|
||||
Sıralamanla ulaşabileceğin alanlar. En az bir tane seç.
|
||||
</p>
|
||||
<div className="mt-4 flex flex-wrap gap-2">
|
||||
<CipGrubu etiket="İlgi alanları" className="mt-4">
|
||||
{facetler.kategoriler.map((k) => (
|
||||
<Cip
|
||||
key={k.ad}
|
||||
@@ -348,7 +309,7 @@ export function SihirbazAdimlar({
|
||||
<span className="ml-1.5 text-xs font-medium opacity-70">{k.adet}</span>
|
||||
</Cip>
|
||||
))}
|
||||
</div>
|
||||
</CipGrubu>
|
||||
</div>
|
||||
<div ref={panelRef}>
|
||||
<h3 className="font-heading text-xl font-bold text-slate-900">
|
||||
@@ -387,8 +348,9 @@ export function SihirbazAdimlar({
|
||||
görünüm ilk 10 il; kalanı "+N il daha" rozetiyle açılır. Arama
|
||||
yalnızca görünümü daraltır, seçimleri etkilemez ve kırpmayı
|
||||
devre dışı bırakır. */}
|
||||
<div
|
||||
className={`mt-3 flex max-h-64 flex-wrap gap-2 overflow-y-auto sm:max-h-none sm:overflow-visible ${
|
||||
<CipGrubu
|
||||
etiket="Şehirler"
|
||||
className={`mt-3 max-h-64 overflow-y-auto sm:max-h-none sm:overflow-visible ${
|
||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
@@ -424,7 +386,7 @@ export function SihirbazAdimlar({
|
||||
Daha az göster
|
||||
</button>
|
||||
) : null}
|
||||
</div>
|
||||
</CipGrubu>
|
||||
|
||||
{ilAramaNorm &&
|
||||
gorunenTurkiyeIlleri.length === 0 &&
|
||||
@@ -439,8 +401,9 @@ export function SihirbazAdimlar({
|
||||
<p className="mb-2 text-sm font-semibold text-slate-700">
|
||||
KKTC & Yurt Dışı
|
||||
</p>
|
||||
<div
|
||||
className={`flex flex-wrap gap-2 ${
|
||||
<CipGrubu
|
||||
etiket="KKTC ve yurt dışı"
|
||||
className={`${
|
||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
@@ -455,7 +418,7 @@ export function SihirbazAdimlar({
|
||||
<span className="ml-1.5 text-xs font-medium opacity-70">{i.adet}</span>
|
||||
</Cip>
|
||||
))}
|
||||
</div>
|
||||
</CipGrubu>
|
||||
</div>
|
||||
) : null}
|
||||
|
||||
@@ -500,8 +463,9 @@ export function SihirbazAdimlar({
|
||||
<p className="mb-2 text-sm font-semibold text-slate-700">
|
||||
Üniversite tipi
|
||||
</p>
|
||||
<div
|
||||
className={`flex flex-wrap gap-2 ${
|
||||
<CipGrubu
|
||||
etiket="Üniversite tipi"
|
||||
className={`${
|
||||
facetYukleniyor ? "animate-pulse opacity-60" : ""
|
||||
}`}
|
||||
>
|
||||
@@ -525,7 +489,7 @@ export function SihirbazAdimlar({
|
||||
>
|
||||
Fark etmez
|
||||
</Cip>
|
||||
</div>
|
||||
</CipGrubu>
|
||||
</div>
|
||||
<div>
|
||||
<p className="mb-2 text-sm font-semibold text-slate-700">
|
||||
@@ -533,7 +497,7 @@ export function SihirbazAdimlar({
|
||||
</p>
|
||||
{/* Telefonda iki sütun, uzun ad iki satıra sarar: tek sütunda
|
||||
yedi çip 44 px'le pencereyi 812 px'in dışına itiyordu. */}
|
||||
<div className="grid grid-cols-2 gap-2 sm:flex sm:flex-wrap">
|
||||
<CipGrubu etiket="Senin için önemli olan" className="grid grid-cols-2 sm:flex sm:flex-wrap">
|
||||
{ONCELIKLER.map((o) => (
|
||||
<Cip
|
||||
key={o}
|
||||
@@ -544,7 +508,7 @@ export function SihirbazAdimlar({
|
||||
{o}
|
||||
</Cip>
|
||||
))}
|
||||
</div>
|
||||
</CipGrubu>
|
||||
<p className="mt-2 text-sm text-slate-500">
|
||||
Listeyi daraltmaz; programların sırasını ve gerekçelerini
|
||||
yönlendirir (istihdam ve kazanç TÜİK 2025, araştırma sırası URAP,
|
||||
@@ -559,7 +523,7 @@ export function SihirbazAdimlar({
|
||||
Özel kontenjan durumun{" "}
|
||||
<span className="font-normal text-slate-500">(isteğe bağlı)</span>
|
||||
</p>
|
||||
<div className="grid grid-cols-2 gap-2 sm:flex sm:flex-wrap">
|
||||
<CipGrubu etiket="Özel kontenjan durumun" className="grid grid-cols-2 sm:flex sm:flex-wrap">
|
||||
{OZEL_DURUMLAR.map((d) => (
|
||||
<Cip
|
||||
key={d}
|
||||
@@ -577,7 +541,7 @@ export function SihirbazAdimlar({
|
||||
{OZEL_DURUM_ETIKET[d]}
|
||||
</Cip>
|
||||
))}
|
||||
</div>
|
||||
</CipGrubu>
|
||||
<p className="mt-2 text-sm text-slate-500">
|
||||
ÖSYM bu durumlar için ayrı kontenjan ayırır. İşaretlersen o
|
||||
kontenjanı olan programlar listende öne çıkar ve danışman bunu
|
||||
|
||||
Reference in New Issue
Block a user