İçeriğe geç
Docs

Tasarım Kimliği (@tecof/app-ui)

@tecof/app-ui ile Tecof panel görünümünde uygulama arayüzü: kurulum, globals.css katman sırası, TecofAppProvider, AppShell ve bileşenler, durum sözlüğü, ekran düzenleri, metin tonu ve yasaklar.

Son güncelleme:

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/schemaSunucu-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.cssTailwind 4 CSSTema 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#

Terminal
npm install @tecof/app-ui @tecof/app-bridge @tecof/app-sdk rsuite lucide-react geist
npm install -D tailwindcss @tailwindcss/postcss
postcss.config.mjs
export 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:

app/globals.css
@layer theme, base, rsuite, components, utilities;
@import "tailwindcss";
@import "rsuite/dist/rsuite-no-reset.min.css" layer(rsuite);
@import "@tecof/app-ui/styles.css";
app/layout.tsx
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>
  );
}
app/providers.tsx
"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#

app/app-shell.tsx
"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şenKullanım
PageHeaderSayfa başlığı ve tek ana eylem; eyebrow yazıldığı gibi gösterilir (eyebrowCase="upper" isteğe bağlı)
SectionKart; form ve tablo için padded={false}, tehlikeli işlem için tone="danger"
StatGrid + StatCard2–4 metrik; loading destekler
DataTableReact 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
StatusBadgeOrtak durum sözlüğünden ton ve tr/en etiket
CalloutBilgi/uyarı/hata mesajı (tone)
EmptyStateBoş durum: ne olacağını ve ilk adımı söyler
KeyValueList, CopyValue, LogListAyrıntı ekranları
ConfirmButtonPanelde 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.

GrupDurumlar
Genelsuccess · warning · error · info · neutral · pending
Faturacreating · draft · issued · signed · failed · skipped · needs-cancellation · deleted · cancelled
Gönderimqueued · processing · sending · sent · delivered · undelivered · rejected
Kargolabel-created · shipped · in-transit · out-for-delivery · returned
Bağlantı / abonelikconnected · 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#

EkranDü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 penceresiKabuksuz: 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 uppercase vermeyin (Türkçe büyük harf “KolayBi” → “KOLAYBİ”).
  • Kendi renk paleti, CSS değişken seti, ayrı .css dosyası, 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-scheme ile tema; @custom-variant dark yeniden 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.