Next.js

Merid, App Router'da hiçbir ayar gerektirmeden çalışır. Bu site de Merid ile yapılmış bir Next.js 16 uygulaması.

npx create-next-app@latest my-app
cd my-app
npx @meridui/cli init

init, @meridui/react'i kurar, stil dosyasını app/layout.tsx'te import eder ve şablonun globals.css dosyasını düzeltir (aşağıda). Her değişikliği yazmadan önce diff olarak gösterir.

Kurulum

// app/layout.tsx
import type { Metadata, Viewport } from "next";
import "@meridui/react/styles.css";
import "./globals.css"; // kendi CSS'in Merid'inkinden sonra (Tailwind'de tersi, aşağıya bak)

export const metadata: Metadata = {
  title: { default: "Acme", template: "%s — Acme" },
};

export const viewport: Viewport = {
  // Açık ve koyu temada --mrd-bg ile eşleşir; mobil tarayıcı arayüzü sayfayla bütünleşir.
  themeColor: [
    { media: "(prefers-color-scheme: light)", color: "#ffffff" },
    { media: "(prefers-color-scheme: dark)", color: "#0b0d12" },
  ],
};

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="tr">
      <body>{children}</body>
    </html>
  );
}

Base layer tipografi, arka plan ve focus stillerini dokümana sıfır specificity ile uygular; hiçbir sınıf gerekmez. transpilePackages girdisi de gerekmez. Server component dosyalarında düz parça adlarını (DialogRoot, TabsList, …) ve router linkleri için asChild'ı kullan; ayrıntılar Server component'ler sayfasında.

Şablonun globals.css dosyası

create-next-app'in yazdığı app/globals.css dosyasındaki kurallar bir cascade layer'da olmadığı için Merid'inkileri ezer.

Tailwind'li şablonda (varsayılan) iki şeyi değiştirmen gerekir. body kuralı Arial'ı ve şablonun renklerini koyar; onu sil. Tailwind'in reset'i Preflight ise base adlı bir layer'dadır: Merid'in stil dosyası önce yüklenirse bu layer Merid'in üstüne çıkar ve butonlarla input'ların padding'ini, kenarlığını ve arka planını siler. Layer sırasını globals.css'in en üstüne yaz ve globals.css'i Merid'den önce import et:

/* app/globals.css */
@layer theme, base, merid, components, utilities;

@import "tailwindcss";
// app/layout.tsx
import "./globals.css";
import "@meridui/react/styles.css";

Tailwind'siz şablonda üç kural sorun çıkarır: her component'in iç boşluğunu sıfırlayan * { padding: 0; margin: 0 }, Link'i görünmez yapan a { color: inherit; text-decoration: none } ve body'deki Arial. Bunları sil, body { margin: 0 }'ı bırak. --background ve --foreground değişkenleri kalabilir; Merid onları kullanmaz.

npx @meridui/cli init bu değişiklikleri yapar ve yazmadan önce sorar. Yalnızca şablondaki haliyle duran kuralları kaldırır, senin düzenlemelerin kalır. Bu kurallardan biri kaldıkça npx @meridui/cli doctor uyarır. Merid'in token'larını Tailwind temana taşımak için Tailwind CSS sayfasına bak.

Server component'ler

Her etkileşimli component kendi "use client" direktifiyle gelir; bu yüzden bir server component'te @meridui/react'ten import edip doğrudan render'layabilirsin. Görsel component'ler (Card, Stack, Heading, Text, Badge, Table, …) kendilerine ait hiçbir istemci JavaScript'i olmadan sunucuda render'lanır. Event handler'lar yine de bir client sınırı ister; bkz. Server component'ler.

// app/projects/page.tsx — bir server component
import { Badge, Card, Heading, Stack, Text } from "@meridui/react";

export default async function Projects() {
  const projects = await db.project.findMany();
  return (
    <Stack gap={4}>
      <Heading level={1} size="h2">Projeler</Heading>
      {projects.map((p) => (
        <Card key={p.id} variant="outline">
          <Text tone="ink" weight="medium">{p.name}</Text>
          <Badge tone={p.live ? "success" : "neutral"}>{p.live ? "Yayında" : "Taslak"}</Badge>
        </Card>
      ))}
    </Stack>
  );
}

Linkler

Anchor render'layan component'ler bir as prop'u alır; next/link verdiğinde istemci tarafı gezinme ve prefetch kazanırlar:

import NextLink from "next/link";
import { Breadcrumb, Card, SidebarNav } from "@meridui/react";

<SidebarNav.Item as={NextLink} href="/settings" active={pathname === "/settings"}>Ayarlar</SidebarNav.Item>
<Breadcrumb.Link as={NextLink} href="/projects">Projeler</Breadcrumb.Link>
<Card as={NextLink} href={`/projects/${id}`} interactive>…</Card>

Overlay tetikleyicileri (Dialog.Trigger, Popover.Trigger, DropdownMenu.Trigger, Tooltip) asChild alır; yani bir next/link aynı zamanda bir tooltip'in ya da menünün tetikleyicisi olabilir.

Button, Link ve Breadcrumb.Link asChild alır. Bu, as={NextLink} geçilemeyen server component dosyalarında da çalışır:

<Button asChild variant="primary">
  <NextLink href="/new">Yeni proje</NextLink>
</Button>

<Link asChild>
  <NextLink href="/pricing">Fiyatlandırma</NextLink>
</Link>

getHref verilen Pagination düz anchor'lar render'lar (sayfa baştan yüklenir). Bunları next/link üzerinden yönlendirmek için renderLink ver: renderLink={({ page, ...props }) => <NextLink {...props} />}. Uygulama içinde onPageChange ve router.push da kullanabilirsin; getHref'i herkese açık sayfalarda taranabilir sayfalama için sakla.

Fontlar

Merid, Geist ve Geist Mono'yu paketinde taşır ve stil dosyasındaki @font-face ile yükler; başka bir şey gerekmez. Bunun yerine next/font kullanmak için (kendi sunucunda barınan, önceden yüklenen, layout kayması olmayan) token'ları onun değişkenine yönlendir:

import { Inter } from "next/font/google";
const inter = Inter({ subsets: ["latin"], variable: "--font-inter" });

<html lang="tr" className={inter.variable}>
/* globals.css */
:root {
  --mrd-font-sans: var(--font-inter), ui-sans-serif, system-ui, sans-serif;
}

Tarayıcılar yalnızca kullanılan font dosyalarını indirir; token başka bir yeri gösterdiği anda paketteki Geist dosyaları hiç istenmez.

Yanıp sönmeden dark mode

İlk boyamadan önce <head> içindeki inline bir script ile data-theme'i ayarla ve attribute sunucu render'ından farklı olacağı için <html>'e suppressHydrationWarning ekle. Bkz. Dark mode stratejileri.