10 β Nuxt UI komponentlari (to'liq ma'lumotnoma)¶
β¬ οΈ Oldingi: 09 β Nuxt UI asoslar Β· π README
Bu β Nuxt UI'ning 125+ komponentini kategoriya bo'yicha ko'rib chiqadigan ma'lumotnoma. Eng ko'p ishlatadigan komponentlarni chuqur (props + slot + misol), nisbatan kam ishlatiladiganlarni qisqa (nima qiladi + asosiy props + mini-misol) ko'rsataman.
Buni o'qishdan oldin 09-modulni o'qigan bo'l. U yerda color, variant, size, :ui, slot tushunchalari bor β bu yerda ularni qayta tushuntirmayman. Deyarli har bir komponent o'sha 3 propni qabul qiladi.
π‘ Har bir komponentning to'liq prop/slot ro'yxati
ui.nuxt.com/docs/components/<nom>da. Bu yerda amaliy yadroni beraman β kunlik ishda 90% shu kerak bo'ladi.
Kategoriyalar: 1. Element (Button, Badge, Avatar...) Β· 2. Feedback (Alert, Toast, Progress...) Β· 3. Form (Form + barcha inputlar) Β· 4. Data (Table, Card, Accordion...) Β· 5. Navigation (Menu, Tabs, Pagination...) Β· 6. Overlay (Modal, Slideover, Dropdown...) Β· 7. Layout & Page Β· 8. Dashboard Β· 9. Composables
Quyidagi xarita 8 kategoriyaning har birida nima borligini va hammasining tagidagi umumiy poydevorni (color/variant/size, props β / emits β, Proxy reaktivlik, SSR/hydration) bir ko'rinishda jamlaydi:
1. Element β asosiy qurilish bloklari¶
Button β UButton¶
Eng ko'p ishlatiladigan. Tugma yoki havola (to bersang <NuxtLink> bo'ladi).
| Prop | Vazifa |
|---|---|
label / default slot |
matn |
color, variant, size |
09-modul |
icon |
faqat ikonka (label'siz β icon-only) |
leading-icon / trailing-icon |
chap/o'ng ikonka |
avatar |
ichida avatar ({ src }) |
loading |
spinner ko'rsatadi |
loading-auto |
type="submit" da form yuborilayotganda avtomatik loading |
block |
to'liq kenglik (w-full) |
square |
kvadrat (icon-only uchun) |
disabled, to, type |
β |
<UButton color="primary" icon="i-lucide-save" loading-auto type="submit">Saqlash</UButton>
<UButton color="neutral" variant="ghost" square icon="i-lucide-x" />
<UButton to="/dashboard" trailing-icon="i-lucide-arrow-right">Panelga</UButton>
:ui uchun): base, label, leadingIcon, trailingIcon.
ButtonGroup β UButtonGroup¶
Bir nechta button/inputni yopishtirib qo'yadi (segment).
<UButtonGroup size="md">
<UButton color="neutral" variant="outline" label="Kun" />
<UButton color="neutral" variant="outline" label="Hafta" />
<UButton color="neutral" variant="outline" label="Oy" />
</UButtonGroup>
Badge β UBadge¶
Status/yorliq. color, variant, size, label, icon.
<UBadge color="success" variant="subtle">Faol</UBadge>
<UBadge color="error" variant="soft">To'lanmagan</UBadge>
Avatar / AvatarGroup β UAvatar, UAvatarGroup¶
<UAvatar src="https://github.com/nuxt.png" alt="Nuxt" size="lg" />
<UAvatar text="OQ" /> <!-- rasmsiz: initsiallar -->
<UAvatar icon="i-lucide-user" /> <!-- ikonka -->
<UAvatarGroup :max="3" size="md">
<UAvatar src="..." /><UAvatar src="..." /><UAvatar text="AB" /><UAvatar text="CD" />
</UAvatarGroup> <!-- ortig'i "+N" bo'ladi -->
Chip β UChip¶
Boshqa elementga nuqta/indikator biriktiradi (masalan, avatarga "online" nuqtasi yoki xabar soni).
<UChip color="success" inset>
<UAvatar src="..." />
</UChip>
<UChip :text="5" size="2xl" color="error">
<UButton icon="i-lucide-bell" color="neutral" variant="ghost" />
</UChip>
Icon, Kbd, Separator¶
<UIcon name="i-lucide-rocket" class="size-5 text-primary" />
<UKbd value="meta" /> <UKbd value="K" /> <!-- klaviatura tugmasi -->
<USeparator label="yoki" /> <!-- ajratuvchi chiziq -->
2. Feedback β holat va xabarlar¶
Alert β UAlert¶
Diqqat tortuvchi xabar (sahifa ichida turadi).
<UAlert
color="warning" variant="subtle"
icon="i-lucide-triangle-alert"
title="Diqqat"
description="To'lov muddati tugayapti."
:actions="[{ label: 'To\'lash', color: 'warning' }]"
:close="true"
/>
title, description, icon, color, variant, :actions (button massivi), :close, orientation.
Toast β useToast (komponent emas, composable)¶
Vaqtinchalik bildirishnoma (o'ng pastda paydo bo'lib yo'qoladi). <UApp> shart (09-modul).
<script setup>
const toast = useToast()
toast.add({
title: 'Saqlandi',
description: 'O\'quvchi ma\'lumoti yangilandi.',
color: 'success',
icon: 'i-lucide-check',
duration: 4000,
actions: [{ label: 'Bekor qilish', onClick: () => {} }],
})
// toast.remove(id) Β· toast.update(id, {...}) Β· toast.clear()
</script>
Laravel analogiyasi.
useToastβ session flash message (->with('success', '...')) β lekin client-side, dinamik va action'lar bilan.
Progress, Skeleton, Banner¶
<UProgress v-model="percent" :max="100" /> <!-- yoki animatsion (indeterminate) -->
<USkeleton class="h-12 w-full" /> <!-- yuklanish placeholder -->
UBanner β sahifa tepasidagi global e'lon chizig'i (app.vue da, <UApp> ichida):
3. Form β eng muhim qism (SaaS yuragi)¶
Umumiy arxitektura¶
Nuxt UI form tizimi 2 komponentdan iborat:
- UForm β validatsiya + submit'ni boshqaradi.
- UFormField β bitta maydon (label + xato xabari) o'rami.
Validatsiya Standard Schema kutubxonalari bilan: Zod, Valibot, Yup, Joi, Superstruct yoki o'z funksiyang. Hech qaysi biri ichida kelmaydi β kerakligini o'rnatasan (pnpm add zod).
<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'
const schema = z.object({
email: z.email('Email noto\'g\'ri'),
password: z.string().min(8, 'Kamida 8 belgi'),
})
type Schema = z.output<typeof schema>
const state = reactive<Partial<Schema>>({ email: undefined, password: undefined })
const toast = useToast()
async function onSubmit(event: FormSubmitEvent<Schema>) {
// event.data β validatsiyadan o'tgan, type-safe data
await $fetch('/api/login', { method: 'POST', body: event.data })
toast.add({ title: 'Kirildi', color: 'success' })
}
</script>
<template>
<UForm :schema="schema" :state="state" class="space-y-4" @submit="onSubmit">
<UFormField label="Email" name="email" required>
<UInput v-model="state.email" type="email" class="w-full" />
</UFormField>
<UFormField label="Parol" name="password" required>
<UInput v-model="state.password" type="password" class="w-full" />
</UFormField>
<UButton type="submit" loading-auto>Kirish</UButton>
</UForm>
</template>
Eng muhim mexanizm: UFormFieldning name proli schemadagi maydon nomi bilan bir xil bo'lishi kerak β shunda xato xabari avtomatik o'sha maydon tagida chiqadi. Qo'lda hech narsa ulamaysan.
Quyidagi diagramma bu bog'lanishni va Vue 3 oqim semantikasini (props β pastga, emits β tepaga, v-model = ikkalasi) ko'rsatadi:
Laravel analogiyasi. Bu
FormRequestvalidatsiyasiga juda o'xshaydi:rules()= Zod schema, validation messages avtomatik maydonlarga biriktiriladi. Bonus: Zod schema'niserver/api/da qayta ishlatish mumkin β bitta schema ham clientda, ham serverda validatsiya qiladi (DRY). Laravel'da rule'lar faqat serverda; bu yerda ikkalasi.
UForm props/xususiyatlari:
- :schema, :state, @submit, @error
- validate-on β qachon tekshirish: ['blur', 'input', 'change', 'submit']
- :transform β submit'da Zod .transform() natijasini qaytarish (default true)
- nested β ichki (child) form
- Default slot { errors, loading } ni beradi.
- Template ref orqali metodlar: formRef.value.validate(), .clear(), .submit(), .setErrors([...]), .getErrors().
UFormField props: label, name, description, help, hint, error (qo'lda xato), required, size, eager-validation.
Input komponentlari¶
Hammasi v-model, color (focus ring), variant, size, icon, disabled ni qabul qiladi.
UInput β matn/email/parol/raqam:
<UInput v-model="q" icon="i-lucide-search" placeholder="Qidirish..." />
<UInput v-model="pwd" type="password" :ui="{ trailing: 'pe-1' }">
<template #trailing>
<UButton color="neutral" variant="link" icon="i-lucide-eye" @click="toggle" />
</template>
</UInput>
UInputNumber β raqam (stepper bilan): v-model, :min, :max, :step, :format-options.
UTextarea β ko'p qatorli: :rows, autoresize, :maxrows.
USelect β oddiy dropdown (native-ga yaqin):
<USelect v-model="role" :items="['admin', 'teacher', 'student']" placeholder="Rol" />
<!-- obyekt items: -->
<USelect v-model="val" :items="[{ label: 'Admin', value: 'a' }]" />
USelectMenu β kuchaytirilgan select: qidiruv, multiple, custom item rendering, "yangi yaratish":
UInputMenu β combobox (autocomplete + erkin matn / teglar kiritish).
UCheckbox / UCheckboxGroup, URadioGroup, USwitch:
<UCheckbox v-model="agree" label="Shartlarga roziman" />
<USwitch v-model="active" label="Faol" />
<URadioGroup v-model="plan" :items="[{label:'Free',value:'free'},{label:'Pro',value:'pro'}]" />
USlider β diapazon: v-model, :min, :max, :step.
UPinInput β OTP/PIN kiritish: :length, type, otp.
UFileUpload β fayl yuklash (drag-drop): v-model, accept, multiple.
UColorPicker β rang tanlash.
Barchasi
UFormFieldichida ishlaydi vanameorqali avtomatik xato ko'rsatadi.
4. Data β ma'lumot ko'rsatish¶
Table β UTable (eng kuchli data komponenti)¶
TanStack Table (useVueTable) + TanStack Virtual ustiga qurilgan. To'liq type-safe: sort, filter, paginatsiya, qator tanlash, kengaytirish, virtualizatsiya.
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const UBadge = resolveComponent('UBadge')
type Student = { id: number; name: string; status: 'active' | 'inactive'; balance: number }
const data = ref<Student[]>([
{ id: 1, name: 'Ali Valiyev', status: 'active', balance: 250000 },
{ id: 2, name: 'Lola Karimova', status: 'inactive', balance: 0 },
])
const columns: TableColumn<Student>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'F.I.O' },
{
accessorKey: 'status',
header: 'Holat',
// cell β render funksiya (h yoki resolveComponent bilan)
cell: ({ row }) => h(UBadge, {
color: row.original.status === 'active' ? 'success' : 'neutral',
variant: 'subtle',
}, () => row.original.status),
},
{
accessorKey: 'balance',
header: () => h('div', { class: 'text-right' }, 'Balans'),
cell: ({ row }) => h('div', { class: 'text-right' },
new Intl.NumberFormat('uz').format(row.original.balance) + " so'm"),
},
]
</script>
<template>
<UTable :data="data" :columns="columns" :loading="pending" sticky />
</template>
Asosiy nuqtalar:
- :data β obyektlar massivi. :columns bermasang β kalitlardan avtomatik yasaladi.
- column.cell: ({ row }) => ... β row.original orqali qator datasiga kirasan; h() bilan istalgan komponent render qilasan (Badge, Button...).
- column.meta.class.{ th, td } β ustun stilini berish.
- Reaktiv holatlar: v-model:row-selection, v-model:sorting, v-model:column-filters, v-model:expanded, v-model:pagination.
- Slot'lar: #<column>-cell, #<column>-header, #expanded, #empty, #loading.
- Template ref β tableApi (TanStack instansiyasi β full nazorat).
Laravel analogiyasi.
UTable+ TanStack β Laravel'dagi data-table paketlari (yoki Filament Table) β lekin frontend-side. Server-side paginatsiya/sort kerak bo'lsa: holatlarni (sorting,pagination)watchqilib,useFetchquery'siga uzatasan (08-modul bilan birlashtir).
Card β UCard¶
<UCard>
<template #header><h3 class="font-semibold">Statistika</h3></template>
<p>Asosiy kontent shu yerda.</p>
<template #footer>
<UButton color="primary">Batafsil</UButton>
</template>
</UCard>
:ui kalitlari: root, header, body, footer.
Accordion β UAccordion¶
<UAccordion :items="[
{ label: 'Savol 1', icon: 'i-lucide-help-circle', content: 'Javob 1' },
{ label: 'Savol 2', content: 'Javob 2' },
]" type="single" collapsible />
type: single | multiple. Murakkab kontent uchun #content slot.
Boshqalar (qisqa)¶
UCarouselβ slayder (Embla asosida)::items+#default="{ item }".loop,:autoplay,arrows,dots.UMarqueeβ uzluksiz aylanuvchi lenta (logotiplar uchun).UTreeβ daraxt tuzilma::items(nested),v-model.UCalendarβ sana tanlash kalendar (range, multiple).UTimelineβ vaqt chizig'i (qadamlar tarixi).
5. Navigation β navigatsiya¶
NavigationMenu β UNavigationMenu¶
Asosiy menyu (gorizontal yoki vertikal β sidebar uchun ideal).
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const items: NavigationMenuItem[] = [
{ label: 'Bosh sahifa', icon: 'i-lucide-house', to: '/' },
{ label: 'O\'quvchilar', icon: 'i-lucide-users', to: '/students', badge: '24' },
{
label: 'Sozlamalar', icon: 'i-lucide-settings',
children: [
{ label: 'Profil', to: '/settings/profile' },
{ label: 'Billing', to: '/settings/billing' },
],
},
]
</script>
<template>
<UNavigationMenu :items="items" orientation="vertical" />
</template>
label, icon, to, active, badge, children, disabled, onSelect.
Tabs β UTabs¶
<UTabs :items="[
{ label: 'Umumiy', icon: 'i-lucide-info', slot: 'general' },
{ label: 'Xavfsizlik', slot: 'security' },
]" variant="link">
<template #general>Umumiy kontent</template>
<template #security>Xavfsizlik kontenti</template>
</UTabs>
variant: pill | link. orientation. :content="false" (faqat tab tugmalari).
Breadcrumb, Pagination, Stepper, Link¶
<UBreadcrumb :items="[{label:'Bosh',to:'/'},{label:'O\'quvchilar',to:'/students'},{label:'Ali'}]" />
<UPagination v-model:page="page" :total="240" :items-per-page="20" show-edges />
<UStepper v-model="step" :items="[
{ title: 'Ma\'lumot', icon: 'i-lucide-user' },
{ title: 'To\'lov', icon: 'i-lucide-credit-card' },
{ title: 'Tasdiq', icon: 'i-lucide-check' },
]" />
<ULink to="/about" active-class="text-primary">Biz haqimizda</ULink>
CommandPalette β UCommandPalette¶
Cmd+K qidiruv oynasi (Fuse.js fuzzy qidiruv). Odatda Modal ichida:
<UCommandPalette :groups="[
{ id: 'pages', label: 'Sahifalar', items: [
{ label: 'O\'quvchilar', icon: 'i-lucide-users', to: '/students' },
]},
]" placeholder="Buyruq yoki sahifa qidirish..." />
6. Overlay β ustki oynalar¶
Bu guruh <UApp> ga muhtoj (OverlayProvider). Ikki ishlatish usuli bor: deklarativ (v-model:open) va dasturiy (useOverlay).
Quyidagi diagramma SSR β hydration oqimini va nega Overlay/Toast/Tooltip uchun UApp Provider majburiy ekanini, hamda ikki ochish usulini ko'rsatadi:
Modal β UModal¶
Deklarativ:
<script setup>
const open = ref(false)
</script>
<template>
<UModal v-model:open="open" title="O'quvchini o'chirish"
description="Bu amalni qaytarib bo'lmaydi.">
<UButton color="error" label="O'chirish" /> <!-- trigger (default slot) -->
<template #body>
<p>Haqiqatan ham o'chirmoqchimisiz?</p>
</template>
<template #footer="{ close }">
<UButton color="neutral" variant="outline" label="Bekor" @click="close" />
<UButton color="error" label="O'chirish" @click="remove" />
</template>
</UModal>
</template>
#content (butun ichki), yoki #header/#body/#footer alohida. Props: title, description, dismissible (tashqariga bosib yopish), :overlay, :transition, fullscreen, :close.
Slideover β USlideover¶
Ekran chetidan suriladi (filtrlar, detallar paneli uchun). side: right (default) | left | top | bottom. Slot/proplar Modal'ga o'xshash.
<USlideover v-model:open="open" title="Filtrlar" side="right">
<UButton label="Filtr" icon="i-lucide-filter" />
<template #body><!-- filtr formasi --></template>
</USlideover>
Drawer β UDrawer¶
Pastdan chiqadigan "bottom sheet" (mobil-uslub). modal, dismissible, #content.
useOverlay β dasturiy ochish (kuchli pattern)¶
Trigger'ni komponentdan ajratish va natija qaytarish uchun. Confirm dialog'lar uchun ideal.
<!-- 1. Alohida modal komponent β close event chiqaradi -->
<!-- components/ConfirmModal.vue -->
<script setup lang="ts">
defineProps<{ title: string }>()
const emit = defineEmits<{ close: [boolean] }>()
</script>
<template>
<UModal :title="title">
<template #footer>
<UButton variant="outline" label="Yo'q" @click="emit('close', false)" />
<UButton color="error" label="Ha" @click="emit('close', true)" />
</template>
</UModal>
</template>
<!-- 2. Istalgan joyda dasturiy chaqirish -->
<script setup lang="ts">
import { LazyConfirmModal } from '#components'
const overlay = useOverlay()
const confirmModal = overlay.create(LazyConfirmModal)
async function deleteStudent(id: number) {
const instance = confirmModal.open({ title: 'O\'chirishni tasdiqlang' })
const confirmed = await instance.result // close event qiymatini kutadi
if (confirmed) {
await $fetch(`/api/students/${id}`, { method: 'DELETE' })
}
}
</script>
Why bu zo'r. Trigger button modal'dan ajraladi β bitta
ConfirmModalni butun ilovada qayta ishlatasan,awaitbilan "ha/yo'q" natijani olasan.useOverlaycreateSharedComposableasosida β holat butun ilovada bitta.
DropdownMenu, ContextMenu β UDropdownMenu, UContextMenu¶
<UDropdownMenu :items="[
[{ label: 'Profil', icon: 'i-lucide-user' }, { label: 'Sozlama', icon: 'i-lucide-settings' }],
[{ label: 'Chiqish', icon: 'i-lucide-log-out', color: 'error', onSelect: logout }],
]">
<UButton icon="i-lucide-ellipsis-vertical" color="neutral" variant="ghost" />
</UDropdownMenu>
UContextMenu β o'ng-klik menyusi (xuddi shu items).
Popover, Tooltip β UPopover, UTooltip¶
<UPopover mode="click">
<UButton label="Ko'proq" />
<template #content><div class="p-4">Erkin kontent</div></template>
</UPopover>
<UTooltip text="O'chirish" :kbds="['meta', 'D']">
<UButton icon="i-lucide-trash" color="error" variant="ghost" />
</UTooltip>
UTooltip ham <UApp> (TooltipProvider) ga muhtoj.
7. Layout & Page (ilgari Pro β endi bepul)¶
Marketing/landing va hujjat sahifalari uchun tayyor tuzilmalar.
UAppβ root wrapper (majburiy, 09-modul).UContainerβ markazlashgan, max-width konteyner.UHeader/UFooterβ sayt header/footer (slot'lar:#left,#right,#center).UMainβ asosiy kontent zonasi (header balandligini hisobga oladi).UPageβ#left(sidebar) + default +#right(TOC) ustunli layout.UPageHeaderβtitle,description,:links,headline.UPageBody,UPageGrid,UPageColumnsβ kontent tartibi.UPageCard,UPageFeature,UPageSection,UPageHero,UPageCTAβ landing bloklari.UPageList,UPageLinks,UPageLogos,UPageMarquee,UPageAccordionβ yordamchi bloklar.
<template>
<UContainer>
<UPageHero
title="EduCore"
description="O'quv markazlar uchun zamonaviy boshqaruv tizimi"
:links="[{ label: 'Boshlash', to: '/register', color: 'primary' }]"
/>
<UPageGrid>
<UPageCard title="Multi-tenant" description="Har markaz alohida" icon="i-lucide-building" />
<UPageCard title="To'lovlar" description="Avtomatik hisob-kitob" icon="i-lucide-wallet" />
</UPageGrid>
</UContainer>
</template>
8. Dashboard (ilgari Pro β endi bepul) β SaaS admin uchun¶
EduCore admin paneli aynan shu komponentlar bilan tez yig'iladi. Bular birga ishlaydi.
UDashboardGroupβ butun panel wrapper (sidebar holatini, kenglikni boshqaradi, localStorage'da saqlaydi).UDashboardSidebarβ yon panel:collapsible,resizable,mode(mobil:drawer/slideover/modal). Slot'lar:#header, default,#footer.{ collapsed }slot prop.UDashboardPanelβ kontent paneli (id,resizable). Slot'lar:#header,#body,#footer.UDashboardNavbarβ panel ustki paneli:title,icon,:toggle. Slot'lar:#leading,#trailing,#right.UDashboardToolbarβ navbar ostidagi qo'shimcha panel (filtrlar, tablar).UDashboardSearch/UDashboardSearchButtonβ Cmd+K qidiruv.UDashboardResizeHandleβ o'lcham o'zgartirish dastagi.
<!-- app/layouts/dashboard.vue -->
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const items: NavigationMenuItem[] = [
{ label: 'Bosh', icon: 'i-lucide-house', to: '/' },
{ label: 'O\'quvchilar', icon: 'i-lucide-users', to: '/students' },
{ label: 'To\'lovlar', icon: 'i-lucide-wallet', to: '/payments' },
]
</script>
<template>
<UDashboardGroup>
<UDashboardSidebar collapsible resizable>
<template #header="{ collapsed }">
<span v-if="!collapsed" class="font-bold text-lg">EduCore</span>
<UIcon v-else name="i-lucide-graduation-cap" class="size-6 text-primary" />
</template>
<UNavigationMenu :items="items" orientation="vertical" />
<template #footer>
<UDropdownMenu :items="[[{ label: 'Chiqish', icon: 'i-lucide-log-out' }]]">
<UButton block color="neutral" variant="ghost" :avatar="{ src: '/me.png' }" label="Profil" />
</UDropdownMenu>
</template>
</UDashboardSidebar>
<UDashboardPanel>
<template #header>
<UDashboardNavbar title="Boshqaruv paneli">
<template #trailing><UBadge color="primary" variant="subtle">Demo</UBadge></template>
<template #right>
<UColorModeButton />
<UButton icon="i-lucide-bell" color="neutral" variant="ghost" />
</template>
</UDashboardNavbar>
</template>
<template #body>
<slot /> <!-- sahifa kontenti -->
</template>
</UDashboardPanel>
</UDashboardGroup>
</template>
Laravel analogiyasi. Bu komponentlar to'plami β Filament panel β sidebar, navbar, panel hammasi tayyor, faqat
itemsva kontent berasan. Lekin bu yerda to'liq Vue, to'liq sozlanuvchi. EduCore admin'i uchun haftalarcha vaqtni tejaydi.
9. Composables β xulosa¶
| Composable | Vazifa |
|---|---|
useToast() |
toast qo'shish/o'chirish (.add, .remove, .update, .clear) |
useOverlay() |
Modal/Slideover'ni dasturiy ochish (.create, .open, awaitable) |
useColorMode() |
dark/light boshqarish (.preference, .value) |
defineShortcuts({ ... }) |
klaviatura yorliqlari (meta_k: () => ...) |
useFormField() |
maxsus input yozganda Form bilan ulanish (advanced) |
<script setup>
defineShortcuts({
'meta_k': () => { searchOpen.value = true }, // Cmd/Ctrl + K
'g-d': () => navigateTo('/dashboard'), // ketma-ket: g, keyin d
})
</script>
π§© EduCore capstone β to'liq sahifa¶
Yuqoridagi dashboard layout + bu sahifa = ishlaydigan admin ekrani:
<!-- app/pages/students/index.vue -->
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
definePageMeta({ layout: 'dashboard' })
const UBadge = resolveComponent('UBadge')
const slideoverOpen = ref(false)
const { data, pending, refresh } = await useFetch('/api/students')
type Student = { id: number; name: string; status: string }
const columns: TableColumn<Student>[] = [
{ accessorKey: 'name', header: 'F.I.O' },
{ accessorKey: 'status', header: 'Holat',
cell: ({ row }) => h(UBadge, { color: row.original.status === 'active' ? 'success' : 'neutral', variant: 'subtle' }, () => row.original.status) },
]
</script>
<template>
<UDashboardToolbar>
<UInput icon="i-lucide-search" placeholder="Qidirish..." />
<UButton icon="i-lucide-plus" label="O'quvchi qo'shish" @click="slideoverOpen = true" class="ms-auto" />
</UDashboardToolbar>
<div class="p-4">
<UTable :data="data ?? []" :columns="columns" :loading="pending" />
</div>
<USlideover v-model:open="slideoverOpen" title="Yangi o'quvchi" side="right">
<template #body>
<!-- 3-bo'limdagi UForm shu yerga -->
</template>
</USlideover>
</template>
π― Masalalar (22 ta)¶
09-moduldagi
ui-labloyihasida davom et. Mock data uchunserver/api/(08-modul) ishlat.
A β element va feedback¶
- β
UButtonning barcha variant + 3 ta rangini jadval ko'rinishida chiqar (matritsa). - β
UAvatarGroup(:max="3") bilan 6 ta avatar β ortig'i "+3" bo'lsin. - β
Bell ikonkali button'ga
UChipbilan o'qilmagan xabar soni (5) qo'sh. - β
β
UAlertning 4 holatini (success/info/warning/error):actionsva:closebilan yasab chiqar. β - β
β
useToastbilan 4 xil rangdagi toast chiqaruvchi 4 tugma. Bittasigaactions("Bekor qilish") qo'sh. AvvalUAppborligini tekshir. β
B β form (eng muhim)¶
- β
β
Login formasi: Zod schema (email + parol min 8).
UForm+ 2 taUFormField+ submit. Xato xabarlari to'g'ri maydonda chiqsinmi? β - β
β
Ro'yxatdan o'tish formasi: ism, email, parol, parolni takrorlash (
.refinebilan moslik tekshir), shartlarga rozilik (UCheckbox). β - β
β
USelectMenu(searchable) bilan "o'qituvchi tanlash" maydoni qo'sh (mock ro'yxatdan).UFormFieldichida. - β
β
UInputNumberbilan "narx" maydoni (:min="0",format-optionsso'm uchun). - β Nima uchun
UFormFieldningnameproli schema kaliti bilan bir xil bo'lishi shart? Bir xil bo'lmasa nima bo'ladi? - β
β
β
Bitta Zod schema'ni ham
UFormda (client), hamserver/api/students.post.tsda (server) ishlat. DRY validatsiya. (08-modul bilan birlashtir.) β
C β data¶
- β
β
UTableyasab, mock o'quvchilar ro'yxatini ko'rsat.statusustuniniUBadgebilan render qil (cell+h). β - β
β
UTablegav-model:row-selectionqo'shib, tanlangan qatorlar sonini tepada ko'rsat. - β
β
UTable+UPagination:pageniuseFetchquery'siga uzatib, server-side paginatsiya qil. - β
β
UAccordionbilan FAQ bo'limi (5 savol) yasab,#contentslot bilan boyit. - β
UCardbilan 3 ta "statistika kartasi" (o'quvchilar soni, daromad, faol guruhlar) β header/body/footer bilan.
D β navigation va overlay¶
- β
β
UNavigationMenu(vertical) bilan EduCore sidebar menyusi βchildren(ichki menyu) vabadgebilan. β - β
β
UTabsbilan profil sahifasi: "Umumiy", "Xavfsizlik", "Biljing" tablari. - β
β
UModal(deklarativ) bilan "o'chirishni tasdiqlash" dialogi β footer'da Bekor/O'chirish. - β
β
β
useOverlaybilan qayta ishlatiluvchiConfirmModalyoz (close event qaytaradi).awaitbilan "ha/yo'q" olib, jadvaldan qator o'chir. β - β
β
UDropdownMenubilan jadval qatoridagi "..." amallar menyusi (Tahrirlash / O'chirish, guruhlangan).
E β to'liq yig'ish¶
- β
β
β
EduCore admin ekrani.
dashboardlayout (UDashboardGroup+Sidebar+Navbar) + o'quvchilar sahifasi (UTable+UDashboardToolbar+ qo'shish uchunUSlideoverichidaUForm). Capstone misolini asos qilib, ishlaydigan holatga keltir. β
β Tanlangan yechimlar¶
4 β Alert 4 holati
<template>
<div class="space-y-3">
<UAlert v-for="a in alerts" :key="a.color"
:color="a.color" :icon="a.icon" :title="a.title"
variant="subtle" :close="true"
:actions="[{ label: 'Ko\'rish', color: a.color, variant: 'outline' }]" />
</div>
</template>
<script setup>
const alerts = [
{ color: 'success', icon: 'i-lucide-check-circle', title: 'Muvaffaqiyat' },
{ color: 'info', icon: 'i-lucide-info', title: 'Ma\'lumot' },
{ color: 'warning', icon: 'i-lucide-alert-triangle', title: 'Ogohlantirish' },
{ color: 'error', icon: 'i-lucide-x-circle', title: 'Xato' },
]
</script>
6 β Login formasi
<script setup lang="ts">
import * as z from 'zod'
import type { FormSubmitEvent } from '@nuxt/ui'
const schema = z.object({
email: z.email('Email noto\'g\'ri'),
password: z.string().min(8, 'Kamida 8 belgi'),
})
type Schema = z.output<typeof schema>
const state = reactive<Partial<Schema>>({ email: undefined, password: undefined })
const toast = useToast()
async function onSubmit(e: FormSubmitEvent<Schema>) {
toast.add({ title: 'Kirildi', description: e.data.email, color: 'success' })
}
</script>
<template>
<UForm :schema="schema" :state="state" class="space-y-4 max-w-sm" @submit="onSubmit">
<UFormField label="Email" name="email" required>
<UInput v-model="state.email" type="email" class="w-full" icon="i-lucide-mail" />
</UFormField>
<UFormField label="Parol" name="password" required>
<UInput v-model="state.password" type="password" class="w-full" />
</UFormField>
<UButton type="submit" block loading-auto>Kirish</UButton>
</UForm>
</template>
name="email" schema kaliti bilan bir xil β shuning uchun "Email noto'g'ri" aynan email maydoni tagida chiqadi.
7 β Parol moslik tekshiruvi (.refine)
const schema = z.object({
name: z.string().min(2, 'Ism kamida 2 belgi'),
email: z.email(),
password: z.string().min(8),
confirm: z.string(),
agree: z.boolean().refine(v => v === true, 'Shartlarni qabul qiling'),
}).refine(data => data.password === data.confirm, {
message: 'Parollar mos kelmadi',
path: ['confirm'], // xato 'confirm' maydoniga biriktiriladi
})
path: ['confirm'] β bu cross-field xatoni qaysi maydon tagida ko'rsatishni aytadi. Aks holda xato umumiy bo'lib qoladi.
11 β bitta schema, ikki tomon (DRY)
// shared/schemas/student.ts (Nuxt 4 shared/ β client+server)
import * as z from 'zod'
export const studentSchema = z.object({
name: z.string().min(2),
email: z.email(),
})
export type StudentInput = z.output<typeof studentSchema>
// server/api/students.post.ts
import { studentSchema } from '~~/shared/schemas/student'
export default defineEventHandler(async (event) => {
const body = await readBody(event)
const result = studentSchema.safeParse(body) // serverda QAYTA validatsiya
if (!result.success) {
throw createError({ statusCode: 422, data: result.error.flatten() })
}
// result.data β ishonchli
return { ok: true, student: result.data }
})
12 β UTable + Badge
<script setup lang="ts">
import { h, resolveComponent } from 'vue'
import type { TableColumn } from '@nuxt/ui'
const UBadge = resolveComponent('UBadge')
type Student = { id: number; name: string; group: string; status: 'active' | 'inactive' }
const data = ref<Student[]>([
{ id: 1, name: 'Ali Valiyev', group: 'Frontend-1', status: 'active' },
{ id: 2, name: 'Lola Karimova', group: 'Backend-2', status: 'inactive' },
])
const columns: TableColumn<Student>[] = [
{ accessorKey: 'id', header: 'ID' },
{ accessorKey: 'name', header: 'F.I.O' },
{ accessorKey: 'group', header: 'Guruh' },
{ accessorKey: 'status', header: 'Holat',
cell: ({ row }) => h(UBadge,
{ color: row.original.status === 'active' ? 'success' : 'neutral', variant: 'subtle' },
() => row.original.status === 'active' ? 'Faol' : 'Nofaol') },
]
</script>
<template>
<UTable :data="data" :columns="columns" />
</template>
cell ichida h(Component, props, slotFn) β Vue render funksiyasi. row.original β shu qatorning xom obyekti.
17 β sidebar menyu
<script setup lang="ts">
import type { NavigationMenuItem } from '@nuxt/ui'
const items: NavigationMenuItem[] = [
{ label: 'Bosh sahifa', icon: 'i-lucide-house', to: '/' },
{ label: 'O\'quvchilar', icon: 'i-lucide-users', to: '/students', badge: '24' },
{ label: 'To\'lovlar', icon: 'i-lucide-wallet', to: '/payments' },
{ label: 'Sozlamalar', icon: 'i-lucide-settings', children: [
{ label: 'Profil', to: '/settings/profile' },
{ label: 'Markaz', to: '/settings/center' },
{ label: 'Biljing', to: '/settings/billing' },
]},
]
</script>
<template>
<UNavigationMenu :items="items" orientation="vertical" class="w-64" />
</template>
badge β yorliq (o'qilmagan/son), children β ochiluvchi ichki menyu. to bo'lgani uchun active holat avtomatik (Nuxt routing).
20 β useOverlay confirm pattern
<!-- components/ConfirmModal.vue -->
<script setup lang="ts">
defineProps<{ title: string; description?: string }>()
const emit = defineEmits<{ close: [boolean] }>()
</script>
<template>
<UModal :title="title" :description="description">
<template #footer>
<UButton color="neutral" variant="outline" label="Yo'q" @click="emit('close', false)" />
<UButton color="error" label="Ha, o'chirish" @click="emit('close', true)" />
</template>
</UModal>
</template>
<script setup lang="ts">
import { LazyConfirmModal } from '#components'
const overlay = useOverlay()
const confirm = overlay.create(LazyConfirmModal)
const toast = useToast()
async function onDelete(student: { id: number; name: string }) {
const instance = confirm.open({
title: 'O\'chirishni tasdiqlang',
description: `${student.name} o'chiriladi. Qaytarib bo'lmaydi.`,
})
const ok = await instance.result
if (ok) {
await $fetch(`/api/students/${student.id}`, { method: 'DELETE' })
toast.add({ title: 'O\'chirildi', color: 'success' })
}
}
</script>
ConfirmModal butun ilovada bitta β har joyda await bilan ishlatasan. Trigger button modal ichida emas β bu moslashuvchanlik beradi.
22 β EduCore admin (yo'nalish)
app/layouts/dashboard.vue β yuqoridagi "Dashboard capstone" layout'ini ishlat (UDashboardGroup + Sidebar + Panel + Navbar).
app/pages/students/index.vue β "EduCore capstone" sahifasini ishlat: definePageMeta({ layout: 'dashboard' }) + UDashboardToolbar (qidiruv + "Qo'shish") + UTable (mock /api/students) + USlideover ichida UForm (6/7-masaladagi forma).
Bog'lanish:
- server/api/students.get.ts mock ro'yxat qaytaradi (08-modul).
- Qo'shish: forma submit β $fetch('/api/students', { method: 'POST', body }) β refresh().
- O'chirish: 20-masaladagi useOverlay confirm pattern.
Natija: to'liq ishlaydigan, brendlangan (09-modul), CRUD admin ekrani β Vue + Nuxt + Nuxt UI birga.
π Yakun¶
Endi sen Nuxt UI bilan:
- Tizimni tushunasan: color/variant/size + 3 qatlamli theming + :ui override (09).
- 8 kategoriyadagi komponentlarni ishlata olasan: element, feedback, form (Zod bilan), table (TanStack), navigation, overlay (useOverlay), layout/page, dashboard.
- EduCore kabi SaaS admin panelini noldan emas, tayyor bloklardan yig'asan.
Komponentlarning to'liq prop/slot ro'yxati kerak bo'lganda β ui.nuxt.com/docs/components doim ochiq tursin. Bu modul senga "nima borligini va qachon ishlatishni" berdi; hujjat esa "har bir mayda propni" beradi.