tsc-ui-library
v1.0.7
Published
TSC UI Components Library - Reusable Vue 3 components
Maintainers
Readme
TSC Design System
A comprehensive Vue 3 component library built with TypeScript, PrimeVue, and SCSS.
📚 Documentation
- GETTING_STARTED.md - Bắt đầu sử dụng (Chọn file phù hợp)
- USAGE_GUIDE.md - Hướng dẫn sử dụng chi tiết (Tiếng Việt)
- COMPONENTS_INDEX.md - Danh mục tìm kiếm components
- QUICK_START.md - Hướng dẫn nhanh 5 phút
- PUBLISH.md - Hướng dẫn publish và sử dụng
- CHANGELOG.md - Lịch sử thay đổi
📦 Installation
System Requirements
- Node.js: 16.0.0+
- Vue: 3.4.0+
- TypeScript: 5.0.0+ (optional)
- Vite: 5.0.0+ (recommended)
npm install tsc-ui-library --legacy-peer-depsLưu ý: Sử dụng --legacy-peer-deps để tránh lỗi peer dependency
🚀 Quick Start
1. Install Dependencies
npm install vue@^3.4.0 primevue@^3.46.0 primeicons primeflex@^3.3.1 --legacy-peer-deps2. Import and Use
// main.ts
import { createApp } from 'vue'
import App from './App.vue'
import TscUI from 'tsc-ui-library'
import 'primevue/resources/themes/saga-blue/theme.css'
import 'primevue/resources/primevue.min.css'
import 'primeicons/primeicons.css'
import 'primeflex/primeflex.css'
import 'tsc-ui-library/dist/styles/index.css'
const app = createApp(App)
app.use(TscUI)
app.mount('#app')3. Use Components
<template>
<div>
<!-- Basic Components -->
<DaButton label="Click me" />
<DaInputText v-model="text" placeholder="Enter text" />
<!-- Layout Components -->
<MainLayout
:menu-items="menuItems"
:app-name="'My App'"
:user-info="userInfo"
>
<div>Your content here</div>
</MainLayout>
</div>
</template>
<script setup>
import { ref } from 'vue'
const text = ref('')
const menuItems = ref([
{ id: 'home', label: 'Home', icon: 'dashboard-icon', href: '/home' },
{ id: 'about', label: 'About', icon: 'info', href: '/about' }
])
const userInfo = ref({
name: 'John Doe',
role: 'Admin',
avatar: 'JD'
})
</script>📘 Component Usage & CSS Customization
Dưới đây là hướng dẫn chi tiết cách sử dụng và custom CSS cho tất cả 62 components. Ghi đè CSS variables bằng cách đặt trong :root hoặc selector bao ngoài.
:root {
/* Ví dụ: override màu toàn cục */
--tsc-btn-bg: #2563eb;
}🎯 Basic Components
DaButton
Props: label, type, loading, disabled, icon, severity
Events: @click
<DaButton label="Primary" type="button" @click="onClick" />
<DaButton label="Loading" :loading="true" />
<DaButton label="Disabled" :disabled="true" />
<DaButton icon="pi pi-check" label="With Icon" />:root {
--tsc-btn-bg: #2563eb;
--tsc-btn-color: #ffffff;
--tsc-btn-hover-bg: #1d4ed8;
--tsc-btn-border-radius: 6px;
--tsc-btn-padding: 0.5rem 1rem;
--tsc-btn-font-weight: 500;
}DaModal
Props: v-model:visible, title, modal, closable, dismissableMask
Slots: #default, #header, #footer
<DaModal v-model:visible="open" title="Settings" :closable="true">
<template #default>
Nội dung modal
</template>
<template #footer>
<DaButton label="Close" @click="open=false" />
</template>
</DaModal>:root {
--tsc-modal-title-weight: 600;
--tsc-modal-title-size: 1.25rem;
--tsc-modal-title-color: #0f172a;
--tsc-modal-color: #334155;
--tsc-modal-bg: #ffffff;
--tsc-modal-border-radius: 4px;
}DaInputText
Props: v-model, placeholder, disabled, invalid, readonly
Events: @input, @change, @focus, @blur
<DaInputText v-model="value" placeholder="Search..." :invalid="hasError" />
<DaInputText v-model="text" :disabled="true" />:root {
--tsc-input-text-placeholder-color: #94a3b8;
--tsc-input-text-invalid-border: #ef4444;
--tsc-input-text-disabled-bg: #e5e7eb;
--tsc-input-text-border: #d1d5db;
--tsc-input-text-focus-border: #3b82f6;
--tsc-input-text-padding: 0.5rem 0.75rem;
}DaCheckbox
Props: v-model, binary, disabled, readonly
Events: @change
<DaCheckbox v-model="checked" />
<DaCheckbox v-model="value" :binary="true" />:root {
--tsc-checkbox-border: #d1d5db;
--tsc-checkbox-bg: #ffffff;
--tsc-checkbox-hover-border: #3b82f6;
--tsc-checkbox-checked-bg: #3b82f6;
--tsc-checkbox-checked-border: #3b82f6;
--tsc-checkbox-icon-color: #ffffff;
}DaTriStateCheckBox
Props: v-model, disabled, readonly
Events: @change
<DaTriStateCheckBox v-model="state" />
<!-- state: true, false, null -->:root {
--tsc-tristate-checkbox-border: #cbd5e1;
--tsc-tristate-checkbox-bg: #ffffff;
--tsc-tristate-checkbox-hover-border: #3b82f6;
--tsc-tristate-checkbox-active-bg: #3b82f6;
--tsc-tristate-checkbox-active-border: #3b82f6;
--tsc-tristate-checkbox-active-hover-bg: #60a5fa;
--tsc-tristate-checkbox-icon-color: #ffffff;
}DaTabs
Props: tabs, v-model:activeIndex, scrollable
Events: @tab-change
<DaTabs :tabs="tabs" v-model:activeIndex="active" />:root {
--tsc-tabs-skeleton-bg: #e5e7eb;
--tsc-tabs-active-color: #00a7cf;
--tsc-tabs-active-border: #00a7cf;
--tsc-tabs-tab-padding: 0.75rem 1rem;
--tsc-tabs-tab-font-weight: 500;
}DaChips
Props: v-model, addOnBlur, allowDuplicate, max
Events: @add, @remove
<DaChips v-model="chips" placeholder="Add tags" />:root {
--tsc-chips-bg: #f3f4f6;
--tsc-chips-color: #374151;
--tsc-chips-border: #d1d5db;
--tsc-chips-remove-bg: #ef4444;
--tsc-chips-remove-color: #ffffff;
}DaMessage
Props: severity, closable, sticky
Events: @close
<DaMessage severity="success" :closable="true">Success message</DaMessage>
<DaMessage severity="error">Error message</DaMessage>:root {
--tsc-message-success-bg: #d1fae5;
--tsc-message-success-border: #10b981;
--tsc-message-success-color: #065f46;
--tsc-message-error-bg: #fee2e2;
--tsc-message-error-border: #ef4444;
--tsc-message-error-color: #991b1b;
}DaImg
Props: src, alt, width, height, preview
Events: @error, @load
<DaImg src="/image.jpg" alt="Description" :preview="true" />
<DaImg src="data:image/svg+xml;base64,..." width="24" height="24" />:root {
--tsc-img-tooltip-bg: #ffffff;
--tsc-img-tooltip-color: #002550;
--tsc-img-border-radius: 4px;
}DaError
Props: message, showRefresh
Events: @refresh
<DaError message="Something went wrong" :showRefresh="true" @refresh="retry" />:root {
--tsc-error-color: #ef4444;
--tsc-error-bg: #fef2f2;
--tsc-error-border: #fecaca;
}📝 Form Components
DaTextarea
Props: v-model, placeholder, rows, cols, autoResize
Events: @input, @change
<DaTextarea v-model="text" placeholder="Enter description" :rows="4" />
<DaTextarea v-model="content" :autoResize="true" />:root {
--tsc-textarea-placeholder-color: #94a3b8;
--tsc-textarea-border: #d1d5db;
--tsc-textarea-focus-border: #3b82f6;
--tsc-textarea-padding: 0.5rem 0.75rem;
--tsc-textarea-resize: vertical;
}DaInputNumber
Props: v-model, min, max, step, currency, locale
Events: @input, @change
<DaInputNumber v-model="value" :min="0" :max="100" :step="1" />
<DaInputNumber v-model="price" currency="USD" />:root {
--tsc-input-number-border: #d1d5db;
--tsc-input-number-focus-border: #3b82f6;
--tsc-input-number-button-bg: #f9fafb;
--tsc-input-number-button-hover-bg: #f3f4f6;
}DaSelectButton
Props: v-model, options, multiple, disabled
Events: @change
<DaSelectButton v-model="value" :options="options" />
<DaSelectButton v-model="values" :options="options" :multiple="true" />:root {
--tsc-select-button-bg: #ffffff;
--tsc-select-button-border: #d1d5db;
--tsc-select-button-selected-bg: #3b82f6;
--tsc-select-button-selected-color: #ffffff;
--tsc-select-button-hover-bg: #f3f4f6;
}DaDropdown
Props: v-model, options, optionLabel, optionValue, placeholder
Events: @change, @filter
<DaDropdown v-model="selected" :options="options" optionLabel="name" />
<DaDropdown v-model="city" :options="cities" placeholder="Select city" />:root {
--tsc-dropdown-border: #d1d5db;
--tsc-dropdown-focus-border: #3b82f6;
--tsc-dropdown-panel-bg: #ffffff;
--tsc-dropdown-option-hover-bg: #f3f4f6;
--tsc-dropdown-option-selected-bg: #dbeafe;
}DaInputSwitch
Props: v-model, disabled, readonly
Events: @change
<DaInputSwitch v-model="checked" />
<DaInputSwitch v-model="enabled" :disabled="true" />:root {
--tsc-input-switch-bg: #d1d5db;
--tsc-input-switch-checked-bg: #3b82f6;
--tsc-input-switch-handle-bg: #ffffff;
--tsc-input-switch-handle-checked-bg: #ffffff;
}DaPassword
Props: v-model, placeholder, feedback, toggleMask
Events: @input, @change
<DaPassword v-model="password" :feedback="true" />
<DaPassword v-model="pwd" placeholder="Enter password" />:root {
--tsc-password-border: #d1d5db;
--tsc-password-focus-border: #3b82f6;
--tsc-password-toggle-color: #6b7280;
--tsc-password-feedback-bg: #f9fafb;
}DaPagination
Props: totalRecords, rows, v-model:first, pageLinkSize
Events: @page-change
<DaPagination :totalRecords="200" :rows="20" v-model:first="first" />
<DaPagination :totalRecords="1000" :rows="10" :pageLinkSize="5" />:root {
--tsc-pagination-btn-bg: #ffffff;
--tsc-pagination-btn-color: #0f172a;
--tsc-pagination-btn-active-bg: #e0f2fe;
--tsc-pagination-btn-active-color: #0284c7;
--tsc-pagination-btn-hover-bg: #f3f4f6;
--tsc-pagination-btn-border: #d1d5db;
}DaMultiSelect
Props: v-model, options, optionLabel, optionValue, placeholder
Events: @change, @filter
<DaMultiSelect v-model="selected" :options="options" optionLabel="name" />
<DaMultiSelect v-model="tags" :options="tags" placeholder="Select tags" />:root {
--tsc-multiselect-border: #d1d5db;
--tsc-multiselect-focus-border: #3b82f6;
--tsc-multiselect-panel-bg: #ffffff;
--tsc-multiselect-option-hover-bg: #f3f4f6;
--tsc-multiselect-chip-bg: #e0f2fe;
--tsc-multiselect-chip-color: #0284c7;
}DaTreeSelect
Props: v-model, options, optionLabel, optionValue, placeholder
Events: @change, @node-select, @node-unselect
<DaTreeSelect v-model="selected" :options="treeData" optionLabel="label" />:root {
--tsc-tree-select-border: #d1d5db;
--tsc-tree-select-focus-border: #3b82f6;
--tsc-tree-select-panel-bg: #ffffff;
--tsc-tree-select-node-hover-bg: #f3f4f6;
--tsc-tree-select-node-selected-bg: #dbeafe;
}📊 Data Components
DaDataTable
Props: value, paginator, rows, totalRecords, lazy, sortField, sortOrder
Events: @page, @sort, @row-select, @row-unselect
<DaDataTable :value="products" :paginator="true" :rows="10">
<template #header>
<div>Product List</div>
</template>
<Column field="name" header="Name" :sortable="true"></Column>
<Column field="price" header="Price" :sortable="true"></Column>
</DaDataTable>:root {
--tsc-datatable-header-bg: #f8fafc;
--tsc-datatable-header-color: #1e293b;
--tsc-datatable-row-hover-bg: #f1f5f9;
--tsc-datatable-row-selected-bg: #dbeafe;
--tsc-datatable-border: #e2e8f0;
--tsc-datatable-paginator-bg: #ffffff;
}DaFormModal
Props: v-model:visible, title, formData, fields, submitLabel
Events: @submit, @cancel
<DaFormModal
v-model:visible="showModal"
title="Add User"
:formData="userForm"
:fields="formFields"
@submit="handleSubmit"
/>:root {
--tsc-form-modal-bg: #ffffff;
--tsc-form-modal-border-radius: 8px;
--tsc-form-modal-shadow: 0 10px 25px rgba(0,0,0,0.1);
--tsc-form-modal-header-bg: #f8fafc;
--tsc-form-modal-footer-bg: #f8fafc;
}DaListboxWithCheckbox
Props: v-model, options, optionLabel, optionValue, multiple
Events: @change
<DaListboxWithCheckbox
v-model="selected"
:options="options"
optionLabel="name"
:multiple="true"
/>:root {
--tsc-listbox-header-bg: #d1d5db;
--tsc-listbox-header-weight: 500;
--tsc-listbox-header-color: #374151;
--tsc-listbox-error-color: #ef4444;
--tsc-listbox-option-hover-bg: #f3f4f6;
--tsc-listbox-option-selected-bg: #dbeafe;
}DaInputNumberWithUnit
Props: v-model, unit, units, placeholder, min, max
Events: @change, @unit-change
<DaInputNumberWithUnit
v-model="value"
:units="['px', 'em', 'rem']"
placeholder="Enter value"
/>:root {
--tsc-input-number-unit-color: #374151;
--tsc-input-number-dropdown-border: #d1d5db;
--tsc-input-number-invalid-border: #ef4444;
--tsc-input-number-placeholder-color: #9ca3af;
--tsc-input-number-label-weight: 400;
--tsc-input-number-label-size: 14px;
--tsc-input-number-label-color: #374151;
--tsc-input-number-error-color: #ef4444;
--tsc-input-number-disabled-bg: #f3f4f6;
--tsc-input-number-disabled-border: #d1d5db;
--tsc-input-number-disabled-color: #9ca3af;
}DaCalendar
Props: v-model, showTime, timeOnly, minDate, maxDate
Events: @date-select, @change
<DaCalendar v-model="date" :showTime="true" />
<DaCalendar v-model="time" :timeOnly="true" />:root {
--tsc-calendar-label-weight: 400;
--tsc-calendar-label-size: 14px;
--tsc-calendar-label-color: #374151;
--tsc-calendar-error-color: #ef4444;
--tsc-calendar-invalid-border: #ef4444;
--tsc-calendar-time-input-color: #374151;
--tsc-calendar-panel-bg: #ffffff;
--tsc-calendar-today-bg: #3b82f6;
--tsc-calendar-today-color: #ffffff;
}DaPieChart
Props: option, height, width
Events: @chart-click, @chart-ready
<DaPieChart :option="pieChartOption" height="300px" />DaBarChart
Props: option, height, width
Events: @chart-click, @chart-ready
<DaBarChart :option="barChartOption" height="400px" />DaLineChart
Props: series, xAxis, option, height, width
Events: @chart-click, @chart-ready
<DaLineChart
:series="lineChartSeries"
:x-axis="lineChartXAxis"
:option="lineChartOption"
height="350px"
/>:root {
--tsc-chart-tooltip-bg: #002249;
--tsc-chart-tooltip-text-color: #002249;
--tsc-chart-tooltip-label-color: #335173;
--tsc-chart-tooltip-date-color: #616161;
--tsc-chart-legend-color: #374151;
--tsc-chart-axis-color: #6b7280;
}DaDropdownPageSize
Props: v-model, options, placeholder
Events: @change
<DaDropdownPageSize v-model="pageSize" :options="[10, 20, 50, 100]" />:root {
--tsc-dropdown-page-size-border: #d1d5db;
--tsc-dropdown-page-size-focus-border: #3b82f6;
--tsc-dropdown-page-size-panel-bg: #ffffff;
--tsc-dropdown-page-size-option-hover-bg: #f3f4f6;
}DaTableSkeleton
Props: rows, columns
Events: None
<DaTableSkeleton :rows="5" :columns="4" />:root {
--tsc-table-skeleton-bg: #f3f4f6;
--tsc-table-skeleton-animation: pulse 2s infinite;
--tsc-table-skeleton-border-radius: 4px;
}🛠️ Utility Components
DaLabel
Props: for, required
Events: None
<DaLabel for="input1" :required="true">Username</DaLabel>:root {
--tsc-label-weight: 400;
--tsc-label-size: 14px;
--tsc-label-color: #374151;
--tsc-label-required-color: #ef4444;
}DaDotColor
Props: color, size
Events: None
<DaDotColor color="#3b82f6" :size="12" />
<DaDotColor color="red" :size="8" />:root {
--tsc-dot-color-size: 12px;
--tsc-dot-color-border-radius: 50%;
--tsc-dot-color-border: 1px solid #ffffff;
}DaEllipsis
Props: text, maxLength, placement
Events: None
<DaEllipsis :text="longText" :maxLength="50" placement="top" />:root {
--tsc-ellipsis-tooltip-shadow: 0px 0px 4px rgba(0, 0, 0, 0.15);
--tsc-ellipsis-tooltip-color: #1e293b;
--tsc-ellipsis-tooltip-bg: #ffffff;
--tsc-ellipsis-tooltip-border-radius: 4px;
}DaInputGroup
Props: label, required
Events: None
<DaInputGroup label="Email Address" :required="true">
<DaInputText v-model="email" placeholder="Enter email" />
</DaInputGroup>:root {
--tsc-input-group-label-color: #1e293b;
--tsc-input-group-label-size: 12px;
--tsc-input-group-label-weight: 500;
--tsc-input-group-label-margin-bottom: 0.5rem;
}DaInputMask
Props: v-model, mask, placeholder
Events: @input, @change
<DaInputMask v-model="phone" mask="(999) 999-9999" placeholder="(123) 456-7890" />
<DaInputMask v-model="date" mask="99/99/9999" placeholder="MM/DD/YYYY" />:root {
--tsc-input-mask-border: #d1d5db;
--tsc-input-mask-focus-border: #3b82f6;
--tsc-input-mask-placeholder-color: #9ca3af;
--tsc-input-mask-padding: 0.5rem 0.75rem;
}IconHelp
Props: tooltip, placement
Events: None
<IconHelp tooltip="This field is required" placement="top" />:root {
--tsc-icon-help-color: #6b7280;
--tsc-icon-help-hover-color: #374151;
--tsc-icon-help-tooltip-bg: #1f2937;
--tsc-icon-help-tooltip-color: #ffffff;
}RowDetails
Props: expanded, data
Events: @toggle
<RowDetails :expanded="isExpanded" :data="rowData" @toggle="toggleRow" />:root {
--tsc-row-details-bg: #f8fafc;
--tsc-row-details-border: #e2e8f0;
--tsc-row-details-padding: 1rem;
--tsc-row-details-toggle-color: #6b7280;
}🏗️ Layout Components
MainLayout
Props: menuItems, appName, appSubtitle, userInfo, version, copyright, defaultExpanded, backgroundColor, contentPadding
Events: @menu-click, @logo-click
<MainLayout
:menu-items="menuItems"
:app-name="'My App'"
:app-subtitle="'Dashboard'"
:user-info="userInfo"
:version="'2.0.0'"
:copyright="'© 2024 My Company'"
:default-expanded="true"
:backgroundColor="'#f8f9fa'"
:contentPadding="'20px'"
@menu-click="handleMenuClick"
@logo-click="handleLogoClick"
>
<div>Your content</div>
</MainLayout>:root {
--tsc-main-layout-bg: #f8f9fa;
--tsc-main-layout-sidebar-bg: #ffffff;
--tsc-main-layout-sidebar-border: #e5e7eb;
--tsc-main-layout-topbar-bg: #ffffff;
--tsc-main-layout-topbar-border: #e5e7eb;
--tsc-main-layout-content-bg: #f8f9fa;
--tsc-main-layout-content-padding: 20px;
}Topbar
Props: userInfo, showNotifications, showUserMenu
Events: @notification-click, @user-menu-click
<Topbar
:user-info="userInfo"
:showNotifications="true"
:showUserMenu="true"
@notification-click="handleNotification"
@user-menu-click="handleUserMenu"
/>:root {
--tsc-topbar-bg: #ffffff;
--tsc-topbar-border: #e5e7eb;
--tsc-topbar-height: 60px;
--tsc-topbar-padding: 0 1rem;
--tsc-topbar-user-info-color: #374151;
--tsc-topbar-notification-color: #6b7280;
}Sidebar
Props: menuItems, expanded, showLogo
Events: @menu-click, @toggle
<Sidebar
:menu-items="menuItems"
:expanded="isExpanded"
:showLogo="true"
@menu-click="handleMenuClick"
@toggle="toggleSidebar"
/>:root {
--tsc-sidebar-bg: #ffffff;
--tsc-sidebar-border: #e5e7eb;
--tsc-sidebar-width: 250px;
--tsc-sidebar-collapsed-width: 60px;
--tsc-sidebar-menu-item-color: #374151;
--tsc-sidebar-menu-item-hover-bg: #f3f4f6;
--tsc-sidebar-menu-item-active-bg: #dbeafe;
--tsc-sidebar-menu-item-active-color: #2563eb;
}🔔 Toast Components
ToastMessage
Props: None Events: None
<ToastMessage />// Gọi toast
window.triggerToast?.({
severity: 'success',
detail: 'Operation completed successfully!',
life: 3000,
closable: true,
position: 'top'
}):root {
--tsc-toast-success-bg: #e6f5f0;
--tsc-toast-success-border: #4caf50;
--tsc-toast-success-color: #4caf50;
--tsc-toast-success-icon-color: #4caf50;
--tsc-toast-success-text-color: #002550;
--tsc-toast-error-bg: #f5e7e6;
--tsc-toast-error-border: #f44336;
--tsc-toast-error-color: #f44336;
--tsc-toast-error-icon-color: #f44336;
--tsc-toast-error-text-color: #f44336;
}🎨 Advanced Components
DaTieredMenu
Props: model, popup, appendTo
Events: @show, @hide
<DaTieredMenu :model="menuItems" />
<DaTieredMenu :model="menuItems" :popup="true" />:root {
--tsc-tiered-menu-bg: #ffffff;
--tsc-tiered-menu-border: #e5e7eb;
--tsc-tiered-menu-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--tsc-tiered-menu-item-hover-bg: #f3f4f6;
--tsc-tiered-menu-item-active-bg: #dbeafe;
}⚡ Specialized Components
DaPopover
Props: v-model:visible, target, placement, arrow, hover
Events: @show, @hide
<DaPopover v-model:visible="showPopover" target="button" placement="top" :arrow="true">
<template #target>
<DaButton label="Hover me" />
</template>
<template #content>
<div>Popover content</div>
</template>
</DaPopover>:root {
--tsc-popover-bg: #ffffff;
--tsc-popover-border: #e5e7eb;
--tsc-popover-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
--tsc-popover-arrow-color: #ffffff;
--tsc-popover-padding: 0.75rem;
}ErrorWithRefreshButton
Props: errorMessage, showRefresh
Events: @refresh
<ErrorWithRefreshButton
errorMessage="Something went wrong"
:showRefresh="true"
@refresh="retry"
/>:root {
--tsc-error-refresh-message-color: #dc3545;
--tsc-error-refresh-btn-bg: #007bff;
--tsc-error-refresh-btn-color: white;
--tsc-error-refresh-btn-hover-bg: #0056b3;
--tsc-error-refresh-padding: 1rem;
}ActionMenu
Props: items, placement
Events: @item-click
<ActionMenu :items="menuItems" placement="bottom" @item-click="handleAction" />:root {
--tsc-actionmenu-item-color: #6b7280;
--tsc-actionmenu-item-hover-bg: #f3f4f6;
--tsc-actionmenu-green-color: #10b981;
--tsc-actionmenu-red-color: #ef4444;
--tsc-actionmenu-disabled-opacity: 0.5;
}DaDropdownButton
Props: label, items, split
Events: @click, @item-click
<DaDropdownButton label="Actions" :items="menuItems" />
<DaDropdownButton label="Split" :items="menuItems" :split="true" />:root {
--tsc-dropdown-button-bg: #3b82f6;
--tsc-dropdown-button-color: #ffffff;
--tsc-dropdown-button-hover-bg: #2563eb;
--tsc-dropdown-button-border: #3b82f6;
--tsc-dropdown-button-split-border: #2563eb;
}DaNavbarItems
Props: items, activeItem
Events: @item-click
<DaNavbarItems :items="navItems" :activeItem="activeNav" @item-click="handleNav" />:root {
--tsc-navbar-item-color: #374151;
--tsc-navbar-item-hover-bg: #f3f4f6;
--tsc-navbar-item-active-bg: #dbeafe;
--tsc-navbar-item-active-color: #2563eb;
--tsc-navbar-item-active-weight: 500;
--tsc-navbar-item-active-border: #1e293b;
--tsc-navbar-item-icon-color: #6b7280;
--tsc-navbar-item-active-icon-color: #2563eb;
}DaTableToolBar
Props: title, showSearch, showFilter, showExport
Events: @search, @filter, @export
<DaTableToolBar
title="Products"
:showSearch="true"
:showFilter="true"
:showExport="true"
@search="handleSearch"
@filter="handleFilter"
@export="handleExport"
/>:root {
--tsc-table-toolbar-bg: #f8fafc;
--tsc-table-toolbar-border: #e2e8f0;
--tsc-table-toolbar-padding: 1rem;
--tsc-table-toolbar-title-color: #1e293b;
--tsc-table-toolbar-title-weight: 600;
}DaTableFilter
Props: filters, showClear
Events: @filter-change, @clear
<DaTableFilter :filters="filterOptions" :showClear="true" @filter-change="handleFilter" />:root {
--tsc-table-filter-bg: #ffffff;
--tsc-table-filter-border: #d1d5db;
--tsc-table-filter-padding: 0.75rem;
--tsc-table-filter-input-border: #d1d5db;
--tsc-table-filter-input-focus-border: #3b82f6;
}DaTableContent
Props: loading, emptyMessage
Events: None
<DaTableContent :loading="isLoading" emptyMessage="No data available" />:root {
--tsc-table-content-loading-bg: #f8fafc;
--tsc-table-content-empty-color: #6b7280;
--tsc-table-content-empty-bg: #f8fafc;
--tsc-table-content-padding: 2rem;
}🎨 Icon Components
BroadcastStationIcon
Props: size, color
Events: None
<BroadcastStationIcon :size="24" color="#3b82f6" />CaretIcon
Props: direction, size, color
Events: None
<CaretIcon direction="down" :size="16" color="#6b7280" />
<CaretIcon direction="up" :size="16" color="#6b7280" />GroupIcon
Props: size, color
Events: None
<GroupIcon :size="20" color="#10b981" />NotificationIcon
Props: size, color, badge
Events: @click
<NotificationIcon :size="24" color="#6b7280" :badge="5" @click="showNotifications" />PeopleCommunityIcon
Props: size, color
Events: None
<PeopleCommunityIcon :size="20" color="#8b5cf6" />PersonIcon
Props: size, color
Events: None
<PersonIcon :size="20" color="#f59e0b" />RadioDeviceIcon
Props: size, color
Events: None
<RadioDeviceIcon :size="24" color="#ef4444" />RadioUnitIcon
Props: size, color
Events: None
<RadioUnitIcon :size="24" color="#06b6d4" />StopIcon
Props: size, color
Events: None
<StopIcon :size="20" color="#ef4444" />TalkgroupIcon
Props: size, color
Events: None
<TalkgroupIcon :size="20" color="#84cc16" />TrashBinIcon
Props: size, color
Events: None
<TrashBinIcon :size="20" color="#ef4444" />🎯 Misc Components
DaNotification
Props: count, maxCount, showZero
Events: @click
<DaNotification :count="5" :maxCount="99" @click="showNotifications" />:root {
--tsc-notification-icon-color: #6b7280;
--tsc-notification-badge-bg: #ef4444;
--tsc-notification-badge-color: white;
--tsc-notification-badge-size: 18px;
--tsc-notification-badge-border-radius: 50%;
}Gợi ý: Để xem đầy đủ CSS variables cho tất cả components, tham khảo file
src/styles/variables.scsstrong thư viện hoặcUSAGE_GUIDE.mdđể biết chi tiết props, events, slots của từng component.
📚 Component Categories
🎯 Basic Components (10)
TheLoader- Loading spinnerDaColorChip- Color display chipDaError- Error message displayDaMessage- Message componentDaTabs- Tab navigationDaChips- Chip componentsDaButton- Button componentDaModal- Modal dialogDaImg- Image component with iconsDaCheckbox- Checkbox input
📝 Form Components (10)
DaTextarea- Textarea inputDaInputNumber- Number inputDaSelectButton- Select button groupDaInputText- Text inputDaDropdown- Dropdown selectDaInputSwitch- Toggle switchDaPassword- Password inputDaPagination- Pagination controlsDaMultiSelect- Multi-select dropdownDaTreeSelect- Tree select component
📊 Data Components (10)
DaFormModal- Form modalDaDataTable- Data tableDaListboxWithCheckbox- Listbox with checkboxesDaInputNumberWithUnit- Number input with unitDaCalendar- Calendar with time pickerDaPieChart- Pie chartDaBarChart- Bar chartDaLineChart- Line chartDaDropdownPageSize- Page size selectorDaTableSkeleton- Table skeleton loader
🛠️ Utility Components (7)
DaLabel- Label componentDaDotColor- Color dot indicatorDaTriStateCheckBox- Three-state checkboxDaEllipsis- Text ellipsis with tooltipDaInputGroup- Input group wrapperDaInputMask- Input with maskIconHelp- Help icon with popoverRowDetails- Expandable row details
🎨 Advanced Components (1)
DaTieredMenu- Multi-level menu
⚡ Specialized Components (7)
DaPopover- Popover componentErrorWithRefreshButton- Error with refreshActionMenu- Action menuDaDropdownButton- Dropdown buttonDaNavbarItems- Navbar itemsDaTableToolBar- Table toolbarDaTableFilter- Table filterDaTableContent- Table content
🏗️ Layout Components (3)
MainLayout- Main layout wrapperTopbar- Top navigation barSidebar- Sidebar navigation
🎨 Icon Components (11)
BroadcastStationIcon- Broadcast station iconCaretIcon- Caret iconGroupIcon- Group iconNotificationIcon- Notification iconPeopleCommunityIcon- People community iconPersonIcon- Person iconRadioDeviceIcon- Radio device iconRadioUnitIcon- Radio unit iconStopIcon- Stop iconTalkgroupIcon- Talkgroup iconTrashBinIcon- Trash bin icon
🔔 Toast Components (1)
ToastMessage- Toast notification
🎯 Misc Components (2)
DaPopover- Popover componentErrorWithRefreshButton- Error with refresh button
🎨 Styling
The library uses SCSS modules for styling. You can override styles by:
- CSS Variables: Override CSS custom properties
- SCSS Variables: Import and override SCSS variables
- Component Classes: Use component-specific classes
// Override main layout background
.main-layout {
--background-color: #ffffff;
}
// Override button styles
.da-button {
--button-primary-color: #007bff;
--button-border-radius: 8px;
}🔧 Configuration
Vue Router Integration
// router/index.ts
import { createRouter, createWebHistory } from 'vue-router'
const router = createRouter({
history: createWebHistory(),
routes: [
{ path: '/', component: Home },
{ path: '/dashboard', component: Dashboard },
{ path: '/users', component: Users }
]
})
export default routerEvent Handling
<template>
<div>
<!-- Error with refresh -->
<ErrorWithRefreshButton
error-message="Something went wrong"
@refresh="handleRefresh"
/>
<!-- Popover -->
<DaPopover hover arrow placement="top">
<DaButton label="Hover me" />
<template #content>
<div>Popover content</div>
</template>
</DaPopover>
</div>
</template>
<script setup>
const handleRefresh = () => {
// Retry the failed operation
console.log('Refreshing...')
}
</script>📱 Responsive Design
All components are responsive and work on:
- Desktop (1200px+)
- Tablet (768px - 1199px)
- Mobile (320px - 767px)
🎯 Browser Support
- Chrome 90+
- Firefox 88+
- Safari 14+
- Edge 90+
📄 License
Copyright (c) 2024 TSC Communications. All rights reserved.
🤝 Contributing
- Fork the repository
- Create a feature branch
- Make your changes
- Add tests
- Submit a pull request
📞 Support
For support and questions:
- Create an issue on GitHub
- Contact: [email protected]
Total Components: 62 Categories: 9 Built with: Vue 3, TypeScript, PrimeVue, SCSS
📘 Component Reference & Custom CSS Guide
Ghi chú chung:
- Tất cả components hỗ trợ
customClass?: stringđể nhận CSS tùy biến. - Mỗi component có fixed class name (bắt đầu với
da-...) để target CSS toàn cục khi cần. - Ví dụ chỉ mang tính minh họa, có thể thay đổi theo nhu cầu UI.
Basic
- DaButton (fixed:
da-button):label,severity,size,disabled,loading,customClass- Dùng:
<DaButton label="Save" severity="success" customClass="my-btn" /> - CSS:
.da-button.my-btn{border-radius:12px;background:#2563eb!important;color:#fff!important;}
- Dùng:
- DaModal (fixed:
da-modal):header,visible,customClass - DaMessage (fixed:
da-message):message,severity,customClass - DaError (fixed:
da-error):message,htmlMessage,retryButton,customClass - DaImg (fixed:
da-img):name,type,tooltip,customClass - DaTabs (fixed:
da-tabs):items,activeIndex,loading,customClass
Form
- DaInputText (fixed:
da-input-text):v-model,label,icon,helpText,disabled,validator,customClass - DaTextarea (fixed:
da-textarea):v-model,label,disabled,validator,customClass - DaInputNumber (fixed:
da-input-number):v-model,label,min,max,disabled,customClass - DaDropdown (fixed:
da-dropdown):v-model,options,optionLabel,optionValue,label,placeholder,customClass - DaSelectButton (fixed:
da-select-button):v-model,options(nhậnoptionLabel/optionValuequa $attrs),customClass - DaInputSwitch (fixed:
da-input-switch):v-model:boolean,label,customClass - DaPassword (fixed:
da-password):v-model,toggleMask?,feedback?,customClass - DaPagination (fixed:
da-pagination):v-model(page),total,rows,customClass - DaMultiSelect (fixed:
da-multi-select):v-model[],options,optionLabel,optionValue,customClass - DaTreeSelect (fixed:
da-tree-select):v-model,options(Tree),customClass - DaInputMask (fixed:
da-input-mask):v-model,mask,customClass
Data
- DaDataTable (fixed:
da-data-table):value,columns,loading,paginator,customClass - DaFormModal, DaListboxWithCheckbox, DaInputNumberWithUnit, DaCalendar, DaDropdownPageSize, DaTableSkeleton
Utility
- DaLabel (
da-label), DaDotColor (da-dot-color), DaEllipsis (da-ellipsis), DaInputGroup (da-input-group), IconHelp (icon-help), RowDetails (da-row-details), TheLoader (the-loader), ErrorWithRefreshButton (error-with-refresh-button), DaTriStateCheckBox
Advanced & Specialized
- DaTieredMenu, DaPopover, ActionMenu, DaDropdownButton, DaNavbarItems, DaTableToolBar, DaTableFilter, DaTableContent
Layout
- MainLayout (
main-layout), Topbar (topbar), Sidebar (sidebar)
Charts
- DaPieChart (
da-pie-chart), DaBarChart (da-bar-chart), DaLineChart (da-line-chart)
Toast & Notifications
- ToastMessage (
da-toast-message): dùngwindow.triggerToast({ severity, detail, life, position }) - DaNotification (
da-notification): icon chuông + badge, canh vị trí bằngcustomClass
Mẫu CSS nhanh
.da-button.my-btn { border-radius: 12px; background:#2563eb !important; color:#fff !important; }
.da-input-text.rounded { border-radius: 12px !important; padding: 10px 14px !important; }
.da-dropdown.flat :global(.p-dropdown) { border-radius: 10px; border: 2px solid #e5e7eb; }
.da-modal.card { border-radius: 16px; box-shadow: 0 20px 40px rgba(0,0,0,.2); }