v1-beta-tema #9
@@ -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
|
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
|
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
|
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
|
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
|
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.
|
ı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 { useSyncExternalStore } from "react";
|
||||||
import { useTheme } from "next-themes";
|
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 { Kbd } from "@/components/ui/kbd";
|
||||||
import { temayiGecisle } from "@/lib/tema-gecisi";
|
import { temayiGecisle } from "@/lib/tema-gecisi";
|
||||||
import { cn } from "@/lib/utils";
|
import { cn } from "@/lib/utils";
|
||||||
|
|
||||||
const SECENEKLER = [
|
const SECENEKLER = [
|
||||||
{ deger: "light", etiket: "Açık", ikon: Sun },
|
{ deger: "light", etiket: "Açık" },
|
||||||
{ deger: "dark", etiket: "Koyu", ikon: Moon },
|
{ deger: "dark", etiket: "Koyu" },
|
||||||
{ deger: "system", etiket: "Sistem", ikon: Monitor },
|
{ deger: "system", etiket: "Sistem" },
|
||||||
] as const;
|
] as const;
|
||||||
|
|
||||||
const aboneOlma = () => () => {};
|
const aboneOlma = () => () => {};
|
||||||
@@ -18,7 +18,8 @@ const aboneOlma = () => () => {};
|
|||||||
/**
|
/**
|
||||||
* Tema seçici: açık / koyu / sistem (DESIGN.md §2.3). Seçili tema yalnızca
|
* 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,
|
* 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.
|
* gibi yayılarak uygulanır (lib/tema-gecisi.ts); altında `D` kısayolu ipucu durur.
|
||||||
*/
|
*/
|
||||||
export function TemaSecici({ className }: { className?: string }) {
|
export function TemaSecici({ className }: { className?: string }) {
|
||||||
@@ -36,7 +37,7 @@ export function TemaSecici({ className }: { className?: string }) {
|
|||||||
aria-label="Tema"
|
aria-label="Tema"
|
||||||
className="inline-flex items-center gap-1 rounded-full border border-slate-200 bg-card p-1"
|
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;
|
const secili = tarayicida && theme === deger;
|
||||||
return (
|
return (
|
||||||
<button
|
<button
|
||||||
@@ -52,7 +53,7 @@ export function TemaSecici({ className }: { className?: string }) {
|
|||||||
: "text-slate-600 hover:text-orange-500",
|
: "text-slate-600 hover:text-orange-500",
|
||||||
)}
|
)}
|
||||||
>
|
>
|
||||||
<Ikon className="size-4" aria-hidden />
|
<TemaIkonu tur={deger} className="size-[18px]" />
|
||||||
{etiket}
|
{etiket}
|
||||||
</button>
|
</button>
|
||||||
);
|
);
|
||||||
|
|||||||
Reference in New Issue
Block a user