Tabs
Starter kit, çok bölümlü ekranları temiz tutmak için SkTabs ve fluent TB builder yapısını kullanır. Ayarlar, profil ve benzeri ekranlar zamanla çok parçalı hale gelir — tabs yapısı, sayfayı birçok farklı route'a bölmeden tek route içinde düzenli bir arayüz kurar.
İmportlar
import { TB } from '@lvntr/components/TabBuilder/core';
import SkTabs from '@lvntr/components/TabBuilder/SkTabs.vue';
import type { TabIconColor, TabBadgeSeverity } from '@lvntr/components/TabBuilder/core';
import type { TabChangePayload, SkTabsExposed, TabPanelMode, TabHistoryMode, TabUrlMode } from '@lvntr/components/TabBuilder/core';
Temel Örnek
<script setup lang="ts">
import { TB } from '@lvntr/components/TabBuilder/core';
import SkTabs from '@lvntr/components/TabBuilder/SkTabs.vue';
const tabConfig = TB.tabs()
.queryParam('tab')
.addTabs(
TB.item().key('general').label('Genel').icon('pi pi-user'),
TB.item().key('security').label('Güvenlik').icon('pi pi-shield'),
TB.item().key('sessions').label('Oturumlar').icon('pi pi-desktop'),
)
.build();
</script>
<template>
<SkTabs :config="tabConfig">
<template #general>
<p>Genel içerik</p>
</template>
<template #security>
<p>Güvenlik içeriği</p>
</template>
<template #sessions>
<p>Oturum içeriği</p>
</template>
</SkTabs>
</template>
Tabs Builder API
layout('horizontal' | 'vertical')vertical()horizontal()queryParam(string)class(string)cardTitle(string)cardSubtitle(string)isCard(boolean)addTabs(...tabs)lazy(value = true)— yalnızca aktif paneli mount eder (panels: 'active');lazy(false)override'ı temizlerkeepAlive(value = true)— her paneli mount edip geçişler arasında canlı tutar (panels: 'all');keepAlive(false)override'ı temizlerhistory('push' | 'replace')— sekme geçişinde yazılan history girdisi; varsayılanreplaceurlMode('server' | 'client')—serverbir Inertia visit'i üzerinden senkronize eder (varsayılan),clientsunucuya istek atmadan URL'i güncellersyncUrl(boolean)— aktif sekmeyi URL query string'inde yansıtır; varsayılantrue
Tab Item API
key(string)label(string)icon(string)description(string)— label altında ikincil satır (yalnızca dikey düzen)iconColor(color)— renkli icon tile preset'i (yalnızca dikey düzen); varsayılanslate. Seçenekler:blue,amber,emerald,purple,teal,red,rose,indigo,slate,pink,orange,cyan,green,yellowbadge(value, severity?)— sağ tarafta badge (metin veya sayı). Severity:success/warn/info/danger/secondary(varsayılan)checked(value = true)— sağ tarafta yeşil check işareti;badgeüzerinde önceliklidirpermission(...permissions)— kullanıcı verilen yetkilerden en az birine sahip değilse sekmeyi gizler (variadic; birden çok değerde OR —canAny()ile aynı mantık)role(...roles)— kullanıcı verilen rollerden en az birine sahip değilse sekmeyi gizler (variadic; birden çok değerde OR)visible(boolean | () => boolean)disabled(boolean | () => boolean)isCard(boolean)cardTitle(string)cardSubtitle(string)
TB.item().key('billing').label('Faturalama').permission('billing.view', 'billing.manage'),
TB.item().key('admin-tools').label('Yönetici Araçları').role('admin', 'superadmin'),
Bileşen Prop'ları ve Event'leri
config: TabBuilderConfig— build edilmiş config (zorunlu)v-model(modelValue?: string) — aktif sekme anahtarı için opsiyonel iki yönlü binding. URL modunda mount sırasında bir deep link (örn.?tab=security), farklı birmodelValue'nun önüne geçer; local modda (.syncUrl(false)) isemodelValuebaşlangıç seçimini besler. Her iki durumda damodelValueyazmak, bir tıklamanın kullandığı aynı setter'dan geçer.@update:modelValue="(key: string) => …"— çözümlenen aktif anahtarmodelValue'dan farklı olduğunda, mount sonrası dahil her seferinde tetiklenir@change="(payload: TabChangePayload) => …"— mount sonrasındaki her sekme değişiminde tetiklenir (ilk mount bir değişiklik sayılmaz); payload{ key, previousKey, tab }şeklindedir — daha önce çözümlenebilen bir sekme yoksapreviousKeynullolur#emptyslot'u — seçilebilir sekme kalmadığında, yani.permission()/.role()/.visible()yüzünden tüm sekmeler elenmişse ya da görünür sekmelerin hepsi.disabled()ise, sidebar veya tab şeridi olmadan tek başına render edilir- expose edilen instance (
SkTabsExposed, template ref üzerinden) —{ activeTab: string; isActive: (key: string) => boolean }
<script setup lang="ts">
import { ref } from 'vue';
import type { TabChangePayload } from '@lvntr/components/TabBuilder/core';
const activeTab = ref('general');
function onTabChange(payload: TabChangePayload) {
console.log(payload.previousKey, '→', payload.key);
}
</script>
<template>
<SkTabs :config="tabConfig" v-model="activeTab" @change="onTabChange">
<!-- ... -->
</SkTabs>
</template>
Zengin Dikey Tab Görünümü
Dikey tab'lar daha zengin bir sidebar sunabilir — renkli icon tile, description satırı, trailing badge veya check işareti. Sidebar zaten her zaman bir kart içinde render edilir; .isCard(true) bunun yerine aktif sekmenin içerik panelinin kart mı yoksa şeffaf, kenara yaslı bir panel mi olacağını belirler — SkTabs içindeki tabIsCard() fonksiyonunun okuduğu aynı flag:
<script setup lang="ts">
const tabConfig = TB.tabs()
.vertical()
.isCard(true)
.addTabs(
TB.item()
.key('general')
.label('Genel')
.description('Uygulama adı, dil ve logo')
.icon('pi pi-cog')
.iconColor('blue'),
TB.item()
.key('mail')
.label('E-posta')
.description('SMTP ve gönderici ayarları')
.icon('pi pi-envelope')
.iconColor('emerald')
.badge(3, 'warn'),
TB.item()
.key('storage')
.label('Depolama')
.description('S3, Spaces ve yerel disk')
.icon('pi pi-database')
.iconColor('purple')
.checked(),
)
.build();
</script>
description, iconColor, badge ve checked yatay düzende yok sayılır.
Yararlı Özellikler
- dikey veya yatay düzen
- icon tile, description, badge ve check işareti ile zengin dikey sidebar
- varsayılan olarak query string senkronizasyonu,
.syncUrl(false)ile tamamen local (URL'siz) state - role ve permission bazlı görünürlük
- sekme bazlı disabled mantığı
- hem sekme hem de konteyner seviyesinde başlık ve alt başlıkla opsiyonel card sarmalayıcı
- host tarafında tepki vermek için opsiyonel
v-modelbinding'i ve birchangeevent'i - seçilebilir sekme kalmadığında (hepsi elenmiş ya da görünenlerin hepsi disabled) gösterilecek bir
emptyslot'u - dikey düzende tam klavye/ARIA desteği
Dahili Davranışlar
SkTabs şu özellikleri hazır getirir:
- varsayılan olarak query string senkronizasyonu;
.syncUrl(false)aktif sekmeyi tamamen local tutar - dikey sidebar modu
- dikey düzende
sidebar-headervesidebar-footerslot'ları - sekme anahtarına göre slot tabanlı içerik
- lifecycle: varsayılanlar değişmedi — dikey düzen yalnızca aktif paneli mount eder ve geçişte unmount eder, yatay düzen tüm panelleri bir kez mount edip görünürlüğü toggler; bu yüzden sekme bazlı local state varsayılan olarak yalnızca yatay düzende geçişten sağ çıkar.
.lazy()her iki düzeni de yalnızca-aktif mount moduna zorlar (yatay düzende bu, PrimeVue'nun kendilazymodudur);.keepAlive()her iki düzeni de her paneli mount edip canlı tutmaya zorlar — unmount yerine gizler (dikey düzende sekme bazlı state'i geçişler arasında korumak için kullanışlıdır) - URL senkronizasyonu:
?tab=görünür ve enabled bir sekmeyi adlandırmalı, aksi halde ilk seçilebilir sekme kazanır; disabled bir sekme URL'den asla aktive edilemez; aktif sekmeyi tekrar seçmek no-op'tur;#hashgeçişler arasında korunur..urlMode('server')(varsayılan) sayfayı yeniden çözümleyen bir Inertia visit'i üzerinden senkronize eder;.urlMode('client')sunucuya istek atmadan URL'i günceller..history('replace')(varsayılan) her geçişte mevcut history girdisini değiştirir,.history('push')her geçişe kendi girdisini verir..syncUrl(false)URL senkronizasyonunu tamamen kaldırır — aktif sekme yalnızca component state'inde (vev-model'de) yaşar - erişilebilirlik (dikey düzen): tab listesi
aria-orientation="vertical"ilerole="tablist"'tır, her sekme butonuaria-selected/aria-controls/aria-disabledve rovingtabindex(aktif sekmede0, diğerlerinde-1) ilerole="tab"'tır; panel iserole="tabpanel"ile sarmalanır. Arrow Down/Up, enabled sekmeler arasında odağı taşır (uçlarda başa/sona sarar), Home/End ilk/son enabled sekmeye atlar — yalnızca odak, manuel aktivasyon — Enter/Space ise butonun native click'i üzerinden seçim yapar. Sekme ikonları her iki düzende dearia-hidden'dır (adı label taşır);.checked()bir sekme durumunu, gizlenmiş check ikonunun yanındaki görsel olarak gizli metinle (sk-common.completed) duyurur. Yatay düzen PrimeVue'nun kendi erişilebilirliğini korur - builder doğrulaması:
TB.item()…build()boş veya yalnızca boşluktan oluşan bir key'de hata fırlatır;TB.tabs()…build()hiç sekme eklenmemişse hata fırlatır, development build'lerinde yinelenen bir sekme key'inde de hata fırlatır (production'da aynı mesajıconsole.errorile basar, dedupe yapmadan);TB.tabs().queryParam()boş veya yalnızca boşluktan oluşan bir isimde development build'lerinde hata fırlatır (production'daconsole.errorbasar ve önceden ayarlı ismi korur); herbuild()çağrısı taze bir snapshot döndürür — böylece aynı builder üzerindeki sonraki.addTabs()çağrıları veya döndürülen config'in mutate edilmesi, zaten build edilmiş bir config'i asla etkilemez - aynı sayfadaki birden fazla
SkTabsörneği farklı.queryParam()değerlerine ihtiyaç duyar .permission()/.role()filtrelemesi yalnızca sunum amaçlıdır — asıl veriyi sunucu tarafında yetkilendirin, gizli sekmenin verisini sayfa prop'larına serileştirmeyin
Gerektiğinde parent bileşenler aktif sekmeye defineExpose üzerinden erişebilir.
Sekmeler Dialog İçinde
Bir dialog route'lanabilir bir sayfa değildir, bu yüzden sekmelerini URL query string'ine senkronlamak host sayfanın kendi ?tab= parametresiyle çakışabilir (ya da basitçe anlamsızdır). Bunun yerine .syncUrl(false) çağırıp aktif sekmeyi v-model ile yönetin:
<script setup lang="ts">
import { ref } from 'vue';
const activeTab = ref('general');
const tabConfig = TB.tabs().syncUrl(false).addTabs(/* … */).build();
</script>
<template>
<AppDialog>
<SkTabs :config="tabConfig" v-model="activeTab">
<!-- ... -->
</SkTabs>
</AppDialog>
</template>
En Uygun Kullanım
- ayarlar ekranları
- profil ekranları
- mantıksal bölümlere ayrılmış uzun create/edit görünümleri