Update component configurations and styles: add new registry for @magicui in components.json, remove unused opengraph image files, and enhance opengraph-image.tsx with new font loading and styling adjustments. Refactor button sizes and styles in various components for improved responsiveness and visual consistency. Overall, these changes aim to streamline the application and enhance user experience.
Some checks failed
Deploy / deploy (push) Has been cancelled

This commit is contained in:
bilalgursen
2026-08-01 18:54:43 +03:00
parent 55eb32b22a
commit b3dd36fa72
23 changed files with 260 additions and 28 deletions

View File

@@ -22,6 +22,7 @@
"hooks": "@/hooks"
},
"registries": {
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json"
"@skiper-ui": "https://skiper-ui.com/registry/{name}.json",
"@magicui": "https://magicui.design/r/{name}"
}
}

View File

@@ -215,4 +215,4 @@
/* scroll-behavior: smooth KULLANMA — Lenis (ScrollFlow, anchors: true)
kaydırmayı zaten yumuşatıyor; ikisi birlikte çift yumuşatma yapar. */
}
}
}

View File

@@ -1 +0,0 @@
KolayTercih — YKS tercihin, gerçek YÖK Atlas verisiyle. Sıralamanı gir, dengeli 24 tercihlik listeni al.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 43 KiB

View File

@@ -0,0 +1,92 @@
import { ImageResponse } from "next/og";
import { loadSiteOgFonts } from "@/lib/og-fonts";
export const alt =
"KolayTercih — YKS tercihin, gerçek YÖK Atlas verisiyle. Sıralamanı gir, dengeli 24 tercihlik listeni al.";
export const size = { width: 1200, height: 630 };
export const contentType = "image/png";
export default async function OpenGraphImage() {
const fonts = await loadSiteOgFonts();
return new ImageResponse(
(
<div
style={{
display: "flex",
width: "100%",
height: "100%",
alignItems: "center",
justifyContent: "center",
background: "white",
}}
>
<div
style={{
display: "flex",
flexDirection: "column",
alignItems: "center",
maxWidth: 920,
padding: "0 48px",
}}
>
<div
style={{
display: "flex",
alignItems: "center",
fontFamily: "Bricolage Grotesque",
letterSpacing: "-0.05em",
color: "#0f172a",
}}
>
<svg
width="64"
height="64"
viewBox="0 0 180 180"
style={{ display: "flex", marginRight: 4 }}
>
<rect x="27" y="56" width="57" height="57" rx="13" fill="#3b82f6" />
<rect x="91" y="29" width="56" height="56" rx="13" fill="#fdc7a7" />
<rect x="91" y="95" width="56" height="56" rx="13" fill="#ff5a00" />
</svg>
<span style={{ display: "flex", fontSize: 72, lineHeight: 1 }}>
<span style={{ fontWeight: 300 }}>Kolay</span>
<span style={{ fontWeight: 600 }}>Tercih</span>
</span>
</div>
<div
style={{
display: "flex",
marginTop: 28,
fontFamily: "Clarity City",
fontSize: 34,
fontWeight: 600,
lineHeight: 1.25,
textAlign: "center",
color: "#1e293b",
}}
>
YKS tercihin, gerçek YÖK Atlas verisiyle
</div>
<div
style={{
display: "flex",
marginTop: 16,
fontFamily: "Clarity City",
fontSize: 26,
fontWeight: 300,
lineHeight: 1.3,
textAlign: "center",
color: "#64748b",
}}
>
Sıralamanı gir · Dengeli 24 tercihlik listeni al
</div>
</div>
</div>
),
{ ...size, fonts },
);
}

View File

