feat(tema): tema seçici ikonları güneş, ay ve logo kareleri
Geçişte logonun dönüştüğü biçimlerin durağan hâli (tema-ikonu.tsx): Açık için güneş ve halesi, Koyu için hilal ve iki yıldız, Sistem için logonun üç karesi. lucide Sun/Moon/Monitor seçiciden kalktı. DESIGN §2.3 güncel. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -138,7 +138,9 @@ tema header'daki logodan **yumuşak bir halka** gibi açılır: kenarı keskin d
|
||||
tüylü (ışık yayılır gibi), 1100 ms, yumuşak kalkıp yumuşak durur. Aynı anda logonun kareleri
|
||||
yeni temanın biçimine dönüşür: koyuya geçişte şeftali kare hilale, mavi ve turuncu kareler iki
|
||||
yıldıza; açığa geçişte turuncu kare güneşe, şeftali kare halesine. Kısa bir an durur, yeniden
|
||||
logoya toplanır (`animasyonlu-mark.tsx` `temaSekli`, 1,7 sn; yalnız header'daki logo). View Transitions + radyal degrade
|
||||
logoya toplanır (`animasyonlu-mark.tsx` `temaSekli`, 1,7 sn; yalnız header'daki logo). Tema
|
||||
seçicinin ikonları aynı biçimlerin durağan hâlidir (`tema-ikonu.tsx`: güneş, ay, Sistem için
|
||||
logonun üç karesi); burada lucide ikonu kullanılmaz. View Transitions + radyal degrade
|
||||
maskesi: `src/lib/tema-gecisi.ts`, `globals.css` `.kt-tema-gecis`; hareket azaltılmışsa düz
|
||||
değişir. Denenip bırakılanlar: logo biçimli maske ("logo içinde logo"), düz crossfade, piksel
|
||||
ızgarası (sert bulundu). Kural: bu geçişte sert kenar ve ikinci bir şekil yok.
|
||||
|
||||
53
src/components/tema-ikonu.tsx
Normal file
53
src/components/tema-ikonu.tsx
Normal file
@@ -0,0 +1,53 @@
|
||||
import { useId } from "react";
|
||||
|
||||
// Tema seçicinin ikonları (DESIGN.md §2.3): tema geçişinde header'daki logonun
|
||||
// dönüştüğü biçimlerin durağan hâli (animasyonlu-mark.tsx `temaSekli`).
|
||||
// - "light": güneş — turuncu daire, arkasında şeftali hale.
|
||||
// - "dark": ay — şeftali hilal, yanında mavi ve turuncu iki yıldız.
|
||||
// - "system": logonun üç karesi — ikisine de dönüşebilen hâl.
|
||||
// Renkler logonun renkleridir ve iki temada aynıdır (§2.3); 180'lik kutu
|
||||
// public/kolay-tercih-mark.svg ile aynı. Dekoratiftir: anlamı yanındaki
|
||||
// etiket taşır.
|
||||
|
||||
const MAVI = "#3b82f6";
|
||||
const SEFTALI = "#fdc7a7";
|
||||
const TURUNCU = "#ff5a00";
|
||||
|
||||
export type TemaIkonuTuru = "light" | "dark" | "system";
|
||||
|
||||
export function TemaIkonu({
|
||||
tur,
|
||||
className,
|
||||
}: {
|
||||
tur: TemaIkonuTuru;
|
||||
className?: string;
|
||||
}) {
|
||||
const maskeId = useId();
|
||||
return (
|
||||
<svg viewBox="0 0 180 180" aria-hidden="true" className={className}>
|
||||
{tur === "light" ? (
|
||||
<>
|
||||
<circle cx="90" cy="90" r="84" fill={SEFTALI} opacity="0.55" />
|
||||
<circle cx="90" cy="90" r="52" fill={TURUNCU} />
|
||||
</>
|
||||
) : tur === "dark" ? (
|
||||
<>
|
||||
{/* Hilal: daireden, sola-yukarı kaydırılmış ikinci daire çıkarılır. */}
|
||||
<mask id={maskeId}>
|
||||
<rect width="180" height="180" fill="#fff" />
|
||||
<circle cx="64" cy="76" r="66" fill="#000" />
|
||||
</mask>
|
||||
<circle cx="104" cy="92" r="74" fill={SEFTALI} mask={`url(#${maskeId})`} />
|
||||
<circle cx="40" cy="42" r="15" fill={MAVI} />
|
||||
<circle cx="74" cy="92" r="10" fill={TURUNCU} />
|
||||
</>
|
||||
) : (
|
||||
<>
|
||||
<rect x="27" y="56" width="57" height="57" rx="13" fill={MAVI} />
|
||||
<rect x="91" y="29" width="56" height="56" rx="13" fill={SEFTALI} />
|
||||
<rect x="91" y="95" width="56" height="56" rx="13" fill={TURUNCU} />
|
||||
</>
|
||||
)}
|
||||
</svg>
|
||||
);
|
||||
}
|
||||
@@ -2,15 +2,15 @@
|
||||
|
||||
import { useSyncExternalStore } from "react";
|
||||
import { useTheme } from "next-themes";
|
||||
import { Monitor, Moon, Sun } from "lucide-react";
|
||||
import { TemaIkonu } from "@/components/tema-ikonu";
|
||||
import { Kbd } from "@/components/ui/kbd";
|
||||
import { temayiGecisle } from "@/lib/tema-gecisi";
|
||||
import { cn } from "@/lib/utils";
|
||||
|
||||
const SECENEKLER = [
|
||||
{ deger: "light", etiket: "Açık", ikon: Sun },
|
||||
{ deger: "dark", etiket: "Koyu", ikon: Moon },
|
||||
{ deger: "system", etiket: "Sistem", ikon: Monitor },
|
||||
{ deger: "light", etiket: "Açık" },
|
||||
{ deger: "dark", etiket: "Koyu" },
|
||||
{ deger: "system", etiket: "Sistem" },
|
||||
] as const;
|
||||
|
||||
const aboneOlma = () => () => {};
|
||||
@@ -18,7 +18,8 @@ const aboneOlma = () => () => {};
|
||||
/**
|
||||
* Tema seçici: açık / koyu / sistem (DESIGN.md §2.3). Seçili tema yalnızca
|
||||
* tarayıcıda bilinir; sunucu HTML'inde hiçbir seçenek işaretli gelmez,
|
||||
* hydration sonrası işaretlenir (yerleşim oynamaz). Seçim logodan yumuşak bir halka
|
||||
* hydration sonrası işaretlenir (yerleşim oynamaz). İkonlar geçişte logonun
|
||||
* dönüştüğü biçimlerdir: güneş, ay ve logonun kendisi (tema-ikonu.tsx). Seçim logodan yumuşak bir halka
|
||||
* gibi yayılarak uygulanır (lib/tema-gecisi.ts); altında `D` kısayolu ipucu durur.
|
||||
*/
|
||||
export function TemaSecici({ className }: { className?: string }) {
|
||||
@@ -36,7 +37,7 @@ export function TemaSecici({ className }: { className?: string }) {
|
||||
aria-label="Tema"
|
||||
className="inline-flex items-center gap-1 rounded-full border border-slate-200 bg-card p-1"
|
||||
>
|
||||
{SECENEKLER.map(({ deger, etiket, ikon: Ikon }) => {
|
||||
{SECENEKLER.map(({ deger, etiket }) => {
|
||||
const secili = tarayicida && theme === deger;
|
||||
return (
|
||||
<button
|
||||
@@ -52,7 +53,7 @@ export function TemaSecici({ className }: { className?: string }) {
|
||||
: "text-slate-600 hover:text-orange-500",
|
||||
)}
|
||||
>
|
||||
<Ikon className="size-4" aria-hidden />
|
||||
<TemaIkonu tur={deger} className="size-[18px]" />
|
||||
{etiket}
|
||||
</button>
|
||||
);
|
||||
|
||||
Reference in New Issue
Block a user