Panelde iframe içinde açılan her Tecof uygulaması aynı görünür ve aynı davranır. @tecof/app-ui bu ortak kimliği verir: React Suite 6 + Tailwind CSS 4 + lucide-react üzerine panelle aynı görsel dil — Tecof lime imza rengi, zinc nötrler, Geist, rounded-2xl kartlar, panelden gelen açık/koyu tema ve tr/en metinler.
| Giriş | Ortam | İçerik |
|---|---|---|
@tecof/app-ui | İstemci ("use client" derlemede eklenir) | TecofAppProvider, kabuk ve yerleşim, durum, tablo, form bileşenleri, useAppToast, useAppConfirm |
@tecof/app-ui/schema | Sunucu-güvenli (React/DOM yok) | createModel, v kuralları, validateOnServer, VKN/TCKN/IBAN/telefon doğrulayıcıları, durum sözlüğü, biçimlendiriciler |
@tecof/app-ui/styles.css | Tailwind 4 CSS | Tema belirteçleri, React Suite → Tecof değişkenleri |
Peer bağımlılıklar: react ^19, react-dom ^19, rsuite ^6.2, lucide-react, @tecof/app-bridge ^0.1. tecof app init şablonları bu kurulumla gelir; aşağıdaki adımlar mevcut bir uygulamayı taşırken ya da elle kurarken gereklidir.
Kurulum#
npm install @tecof/app-ui @tecof/app-bridge @tecof/app-sdk rsuite lucide-react geist
npm install -D tailwindcss @tailwindcss/postcsspnpm add @tecof/app-ui @tecof/app-bridge @tecof/app-sdk rsuite lucide-react geist
pnpm add -D tailwindcss @tailwindcss/postcssyarn add @tecof/app-ui @tecof/app-bridge @tecof/app-sdk rsuite lucide-react geist
yarn add -D tailwindcss @tailwindcss/postcssbun add @tecof/app-ui @tecof/app-bridge @tecof/app-sdk rsuite lucide-react geist
bun add -d tailwindcss @tailwindcss/postcssexport default { plugins: { "@tailwindcss/postcss": {} } };app/globals.css tam olarak şu dört satırdır; katman sırası önemlidir ve başka global CSS eklenmez:
@layer theme, base, rsuite, components, utilities;
@import "tailwindcss";
@import "rsuite/dist/rsuite-no-reset.min.css" layer(rsuite);
@import "@tecof/app-ui/styles.css";import type { Metadata } from "next";
import { GeistMono } from "geist/font/mono";
import { GeistSans } from "geist/font/sans";
import { Providers } from "./providers";
import "./globals.css";
export const metadata: Metadata = { title: "Uygulamam", robots: { index: false, follow: false } };
export default function RootLayout({ children }: { children: React.ReactNode }) {
return (
<html lang="tr" data-theme="light" suppressHydrationWarning className={`${GeistSans.variable} ${GeistMono.variable}`}>
<body>
<Providers>{children}</Providers>
</body>
</html>
);
}"use client";
import { TecofAppProvider } from "@tecof/app-ui";
export function Providers({ children }: { children: React.ReactNode }) {
// App Bridge'i kurar, tema/dili panelden alır, <html data-theme class="dark" lang> ayarlar,
// toast ve onay köprüsünü sağlar.
return <TecofAppProvider>{children}</TecofAppProvider>;
}Panel dışında geliştirmek için allowStandalone (köprü null, toast/onay React Suite ile çalışır) ya da geçici olarak bridge="off" theme="dark" locale="en" verin. Kalıcı kodda bridge="off" bırakmayın.
Kabuk#
"use client";
import Link from "next/link";
import { usePathname } from "next/navigation";
import { AppShell, StatusBadge, useTecofApp } from "@tecof/app-ui";
import { FileText, LayoutDashboard, Settings } from "lucide-react";
export function Shell({ children }: { children: React.ReactNode }) {
const { context, locale } = useTecofApp();
const en = locale === "en";
return (
<AppShell
title={context?.app.name ?? "Uygulama"}
subtitle={context?.merchant.name}
icon={<FileText />}
status={<StatusBadge status="connected" />}
linkAs={Link}
activeHref={usePathname()}
tabs={[
{ href: "/", label: en ? "Overview" : "Genel bakış", icon: <LayoutDashboard /> },
{ href: "/settings", label: en ? "Settings" : "Ayarlar", icon: <Settings /> },
]}
>
{children}
</AppShell>
);
}AppShell’e linkAs={Link} bir fonksiyon geçtiği için kabuğu istemci bileşeninde kullanın. Simge prop’ları eleman alır (icon={<Receipt />}), böylece sunucu bileşenlerinden de verilebilir.
Bileşenler#
| Bileşen | Kullanım |
|---|---|
PageHeader | Sayfa başlığı ve tek ana eylem; eyebrow yazıldığı gibi gösterilir (eyebrowCase="upper" isteğe bağlı) |
Section | Kart; form ve tablo için padded={false}, tehlikeli işlem için tone="danger" |
StatGrid + StatCard | 2–4 metrik; loading destekler |
DataTable | React Suite tablosu; 640 px altında kart görünümü (mobile: "title" | "badge" | "meta" | "hidden"), uzun metin için truncate: true, boş liste için empty |
StatusBadge | Ortak durum sözlüğünden ton ve tr/en etiket |
Callout | Bilgi/uyarı/hata mesajı (tone) |
EmptyState | Boş durum: ne olacağını ve ilk adımı söyler |
KeyValueList, CopyValue, LogList | Ayrıntı ekranları |
ConfirmButton | Panelde App Bridge onayıyla çalışan tehlikeli eylem düğmesi |
useAppToast(), useAppConfirm() | Panel toast’ı ve onayı |
Düğmeler React Suite Button’dır: ekranda tek ana eylem appearance="primary" (lime), diğerleri default ya da subtle. İkonlar yalnız lucide-react, düğmede size-4.
Durum sözlüğü#
<StatusBadge status="…" /> tek sözlükten ton ve etiket alır; sözlükte olmayan durum için tone + label verin, yeni renk uydurmayın.
| Grup | Durumlar |
|---|---|
| Genel | success · warning · error · info · neutral · pending |
| Fatura | creating · draft · issued · signed · failed · skipped · needs-cancellation · deleted · cancelled |
| Gönderim | queued · processing · sending · sent · delivered · undelivered · rejected |
| Kargo | label-created · shipped · in-transit · out-for-delivery · returned |
| Bağlantı / abonelik | connected · disconnected · not-configured · active · inactive · trialing · past_due · expired |
Sunucuda aynı sözlük statusTone / statusLabel ile (@tecof/app-ui/schema) okunur.
Ekran düzenleri#
| Ekran | Düzen |
|---|---|
Genel bakış (/) | PageHeader (+ tek ana eylem) → yalnız eylem gerektiren Callout (ayar eksik, test modu, plan) → StatGrid → son kayıtlar Section + DataTable (5–10 satır, “Tümünü gör”) → hiç kayıt yoksa EmptyState |
Ayarlar (/settings) | PageHeader → AppForm içinde konu başına Section padded={false} → FormActions (mobilde alta yapışık) → ayrı Section tone="danger" (bağlantıyı kes, ConfirmButton) |
Kayıtlar (/invoices, /logs…) | PageHeader (+ filtre) → Section padded={false} + DataTable (onRowClick → Drawer ya da detay sayfası) → Pagination; detayda KeyValueList + LogList |
| Aksiyon penceresi | Kabuksuz: başlık yalnız bridge.setTitle(...) ile panel çekmecesine gider (sayfada başlık satırı ve kendi X’i yok); kısa bağlam satırı + Section + altta yapışık Vazgeç/Tamamla; bitince bridge.close({ refresh: true, message, kind }). Fatura uygulamalarında @tecof/invoice-kit/ui ActionFrame |
Durumlar: yükleniyor → Placeholder.Paragraph / StatCard loading / DataTable loading; hata → Callout tone="error" + “Tekrar dene”; boş → EmptyState. Tarih ve para için formatDateTime (Europe/Istanbul, hidrasyon güvenli) ve formatMoney (@tecof/app-ui/schema).
Metin tonu#
Türkçe öncelikli, en karşılığıyla. Kısa, “siz” dili, cümle düzeni (“Ayarları Kaydet” değil “Kaydet”). Eylemler fiille (“Bağlan”, “Tekrar dene”, “Fatura oluştur”). Hata metni ne olduğunu ve ne yapılacağını söyler: “Sağlayıcı kimlik bilgilerini reddetti. API anahtarını kontrol edip tekrar deneyin.” Ünlem, teknik kod ve stack izi yok. Dil useTecofApp().locale (tr | en); sunucuda resolveLocale(session.locale).
Yapmayın#
- Marka/ürün adına
uppercasevermeyin (Türkçe büyük harf “KolayBi” → “KOLAYBİ”). - Kendi renk paleti, CSS değişken seti, ayrı
.cssdosyası, inline style ile tema, başka UI kütüphanesi (shadcn, MUI…), başka ikon seti ya da emoji. - Ham
<input>/<select>/<button>ile form;prefers-color-schemeile tema;@custom-variant darkyeniden tanımı. Koyu tema panelden gelir,dark:sınıflarıyla kullanılır. - Sunucu kodunda
@tecof/app-ui(istemci girişi) — sunucuda yalnız@tecof/app-ui/schema. - Sır değerini, oturum token’ını ya da müşteri kişisel verisini ekrana veya günlüğe basmak.
- Kit eksiğini kalıcı geçici çözümle kapatmak: önce kitte karşılığını arayın (
truncate,SubmitButton,onCheckFail).
Formlar ve tek şemalı doğrulama: Formlar ve şema. Görsel doğrulama için uygulamayı panel dışında allowStandalone ile açıp masaüstü (1280) ve mobil (390) genişlikte, açık ve koyu temada kontrol edin.