@@ -1,5 +1,6 @@
import { ImageResponse } from "next/og";
import { getRehber } from "@/lib/rehber";
import { loadRehberOgFonts } from "@/lib/og-fonts";
import {
rehberBasliginiBol,
rehberMetniniParcala,
@@ -18,6 +19,7 @@ export default async function RehberOpenGraphImage({
const yazi = getRehber(slug);
const baslik = yazi?.baslik ?? "Tercih Rehberi";
const { vurgu, kalan } = rehberBasliginiBol(baslik);
const fonts = await loadRehberOgFonts();
return new ImageResponse(
(
@@ -30,7 +32,7 @@ export default async function RehberOpenGraphImage({
overflow: "hidden",
background: "white",
color: "#2563eb",
fontFamily: "sans-serif",
fontFamily: "Bricolage Grotesque",
}}
>
{[
@@ -108,6 +110,7 @@ export default async function RehberOpenGraphImage({
style={{
display: "flex",
alignItems: "center",
fontFamily: "Clarity City",
fontSize: 20,
fontWeight: 700,
letterSpacing: "0.18em",
@@ -123,8 +126,9 @@ export default async function RehberOpenGraphImage({
display: "flex",
flexWrap: "wrap",
maxWidth: 980,
fontFamily: "Cal Sans",
fontSize: baslik.length > 70 ? 48 : baslik.length > 52 ? 54 : 62,
fontWeight: 300,
fontWeight: 400,
lineHeight: 1.02,
letterSpacing: "-0.025em",
color: "#2563eb",
@@ -133,8 +137,9 @@ export default async function RehberOpenGraphImage({
<span
style={{
display: "flex",
fontFamily: "Bricolage Grotesque",
color: "#ff5a00",
fontWeight: 700,
fontWeight: 600,
letterSpacing: "-0.04em",
}}
>
@@ -144,6 +149,7 @@ export default async function RehberOpenGraphImage({
key={i}
style={{
display: "flex",
fontFamily: "Bricolage Grotesque",
fontStyle: "italic",
fontWeight: 800,
}}
@@ -168,6 +174,7 @@ export default async function RehberOpenGraphImage({
key={i}
style={{
display: "flex",
fontFamily: "Bricolage Grotesque",
fontStyle: "italic",
fontWeight: 800,
}}
@@ -203,18 +210,19 @@ export default async function RehberOpenGraphImage({
style={{
display: "flex",
marginLeft: 2,
fontFamily: "Bricolage Grotesque",
fontSize: 24,
letterSpacing: "-0.05em",
color: "#2563eb",
}}
>
<span style={{ fontWeight: 300 }}>Kolay</span>
<span style={{ fontWeight: 700 }}>Tercih</span>
<span style={{ fontWeight: 600 }}>Tercih</span>
</span>
</div>
</div>
</div>
),
size,
{ ...size, fonts },
);
}

View File

@@ -122,7 +122,7 @@ export function KatalogArama() {
type="button"
onClick={() => setAcik(true)}
aria-label="Bölüm veya üniversite ara"
className="ml-auto flex size-10 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white text-slate-700 transition-[background-color,transform] duration-150 hover:bg-slate-100 active:scale-[0.96] sm:hidden"
className="ml-auto flex size-9 shrink-0 cursor-pointer items-center justify-center rounded-full border border-slate-200 bg-white text-slate-700 transition-[background-color,transform] duration-150 hover:bg-slate-100 active:scale-[0.96] sm:hidden"
>
<Search className="size-4" aria-hidden />
</button>

View File

@@ -29,9 +29,9 @@ export function ListemButonu() {
aria-expanded={acik}
aria-label={`Seçtiklerim — ${liste.length}/${MANUEL_LISTE_MAX} program`}
title="Tablodan seçtiğin programlar"
className="relative inline-flex h-12 cursor-pointer items-center gap-2 whitespace-nowrap rounded-full border border-slate-200 bg-white px-5 text-sm font-semibold text-slate-700 transition-[color,background-color,border-color,transform] duration-200 hover:border-slate-300 hover:bg-slate-50 active:scale-[0.97]"
className="relative inline-flex h-9 cursor-pointer items-center gap-1.5 whitespace-nowrap rounded-full border border-slate-200 bg-white px-3 text-xs font-semibold text-slate-700 transition-[color,background-color,border-color,transform] duration-200 hover:border-slate-300 hover:bg-slate-50 active:scale-[0.97] sm:h-12 sm:gap-2 sm:px-5 sm:text-sm"
>
<ListChecks className="size-4 text-primary" aria-hidden />
<ListChecks className="size-3.5 text-primary sm:size-4" aria-hidden />
<span className="hidden sm:inline">Seçtiklerim</span>
{liste.length > 0 ? (
// key=length: her eklemede rozet yeniden doğar ve spring ile oturur

View File

@@ -11,14 +11,14 @@ export function SignOutButton() {
<Button
size="sm"
variant="ghost"
className="size-12 cursor-pointer rounded-full border border-slate-200 bg-white text-slate-600 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50 hover:text-slate-900"
className="size-9 cursor-pointer rounded-full border border-slate-200 bg-white text-slate-600 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50 hover:text-slate-900 sm:size-12"
aria-label=ıkış yap"
onClick={async () => {
await authClient.signOut();
router.refresh();
}}
>
<LogOut className="size-5" aria-hidden />
<LogOut className="size-4 sm:size-5" aria-hidden />
</Button>
);
}

View File

@@ -6,11 +6,11 @@ import { UserNav, UserNavFallback } from "@/components/user-nav";
export function SiteHeader() {
return (
<header className="sticky top-6 z-50 mt-6 print:hidden">
<div className="relative mx-auto flex h-16 max-w-6xl items-center justify-between gap-3 px-4">
<header className="sticky top-4 z-50 mt-4 sm:top-6 sm:mt-6 print:hidden">
<div className="relative mx-auto flex h-12 max-w-6xl items-center justify-between gap-2 px-3 sm:h-16 sm:gap-3 sm:px-4">
<Link
href="/"
className="group flex items-center font-bricolage text-xl"
className="group flex min-w-0 shrink items-center font-bricolage"
>
<Image
src="/kolay-tercih-mark.svg"
@@ -18,11 +18,13 @@ export function SiteHeader() {
width={44}
height={44}
aria-hidden="true"
className="size-11 shrink-0"
className="size-8 shrink-0 sm:size-11"
/>
<span>
<span className="font-light text-3xl tracking-tighter">Kolay</span>
<span className="font-semibold text-3xl tracking-tighter">
<span className="truncate">
<span className="text-lg font-light tracking-tighter sm:text-3xl">
Kolay
</span>
<span className="text-lg font-semibold tracking-tighter sm:text-3xl">
Tercih
</span>
</span>

View File

@@ -11,8 +11,8 @@ import { SignOutButton } from "./sign-out-button";
*/
export function UserNavFallback() {
return (
<div className="flex items-center gap-2" aria-hidden>
<div className="h-12 w-28 rounded-full bg-slate-900/10" />
<div className="flex shrink-0 items-center gap-1.5 sm:gap-2" aria-hidden>
<div className="h-9 w-16 rounded-full bg-slate-900/10 sm:h-12 sm:w-28" />
</div>
);
}
@@ -23,11 +23,11 @@ export async function UserNav() {
// Manuel liste localStorage'ta yaşadığı için Listem girişsiz de çalışır
if (!u) {
return (
<div className="flex items-center gap-2">
<div className="flex shrink-0 items-center gap-1.5 sm:gap-2">
<ListemButonu />
<Button
asChild
className="h-12 cursor-pointer rounded-full bg-slate-900 px-7 text-base font-medium text-white transition-colors duration-200 hover:bg-slate-700"
className="h-9 cursor-pointer rounded-full bg-slate-900 px-3.5 text-sm font-medium text-white transition-colors duration-200 hover:bg-slate-700 sm:h-12 sm:px-7 sm:text-base"
>
<Link href="/giris">Giriş yap</Link>
</Button>
@@ -36,15 +36,16 @@ export async function UserNav() {
}
return (
<div className="flex items-center gap-2">
<div className="flex shrink-0 items-center gap-1.5 sm:gap-2">
<ListemButonu />
<Link
href="/paket"
className="inline-flex h-12 items-center gap-2 whitespace-nowrap rounded-full border border-slate-200 bg-white px-5 text-sm font-semibold text-slate-700 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50"
className="inline-flex h-9 items-center gap-1.5 whitespace-nowrap rounded-full border border-slate-200 bg-white px-3 text-xs font-semibold text-slate-700 transition-colors duration-200 hover:border-slate-300 hover:bg-slate-50 sm:h-12 sm:gap-2 sm:px-5 sm:text-sm"
title="Kredilerin — yüklemek için tıkla"
>
<Coins className="size-4 text-amber-500" aria-hidden />
{u.creditBalance} kredi
<Coins className="size-3.5 text-amber-500 sm:size-4" aria-hidden />
<span className="tabular-nums">{u.creditBalance}</span>
<span className="hidden sm:inline">kredi</span>
</Link>
<SignOutButton />
</div>

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

129
src/lib/og-fonts.ts Normal file
View File

@@ -0,0 +1,129 @@
import { readFile } from "node:fs/promises";
import { join } from "node:path";
const OG_FONT_DIR = join(process.cwd(), "src/fonts/og");
function toArrayBuffer(buf: Buffer): ArrayBuffer {
return buf.buffer.slice(
buf.byteOffset,
buf.byteOffset + buf.byteLength,
) as ArrayBuffer;
}
async function loadFont(fileName: string): Promise<ArrayBuffer> {
return toArrayBuffer(await readFile(join(OG_FONT_DIR, fileName)));
}
type OgFont = {
name: string;
data: ArrayBuffer;
weight: 300 | 400 | 600 | 700 | 800;
style: "normal" | "italic";
};
/** latin + latin-ext çiftini aynı aile/ağırlıkta kaydeder (Türkçe glifler için). */
async function latinPair(
name: string,
weight: OgFont["weight"],
latinFile: string,
latinExtFile: string,
style: OgFont["style"] = "normal",
): Promise<OgFont[]> {
const [latin, latinExt] = await Promise.all([
loadFont(latinFile),
loadFont(latinExtFile),
]);
return [
{ name, data: latin, weight, style },
{ name, data: latinExt, weight, style },
];
}
/** Ana sayfa OG: Bricolage (marka) + ClarityCity (gövde). */
export async function loadSiteOgFonts(): Promise<OgFont[]> {
const [bricolage, clarityLight, claritySemiBold] = await Promise.all([
Promise.all([
latinPair(
"Bricolage Grotesque",
300,
"bricolage-grotesque-latin-300-normal.woff",
"bricolage-grotesque-latin-ext-300-normal.woff",
),
latinPair(
"Bricolage Grotesque",
600,
"bricolage-grotesque-latin-600-normal.woff",
"bricolage-grotesque-latin-ext-600-normal.woff",
),
]).then((pairs) => pairs.flat()),
loadFont("ClarityCity-Light.ttf"),
loadFont("ClarityCity-SemiBold.ttf"),
]);
return [
...bricolage,
{
name: "Clarity City",
data: clarityLight,
weight: 300,
style: "normal",
},
{
name: "Clarity City",
data: claritySemiBold,
weight: 600,
style: "normal",
},
];
}
/** Rehber kapak OG: ClarityCity + Cal Sans + Bricolage. */
export async function loadRehberOgFonts(): Promise<OgFont[]> {
const [clarityBold, calSans, light, semiBold, extraBold] = await Promise.all([
loadFont("ClarityCity-Bold.ttf"),
latinPair(
"Cal Sans",
400,
"cal-sans-latin-400-normal.woff",
"cal-sans-latin-ext-400-normal.woff",
),
latinPair(
"Bricolage Grotesque",
300,
"bricolage-grotesque-latin-300-normal.woff",
"bricolage-grotesque-latin-ext-300-normal.woff",
),
latinPair(
"Bricolage Grotesque",
600,
"bricolage-grotesque-latin-600-normal.woff",
"bricolage-grotesque-latin-ext-600-normal.woff",
),
latinPair(
"Bricolage Grotesque",
800,
"bricolage-grotesque-latin-800-normal.woff",
"bricolage-grotesque-latin-ext-800-normal.woff",
),
]);
// Sitede italic kullanılıyor; ayrı italic dosya yok — aynı kesimi italic olarak kaydet.
const extraBoldItalic = extraBold.map((font) => ({
...font,
style: "italic" as const,
}));
return [
{
name: "Clarity City",
data: clarityBold,
weight: 700,
style: "normal",
},
...calSans,
...light,
...semiBold,
...extraBold,
...extraBoldItalic,
];
}