@pinooxhq/luma
@pinooxhq/luma
Vue 3 dashboard framework for Pinoox apps — routing, Pinia, auth, layouts, theming, and a PrimeVue 4 UI layer in one package.
Luma is more than a component kit. It is the front-end foundation of a Pinoox admin app: boot the shell with createApp(), drop in PageLayout, and ship pages with PrimeVue + Luma wrappers. Every layer (tokens, layouts, router, auth, components) can be replaced without forking.
Table of contents
- Requirements
- Install
- Vite plugin
- Quick start
createAppoptions- Direction (RTL / LTR)
- Customization
- Authentication
- Usage examples
- Components
- Subpath exports
- Upgrading
- License
Full prop / slot reference: docs/ui-reference.md · docs index: docs/README.md · page kit: docs/page-kit.md · entity forms: docs/guides/entity-form.md · release notes: CHANGELOG.md
Requirements
| Package | Version | Role |
|---|---|---|
vue |
^3.5 |
Runtime |
primevue |
^4.5 |
UI components |
@primeuix/themes |
^2 |
Aura-based theming (Luma Console preset) |
pinia |
^4 |
State |
@vue/devtools-api |
^8 |
Required by Pinia 4 |
vue-router |
^5 |
Routing |
axios |
^1 |
HTTP (used by auth / http) |
lucide-vue-next |
^1 |
Icons for <LIcon> |
sass |
^1 |
Compile @pinooxhq/luma/styles (devDependency) |
@pinooxhq/auth |
^0.1 |
Optional — bundled auth helpers |
@pinooxhq/slug |
^0.1 |
Persian → Finglish slugs (slugify, LSlugField) |
Node ≥ 18. Luma targets PrimeVue 4.x (latest 4.5 line) with @primeuix/themes 2.x.
Install
npm install @pinooxhq/luma
Peers (and Sass for styles):
npm install primevue@^4 @primeuix/themes@^2 pinia@^4 @vue/devtools-api@^8 vue-router axios lucide-vue-next
npm install -D sass
Optional auth package (needed for useAuthStore / configureAuth flows):
npm install @pinooxhq/auth
Without @pinooxhq/auth, createApp still boots and public pages work; requiresAuth routes redirect.
Import styles once in your app entry SCSS:
@use '@pinooxhq/luma/styles';
Vite plugin
Use the official plugin so peer packages are deduped, path aliases are configured, performance is optimized, and file:-linked Luma hot-reloads correctly:
// vite.config.js
import { defineConfig } from 'vite';
import vue from '@vitejs/plugin-vue';
import luma from '@pinooxhq/luma/vite';
export default defineConfig({
plugins: [luma(), vue()],
});
Or use createLumaViteConfig for a zero-boilerplate setup:
// vite.config.js
import vue from '@vitejs/plugin-vue';
import { createLumaViteConfig } from '@pinooxhq/luma/vite';
export default createLumaViteConfig({
plugins: [vue()],
});
What luma() does:
- Dedupes & pre-bundles peers (
primevue,pinia,vue-router,yup, …) against the consumernode_modules— avoids duplicate inject keys and optimizes cold-start dev speed. - Auto-detects entry & warmup — resolves theme entry from
frontend.config.php,index.html, orsrc/main.jsand configures server warmup. - App aliases — automatically registers standard Pinoox theme aliases (
@/,@views,@pages,@stores,@components,@composables,@config,@utils,@api,@assets,@layouts). - Vendor chunk splitting — splits production builds into clean vendor chunks (
vendor-vue,vendor-luma,vendor-prime,vendor-tiptap,vendor-icons,vendor-date,vendor-http). - Config & Environment — automatically reads
luma.config.jsand loads.env/.env.localfiles. - Diagnostics (
lumaDoctor) — checks consumernode_modulesduringvite devand warns if required dependencies or local checkout paths are missing. - Allows the Luma package root through
server.fs.allowand enables watch polling forfile:/ symlink installs. - Optional local checkout — set
LUMA_LOCAL=/path/to/luma-uiorluma({ local: '/path/to/luma-ui' }). Aliases every@pinooxhq/lumaentry (JS, Sass, Vazir fonts) to that tree. Leave unset to use npm.
Typography: Luma’s default stack is Vazir ($px-font-sans + @font-face in styles, and DEFAULT_THEME_CONFIG.font). Override with applyThemeConfig({ font: { sans, mono } }) when needed.
Plugin options
luma({
perf: true, // Dev pre-bundling & build chunk splitting (default: true)
entry: 'src/main.js', // Custom entry file (or auto-detected)
warmup: ['src/main.js'], // Dev server warmup files
configFile: 'luma.config.js', // Theme config file (or set appConfig: false)
doctor: true, // Run dependency health-checks in dev (default: true)
dedupe: ['my-shared-lib'], // Additional packages to dedupe
alias: { '@custom': 'src/custom' }, // Custom aliases
extraOptimizeDeps: ['my-lib'], // Additional optimizeDeps
extraChunkGroups: [], // Custom Rollup/Rolldown vendor chunk groups
fsAllow: ['/custom/peer-dir'], // Additional server.fs.allow paths
watchPolling: false, // Polling options for file links
local: '/path/to/luma', // Local Luma source override
})
Local ↔ npm switch
# .env.local (app) — use checkout
LUMA_LOCAL={PATH_TO_LOCAL_LUMA}/luma-ui
# unset / comment out — use published @pinooxhq/luma from node_modules
Prefer loading the checkout’s vite.js when LUMA_LOCAL is set so plugin fixes apply before publish:
import { defineConfig, loadEnv } from 'vite';
import { pathToFileURL } from 'node:url';
import path from 'node:path';
export default defineConfig(async ({ mode }) => {
const env = loadEnv(mode, process.cwd(), '');
const local = (env.LUMA_LOCAL || '').trim();
const { default: luma } = local
? await import(pathToFileURL(path.join(path.resolve(local), 'vite.js')).href)
: await import('@pinooxhq/luma/vite');
return {
plugins: [luma(local ? { local } : {})],
};
});
Quick start
Minimal layout:
your-app/
├── package.json
├── vite.config.js
├── theme.config.js ← visual tokens (colors, fonts, layout)
└── src/
├── main.js ← createApp(...)
└── config/
├── theme.js ← brand, nav, pageMeta
└── routes.js
theme.config.js — visual tokens
Written to :root as CSS variables at boot (no Sass rebuild to rebrand):
export default {
brand: {
primary: '#0E73FD',
primaryHover: '#0858D4',
primaryActive: '#0644A8',
primarySoft: '#DBE7FE',
bgLight: '#F4F4FE',
bgDark: '#060912',
},
font: {
sans: 'Vazir, Vazirmatn, Inter, system-ui, sans-serif',
mono: 'JetBrains Mono, monospace',
},
layout: {
sidebarWidth: '280px',
sidebarCollapsedWidth: '76px',
topbarHeight: '64px',
pageMaxWidth: '1280px',
radius: 'lg',
},
// Optional:
// direction: 'rtl',
// auth: { endpoints: { me, login, logout }, skipMe, autoLoginFromUrl },
};
src/config/theme.js — brand, nav, page meta
import logo from '@/assets/images/brand.svg';
export const themeConfig = {
brand: {
title: 'Acme Shop',
subtitle: 'Sales admin',
logo,
},
nav: {
sections: [
{
key: 'overview',
label: 'Overview', // static heading; set collapsible: true for accordion
items: [
{ key: 'dashboard', label: 'Dashboard', icon: 'layout-dashboard', route: 'shop.dashboard' },
{ key: 'orders', label: 'Orders', icon: 'shopping-cart', route: 'shop.orders' },
{
key: 'catalog',
label: 'Catalog',
icon: 'layers',
children: [
{ key: 'categories', label: 'Categories', icon: 'folder-tree', route: 'shop.products.categories' },
{ key: 'brands', label: 'Brands', icon: 'award', route: 'shop.products.brands' },
],
},
],
},
],
},
pageMeta: {
'shop.dashboard': { title: 'Dashboard', lead: 'Sales overview', badge: 'Live' },
'shop.orders': { title: 'Orders', lead: 'Open and completed', badge: 'Sales' },
},
user: { roleLabel: 'Store manager' },
};
export default themeConfig;
src/config/routes.js
import { PageLayout } from '@pinooxhq/luma/layouts';
export const routes = [
{
path: '/',
component: PageLayout,
meta: { requiresAuth: true },
children: [
{
path: '',
name: 'shop.dashboard',
component: () => import('@pages/dashboard/page-dashboard.vue'),
},
{
path: 'orders',
name: 'shop.orders',
component: () => import('@pages/orders/page-orders.vue'),
},
],
},
];
src/main.js
import { createApp } from '@pinooxhq/luma';
import { RootShell } from '@pinooxhq/luma/layouts';
import pinia from '@stores/index.js';
import themeConfig from '../theme.config.js';
import { themeConfig as appThemeConfig } from '@/config/theme.js';
import { routes } from '@/config/routes.js';
createApp({
AppRoot: RootShell,
themeConfig: {
...appThemeConfig,
brand: { ...appThemeConfig.brand, ...themeConfig.brand },
font: themeConfig.font,
layout: themeConfig.layout,
direction: themeConfig.direction,
auth: themeConfig.auth,
},
routes,
pinia,
});
In pages:
import { usePage } from '@pinooxhq/luma';
const { pageTitle, pageLead, pageBadge } = usePage();
createApp options
| Option | Required | Description |
|---|---|---|
AppRoot |
yes | Top-level Vue component — usually RootShell from @pinooxhq/luma/layouts |
themeConfig |
no | Brand, nav, pageMeta, tokens, direction, auth |
routes |
no | Vue Router route table (default []) |
pinia |
no | Pinia instance; installed and set active for guards |
mount |
no | Mount selector (default #app) |
auth |
no | Options passed to configureAuth() (overrides themeConfig.auth) |
verifyAuth |
no | Async hook — full control over session checks (skips built-in me()) |
IconComponent |
no | Global <LIcon> registration (e.g. pass Luma’s LIcon) |
AppRoot is required so the Node-safe root barrel never pulls .vue SFCs into smoke tests / tooling.
Direction (RTL / LTR)
createApp resolves direction and syncs <html dir> + PrimeVue rtl:
themeConfig.direction('rtl'|'ltr')- Existing
<html dir>/<body dir> window.__PINOOX__.direction(boot payload /VITE_DIRECTION)- Fallback:
'ltr'
Teleported overlays (Select, DatePicker, menus, confirm) inherit direction via Luma SCSS — no per-app overlay CSS required for the common cases.
// theme.config.js
export default {
direction: 'rtl',
// …
};
Customization
Visual tokens
| Group | Keys |
|---|---|
brand |
primary, primaryHover, primaryActive, primarySoft, bgLight, bgDark |
font |
sans, mono |
layout |
sidebarWidth, sidebarCollapsedWidth, topbarHeight, pageMaxWidth, radius |
createApp calls applyThemeConfig() for you. You can also call it at runtime (white-label / multi-tenant):
import { applyThemeConfig, useTheme } from '@pinooxhq/luma';
applyThemeConfig({ brand: { primary: '#10b981' } });
const { toggleTheme, isDark } = useTheme();
Sass overrides
@use '@pinooxhq/luma/styles';
:root {
--px-primary-soft: rgba(14, 115, 253, 0.08);
}
[data-theme='dark'] {
--px-bg: #0a0a14;
}
themeConfig shape
{
brand: { title, subtitle?, logo?, primary?, /* visual brand keys */ },
nav: { sections: Array<{ key, label, items: Array<{ key, label, icon, route?, children? }>, collapsible?, defaultCollapsed? }> },
pageMeta: Record<string, { title, lead?, badge? }>,
user?: { roleLabel? },
font?: { sans?, mono? },
layout?: { sidebarWidth?, sidebarCollapsedWidth?, topbarHeight?, pageMaxWidth?, radius? },
direction?: 'rtl' | 'ltr',
auth?: { endpoints?, skipMe?, autoLoginFromUrl? },
loading?: { enabled?, delay?, exclude?, label? },
}
Omitted fields fall back to Luma defaults. Nav section label is a static heading; set collapsible: true for accordion sections. Nav items may include children for a nested submenu.
Layouts
Typical pattern: RootShell as AppRoot, PageLayout as the authenticated route layout (sidebar, topbar, mobile nav, drawer).
import { RootShell, PageLayout } from '@pinooxhq/luma/layouts';
import { LSidebar, LTopbar, LMobileNav } from '@pinooxhq/luma/ds';
import { LView, LHeader, LIcon } from '@pinooxhq/luma/ui';
Compose DS / UI pieces into a custom layout when PageLayout is too opinionated — RootShell only provides the outer wrapper, global Toast, confirm dialog, HTTP loading overlay, and theme CSS variables.
Global HTTP loading
RootShell mounts <LLoading />. Any request through Luma http is counted; the overlay appears after delay ms so fast calls do not flash.
// theme.config.js
export default {
loading: {
enabled: true,
delay: 220,
exclude: ['/pricing/fx/quotes'],
label: 'Loading',
},
};
http.get('/pricing/fx/quotes', { skipLoading: true });
configureHttpLoading() updates the same options at runtime. { skipLoading: true } always wins for that request.
While a local loading surface is active (table skeleton, custom spinner), the overlay stays hidden even if HTTP is in flight. LDataTable :loading and useTableRows() register automatically. Anywhere else:
import { useLocalLoading } from '@pinooxhq/luma';
useLocalLoading(loading); // ref or computed
Table skeleton
Keep the table visible while the first fetch runs. Pass :loading to LDataTable and wrap cells with LColumnBody:
<LDataTable :value="rows" :loading="loading" paginator data-key="id">
<Column field="name" header="Name">
<template #body="{ data }">
<LColumnBody :data="data" part="entity">
{{ data.name }}
</LColumnBody>
</template>
</Column>
<Column header="">
<template #body="{ data }">
<LColumnBody :data="data" part="actions" :skel-props="{ count: 2 }">
…
</LColumnBody>
</template>
</Column>
</LDataTable>
For a custom PrimeVue DataTable, use useTableRows(items, loading) and LTableSkel / isSkelRow().
Authentication
Defaults match Pinoox account APIs. Override only what you need.
Default guard flow
On first navigation, authGuard:
- Optionally adopts
?__manager_token=…whenthemeConfig.auth.autoLoginFromUrl: true - Calls
auth.me()once (remotestrategy →/account/api/v1/auth/{login,logout,get}by default) - Redirects to
/account/loginwhenrequiresAuthcannot proceed
Custom endpoints
// theme.config.js
auth: {
endpoints: {
me: '/api/v1/auth/me',
login: '/api/v1/auth/login',
logout: '/api/v1/auth/logout',
},
},
Replace the strategy
import { createApp, configureAuth } from '@pinooxhq/luma';
import { RootShell } from '@pinooxhq/luma/layouts';
configureAuth({
endpoints: { me: '/api/auth/me', login: '/api/auth/login' },
});
createApp({ AppRoot: RootShell, themeConfig, routes, pinia });
Skip me()
auth: { skipMe: true, autoLoginFromUrl: true },
Trusts token presence and skips the HTTP round-trip.
Full control — verifyAuth
createApp({
AppRoot: RootShell,
themeConfig,
routes,
pinia,
verifyAuth: async ({ store, route, adoptedFromUrl }) => {
if (!store.token) return false;
const profile = await fetchMyProfile();
store.user = profile;
return profile.active === true;
},
});
| Return | Effect |
|---|---|
true |
Allow navigation |
false / throw |
Redirect to login |
Helpers
import { auth, useAuthStore, http, configureAuth, getActiveAuth } from '@pinooxhq/luma';
http is an axios client with auth headers wired — prefer it over a fresh axios instance.
Theme-context panels mount under __PINOOX__.url.BASE (/panel) and set auth.loginUrl to the browser path (/panel/auth/login). Vue Router still uses unprefixed records (/auth/login). Do not rewrite url.BASE in the app. Use:
import {
resolveHistoryBase,
bindAuthRedirect,
resolveGuestExit,
} from '@pinooxhq/luma';
const router = createRouter({
history: createWebHistory(resolveHistoryBase()),
routes,
});
bindAuthRedirect(router);
Usage examples
DataTable page
<script setup>
import { ref } from 'vue';
import DataTable from 'primevue/datatable';
import Column from 'primevue/column';
import Tag from 'primevue/tag';
import Button from 'primevue/button';
import InputText from 'primevue/inputtext';
import IconField from 'primevue/iconfield';
import InputIcon from 'primevue/inputicon';
import { usePage } from '@pinooxhq/luma';
import { LView, LHeader, LCard } from '@pinooxhq/luma/ui';
const { pageTitle, pageLead } = usePage();
const orders = ref([
{ id: 1001, customer: 'Alex Rivera', total: 1250, status: 'paid' },
{ id: 1002, customer: 'Sam Chen', total: 890, status: 'pending' },
]);
const filters = ref({ global: '' });
const statusSeverity = { paid: 'success', pending: 'warn', shipped: 'info' };
</script>
<template>
<LView>
<LHeader :title="pageTitle" :lead="pageLead">
<Button label="New order" severity="primary" />
</LHeader>
<LCard>
<IconField>
<InputIcon class="pi pi-search" />
<InputText v-model="filters.global" placeholder="Search…" />
</IconField>
<DataTable
:value="orders"
v-model:filters="filters"
:global-filter-fields="['customer', 'status']"
paginator
:rows="10"
striped-rows
>
<Column field="id" header="ID" sortable />
<Column field="customer" header="Customer" sortable />
<Column field="status" header="Status">
<template #body="{ data }">
<Tag :value="data.status" :severity="statusSeverity[data.status]" />
</template>
</Column>
</DataTable>
</LCard>
</LView>
</template>
Docs: primevue.org/datatable
Form + LField
For entity CRUD with Yup defaults / toForm / toPayload, see Entity Form (index: docs/README.md).
<script setup>
import { reactive, ref } from 'vue';
import InputText from 'primevue/inputtext';
import Select from 'primevue/select';
import Button from 'primevue/button';
import { http } from '@pinooxhq/luma';
import { LView, LHeader, LCard, LField } from '@pinooxhq/luma/ui';
const form = reactive({ name: '', category: null });
const errors = ref({});
const submitting = ref(false);
const categories = [
{ label: 'Apparel', value: 'apparel' },
{ label: 'Shoes', value: 'shoes' },
];
async function submit() {
submitting.value = true;
errors.value = {};
try {
await http.post('/api/v1/products', form);
} catch (err) {
errors.value = err.response?.data?.errors ?? {};
} finally {
submitting.value = false;
}
}
</script>
<template>
<LView>
<LHeader title="New product" lead="Add an item to the catalog" />
<LCard>
<form class="product-form" @submit.prevent="submit">
<LField label="Name" :error="errors.name?.[0]">
<InputText v-model="form.name" :invalid="!!errors.name" />
</LField>
<LField label="Category">
<Select
v-model="form.category"
:options="categories"
option-label="label"
option-value="value"
placeholder="Select…"
/>
</LField>
<Button type="submit" label="Save" :loading="submitting" />
</form>
</LCard>
</LView>
</template>
Toast / Dialog
Global Toast is mounted by RootShell. Use useToast() anywhere:
<script setup>
import Button from 'primevue/button';
import Dialog from 'primevue/dialog';
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const open = ref(false);
function notify() {
toast.add({
severity: 'success',
summary: 'Saved',
detail: 'Changes were stored.',
life: 3000,
});
}
</script>
<template>
<Button label="Notify" @click="notify" />
<Button label="Delete" severity="danger" @click="open = true" />
<Dialog v-model:visible="open" header="Confirm" modal>
<p>Delete this item?</p>
<template #footer>
<Button label="Cancel" text @click="open = false" />
<Button label="Delete" severity="danger" @click="open = false" />
</template>
</Dialog>
</template>
Dark mode
<script setup>
import { useTheme } from '@pinooxhq/luma';
import { LThemeToggle } from '@pinooxhq/luma/ds';
const { isDark, toggleTheme } = useTheme();
</script>
<template>
<LThemeToggle :model-value="isDark" @update:model-value="toggleTheme" />
</template>
Components
Rule of thumb: use PrimeVue directly for forms, tables, overlays. Reach for an L* wrapper when you want Luma’s themed chrome on top.
Luma UI (@pinooxhq/luma/ui)
| Component | Purpose |
|---|---|
LView / LPage |
Page shells with consistent padding |
LHeader |
Classic page header (title, lead, badge, actions slot) |
LPageHeader |
Modern header (eyebrow, title, lead, icon) |
LPageToolbar |
Sticky page actions |
LPageContainer |
Honors pageMaxWidth + gutters |
LPanel |
Content panel (incl. flush table chrome) |
LCard |
Themed card (PrimeVue Card) |
LStatCard |
KPI / metric card |
LEmptyPanel |
Empty state + CTA |
LBadge |
Status tag |
LButton |
Variant / severity / size / shape system |
LField |
Label, hint, error + input slot |
LDatePicker |
Themed date picker |
LTabs |
Tab strip helpers |
LToolbar |
Filter / action row |
LSpinner |
Loading spinner |
LToast |
In-page toast host (global Toast still in RootShell) |
LConfirmDialog |
Confirm surface with RTL-aware layout |
LRichEditor |
TipTap rich text |
LIcon |
Lucide wrapper (<LIcon name="shopping-cart" />) |
Design-system chrome (@pinooxhq/luma/ds)
| Component | Purpose |
|---|---|
LSidebar |
Nav sidebar (PageLayout) |
LTopbar |
Top bar |
LMobileNav |
Mobile bottom nav |
LThemeToggle |
Light / dark control |
LEmptyState |
Deprecated alias of LEmptyPanel |
PrimeVue 4 (wired via Console preset)
Import any core component in pages — preset, ripple, RTL, and dark mode are already installed by setupPrimeVue:
| Area | Components |
|---|---|
| Form | InputText, Textarea, Password, InputMask, InputNumber, InputOtp, Select, MultiSelect, AutoComplete, Checkbox, RadioButton, ToggleSwitch, SelectButton, Slider, Rating, DatePicker, … |
| Data | DataTable, DataView, Tree, TreeTable, Timeline, Paginator |
| Panels | Card, Panel, Accordion, Tabs, Stepper, Toolbar |
| Overlay | Dialog, Drawer, Popover, Tooltip, ConfirmDialog, ConfirmPopup |
| Feedback | Toast, Message, Tag, Badge, Chip, ProgressBar, ProgressSpinner, Skeleton |
| Menu | Menu, Menubar, MegaMenu, PanelMenu, TieredMenu, Breadcrumb |
| Media | Image, Carousel, FileUpload |
| Misc | Avatar, Divider, Splitter, ScrollPanel, Knob, Button, ToggleButton |
See primevue.org for the full API. Theme CSS comes from @primeuix/themes via Luma’s preset — you do not need a separate PrimeVue CSS import for the Console look.
Subpath exports
| Path | Contents |
|---|---|
@pinooxhq/luma |
Node-safe barrel (createApp, composables, auth, theme helpers — no .vue SFCs) |
@pinooxhq/luma/ui |
UI primitives listed above |
@pinooxhq/luma/ds |
Shell chrome + legacy LEmptyState |
@pinooxhq/luma/layouts |
RootShell, PageLayout |
@pinooxhq/luma/composables |
usePage, … |
@pinooxhq/luma/router |
createAppRouter, authGuard, bindAuthRedirect, redirectToLogin, route prefetching, BASE/login helpers |
@pinooxhq/luma/core |
auth, http, useAuthStore, configureAuth, env, dates, media helpers |
@pinooxhq/luma/plugins |
setupPrimeVue, ConsolePreset |
@pinooxhq/luma/styles |
Main SCSS bundle |
@pinooxhq/luma/tokens |
SCSS design tokens |
@pinooxhq/luma/fonts |
Vazir registration |
@pinooxhq/luma/theme-config |
Nav / pageMeta / theme resolution helpers |
@pinooxhq/luma/createApp |
Factory only |
@pinooxhq/luma/vite |
Vite plugin, presets, and context loader |
@pinooxhq/luma/vite/perf |
Vite pre-bundling and vendor chunk splitting presets |
@pinooxhq/luma/vite/config |
createLumaViteConfig, createAppAliases, lumaDoctor, config loaders |
@pinooxhq/luma/vite/theme-auto |
Automatic theme entry detection and icon aliases |
@pinooxhq/luma/preset |
Console preset (default export) |
Upgrading
npm update @pinooxhq/luma
Semantic versioning (see CHANGELOG.md):
- Patch — internal fixes, no public API break
- Minor — new components / helpers, backwards compatible
- Major — breaking changes, documented in the changelog
Pin to ^0.4.0 (or stricter) for predictable upgrades.
Migrating from 0.3.x → 0.4.x
| Package | 0.3.x | 0.4.x |
|---|---|---|
primevue |
^4 |
^4.5 |
@primeuix/themes |
^1 |
^2 |
pinia |
^3 |
^4 |
@vue/devtools-api |
— | ^8 |
- Install the peer set from Install.
- Prefer
LEmptyPaneloverLEmptyState. - Prefer the
luma()Vite plugin when developing against afile:link. - Set
themeConfig.directionwhen you need explicit RTL.
License
MIT © Pinoox
Related Packages
A Nuxt 4 module for Vorna Company to simplify and accelerate building Persian-la...
Adaptador de PrimeVue 4 con prefijo Is* y plugin centralizado para Interseguro.
A configurable Vue 3 plugin that adds router guards, axios interceptors, and pin...
Framework-independent design system and UI library by Armsys Technology — dark-f...
Version History
| Version | Released | Vue | License |
|---|---|---|---|
| 0.4.15 | ^3.5.41 | MIT | |
| 0.4.14 | ^3.5.41 | MIT | |
| 0.4.13 | ^3.5.41 | MIT | |
| 0.4.12 | ^3.5.41 | MIT | |
| 0.4.11 | ^3.5.41 | MIT | |
| 0.4.10 | ^3.5.41 | MIT | |
| 0.4.9 | ^3.5.41 | MIT | |
| 0.4.8 | ^3.5.41 | MIT | |
| 0.4.7 | ^3.5.41 | MIT | |
| 0.4.6 | ^3.5.41 | MIT | |
| 0.4.5 | ^3.5.41 | MIT | |
| 0.4.4 | ^3.5.41 | MIT | |
| 0.4.3 | ^3.5.41 | MIT | |
| 0.4.2 | ^3.5.41 | MIT | |
| 0.4.0 | ^3.5.41 | MIT | |
| 0.3.5 | ^3.5.35 | MIT | |
| 0.3.4 | ^3.5.35 | MIT | |
| 0.3.0 | ^3.5.35 | MIT | |
| 0.2.0 | ^3.5.35 | MIT | |
| 0.1.0 | ^3.5.35 | MIT |