Files
TrainHub/LLM_CONTEXTS/sakaifrontend.txt
Kazimierz Ciołek 61e3482715 Initialize repo
2026-02-02 13:42:04 +01:00

10379 lines
430 KiB
Plaintext

Directory structure:
└── primefaces-sakai-vue/
├── README.md
├── CHANGELOG.md
├── index.html
├── jsconfig.json
├── LICENSE.md
├── package.json
├── vercel.json
├── vite.config.mjs
├── .editorconfig
├── .eslintrc.cjs
├── .prettierrc.json
├── public/
│ └── demo/
│ └── data/
│ ├── countries.json
│ ├── customers-medium.json
│ ├── events.json
│ ├── photos.json
│ ├── products-orders-small.json
│ ├── products-small.json
│ ├── products.json
│ ├── treenodes.json
│ └── treetablenodes.json
└── src/
├── App.vue
├── main.js
├── components/
│ ├── BlockViewer.vue
│ ├── FloatingConfigurator.vue
│ ├── dashboard/
│ │ ├── BestSellingWidget.vue
│ │ ├── NotificationsWidget.vue
│ │ ├── RecentSalesWidget.vue
│ │ ├── RevenueStreamWidget.vue
│ │ └── StatsWidget.vue
│ └── landing/
│ ├── FeaturesWidget.vue
│ ├── FooterWidget.vue
│ ├── HeroWidget.vue
│ ├── HighlightsWidget.vue
│ ├── PricingWidget.vue
│ └── TopbarWidget.vue
├── layout/
│ ├── AppConfigurator.vue
│ ├── AppFooter.vue
│ ├── AppLayout.vue
│ ├── AppMenu.vue
│ ├── AppMenuItem.vue
│ ├── AppSidebar.vue
│ ├── AppTopbar.vue
│ └── composables/
│ └── layout.js
├── router/
│ └── index.js
├── service/
│ ├── CountryService.js
│ ├── NodeService.js
│ ├── PhotoService.js
│ └── ProductService.js
└── views/
├── Dashboard.vue
├── pages/
│ ├── Crud.vue
│ ├── Documentation.vue
│ ├── Empty.vue
│ ├── Landing.vue
│ ├── NotFound.vue
│ └── auth/
│ ├── Access.vue
│ ├── Error.vue
│ └── Login.vue
└── uikit/
├── ButtonDoc.vue
├── ChartDoc.vue
├── FileDoc.vue
├── FormLayout.vue
├── InputDoc.vue
├── ListDoc.vue
├── MediaDoc.vue
├── MenuDoc.vue
├── MessagesDoc.vue
├── MiscDoc.vue
├── OverlayDoc.vue
├── PanelsDoc.vue
├── TableDoc.vue
├── TimelineDoc.vue
└── TreeDoc.vue
================================================
FILE: README.md
================================================
Sakai is an application template for Vue based on the [create-vue](https://github.com/vuejs/create-vue), the recommended way to start a Vite-powered Vue projects.
Visit the [documentation](https://sakai.primevue.org/documentation) to get started.
================================================
FILE: CHANGELOG.md
================================================
# Changelog
## 4.3.0 (2025-02-26)
**Implemented New Features and Enhancements**
- Update PrimeVue version
## 4.2.0 (2024-12-09)
**Implemented New Features and Enhancements**
- Refactored dashboard sections to components
- Migrate sass from @import to @use
## 4.1.0 (2024-07-29)
- Changed menu button location at topbar
- Add border to overlay menu
- Animation for mobile mask
- Fixed chart colors
## 4.0.0 (2024-07-29)
- Updated to PrimeVue v4
## 3.10.0 (2024-03-11)
**Migration Guide**
- Update theme files.
**Implemented New Features and Enhancements**
- Upgrade to PrimeVue 3.49.1
## 3.9.0 (2023-11-01)
**Migration Guide**
- Update theme files.
**Implemented New Features and Enhancements**
- Upgrade to PrimeVue 3.39.0
## 3.8.0 (2023-07-24)
**Migration Guide**
- Update theme files.
- Update assets style files
- Remove code highlight
**Implemented New Features and Enhancements**
- Upgrade to PrimeVue 3.30.2
## 3.7.0 (2023-05-06)
- Upgrade to PrimeVue 3.28.0
**Implemented New Features and Enhancements**
## 3.6.0 (2023-04-12)
**Implemented New Features and Enhancements**
- Upgrade to PrimeVue 3.26.1
- Upgrade to vite 4.2.1
================================================
FILE: index.html
================================================
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<link rel="icon" href="/favicon.ico">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Sakai Vue</title>
<link href="https://fonts.cdnfonts.com/css/lato" rel="stylesheet">
</head>
<body>
<div id="app"></div>
<script type="module" src="/src/main.js"></script>
</body>
</html>
================================================
FILE: jsconfig.json
================================================
{
"compilerOptions": {
"paths": {
"@/*": [
"./src/*"
]
}
},
"exclude": [
"node_modules",
"dist"
]
}
================================================
FILE: LICENSE.md
================================================
The MIT License (MIT)
Copyright (c) 2018-2022 PrimeTek
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in
all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
THE SOFTWARE.
================================================
FILE: package.json
================================================
{
"name": "sakai-vue",
"version": "4.3.0",
"scripts": {
"dev": "vite",
"build": "vite build",
"preview": "vite preview",
"lint": "eslint --fix . --ext .vue,.js,.jsx,.cjs,.mjs --fix --ignore-path .gitignore"
},
"dependencies": {
"@primeuix/themes": "^2.0.0",
"chart.js": "3.3.2",
"primeicons": "^7.0.0",
"primevue": "^4.5.2",
"tailwindcss-primeui": "^0.6.0",
"vue": "^3.4.34",
"vue-router": "^4.4.0"
},
"devDependencies": {
"@primevue/auto-import-resolver": "^4.3.1",
"@rushstack/eslint-patch": "^1.8.0",
"@tailwindcss/vite": "^4.1.17",
"@vitejs/plugin-vue": "^5.0.5",
"@vue/eslint-config-prettier": "^9.0.0",
"eslint": "^8.57.0",
"eslint-plugin-vue": "^9.23.0",
"prettier": "^3.2.5",
"sass": "^1.55.0",
"tailwindcss": "^4.1.17",
"unplugin-vue-components": "^0.27.3",
"vite": "^5.3.1"
}
}
================================================
FILE: vercel.json
================================================
{
"rewrites": [
{
"source": "/:path*",
"destination": "/index.html"
}
],
"trailingSlash": false
}
================================================
FILE: vite.config.mjs
================================================
import { fileURLToPath, URL } from 'node:url';
import { PrimeVueResolver } from '@primevue/auto-import-resolver';
import tailwindcss from '@tailwindcss/vite';
import vue from '@vitejs/plugin-vue';
import Components from 'unplugin-vue-components/vite';
import { defineConfig } from 'vite';
// https://vitejs.dev/config/
export default defineConfig({
optimizeDeps: {
noDiscovery: true
},
plugins: [
vue(),
tailwindcss(),
Components({
resolvers: [PrimeVueResolver()]
})
],
resolve: {
alias: {
'@': fileURLToPath(new URL('./src', import.meta.url))
}
},
css: {
preprocessorOptions: {
scss: {
api: 'modern-compiler'
}
}
}
});
================================================
FILE: .editorconfig
================================================
# Editor configuration, see https://editorconfig.org
root = true
[*]
charset = utf-8
indent_style = space
indent_size = 4
insert_final_newline = true
trim_trailing_whitespace = true
[*.md]
max_line_length = off
trim_trailing_whitespace = false
================================================
FILE: .eslintrc.cjs
================================================
/* eslint-env node */
require('@rushstack/eslint-patch/modern-module-resolution');
module.exports = {
root: true,
env: {
node: true
},
extends: ['plugin:vue/vue3-essential', 'eslint:recommended', '@vue/eslint-config-prettier'],
parserOptions: {
ecmaVersion: 'latest'
},
rules: {
'vue/multi-word-component-names': 'off',
'vue/no-reserved-component-names': 'off',
'vue/component-tags-order': [
'error',
{
order: ['script', 'template', 'style']
}
]
}
};
================================================
FILE: .prettierrc.json
================================================
{
"useTabs": false,
"tabWidth": 4,
"trailingComma": "none",
"semi": true,
"singleQuote": true,
"vueIndentScriptAndStyle": false,
"printWidth": 250,
"bracketSameLine": false
}
================================================
FILE: public/demo/data/countries.json
================================================
{
"data": [
{"name": "Afghanistan", "code": "AF"},
{"name": "Åland Islands", "code": "AX"},
{"name": "Albania", "code": "AL"},
{"name": "Algeria", "code": "DZ"},
{"name": "American Samoa", "code": "AS"},
{"name": "Andorra", "code": "AD"},
{"name": "Angola", "code": "AO"},
{"name": "Anguilla", "code": "AI"},
{"name": "Antarctica", "code": "AQ"},
{"name": "Antigua and Barbuda", "code": "AG"},
{"name": "Argentina", "code": "AR"},
{"name": "Armenia", "code": "AM"},
{"name": "Aruba", "code": "AW"},
{"name": "Australia", "code": "AU"},
{"name": "Austria", "code": "AT"},
{"name": "Azerbaijan", "code": "AZ"},
{"name": "Bahamas", "code": "BS"},
{"name": "Bahrain", "code": "BH"},
{"name": "Bangladesh", "code": "BD"},
{"name": "Barbados", "code": "BB"},
{"name": "Belarus", "code": "BY"},
{"name": "Belgium", "code": "BE"},
{"name": "Belize", "code": "BZ"},
{"name": "Benin", "code": "BJ"},
{"name": "Bermuda", "code": "BM"},
{"name": "Bhutan", "code": "BT"},
{"name": "Bolivia", "code": "BO"},
{"name": "Bosnia and Herzegovina", "code": "BA"},
{"name": "Botswana", "code": "BW"},
{"name": "Bouvet Island", "code": "BV"},
{"name": "Brazil", "code": "BR"},
{"name": "British Indian Ocean Territory", "code": "IO"},
{"name": "Brunei Darussalam", "code": "BN"},
{"name": "Bulgaria", "code": "BG"},
{"name": "Burkina Faso", "code": "BF"},
{"name": "Burundi", "code": "BI"},
{"name": "Cambodia", "code": "KH"},
{"name": "Cameroon", "code": "CM"},
{"name": "Canada", "code": "CA"},
{"name": "Cape Verde", "code": "CV"},
{"name": "Cayman Islands", "code": "KY"},
{"name": "Central African Republic", "code": "CF"},
{"name": "Chad", "code": "TD"},
{"name": "Chile", "code": "CL"},
{"name": "China", "code": "CN"},
{"name": "Christmas Island", "code": "CX"},
{"name": "Cocos (Keeling) Islands", "code": "CC"},
{"name": "Colombia", "code": "CO"},
{"name": "Comoros", "code": "KM"},
{"name": "Congo", "code": "CG"},
{"name": "Congo, The Democratic Republic of the", "code": "CD"},
{"name": "Cook Islands", "code": "CK"},
{"name": "Costa Rica", "code": "CR"},
{"name": "Cote D\"Ivoire", "code": "CI"},
{"name": "Croatia", "code": "HR"},
{"name": "Cuba", "code": "CU"},
{"name": "Cyprus", "code": "CY"},
{"name": "Czech Republic", "code": "CZ"},
{"name": "Denmark", "code": "DK"},
{"name": "Djibouti", "code": "DJ"},
{"name": "Dominica", "code": "DM"},
{"name": "Dominican Republic", "code": "DO"},
{"name": "Ecuador", "code": "EC"},
{"name": "Egypt", "code": "EG"},
{"name": "El Salvador", "code": "SV"},
{"name": "Equatorial Guinea", "code": "GQ"},
{"name": "Eritrea", "code": "ER"},
{"name": "Estonia", "code": "EE"},
{"name": "Ethiopia", "code": "ET"},
{"name": "Falkland Islands (Malvinas)", "code": "FK"},
{"name": "Faroe Islands", "code": "FO"},
{"name": "Fiji", "code": "FJ"},
{"name": "Finland", "code": "FI"},
{"name": "France", "code": "FR"},
{"name": "French Guiana", "code": "GF"},
{"name": "French Polynesia", "code": "PF"},
{"name": "French Southern Territories", "code": "TF"},
{"name": "Gabon", "code": "GA"},
{"name": "Gambia", "code": "GM"},
{"name": "Georgia", "code": "GE"},
{"name": "Germany", "code": "DE"},
{"name": "Ghana", "code": "GH"},
{"name": "Gibraltar", "code": "GI"},
{"name": "Greece", "code": "GR"},
{"name": "Greenland", "code": "GL"},
{"name": "Grenada", "code": "GD"},
{"name": "Guadeloupe", "code": "GP"},
{"name": "Guam", "code": "GU"},
{"name": "Guatemala", "code": "GT"},
{"name": "Guernsey", "code": "GG"},
{"name": "Guinea", "code": "GN"},
{"name": "Guinea-Bissau", "code": "GW"},
{"name": "Guyana", "code": "GY"},
{"name": "Haiti", "code": "HT"},
{"name": "Heard Island and Mcdonald Islands", "code": "HM"},
{"name": "Holy See (Vatican City State)", "code": "VA"},
{"name": "Honduras", "code": "HN"},
{"name": "Hong Kong", "code": "HK"},
{"name": "Hungary", "code": "HU"},
{"name": "Iceland", "code": "IS"},
{"name": "India", "code": "IN"},
{"name": "Indonesia", "code": "ID"},
{"name": "Iran, Islamic Republic Of", "code": "IR"},
{"name": "Iraq", "code": "IQ"},
{"name": "Ireland", "code": "IE"},
{"name": "Isle of Man", "code": "IM"},
{"name": "Israel", "code": "IL"},
{"name": "Italy", "code": "IT"},
{"name": "Jamaica", "code": "JM"},
{"name": "Japan", "code": "JP"},
{"name": "Jersey", "code": "JE"},
{"name": "Jordan", "code": "JO"},
{"name": "Kazakhstan", "code": "KZ"},
{"name": "Kenya", "code": "KE"},
{"name": "Kiribati", "code": "KI"},
{"name": "Korea, Democratic People\"S Republic of", "code": "KP"},
{"name": "Korea, Republic of", "code": "KR"},
{"name": "Kuwait", "code": "KW"},
{"name": "Kyrgyzstan", "code": "KG"},
{"name": "Lao People\"S Democratic Republic", "code": "LA"},
{"name": "Latvia", "code": "LV"},
{"name": "Lebanon", "code": "LB"},
{"name": "Lesotho", "code": "LS"},
{"name": "Liberia", "code": "LR"},
{"name": "Libyan Arab Jamahiriya", "code": "LY"},
{"name": "Liechtenstein", "code": "LI"},
{"name": "Lithuania", "code": "LT"},
{"name": "Luxembourg", "code": "LU"},
{"name": "Macao", "code": "MO"},
{"name": "Macedonia, The Former Yugoslav Republic of", "code": "MK"},
{"name": "Madagascar", "code": "MG"},
{"name": "Malawi", "code": "MW"},
{"name": "Malaysia", "code": "MY"},
{"name": "Maldives", "code": "MV"},
{"name": "Mali", "code": "ML"},
{"name": "Malta", "code": "MT"},
{"name": "Marshall Islands", "code": "MH"},
{"name": "Martinique", "code": "MQ"},
{"name": "Mauritania", "code": "MR"},
{"name": "Mauritius", "code": "MU"},
{"name": "Mayotte", "code": "YT"},
{"name": "Mexico", "code": "MX"},
{"name": "Micronesia, Federated States of", "code": "FM"},
{"name": "Moldova, Republic of", "code": "MD"},
{"name": "Monaco", "code": "MC"},
{"name": "Mongolia", "code": "MN"},
{"name": "Montserrat", "code": "MS"},
{"name": "Morocco", "code": "MA"},
{"name": "Mozambique", "code": "MZ"},
{"name": "Myanmar", "code": "MM"},
{"name": "Namibia", "code": "NA"},
{"name": "Nauru", "code": "NR"},
{"name": "Nepal", "code": "NP"},
{"name": "Netherlands", "code": "NL"},
{"name": "Netherlands Antilles", "code": "AN"},
{"name": "New Caledonia", "code": "NC"},
{"name": "New Zealand", "code": "NZ"},
{"name": "Nicaragua", "code": "NI"},
{"name": "Niger", "code": "NE"},
{"name": "Nigeria", "code": "NG"},
{"name": "Niue", "code": "NU"},
{"name": "Norfolk Island", "code": "NF"},
{"name": "Northern Mariana Islands", "code": "MP"},
{"name": "Norway", "code": "NO"},
{"name": "Oman", "code": "OM"},
{"name": "Pakistan", "code": "PK"},
{"name": "Palau", "code": "PW"},
{"name": "Palestinian Territory, Occupied", "code": "PS"},
{"name": "Panama", "code": "PA"},
{"name": "Papua New Guinea", "code": "PG"},
{"name": "Paraguay", "code": "PY"},
{"name": "Peru", "code": "PE"},
{"name": "Philippines", "code": "PH"},
{"name": "Pitcairn", "code": "PN"},
{"name": "Poland", "code": "PL"},
{"name": "Portugal", "code": "PT"},
{"name": "Puerto Rico", "code": "PR"},
{"name": "Qatar", "code": "QA"},
{"name": "Reunion", "code": "RE"},
{"name": "Romania", "code": "RO"},
{"name": "Russian Federation", "code": "RU"},
{"name": "RWANDA", "code": "RW"},
{"name": "Saint Helena", "code": "SH"},
{"name": "Saint Kitts and Nevis", "code": "KN"},
{"name": "Saint Lucia", "code": "LC"},
{"name": "Saint Pierre and Miquelon", "code": "PM"},
{"name": "Saint Vincent and the Grenadines", "code": "VC"},
{"name": "Samoa", "code": "WS"},
{"name": "San Marino", "code": "SM"},
{"name": "Sao Tome and Principe", "code": "ST"},
{"name": "Saudi Arabia", "code": "SA"},
{"name": "Senegal", "code": "SN"},
{"name": "Serbia and Montenegro", "code": "CS"},
{"name": "Seychelles", "code": "SC"},
{"name": "Sierra Leone", "code": "SL"},
{"name": "Singapore", "code": "SG"},
{"name": "Slovakia", "code": "SK"},
{"name": "Slovenia", "code": "SI"},
{"name": "Solomon Islands", "code": "SB"},
{"name": "Somalia", "code": "SO"},
{"name": "South Africa", "code": "ZA"},
{"name": "South Georgia and the South Sandwich Islands", "code": "GS"},
{"name": "Spain", "code": "ES"},
{"name": "Sri Lanka", "code": "LK"},
{"name": "Sudan", "code": "SD"},
{"name": "Suriname", "code": "SR"},
{"name": "Svalbard and Jan Mayen", "code": "SJ"},
{"name": "Swaziland", "code": "SZ"},
{"name": "Sweden", "code": "SE"},
{"name": "Switzerland", "code": "CH"},
{"name": "Syrian Arab Republic", "code": "SY"},
{"name": "Taiwan, Province of China", "code": "TW"},
{"name": "Tajikistan", "code": "TJ"},
{"name": "Tanzania, United Republic of", "code": "TZ"},
{"name": "Thailand", "code": "TH"},
{"name": "Timor-Leste", "code": "TL"},
{"name": "Togo", "code": "TG"},
{"name": "Tokelau", "code": "TK"},
{"name": "Tonga", "code": "TO"},
{"name": "Trinidad and Tobago", "code": "TT"},
{"name": "Tunisia", "code": "TN"},
{"name": "Turkey", "code": "TR"},
{"name": "Turkmenistan", "code": "TM"},
{"name": "Turks and Caicos Islands", "code": "TC"},
{"name": "Tuvalu", "code": "TV"},
{"name": "Uganda", "code": "UG"},
{"name": "Ukraine", "code": "UA"},
{"name": "United Arab Emirates", "code": "AE"},
{"name": "United Kingdom", "code": "GB"},
{"name": "United States", "code": "US"},
{"name": "United States Minor Outlying Islands", "code": "UM"},
{"name": "Uruguay", "code": "UY"},
{"name": "Uzbekistan", "code": "UZ"},
{"name": "Vanuatu", "code": "VU"},
{"name": "Venezuela", "code": "VE"},
{"name": "Viet Nam", "code": "VN"},
{"name": "Virgin Islands, British", "code": "VG"},
{"name": "Virgin Islands, U.S.", "code": "VI"},
{"name": "Wallis and Futuna", "code": "WF"},
{"name": "Western Sahara", "code": "EH"},
{"name": "Yemen", "code": "YE"},
{"name": "Zambia", "code": "ZM"},
{"name": "Zimbabwe", "code": "ZW"}
]
}
================================================
FILE: public/demo/data/customers-medium.json
================================================
{
"data": [
{
"id": 1000,
"name": "James Butt",
"country": {
"name": "Algeria",
"code": "dz"
},
"company": "Benton, John B Jr",
"date": "2015-09-13",
"status": "unqualified",
"activity": 17,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1001,
"name": "Josephine Darakjy",
"country": {
"name": "Egypt",
"code": "eg"
},
"company": "Chanay, Jeffrey A Esq",
"date": "2019-02-09",
"status": "proposal",
"activity": 0,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1002,
"name": "Art Venere",
"country": {
"name": "Panama",
"code": "pa"
},
"company": "Chemel, James L Cpa",
"date": "2017-05-13",
"status": "qualified",
"activity": 63,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
},
{
"id": 1003,
"name": "Lenna Paprocki",
"country": {
"name": "Slovenia",
"code": "si"
},
"company": "Feltz Printing Service",
"date": "2020-09-15",
"status": "new",
"activity": 37,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1004,
"name": "Donette Foller",
"country": {
"name": "South Africa",
"code": "za"
},
"company": "Printing Dimensions",
"date": "2016-05-20",
"status": "proposal",
"activity": 33,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
},
{
"id": 1005,
"name": "Simona Morasca",
"country": {
"name": "Egypt",
"code": "eg"
},
"company": "Chapman, Ross E Esq",
"date": "2018-02-16",
"status": "qualified",
"activity": 68,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1006,
"name": "Mitsue Tollner",
"country": {
"name": "Paraguay",
"code": "py"
},
"company": "Morlong Associates",
"date": "2018-02-19",
"status": "renewal",
"activity": 54,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1007,
"name": "Leota Dilliard",
"country": {
"name": "Serbia",
"code": "rs"
},
"company": "Commercial Press",
"date": "2019-08-13",
"status": "renewal",
"activity": 69,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1008,
"name": "Sage Wieser",
"country": {
"name": "Egypt",
"code": "eg"
},
"company": "Truhlar And Truhlar Attys",
"date": "2018-11-21",
"status": "unqualified",
"activity": 76,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1009,
"name": "Kris Marrier",
"country": {
"name": "Mexico",
"code": "mx"
},
"company": "King, Christopher A Esq",
"date": "2015-07-07",
"status": "proposal",
"activity": 3,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1010,
"name": "Minna Amigon",
"country": {
"name": "Romania",
"code": "ro"
},
"company": "Dorl, James J Esq",
"date": "2018-11-07",
"status": "qualified",
"activity": 38,
"representative": {
"name": "Anna Fali",
"image": "annafali.png"
}
},
{
"id": 1011,
"name": "Abel Maclead",
"country": {
"name": "Singapore",
"code": "sg"
},
"company": "Rangoni Of Florence",
"date": "2017-03-11",
"status": "qualified",
"activity": 87,
"representative": {
"name": "Bernardo Dominic",
"image": "bernardodominic.png"
}
},
{
"id": 1012,
"name": "Kiley Caldarera",
"country": {
"name": "Serbia",
"code": "rs"
},
"company": "Feiner Bros",
"date": "2015-10-20",
"status": "unqualified",
"activity": 80,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1013,
"name": "Graciela Ruta",
"country": {
"name": "Chile",
"code": "cl"
},
"company": "Buckley Miller \u0026 Wright",
"date": "2016-07-25",
"status": "negotiation",
"activity": 59,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1014,
"name": "Cammy Albares",
"country": {
"name": "Philippines",
"code": "ph"
},
"company": "Rousseaux, Michael Esq",
"date": "2019-06-25",
"status": "new",
"activity": 90,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
},
{
"id": 1015,
"name": "Mattie Poquette",
"country": {
"name": "Venezuela",
"code": "ve"
},
"company": "Century Communications",
"date": "2017-12-12",
"status": "negotiation",
"activity": 52,
"representative": {
"name": "Anna Fali",
"image": "annafali.png"
}
},
{
"id": 1016,
"name": "Meaghan Garufi",
"country": {
"name": "Malaysia",
"code": "my"
},
"company": "Bolton, Wilbur Esq",
"date": "2018-07-04",
"status": "unqualified",
"activity": 31,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1017,
"name": "Gladys Rim",
"country": {
"name": "Netherlands",
"code": "nl"
},
"company": "T M Byxbee Company Pc",
"date": "2020-02-27",
"status": "renewal",
"activity": 48,
"representative": {
"name": "Stephen Shaw",
"image": "stephenshaw.png"
}
},
{
"id": 1018,
"name": "Yuki Whobrey",
"country": {
"name": "Israel",
"code": "il"
},
"company": "Farmers Insurance Group",
"date": "2017-12-21",
"status": "negotiation",
"activity": 16,
"representative": {
"name": "Bernardo Dominic",
"image": "bernardodominic.png"
}
},
{
"id": 1019,
"name": "Fletcher Flosi",
"country": {
"name": "Argentina",
"code": "ar"
},
"company": "Post Box Services Plus",
"date": "2016-01-04",
"status": "renewal",
"activity": 19,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1020,
"name": "Bette Nicka",
"country": {
"name": "Paraguay",
"code": "py"
},
"company": "Sport En Art",
"date": "2016-10-21",
"status": "renewal",
"activity": 100,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1021,
"name": "Veronika Inouye",
"country": {
"name": "Ecuador",
"code": "ec"
},
"company": "C 4 Network Inc",
"date": "2017-03-24",
"status": "renewal",
"activity": 72,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1022,
"name": "Willard Kolmetz",
"country": {
"name": "Tunisia",
"code": "tn"
},
"company": "Ingalls, Donald R Esq",
"date": "2017-04-15",
"status": "renewal",
"activity": 94,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
},
{
"id": 1023,
"name": "Maryann Royster",
"country": {
"name": "Belarus",
"code": "by"
},
"company": "Franklin, Peter L Esq",
"date": "2017-03-11",
"status": "qualified",
"activity": 56,
"representative": {
"name": "Elwin Sharvill",
"image": "elwinsharvill.png"
}
},
{
"id": 1024,
"name": "Alisha Slusarski",
"country": {
"name": "Iceland",
"code": "is"
},
"company": "Wtlz Power 107 Fm",
"date": "2018-03-27",
"status": "qualified",
"activity": 7,
"representative": {
"name": "Stephen Shaw",
"image": "stephenshaw.png"
}
},
{
"id": 1025,
"name": "Allene Iturbide",
"country": {
"name": "Italy",
"code": "it"
},
"company": "Ledecky, David Esq",
"date": "2016-02-20",
"status": "qualified",
"activity": 1,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1026,
"name": "Chanel Caudy",
"country": {
"name": "Argentina",
"code": "ar"
},
"company": "Professional Image Inc",
"date": "2018-06-24",
"status": "new",
"activity": 26,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1027,
"name": "Ezekiel Chui",
"country": {
"name": "Ireland",
"code": "ie"
},
"company": "Sider, Donald C Esq",
"date": "2016-09-24",
"status": "new",
"activity": 76,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1028,
"name": "Willow Kusko",
"country": {
"name": "Romania",
"code": "ro"
},
"company": "U Pull It",
"date": "2020-04-11",
"status": "qualified",
"activity": 7,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1029,
"name": "Bernardo Figeroa",
"country": {
"name": "Israel",
"code": "il"
},
"company": "Clark, Richard Cpa",
"date": "2018-04-11",
"status": "renewal",
"activity": 81,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1030,
"name": "Ammie Corrio",
"country": {
"name": "Hungary",
"code": "hu"
},
"company": "Moskowitz, Barry S",
"date": "2016-06-11",
"status": "negotiation",
"activity": 56,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
},
{
"id": 1031,
"name": "Francine Vocelka",
"country": {
"name": "Honduras",
"code": "hn"
},
"company": "Cascade Realty Advisors Inc",
"date": "2017-08-02",
"status": "qualified",
"activity": 94,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1032,
"name": "Ernie Stenseth",
"country": {
"name": "Australia",
"code": "au"
},
"company": "Knwz Newsradio",
"date": "2018-06-06",
"status": "renewal",
"activity": 68,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1033,
"name": "Albina Glick",
"country": {
"name": "Ukraine",
"code": "ua"
},
"company": "Giampetro, Anthony D",
"date": "2019-08-08",
"status": "proposal",
"activity": 85,
"representative": {
"name": "Bernardo Dominic",
"image": "bernardodominic.png"
}
},
{
"id": 1034,
"name": "Alishia Sergi",
"country": {
"name": "Qatar",
"code": "qa"
},
"company": "Milford Enterprises Inc",
"date": "2018-05-19",
"status": "negotiation",
"activity": 46,
"representative": {
"name": "Ivan Magalhaes",
"image": "ivanmagalhaes.png"
}
},
{
"id": 1035,
"name": "Solange Shinko",
"country": {
"name": "Cameroon",
"code": "cm"
},
"company": "Mosocco, Ronald A",
"date": "2015-02-12",
"status": "qualified",
"activity": 32,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1036,
"name": "Jose Stockham",
"country": {
"name": "Italy",
"code": "it"
},
"company": "Tri State Refueler Co",
"date": "2018-04-25",
"status": "qualified",
"activity": 77,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1037,
"name": "Rozella Ostrosky",
"country": {
"name": "Venezuela",
"code": "ve"
},
"company": "Parkway Company",
"date": "2016-02-27",
"status": "unqualified",
"activity": 66,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1038,
"name": "Valentine Gillian",
"country": {
"name": "Paraguay",
"code": "py"
},
"company": "Fbs Business Finance",
"date": "2019-09-17",
"status": "qualified",
"activity": 25,
"representative": {
"name": "Bernardo Dominic",
"image": "bernardodominic.png"
}
},
{
"id": 1039,
"name": "Kati Rulapaugh",
"country": {
"name": "Puerto Rico",
"code": "pr"
},
"company": "Eder Assocs Consltng Engrs Pc",
"date": "2016-12-03",
"status": "renewal",
"activity": 51,
"representative": {
"name": "Ioni Bowcher",
"image": "ionibowcher.png"
}
},
{
"id": 1040,
"name": "Youlanda Schemmer",
"country": {
"name": "Bolivia",
"code": "bo"
},
"company": "Tri M Tool Inc",
"date": "2017-12-15",
"status": "negotiation",
"activity": 49,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1041,
"name": "Dyan Oldroyd",
"country": {
"name": "Argentina",
"code": "ar"
},
"company": "International Eyelets Inc",
"date": "2017-02-02",
"status": "qualified",
"activity": 5,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1042,
"name": "Roxane Campain",
"country": {
"name": "France",
"code": "fr"
},
"company": "Rapid Trading Intl",
"date": "2018-12-25",
"status": "unqualified",
"activity": 100,
"representative": {
"name": "Anna Fali",
"image": "annafali.png"
}
},
{
"id": 1043,
"name": "Lavera Perin",
"country": {
"name": "Vietnam",
"code": "vn"
},
"company": "Abc Enterprises Inc",
"date": "2018-04-10",
"status": "qualified",
"activity": 71,
"representative": {
"name": "Stephen Shaw",
"image": "stephenshaw.png"
}
},
{
"id": 1044,
"name": "Erick Ferencz",
"country": {
"name": "Belgium",
"code": "be"
},
"company": "Cindy Turner Associates",
"date": "2018-05-06",
"status": "unqualified",
"activity": 54,
"representative": {
"name": "Amy Elsner",
"image": "amyelsner.png"
}
},
{
"id": 1045,
"name": "Fatima Saylors",
"country": {
"name": "Canada",
"code": "ca"
},
"company": "Stanton, James D Esq",
"date": "2019-07-10",
"status": "renewal",
"activity": 93,
"representative": {
"name": "Onyama Limba",
"image": "onyamalimba.png"
}
},
{
"id": 1046,
"name": "Jina Briddick",
"country": {
"name": "Mexico",
"code": "mx"
},
"company": "Grace Pastries Inc",
"date": "2018-02-19",
"status": "unqualified",
"activity": 97,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1047,
"name": "Kanisha Waycott",
"country": {
"name": "Ecuador",
"code": "ec"
},
"company": "Schroer, Gene E Esq",
"date": "2019-11-27",
"status": "new",
"activity": 80,
"representative": {
"name": "Xuxue Feng",
"image": "xuxuefeng.png"
}
},
{
"id": 1048,
"name": "Emerson Bowley",
"country": {
"name": "Finland",
"code": "fi"
},
"company": "Knights Inn",
"date": "2018-11-24",
"status": "new",
"activity": 63,
"representative": {
"name": "Stephen Shaw",
"image": "stephenshaw.png"
}
},
{
"id": 1049,
"name": "Blair Malet",
"country": {
"name": "Finland",
"code": "fi"
},
"company": "Bollinger Mach Shp \u0026 Shipyard",
"date": "2018-04-19",
"status": "new",
"activity": 92,
"representative": {
"name": "Asiya Javayant",
"image": "asiyajavayant.png"
}
}
]
}
================================================
FILE: public/demo/data/events.json
================================================
{
"data": [
{
"id": 1,
"title": "All Day Event",
"start": "2021-01-03"
},
{
"id": 2,
"title": "Long Event",
"start": "2021-01-09",
"end": "2021-01-12"
},
{
"id": 3,
"title": "Repeating Event",
"start": "2021-01-11T16:00:00"
},
{
"id": 4,
"title": "Repeating Event",
"start": "2021-01-18T16:00:00"
},
{
"id": 5,
"title": "Conference",
"start": "2021-01-13",
"end": "2021-01-15"
},
{
"id": 6,
"title": "Meeting",
"start": "2021-01-14T10:30:00",
"end": "2021-01-14T12:30:00"
},
{
"id": 7,
"title": "Lunch",
"start": "2021-01-14T12:00:00"
},
{
"id": 8,
"title": "Meeting",
"start": "2021-01-14T14:30:00"
},
{
"id": 9,
"title": "Happy Hour",
"start": "2021-01-14T17:30:00"
},
{
"id": 10,
"title": "Dinner",
"start": "2021-01-14T20:00:00"
},
{
"id": 11,
"title": "Birthday Party",
"start": "2021-01-15T07:00:00"
},
{
"id": 12,
"title": "Click for Google",
"url": "http://google.com/",
"start": "2021-01-30"
}
]
}
================================================
FILE: public/demo/data/photos.json
================================================
{
"data":[
{
"itemImageSrc": "/demo/images/galleria/galleria1.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria1s.jpg",
"alt": "Description for Image 1",
"title": "Title 1"
},
{
"itemImageSrc": "/demo/images/galleria/galleria2.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria2s.jpg",
"alt": "Description for Image 2",
"title": "Title 2"
},
{
"itemImageSrc": "/demo/images/galleria/galleria3.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria3s.jpg",
"alt": "Description for Image 3",
"title": "Title 3"
},
{
"itemImageSrc": "/demo/images/galleria/galleria4.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria4s.jpg",
"alt": "Description for Image 4",
"title": "Title 4"
},
{
"itemImageSrc": "/demo/images/galleria/galleria5.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria5s.jpg",
"alt": "Description for Image 5",
"title": "Title 5"
},
{
"itemImageSrc": "/demo/images/galleria/galleria6.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria6s.jpg",
"alt": "Description for Image 6",
"title": "Title 6"
},
{
"itemImageSrc": "/demo/images/galleria/galleria7.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria7s.jpg",
"alt": "Description for Image 7",
"title": "Title 7"
},
{
"itemImageSrc": "/demo/images/galleria/galleria8.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria8s.jpg",
"alt": "Description for Image 8",
"title": "Title 8"
},
{
"itemImageSrc": "/demo/images/galleria/galleria9.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria9s.jpg",
"alt": "Description for Image 9",
"title": "Title 9"
},
{
"itemImageSrc": "/demo/images/galleria/galleria10.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria10s.jpg",
"alt": "Description for Image 10",
"title": "Title 10"
},
{
"itemImageSrc": "/demo/images/galleria/galleria11.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria11s.jpg",
"alt": "Description for Image 11",
"title": "Title 11"
},
{
"itemImageSrc": "/demo/images/galleria/galleria12.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria12s.jpg",
"alt": "Description for Image 12",
"title": "Title 12"
},
{
"itemImageSrc": "/demo/images/galleria/galleria13.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria13s.jpg",
"alt": "Description for Image 13",
"title": "Title 13"
},
{
"itemImageSrc": "/demo/images/galleria/galleria14.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria14s.jpg",
"alt": "Description for Image 14",
"title": "Title 14"
},
{
"itemImageSrc": "/demo/images/galleria/galleria15.jpg",
"thumbnailImageSrc": "/demo/images/galleria/galleria15s.jpg",
"alt": "Description for Image 15",
"title": "Title 15"
}
]
}
================================================
FILE: public/demo/data/products-orders-small.json
================================================
{
"data": [
{
"id": "1000",
"code": "f230fh0g3",
"name": "Bamboo Watch",
"description": "Product Description",
"image": "bamboo-watch.jpg",
"price": 65,
"category": "Accessories",
"quantity": 24,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": [
{
"id": "1000",
"productCode": "f230fh0g3",
"date": "2020-09-13",
"amount": 65,
"quantity": 1,
"customer": "David James",
"status": "PENDING"
},
{
"id": "1001",
"productCode": "f230fh0g3",
"date": "2020-05-14",
"amount": 130,
"quantity": 2,
"customer": "Leon Rodrigues",
"status": "DELIVERED"
},
{
"id": "1002",
"productCode": "f230fh0g3",
"date": "2019-01-04",
"amount": 65,
"quantity": 1,
"customer": "Juan Alejandro",
"status": "RETURNED"
},
{
"id": "1003",
"productCode": "f230fh0g3",
"date": "2020-09-13",
"amount": 195,
"quantity": 3,
"customer": "Claire Morrow",
"status": "CANCELLED"
}
]
},
{
"id": "1001",
"code": "nvklal433",
"name": "Black Watch",
"description": "Product Description",
"image": "black-watch.jpg",
"price": 72,
"category": "Accessories",
"quantity": 61,
"inventoryStatus": "INSTOCK",
"rating": 4,
"orders": [
{
"id": "2000",
"productCode": "nvklal433",
"date": "2020-05-14",
"amount": 72,
"quantity": 1,
"customer": "Maisha Jefferson",
"status": "DELIVERED"
},
{
"id": "2001",
"productCode": "nvklal433",
"date": "2020-02-28",
"amount": 144,
"quantity": 2,
"customer": "Octavia Murillo",
"status": "PENDING"
}
]
},
{
"id": "1002",
"code": "zz21cz3c1",
"name": "Blue Band",
"description": "Product Description",
"image": "blue-band.jpg",
"price": 79,
"category": "Fitness",
"quantity": 2,
"inventoryStatus": "LOWSTOCK",
"rating": 3,
"orders": [
{
"id": "3000",
"productCode": "zz21cz3c1",
"date": "2020-07-05",
"amount": 79,
"quantity": 1,
"customer": "Stacey Leja",
"status": "DELIVERED"
},
{
"id": "3001",
"productCode": "zz21cz3c1",
"date": "2020-02-06",
"amount": 79,
"quantity": 1,
"customer": "Ashley Wickens",
"status": "DELIVERED"
}
]
},
{
"id": "1003",
"code": "244wgerg2",
"name": "Blue T-Shirt",
"description": "Product Description",
"image": "blue-t-shirt.jpg",
"price": 29,
"category": "Clothing",
"quantity": 25,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": []
},
{
"id": "1004",
"code": "h456wer53",
"name": "Bracelet",
"description": "Product Description",
"image": "bracelet.jpg",
"price": 15,
"category": "Accessories",
"quantity": 73,
"inventoryStatus": "INSTOCK",
"rating": 4,
"orders": [
{
"id": "5000",
"productCode": "h456wer53",
"date": "2020-09-05",
"amount": 60,
"quantity": 4,
"customer": "Mayumi Misaki",
"status": "PENDING"
},
{
"id": "5001",
"productCode": "h456wer53",
"date": "2019-04-16",
"amount": 2,
"quantity": 30,
"customer": "Francesco Salvatore",
"status": "DELIVERED"
}
]
},
{
"id": "1005",
"code": "av2231fwg",
"name": "Brown Purse",
"description": "Product Description",
"image": "brown-purse.jpg",
"price": 120,
"category": "Accessories",
"quantity": 0,
"inventoryStatus": "OUTOFSTOCK",
"rating": 4,
"orders": [
{
"id": "6000",
"productCode": "av2231fwg",
"date": "2020-01-25",
"amount": 120,
"quantity": 1,
"customer": "Isabel Sinclair",
"status": "RETURNED"
},
{
"id": "6001",
"productCode": "av2231fwg",
"date": "2019-03-12",
"amount": 240,
"quantity": 2,
"customer": "Lionel Clifford",
"status": "DELIVERED"
},
{
"id": "6002",
"productCode": "av2231fwg",
"date": "2019-05-05",
"amount": 120,
"quantity": 1,
"customer": "Cody Chavez",
"status": "DELIVERED"
}
]
},
{
"id": "1006",
"code": "bib36pfvm",
"name": "Chakra Bracelet",
"description": "Product Description",
"image": "chakra-bracelet.jpg",
"price": 32,
"category": "Accessories",
"quantity": 5,
"inventoryStatus": "LOWSTOCK",
"rating": 3,
"orders": [
{
"id": "7000",
"productCode": "bib36pfvm",
"date": "2020-02-24",
"amount": 32,
"quantity": 1,
"customer": "Arvin Darci",
"status": "DELIVERED"
},
{
"id": "7001",
"productCode": "bib36pfvm",
"date": "2020-01-14",
"amount": 64,
"quantity": 2,
"customer": "Izzy Jones",
"status": "PENDING"
}
]
},
{
"id": "1007",
"code": "mbvjkgip5",
"name": "Galaxy Earrings",
"description": "Product Description",
"image": "galaxy-earrings.jpg",
"price": 34,
"category": "Accessories",
"quantity": 23,
"inventoryStatus": "INSTOCK",
"rating": 5,
"orders": [
{
"id": "8000",
"productCode": "mbvjkgip5",
"date": "2020-06-19",
"amount": 34,
"quantity": 1,
"customer": "Jennifer Smith",
"status": "DELIVERED"
}
]
},
{
"id": "1008",
"code": "vbb124btr",
"name": "Game Controller",
"description": "Product Description",
"image": "game-controller.jpg",
"price": 99,
"category": "Electronics",
"quantity": 2,
"inventoryStatus": "LOWSTOCK",
"rating": 4,
"orders": [
{
"id": "9000",
"productCode": "vbb124btr",
"date": "2020-01-05",
"amount": 99,
"quantity": 1,
"customer": "Jeanfrancois David",
"status": "DELIVERED"
},
{
"id": "9001",
"productCode": "vbb124btr",
"date": "2020-01-19",
"amount": 198,
"quantity": 2,
"customer": "Ivar Greenwood",
"status": "RETURNED"
}
]
},
{
"id": "1009",
"code": "cm230f032",
"name": "Gaming Set",
"description": "Product Description",
"image": "gaming-set.jpg",
"price": 299,
"category": "Electronics",
"quantity": 63,
"inventoryStatus": "INSTOCK",
"rating": 3,
"orders": [
{
"id": "10000",
"productCode": "cm230f032",
"date": "2020-06-24",
"amount": 299,
"quantity": 1,
"customer": "Kadeem Mujtaba",
"status": "PENDING"
},
{
"id": "10001",
"productCode": "cm230f032",
"date": "2020-05-11",
"amount": 299,
"quantity": 1,
"customer": "Ashley Wickens",
"status": "DELIVERED"
},
{
"id": "10002",
"productCode": "cm230f032",
"date": "2019-02-07",
"amount": 299,
"quantity": 1,
"customer": "Julie Johnson",
"status": "DELIVERED"
},
{
"id": "10003",
"productCode": "cm230f032",
"date": "2020-04-26",
"amount": 299,
"quantity": 1,
"customer": "Tony Costa",
"status": "CANCELLED"
}
]
}
]
}
================================================
FILE: public/demo/data/products-small.json
================================================
{
"data": [
{"id": "1000","code": "f230fh0g3","name": "Bamboo Watch","description": "Product Description","image": "bamboo-watch.jpg","price": 65,"category": "Accessories","quantity": 24,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1001","code": "nvklal433","name": "Black Watch","description": "Product Description","image": "black-watch.jpg","price": 72,"category": "Accessories","quantity": 61,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1002","code": "zz21cz3c1","name": "Blue Band","description": "Product Description","image": "blue-band.jpg","price": 79,"category": "Fitness","quantity": 2,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1003","code": "244wgerg2","name": "Blue T-Shirt","description": "Product Description","image": "blue-t-shirt.jpg","price": 29,"category": "Clothing","quantity": 25,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1004","code": "h456wer53","name": "Bracelet","description": "Product Description","image": "bracelet.jpg","price": 15,"category": "Accessories","quantity": 73,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1005","code": "av2231fwg","name": "Brown Purse","description": "Product Description","image": "brown-purse.jpg","price": 120,"category": "Accessories","quantity": 0,"inventoryStatus": "OUTOFSTOCK","rating": 4},
{"id": "1006","code": "bib36pfvm","name": "Chakra Bracelet","description": "Product Description","image": "chakra-bracelet.jpg","price": 32,"category": "Accessories","quantity": 5,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1007","code": "mbvjkgip5","name": "Galaxy Earrings","description": "Product Description","image": "galaxy-earrings.jpg","price": 34,"category": "Accessories","quantity": 23,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1008","code": "vbb124btr","name": "Game Controller","description": "Product Description","image": "game-controller.jpg","price": 99,"category": "Electronics","quantity": 2,"inventoryStatus": "LOWSTOCK","rating": 4},
{"id": "1009","code": "cm230f032","name": "Gaming Set","description": "Product Description","image": "gaming-set.jpg","price": 299,"category": "Electronics","quantity": 63,"inventoryStatus": "INSTOCK","rating": 3}
]
}
================================================
FILE: public/demo/data/products.json
================================================
{
"data": [
{"id": "1000","code": "f230fh0g3","name": "Bamboo Watch","description": "Product Description","image": "bamboo-watch.jpg","price": 65,"category": "Accessories","quantity": 24,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1001","code": "nvklal433","name": "Black Watch","description": "Product Description","image": "black-watch.jpg","price": 72,"category": "Accessories","quantity": 61,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1002","code": "zz21cz3c1","name": "Blue Band","description": "Product Description","image": "blue-band.jpg","price": 79,"category": "Fitness","quantity": 2,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1003","code": "244wgerg2","name": "Blue T-Shirt","description": "Product Description","image": "blue-t-shirt.jpg","price": 29,"category": "Clothing","quantity": 25,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1004","code": "h456wer53","name": "Bracelet","description": "Product Description","image": "bracelet.jpg","price": 15,"category": "Accessories","quantity": 73,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1005","code": "av2231fwg","name": "Brown Purse","description": "Product Description","image": "brown-purse.jpg","price": 120,"category": "Accessories","quantity": 0,"inventoryStatus": "OUTOFSTOCK","rating": 4},
{"id": "1006","code": "bib36pfvm","name": "Chakra Bracelet","description": "Product Description","image": "chakra-bracelet.jpg","price": 32,"category": "Accessories","quantity": 5,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1007","code": "mbvjkgip5","name": "Galaxy Earrings","description": "Product Description","image": "galaxy-earrings.jpg","price": 34,"category": "Accessories","quantity": 23,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1008","code": "vbb124btr","name": "Game Controller","description": "Product Description","image": "game-controller.jpg","price": 99,"category": "Electronics","quantity": 2,"inventoryStatus": "LOWSTOCK","rating": 4},
{"id": "1009","code": "cm230f032","name": "Gaming Set","description": "Product Description","image": "gaming-set.jpg","price": 299,"category": "Electronics","quantity": 63,"inventoryStatus": "INSTOCK","rating": 3},
{"id": "1010","code": "plb34234v","name": "Gold Phone Case","description": "Product Description","image": "gold-phone-case.jpg","price": 24,"category": "Accessories","quantity": 0,"inventoryStatus": "OUTOFSTOCK","rating": 4},
{"id": "1011","code": "4920nnc2d","name": "Green Earbuds","description": "Product Description","image": "green-earbuds.jpg","price": 89,"category": "Electronics","quantity": 23,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1012","code": "250vm23cc","name": "Green T-Shirt","description": "Product Description","image": "green-t-shirt.jpg","price": 49,"category": "Clothing","quantity": 74,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1013","code": "fldsmn31b","name": "Grey T-Shirt","description": "Product Description","image": "grey-t-shirt.jpg","price": 48,"category": "Clothing","quantity": 0,"inventoryStatus": "OUTOFSTOCK","rating": 3},
{"id": "1014","code": "waas1x2as","name": "Headphones","description": "Product Description","image": "headphones.jpg","price": 175,"category": "Electronics","quantity": 8,"inventoryStatus": "LOWSTOCK","rating": 5},
{"id": "1015","code": "vb34btbg5","name": "Light Green T-Shirt","description": "Product Description","image": "light-green-t-shirt.jpg","price": 49,"category": "Clothing","quantity": 34,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1016","code": "k8l6j58jl","name": "Lime Band","description": "Product Description","image": "lime-band.jpg","price": 79,"category": "Fitness","quantity": 12,"inventoryStatus": "INSTOCK","rating": 3},
{"id": "1017","code": "v435nn85n","name": "Mini Speakers","description": "Product Description","image": "mini-speakers.jpg","price": 85,"category": "Clothing","quantity": 42,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1018","code": "09zx9c0zc","name": "Painted Phone Case","description": "Product Description","image": "painted-phone-case.jpg","price": 56,"category": "Accessories","quantity": 41,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1019","code": "mnb5mb2m5","name": "Pink Band","description": "Product Description","image": "pink-band.jpg","price": 79,"category": "Fitness","quantity": 63,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1020","code": "r23fwf2w3","name": "Pink Purse","description": "Product Description","image": "pink-purse.jpg","price": 110,"category": "Accessories","quantity": 0,"inventoryStatus": "OUTOFSTOCK","rating": 4},
{"id": "1021","code": "pxpzczo23","name": "Purple Band","description": "Product Description","image": "purple-band.jpg","price": 79,"category": "Fitness","quantity": 6,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1022","code": "2c42cb5cb","name": "Purple Gemstone Necklace","description": "Product Description","image": "purple-gemstone-necklace.jpg","price": 45,"category": "Accessories","quantity": 62,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1023","code": "5k43kkk23","name": "Purple T-Shirt","description": "Product Description","image": "purple-t-shirt.jpg","price": 49,"category": "Clothing","quantity": 2,"inventoryStatus": "LOWSTOCK","rating": 5},
{"id": "1024","code": "lm2tny2k4","name": "Shoes","description": "Product Description","image": "shoes.jpg","price": 64,"category": "Clothing","quantity": 0,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1025","code": "nbm5mv45n","name": "Sneakers","description": "Product Description","image": "sneakers.jpg","price": 78,"category": "Clothing","quantity": 52,"inventoryStatus": "INSTOCK","rating": 4},
{"id": "1026","code": "zx23zc42c","name": "Teal T-Shirt","description": "Product Description","image": "teal-t-shirt.jpg","price": 49,"category": "Clothing","quantity": 3,"inventoryStatus": "LOWSTOCK","rating": 3},
{"id": "1027","code": "acvx872gc","name": "Yellow Earbuds","description": "Product Description","image": "yellow-earbuds.jpg","price": 89,"category": "Electronics","quantity": 35,"inventoryStatus": "INSTOCK","rating": 3},
{"id": "1028","code": "tx125ck42","name": "Yoga Mat","description": "Product Description","image": "yoga-mat.jpg","price": 20,"category": "Fitness","quantity": 15,"inventoryStatus": "INSTOCK","rating": 5},
{"id": "1029","code": "gwuby345v","name": "Yoga Set","description": "Product Description","image": "yoga-set.jpg","price": 20,"category": "Fitness","quantity": 25,"inventoryStatus": "INSTOCK","rating": 8}
]
}
================================================
FILE: public/demo/data/treenodes.json
================================================
{
"root": [
{
"key": "0",
"label": "Documents",
"data": "Documents Folder",
"icon": "pi pi-fw pi-inbox",
"children": [{
"key": "0-0",
"label": "Work",
"data": "Work Folder",
"icon": "pi pi-fw pi-cog",
"children": [{ "key": "0-0-0", "label": "Expenses.doc", "icon": "pi pi-fw pi-file", "data": "Expenses Document" }, { "key": "0-0-1", "label": "Resume.doc", "icon": "pi pi-fw pi-file", "data": "Resume Document" }]
},
{
"key": "0-1",
"label": "Home",
"data": "Home Folder",
"icon": "pi pi-fw pi-home",
"children": [{ "key": "0-1-0", "label": "Invoices.txt", "icon": "pi pi-fw pi-file", "data": "Invoices for this month" }]
}]
},
{
"key": "1",
"label": "Events",
"data": "Events Folder",
"icon": "pi pi-fw pi-calendar",
"children": [
{ "key": "1-0", "label": "Meeting", "icon": "pi pi-fw pi-calendar-plus", "data": "Meeting" },
{ "key": "1-1", "label": "Product Launch", "icon": "pi pi-fw pi-calendar-plus", "data": "Product Launch" },
{ "key": "1-2", "label": "Report Review", "icon": "pi pi-fw pi-calendar-plus", "data": "Report Review" }]
},
{
"key": "2",
"label": "Movies",
"data": "Movies Folder",
"icon": "pi pi-fw pi-star",
"children": [{
"key": "2-0",
"icon": "pi pi-fw pi-star",
"label": "Al Pacino",
"data": "Pacino Movies",
"children": [{ "key": "2-0-0", "label": "Scarface", "icon": "pi pi-fw pi-video", "data": "Scarface Movie" }, { "key": "2-0-1", "label": "Serpico", "icon": "pi pi-fw pi-video", "data": "Serpico Movie" }]
},
{
"key": "2-1",
"label": "Robert De Niro",
"icon": "pi pi-fw pi-star",
"data": "De Niro Movies",
"children": [{ "key": "2-1-0", "label": "Goodfellas", "icon": "pi pi-fw pi-video", "data": "Goodfellas Movie" }, { "key": "2-1-1", "label": "Untouchables", "icon": "pi pi-fw pi-video", "data": "Untouchables Movie" }]
}]
}
]
}
================================================
FILE: public/demo/data/treetablenodes.json
================================================
{
"root":
[
{
"key": "0",
"data":{
"name":"Applications",
"size":"100kb",
"type":"Folder"
},
"children":[
{
"key": "0-0",
"data":{
"name":"Vue",
"size":"25kb",
"type":"Folder"
},
"children":[
{
"key": "0-0-0",
"data":{
"name":"vue.app",
"size":"10kb",
"type":"Application"
}
},
{
"key": "0-0-1",
"data":{
"name":"native.app",
"size":"10kb",
"type":"Application"
}
},
{
"key": "0-0-2",
"data":{
"name":"mobile.app",
"size":"5kb",
"type":"Application"
}
}
]
},
{
"key": "0-1",
"data":{
"name":"editor.app",
"size":"25kb",
"type":"Application"
}
},
{
"key": "0-2",
"data":{
"name":"settings.app",
"size":"50kb",
"type":"Application"
}
}
]
},
{
"key": "1",
"data":{
"name":"Cloud",
"size":"20kb",
"type":"Folder"
},
"children":[
{
"key": "1-0",
"data":{
"name":"backup-1.zip",
"size":"10kb",
"type":"Zip"
}
},
{
"key": "1-1",
"data":{
"name":"backup-2.zip",
"size":"10kb",
"type":"Zip"
}
}
]
},
{
"key": "2",
"data": {
"name":"Desktop",
"size":"150kb",
"type":"Folder"
},
"children":[
{
"key": "2-0",
"data":{
"name":"note-meeting.txt",
"size":"50kb",
"type":"Text"
}
},
{
"key": "2-1",
"data":{
"name":"note-todo.txt",
"size":"100kb",
"type":"Text"
}
}
]
},
{
"key": "3",
"data":{
"name":"Documents",
"size":"75kb",
"type":"Folder"
},
"children":[
{
"key": "3-0",
"data":{
"name":"Work",
"size":"55kb",
"type":"Folder"
},
"children":[
{
"key": "3-0-0",
"data":{
"name":"Expenses.doc",
"size":"30kb",
"type":"Document"
}
},
{
"key": "3-0-1",
"data":{
"name":"Resume.doc",
"size":"25kb",
"type":"Resume"
}
}
]
},
{
"key": "3-1",
"data":{
"name":"Home",
"size":"20kb",
"type":"Folder"
},
"children":[
{
"key": "3-1-0",
"data":{
"name":"Invoices",
"size":"20kb",
"type":"Text"
}
}
]
}
]
},
{
"key": "4",
"data": {
"name":"Downloads",
"size":"25kb",
"type":"Folder"
},
"children":[
{
"key": "4-0",
"data": {
"name":"Spanish",
"size":"10kb",
"type":"Folder"
},
"children":[
{
"key": "4-0-0",
"data":{
"name":"tutorial-a1.txt",
"size":"5kb",
"type":"Text"
}
},
{
"key": "4-0-1",
"data":{
"name":"tutorial-a2.txt",
"size":"5kb",
"type":"Text"
}
}
]
},
{
"key": "4-1",
"data":{
"name":"Travel",
"size":"15kb",
"type":"Text"
},
"children":[
{
"key": "4-1-0",
"data":{
"name":"Hotel.pdf",
"size":"10kb",
"type":"PDF"
}
},
{
"key": "4-1-1",
"data":{
"name":"Flight.pdf",
"size":"5kb",
"type":"PDF"
}
}
]
}
]
},
{
"key": "5",
"data": {
"name":"Main",
"size":"50kb",
"type":"Folder"
},
"children":[
{
"key": "5-0",
"data":{
"name":"bin",
"size":"50kb",
"type":"Link"
}
},
{
"key": "5-1",
"data":{
"name":"etc",
"size":"100kb",
"type":"Link"
}
},
{
"key": "5-2",
"data":{
"name":"var",
"size":"100kb",
"type":"Link"
}
}
]
},
{
"key": "6",
"data":{
"name":"Other",
"size":"5kb",
"type":"Folder"
},
"children":[
{
"key": "6-0",
"data":{
"name":"todo.txt",
"size":"3kb",
"type":"Text"
}
},
{
"key": "6-1",
"data":{
"name":"logo.png",
"size":"2kb",
"type":"Picture"
}
}
]
},
{
"key": "7",
"data":{
"name":"Pictures",
"size":"150kb",
"type":"Folder"
},
"children":[
{
"key": "7-0",
"data":{
"name":"barcelona.jpg",
"size":"90kb",
"type":"Picture"
}
},
{
"key": "7-1",
"data":{
"name":"primeng.png",
"size":"30kb",
"type":"Picture"
}
},
{
"key": "7-2",
"data":{
"name":"prime.jpg",
"size":"30kb",
"type":"Picture"
}
}
]
},
{
"key": "8",
"data":{
"name":"Videos",
"size":"1500kb",
"type":"Folder"
},
"children":[
{
"key": "8-0",
"data":{
"name":"primefaces.mkv",
"size":"1000kb",
"type":"Video"
}
},
{
"key": "8-1",
"data":{
"name":"intro.avi",
"size":"500kb",
"type":"Video"
}
}
]
}
]
}
================================================
FILE: src/App.vue
================================================
<script setup></script>
<template>
<router-view />
</template>
<style scoped></style>
================================================
FILE: src/main.js
================================================
import { createApp } from 'vue';
import App from './App.vue';
import router from './router';
import Aura from '@primeuix/themes/aura';
import PrimeVue from 'primevue/config';
import ConfirmationService from 'primevue/confirmationservice';
import ToastService from 'primevue/toastservice';
import '@/assets/tailwind.css';
import '@/assets/styles.scss';
const app = createApp(App);
app.use(router);
app.use(PrimeVue, {
theme: {
preset: Aura,
options: {
darkModeSelector: '.app-dark'
}
}
});
app.use(ToastService);
app.use(ConfirmationService);
app.mount('#app');
================================================
FILE: src/components/BlockViewer.vue
================================================
<script setup>
import { reactive, ref } from 'vue';
const props = defineProps({
header: {
type: String,
default: null
},
code: null,
recent: {
type: Boolean,
default: false
},
free: {
type: Boolean,
default: false
},
containerClass: null,
previewStyle: null
});
const BlockView = reactive({
PREVIEW: 0,
CODE: 1
});
const blockView = ref(0);
const codeCopied = ref(false);
const codeCopyLoading = ref(false);
function activateView(event, blockViewValue) {
blockView.value = blockViewValue;
event.preventDefault();
}
async function copyCode(event) {
if (codeCopied.value || codeCopyLoading.value) return;
codeCopyLoading.value = true;
event.preventDefault();
try {
await navigator.clipboard.writeText(props.code);
codeCopyLoading.value = false;
codeCopied.value = true;
setTimeout(() => {
codeCopied.value = false;
}, 2000);
} catch (err) {
console.error('Clipboard write failed:', err);
codeCopyLoading.value = false;
}
}
</script>
<template>
<div class="mb-16 overflow-hidden">
<div class="flex flex-col lg:flex-row justify-between py-4 gap-4 lg:gap-2 px-0!">
<div class="flex items-center gap-2">
<span class="font-medium text-xl">{{ header }}</span>
<span v-if="free" class="flex items-center justify-center px-1.5 py-1 w-fit bg-emerald-500 text-emerald-100 dark:bg-emerald-400 dark:text-emerald-800 rounded-md leading-none! text-xs md:text-sm">Free</span>
</div>
<div class="flex items-center gap-2">
<!-- Preview/Code Toggle -->
<div class="inline-flex border border-surface-200 dark:border-surface-700 rounded-2xl overflow-hidden min-h-10">
<button
:class="[
'min-w-28 flex items-center gap-1 justify-center px-4 py-2 rounded-2xl transition-all duration-200 font-medium cursor-pointer ',
blockView === BlockView.CODE ? 'bg-primary text-primary-contrast ' : 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-0'
]"
@click="activateView($event, BlockView.CODE)"
>
<span>Code</span>
</button>
<button
:class="[
'min-w-28 flex items-center gap-1 justify-center px-4 py-2 rounded-2xl transition-all duration-200 font-medium cursor-pointer',
blockView === BlockView.PREVIEW ? 'bg-primary text-primary-contrast ' : 'text-surface-600 dark:text-surface-400 hover:text-surface-900 dark:hover:text-surface-0'
]"
@click="activateView($event, BlockView.PREVIEW)"
>
<span>Preview</span>
</button>
</div>
<!-- Separator -->
<div class="h-6 w-px bg-surface-200 dark:bg-surface-700 hidden lg:block"></div>
<!-- Animated Copy Button -->
<div class="flex items-center gap-2 grow lg:grow-0 justify-end lg:justify-start">
<button
@click="copyCode($event)"
:disabled="codeCopyLoading"
class="relative w-10 h-10 border border-surface-200 dark:border-surface-700 rounded-full hover:bg-surface-100 dark:hover:bg-surface-800 transition-all focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-primary focus-visible:ring-offset-2 focus-visible:ring-offset-surface-0 dark:focus-visible:ring-offset-surface-900 cursor-pointer disabled:cursor-wait"
>
<!-- Loading Spinner -->
<span :class="['absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transition-all duration-300 leading-none', codeCopyLoading ? 'opacity-100 scale-100 z-10' : 'opacity-0 scale-50 -z-[2]']">
<i class="pi pi-spinner animate-spin text-surface-700 dark:text-surface-300" style="font-size: 1.25rem"></i>
</span>
<!-- Checkmark Icon -->
<span :class="['absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transition-all duration-300 leading-none', codeCopied && !codeCopyLoading ? 'opacity-100 scale-100 z-10' : 'opacity-0 scale-50 -z-[2]']">
<svg class="w-5 h-5 fill-green-600 dark:fill-green-400" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g id="check">
<path d="M9,18.25A.74.74,0,0,1,8.47,18l-5-5A.75.75,0,1,1,4.53,12L9,16.44,19.47,6A.75.75,0,0,1,20.53,7l-11,11A.74.74,0,0,1,9,18.25Z"></path>
</g>
</svg>
</span>
<!-- Copy Icon -->
<span :class="['absolute top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 transition-all duration-300 leading-none', !codeCopied && !codeCopyLoading ? 'opacity-100 scale-100 z-10' : 'opacity-0 scale-50 -z-[2]']">
<svg class="w-5 h-5 fill-surface-700 dark:fill-surface-300" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24">
<g id="clone">
<path
d="M14,16.75H6A2.75,2.75,0,0,1,3.25,14V6A2.75,2.75,0,0,1,6,3.25h8A2.75,2.75,0,0,1,16.75,6v8A2.75,2.75,0,0,1,14,16.75Zm-8-12A1.25,1.25,0,0,0,4.75,6v8A1.25,1.25,0,0,0,6,15.25h8A1.25,1.25,0,0,0,15.25,14V6A1.25,1.25,0,0,0,14,4.75Z"
></path>
<path d="M18,20.75H10A2.75,2.75,0,0,1,7.25,18V16h1.5v2A1.25,1.25,0,0,0,10,19.25h8A1.25,1.25,0,0,0,19.25,18V10A1.25,1.25,0,0,0,18,8.75H16V7.25h2A2.75,2.75,0,0,1,20.75,10v8A2.75,2.75,0,0,1,18,20.75Z"></path>
</g>
</svg>
</span>
</button>
</div>
</div>
</div>
<div class="p-0 border border-surface-200 dark:border-surface-700 rounded-xl overflow-hidden">
<div :class="containerClass" :style="previewStyle" v-if="blockView == BlockView.PREVIEW">
<slot />
</div>
<div v-if="blockView === BlockView.CODE">
<pre class="app-code"><code>{{code}}</code></pre>
</div>
</div>
</div>
</template>
<style scoped lang="scss">
pre {
border: 0 none !important;
border-radius: 0 !important;
.app-code {
background: var(--p-surface-900) !important;
margin: 0 !important;
border: 0 none !important;
&:before,
&:after {
display: none !important;
}
code {
color: var(--p-surface-50);
padding: 1rem;
line-height: 1.5;
display: block;
font-family: monaco, Consolas, monospace;
}
}
}
</style>
================================================
FILE: src/components/FloatingConfigurator.vue
================================================
<script setup>
import AppConfigurator from '@/layout/AppConfigurator.vue';
import { useLayout } from '@/layout/composables/layout';
const { toggleDarkMode, isDarkTheme } = useLayout();
</script>
<template>
<div class="fixed flex gap-4 top-8 right-8">
<Button type="button" @click="toggleDarkMode" rounded :icon="isDarkTheme ? 'pi pi-moon' : 'pi pi-sun'" severity="secondary" />
<div class="relative">
<Button
icon="pi pi-palette"
v-styleclass="{ selector: '@next', enterFromClass: 'hidden', enterActiveClass: 'animate-scalein', leaveToClass: 'hidden', leaveActiveClass: 'animate-fadeout', hideOnOutsideClick: true }"
type="button"
rounded
/>
<AppConfigurator />
</div>
</div>
</template>
================================================
FILE: src/components/dashboard/BestSellingWidget.vue
================================================
<script setup>
import { ref } from 'vue';
const menu = ref(null);
const items = ref([
{ label: 'Add New', icon: 'pi pi-fw pi-plus' },
{ label: 'Remove', icon: 'pi pi-fw pi-trash' }
]);
</script>
<template>
<div class="card">
<div class="flex justify-between items-center mb-6">
<div class="font-semibold text-xl">Best Selling Products</div>
<div>
<Button icon="pi pi-ellipsis-v" class="p-button-text p-button-plain p-button-rounded" @click="$refs.menu.toggle($event)"></Button>
<Menu ref="menu" popup :model="items" class="min-w-40!"></Menu>
</div>
</div>
<ul class="list-none p-0 m-0">
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Space T-Shirt</span>
<div class="mt-1 text-muted-color">Clothing</div>
</div>
<div class="mt-2 md:mt-0 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-orange-500 h-full" style="width: 50%"></div>
</div>
<span class="text-orange-500 ml-4 font-medium">%50</span>
</div>
</li>
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Portal Sticker</span>
<div class="mt-1 text-muted-color">Accessories</div>
</div>
<div class="mt-2 md:mt-0 ml-0 md:ml-20 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-cyan-500 h-full" style="width: 16%"></div>
</div>
<span class="text-cyan-500 ml-4 font-medium">%16</span>
</div>
</li>
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Supernova Sticker</span>
<div class="mt-1 text-muted-color">Accessories</div>
</div>
<div class="mt-2 md:mt-0 ml-0 md:ml-20 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-pink-500 h-full" style="width: 67%"></div>
</div>
<span class="text-pink-500 ml-4 font-medium">%67</span>
</div>
</li>
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Wonders Notebook</span>
<div class="mt-1 text-muted-color">Office</div>
</div>
<div class="mt-2 md:mt-0 ml-0 md:ml-20 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-green-500 h-full" style="width: 35%"></div>
</div>
<span class="text-primary ml-4 font-medium">%35</span>
</div>
</li>
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Mat Black Case</span>
<div class="mt-1 text-muted-color">Accessories</div>
</div>
<div class="mt-2 md:mt-0 ml-0 md:ml-20 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-purple-500 h-full" style="width: 75%"></div>
</div>
<span class="text-purple-500 ml-4 font-medium">%75</span>
</div>
</li>
<li class="flex flex-col md:flex-row md:items-center md:justify-between mb-6">
<div>
<span class="text-surface-900 dark:text-surface-0 font-medium mr-2 mb-1 md:mb-0">Robots T-Shirt</span>
<div class="mt-1 text-muted-color">Clothing</div>
</div>
<div class="mt-2 md:mt-0 ml-0 md:ml-20 flex items-center">
<div class="bg-surface-300 dark:bg-surface-500 rounded-border overflow-hidden w-40 lg:w-24" style="height: 8px">
<div class="bg-teal-500 h-full" style="width: 40%"></div>
</div>
<span class="text-teal-500 ml-4 font-medium">%40</span>
</div>
</li>
</ul>
</div>
</template>
================================================
FILE: src/components/dashboard/NotificationsWidget.vue
================================================
<script setup>
import { ref } from 'vue';
const menu = ref(null);
const items = ref([
{ label: 'Add New', icon: 'pi pi-fw pi-plus' },
{ label: 'Remove', icon: 'pi pi-fw pi-trash' }
]);
</script>
<template>
<div class="card">
<div class="flex items-center justify-between mb-6">
<div class="font-semibold text-xl">Notifications</div>
<div>
<Button icon="pi pi-ellipsis-v" class="p-button-text p-button-plain p-button-rounded" @click="$refs.menu.toggle($event)"></Button>
<Menu ref="menu" popup :model="items" class="min-w-40!"></Menu>
</div>
</div>
<span class="block text-muted-color font-medium mb-4">TODAY</span>
<ul class="p-0 mx-0 mt-0 mb-6 list-none">
<li class="flex items-center py-2 border-b border-surface">
<div class="w-12 h-12 flex items-center justify-center bg-blue-100 dark:bg-blue-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-dollar text-xl! text-blue-500"></i>
</div>
<span class="text-surface-900 dark:text-surface-0 leading-normal"
>Richard Jones
<span class="text-surface-700 dark:text-surface-100">has purchased a blue t-shirt for <span class="text-primary font-bold">$79.00</span></span>
</span>
</li>
<li class="flex items-center py-2">
<div class="w-12 h-12 flex items-center justify-center bg-orange-100 dark:bg-orange-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-download text-xl! text-orange-500"></i>
</div>
<span class="text-surface-700 dark:text-surface-100 leading-normal">Your request for withdrawal of <span class="text-primary font-bold">$2500.00</span> has been initiated.</span>
</li>
</ul>
<span class="block text-muted-color font-medium mb-4">YESTERDAY</span>
<ul class="p-0 m-0 list-none mb-6">
<li class="flex items-center py-2 border-b border-surface">
<div class="w-12 h-12 flex items-center justify-center bg-blue-100 dark:bg-blue-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-dollar text-xl! text-blue-500"></i>
</div>
<span class="text-surface-900 dark:text-surface-0 leading-normal"
>Keyser Wick
<span class="text-surface-700 dark:text-surface-100">has purchased a black jacket for <span class="text-primary font-bold">$59.00</span></span>
</span>
</li>
<li class="flex items-center py-2 border-b border-surface">
<div class="w-12 h-12 flex items-center justify-center bg-pink-100 dark:bg-pink-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-question text-xl! text-pink-500"></i>
</div>
<span class="text-surface-900 dark:text-surface-0 leading-normal"
>Jane Davis
<span class="text-surface-700 dark:text-surface-100">has posted a new questions about your product.</span>
</span>
</li>
</ul>
<span class="block text-muted-color font-medium mb-4">LAST WEEK</span>
<ul class="p-0 m-0 list-none">
<li class="flex items-center py-2 border-b border-surface">
<div class="w-12 h-12 flex items-center justify-center bg-green-100 dark:bg-green-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-arrow-up text-xl! text-green-500"></i>
</div>
<span class="text-surface-900 dark:text-surface-0 leading-normal">Your revenue has increased by <span class="text-primary font-bold">%25</span>.</span>
</li>
<li class="flex items-center py-2 border-b border-surface">
<div class="w-12 h-12 flex items-center justify-center bg-purple-100 dark:bg-purple-400/10 rounded-full mr-4 shrink-0">
<i class="pi pi-heart text-xl! text-purple-500"></i>
</div>
<span class="text-surface-900 dark:text-surface-0 leading-normal"><span class="text-primary font-bold">12</span> users have added your products to their wishlist.</span>
</li>
</ul>
</div>
</template>
================================================
FILE: src/components/dashboard/RecentSalesWidget.vue
================================================
<script setup>
import { ProductService } from '@/service/ProductService';
import { onMounted, ref } from 'vue';
const products = ref(null);
function formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
onMounted(() => {
ProductService.getProductsSmall().then((data) => (products.value = data));
});
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">Recent Sales</div>
<DataTable :value="products" :rows="5" :paginator="true" responsiveLayout="scroll">
<Column style="width: 15%" header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" width="50" class="shadow" />
</template>
</Column>
<Column field="name" header="Name" :sortable="true" style="width: 35%"></Column>
<Column field="price" header="Price" :sortable="true" style="width: 35%">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column style="width: 15%" header="View">
<template #body>
<Button icon="pi pi-search" type="button" class="p-button-text"></Button>
</template>
</Column>
</DataTable>
</div>
</template>
================================================
FILE: src/components/dashboard/RevenueStreamWidget.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { onMounted, ref, watch } from 'vue';
const { layoutConfig, isDarkTheme } = useLayout();
const chartData = ref(null);
const chartOptions = ref(null);
function setChartData() {
const documentStyle = getComputedStyle(document.documentElement);
return {
labels: ['Q1', 'Q2', 'Q3', 'Q4'],
datasets: [
{
type: 'bar',
label: 'Subscriptions',
backgroundColor: documentStyle.getPropertyValue('--p-primary-400'),
data: [4000, 10000, 15000, 4000],
barThickness: 32
},
{
type: 'bar',
label: 'Advertising',
backgroundColor: documentStyle.getPropertyValue('--p-primary-300'),
data: [2100, 8400, 2400, 7500],
barThickness: 32
},
{
type: 'bar',
label: 'Affiliate',
backgroundColor: documentStyle.getPropertyValue('--p-primary-200'),
data: [4100, 5200, 3400, 7400],
borderRadius: {
topLeft: 8,
topRight: 8
},
borderSkipped: true,
barThickness: 32
}
]
};
}
function setChartOptions() {
const documentStyle = getComputedStyle(document.documentElement);
const borderColor = documentStyle.getPropertyValue('--surface-border');
const textMutedColor = documentStyle.getPropertyValue('--text-color-secondary');
return {
maintainAspectRatio: false,
aspectRatio: 0.8,
scales: {
x: {
stacked: true,
ticks: {
color: textMutedColor
},
grid: {
color: 'transparent',
borderColor: 'transparent'
}
},
y: {
stacked: true,
ticks: {
color: textMutedColor
},
grid: {
color: borderColor,
borderColor: 'transparent',
drawTicks: false
}
}
}
};
}
watch([() => layoutConfig.primary, () => layoutConfig.surface, isDarkTheme], () => {
chartData.value = setChartData();
chartOptions.value = setChartOptions();
});
onMounted(() => {
chartData.value = setChartData();
chartOptions.value = setChartOptions();
});
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">Revenue Stream</div>
<Chart type="bar" :data="chartData" :options="chartOptions" class="h-80" />
</div>
</template>
================================================
FILE: src/components/dashboard/StatsWidget.vue
================================================
<template>
<div class="col-span-12 lg:col-span-6 xl:col-span-3">
<div class="card mb-0">
<div class="flex justify-between mb-4">
<div>
<span class="block text-muted-color font-medium mb-4">Orders</span>
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">152</div>
</div>
<div class="flex items-center justify-center bg-blue-100 dark:bg-blue-400/10 rounded-border" style="width: 2.5rem; height: 2.5rem">
<i class="pi pi-shopping-cart text-blue-500 text-xl!"></i>
</div>
</div>
<span class="text-primary font-medium">24 new </span>
<span class="text-muted-color">since last visit</span>
</div>
</div>
<div class="col-span-12 lg:col-span-6 xl:col-span-3">
<div class="card mb-0">
<div class="flex justify-between mb-4">
<div>
<span class="block text-muted-color font-medium mb-4">Revenue</span>
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">$2.100</div>
</div>
<div class="flex items-center justify-center bg-orange-100 dark:bg-orange-400/10 rounded-border" style="width: 2.5rem; height: 2.5rem">
<i class="pi pi-dollar text-orange-500 text-xl!"></i>
</div>
</div>
<span class="text-primary font-medium">%52+ </span>
<span class="text-muted-color">since last week</span>
</div>
</div>
<div class="col-span-12 lg:col-span-6 xl:col-span-3">
<div class="card mb-0">
<div class="flex justify-between mb-4">
<div>
<span class="block text-muted-color font-medium mb-4">Customers</span>
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">28441</div>
</div>
<div class="flex items-center justify-center bg-cyan-100 dark:bg-cyan-400/10 rounded-border" style="width: 2.5rem; height: 2.5rem">
<i class="pi pi-users text-cyan-500 text-xl!"></i>
</div>
</div>
<span class="text-primary font-medium">520 </span>
<span class="text-muted-color">newly registered</span>
</div>
</div>
<div class="col-span-12 lg:col-span-6 xl:col-span-3">
<div class="card mb-0">
<div class="flex justify-between mb-4">
<div>
<span class="block text-muted-color font-medium mb-4">Comments</span>
<div class="text-surface-900 dark:text-surface-0 font-medium text-xl">152 Unread</div>
</div>
<div class="flex items-center justify-center bg-purple-100 dark:bg-purple-400/10 rounded-border" style="width: 2.5rem; height: 2.5rem">
<i class="pi pi-comment text-purple-500 text-xl!"></i>
</div>
</div>
<span class="text-primary font-medium">85 </span>
<span class="text-muted-color">responded</span>
</div>
</div>
</template>
================================================
FILE: src/components/landing/FeaturesWidget.vue
================================================
<template>
<div id="features" class="py-6 px-6 lg:px-20 mt-8 mx-0 lg:mx-20">
<div class="grid grid-cols-12 gap-4 justify-center">
<div class="col-span-12 text-center mt-20 mb-6">
<div class="text-surface-900 dark:text-surface-0 font-normal mb-2 text-4xl">Marvelous Features</div>
<span class="text-muted-color text-2xl">Placerat in egestas erat...</span>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(253, 228, 165, 0.2), rgba(187, 199, 205, 0.2)), linear-gradient(180deg, rgba(253, 228, 165, 0.2), rgba(187, 199, 205, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-yellow-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-users text-2xl! text-yellow-700"></i>
</div>
<h5 class="mb-2 text-surface-900 dark:text-surface-0">Easy to Use</h5>
<span class="text-surface-600 dark:text-surface-200">Posuere morbi leo urna molestie.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(145, 226, 237, 0.2), rgba(251, 199, 145, 0.2)), linear-gradient(180deg, rgba(253, 228, 165, 0.2), rgba(172, 180, 223, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-cyan-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-palette text-2xl! text-cyan-700"></i>
</div>
<h5 class="mb-2 text-surface-900 dark:text-surface-0">Fresh Design</h5>
<span class="text-surface-600 dark:text-surface-200">Semper risus in hendrerit.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(145, 226, 237, 0.2), rgba(172, 180, 223, 0.2)), linear-gradient(180deg, rgba(172, 180, 223, 0.2), rgba(246, 158, 188, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-indigo-200" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-map text-2xl! text-indigo-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Well Documented</div>
<span class="text-surface-600 dark:text-surface-200">Non arcu risus quis varius quam quisque.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(187, 199, 205, 0.2), rgba(251, 199, 145, 0.2)), linear-gradient(180deg, rgba(253, 228, 165, 0.2), rgba(145, 210, 204, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-slate-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-id-card text-2xl! text-slate-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Responsive Layout</div>
<span class="text-surface-600 dark:text-surface-200">Nulla malesuada pellentesque elit.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(187, 199, 205, 0.2), rgba(246, 158, 188, 0.2)), linear-gradient(180deg, rgba(145, 226, 237, 0.2), rgba(160, 210, 250, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-orange-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-star text-2xl! text-orange-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Clean Code</div>
<span class="text-surface-600 dark:text-surface-200">Condimentum lacinia quis vel eros.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pb-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(251, 199, 145, 0.2), rgba(246, 158, 188, 0.2)), linear-gradient(180deg, rgba(172, 180, 223, 0.2), rgba(212, 162, 221, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-pink-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-moon text-2xl! text-pink-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Dark Mode</div>
<span class="text-surface-600 dark:text-surface-200">Convallis tellus id interdum velit laoreet.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(145, 210, 204, 0.2), rgba(160, 210, 250, 0.2)), linear-gradient(180deg, rgba(187, 199, 205, 0.2), rgba(145, 210, 204, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-teal-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-shopping-cart text-2xl! text-teal-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Ready to Use</div>
<span class="text-surface-600 dark:text-surface-200">Mauris sit amet massa vitae.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg:pr-8 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(145, 210, 204, 0.2), rgba(212, 162, 221, 0.2)), linear-gradient(180deg, rgba(251, 199, 145, 0.2), rgba(160, 210, 250, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-blue-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-globe text-2xl! text-blue-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Modern Practices</div>
<span class="text-surface-600 dark:text-surface-200">Elementum nibh tellus molestie nunc non.</span>
</div>
</div>
</div>
<div class="col-span-12 md:col-span-12 lg:col-span-4 p-0 lg-4 mt-6 lg:mt-0">
<div style="height: 160px; padding: 2px; border-radius: 10px; background: linear-gradient(90deg, rgba(160, 210, 250, 0.2), rgba(212, 162, 221, 0.2)), linear-gradient(180deg, rgba(246, 158, 188, 0.2), rgba(212, 162, 221, 0.2))">
<div class="p-4 bg-surface-0 dark:bg-surface-900 h-full" style="border-radius: 8px">
<div class="flex items-center justify-center bg-purple-200 mb-4" style="width: 3.5rem; height: 3.5rem; border-radius: 10px">
<i class="pi pi-fw pi-eye text-2xl! text-purple-700"></i>
</div>
<div class="mt-6 mb-1 text-surface-900 dark:text-surface-0 text-xl font-semibold">Privacy</div>
<span class="text-surface-600 dark:text-surface-200">Neque egestas congue quisque.</span>
</div>
</div>
</div>
<div
class="col-span-12 mt-20 mb-20 p-2 md:p-20"
style="border-radius: 20px; background: linear-gradient(0deg, rgba(255, 255, 255, 0.6), rgba(255, 255, 255, 0.6)), radial-gradient(77.36% 256.97% at 77.36% 57.52%, #efe1af 0%, #c3dcfa 100%)"
>
<div class="flex flex-col justify-center items-center text-center px-4 py-4 md:py-0">
<div class="text-gray-900 mb-2 text-3xl font-semibold">Joséphine Miller</div>
<span class="text-gray-600 text-2xl">Peak Interactive</span>
<p class="text-gray-900 sm:line-height-2 md:line-height-4 text-2xl mt-6" style="max-width: 800px">
“Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.”
</p>
<img src="/demo/images/landing/peak-logo.svg" class="mt-6" alt="Company logo" />
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/components/landing/FooterWidget.vue
================================================
<template>
<div class="py-6 px-6 mx-0 mt-20 lg:mx-20">
<div class="grid grid-cols-12 gap-4">
<div class="col-span-12 md:col-span-2">
<a class="flex flex-wrap items-center justify-center md:justify-start md:mb-0 mb-4 cursor-pointer">
<svg viewBox="0 0 54 40" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-14 mr-2">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.1637 19.2467C17.1566 19.4033 17.1529 19.561 17.1529 19.7194C17.1529 25.3503 21.7203 29.915 27.3546 29.915C32.9887 29.915 37.5561 25.3503 37.5561 19.7194C37.5561 19.5572 37.5524 19.3959 37.5449 19.2355C38.5617 19.0801 39.5759 18.9013 40.5867 18.6994L40.6926 18.6782C40.7191 19.0218 40.7326 19.369 40.7326 19.7194C40.7326 27.1036 34.743 33.0896 27.3546 33.0896C19.966 33.0896 13.9765 27.1036 13.9765 19.7194C13.9765 19.374 13.9896 19.0316 14.0154 18.6927L14.0486 18.6994C15.0837 18.9062 16.1223 19.0886 17.1637 19.2467ZM33.3284 11.4538C31.6493 10.2396 29.5855 9.52381 27.3546 9.52381C25.1195 9.52381 23.0524 10.2421 21.3717 11.4603C20.0078 11.3232 18.6475 11.1387 17.2933 10.907C19.7453 8.11308 23.3438 6.34921 27.3546 6.34921C31.36 6.34921 34.9543 8.10844 37.4061 10.896C36.0521 11.1292 34.692 11.3152 33.3284 11.4538ZM43.826 18.0518C43.881 18.6003 43.9091 19.1566 43.9091 19.7194C43.9091 28.8568 36.4973 36.2642 27.3546 36.2642C18.2117 36.2642 10.8 28.8568 10.8 19.7194C10.8 19.1615 10.8276 18.61 10.8816 18.0663L7.75383 17.4411C7.66775 18.1886 7.62354 18.9488 7.62354 19.7194C7.62354 30.6102 16.4574 39.4388 27.3546 39.4388C38.2517 39.4388 47.0855 30.6102 47.0855 19.7194C47.0855 18.9439 47.0407 18.1789 46.9536 17.4267L43.826 18.0518ZM44.2613 9.54743L40.9084 10.2176C37.9134 5.95821 32.9593 3.1746 27.3546 3.1746C21.7442 3.1746 16.7856 5.96385 13.7915 10.2305L10.4399 9.56057C13.892 3.83178 20.1756 0 27.3546 0C34.5281 0 40.8075 3.82591 44.2613 9.54743Z"
fill="var(--primary-color)"
/>
<mask id="mask0_1413_1551" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="8" width="54" height="11">
<path d="M27 18.3652C10.5114 19.1944 0 8.88892 0 8.88892C0 8.88892 16.5176 14.5866 27 14.5866C37.4824 14.5866 54 8.88892 54 8.88892C54 8.88892 43.4886 17.5361 27 18.3652Z" fill="var(--primary-color)" />
</mask>
<g mask="url(#mask0_1413_1551)">
<path
d="M-4.673e-05 8.88887L3.73084 -1.91434L-8.00806 17.0473L-4.673e-05 8.88887ZM27 18.3652L26.4253 6.95109L27 18.3652ZM54 8.88887L61.2673 17.7127L50.2691 -1.91434L54 8.88887ZM-4.673e-05 8.88887C-8.00806 17.0473 -8.00469 17.0505 -8.00132 17.0538C-8.00018 17.055 -7.99675 17.0583 -7.9944 17.0607C-7.98963 17.0653 -7.98474 17.0701 -7.97966 17.075C-7.96949 17.0849 -7.95863 17.0955 -7.94707 17.1066C-7.92401 17.129 -7.89809 17.1539 -7.86944 17.1812C-7.8122 17.236 -7.74377 17.3005 -7.66436 17.3743C-7.50567 17.5218 -7.30269 17.7063 -7.05645 17.9221C-6.56467 18.3532 -5.89662 18.9125 -5.06089 19.5534C-3.39603 20.83 -1.02575 22.4605 1.98012 24.0457C7.97874 27.2091 16.7723 30.3226 27.5746 29.7793L26.4253 6.95109C20.7391 7.23699 16.0326 5.61231 12.6534 3.83024C10.9703 2.94267 9.68222 2.04866 8.86091 1.41888C8.45356 1.10653 8.17155 0.867278 8.0241 0.738027C7.95072 0.673671 7.91178 0.637576 7.90841 0.634492C7.90682 0.63298 7.91419 0.639805 7.93071 0.65557C7.93897 0.663455 7.94952 0.673589 7.96235 0.686039C7.96883 0.692262 7.97582 0.699075 7.98338 0.706471C7.98719 0.710167 7.99113 0.714014 7.99526 0.718014C7.99729 0.720008 8.00047 0.723119 8.00148 0.724116C8.00466 0.727265 8.00796 0.730446 -4.673e-05 8.88887ZM27.5746 29.7793C37.6904 29.2706 45.9416 26.3684 51.6602 23.6054C54.5296 22.2191 56.8064 20.8465 58.4186 19.7784C59.2265 19.2431 59.873 18.7805 60.3494 18.4257C60.5878 18.2482 60.7841 18.0971 60.9374 17.977C61.014 17.9169 61.0799 17.8645 61.1349 17.8203C61.1624 17.7981 61.1872 17.7781 61.2093 17.7602C61.2203 17.7512 61.2307 17.7427 61.2403 17.7348C61.2452 17.7308 61.2499 17.727 61.2544 17.7233C61.2566 17.7215 61.2598 17.7188 61.261 17.7179C61.2642 17.7153 61.2673 17.7127 54 8.88887C46.7326 0.0650536 46.7357 0.0625219 46.7387 0.0600241C46.7397 0.0592345 46.7427 0.0567658 46.7446 0.0551857C46.7485 0.0520238 46.7521 0.0489887 46.7557 0.0460799C46.7628 0.0402623 46.7694 0.0349487 46.7753 0.0301318C46.7871 0.0204986 46.7966 0.0128495 46.8037 0.00712562C46.818 -0.00431848 46.8228 -0.00808311 46.8184 -0.00463784C46.8096 0.00228345 46.764 0.0378652 46.6828 0.0983779C46.5199 0.219675 46.2165 0.439161 45.7812 0.727519C44.9072 1.30663 43.5257 2.14765 41.7061 3.02677C38.0469 4.79468 32.7981 6.63058 26.4253 6.95109L27.5746 29.7793ZM54 8.88887C50.2691 -1.91433 50.27 -1.91467 50.271 -1.91498C50.2712 -1.91506 50.272 -1.91535 50.2724 -1.9155C50.2733 -1.91581 50.274 -1.91602 50.2743 -1.91616C50.2752 -1.91643 50.275 -1.91636 50.2738 -1.91595C50.2714 -1.91515 50.2652 -1.91302 50.2552 -1.9096C50.2351 -1.90276 50.1999 -1.89078 50.1503 -1.874C50.0509 -1.84043 49.8938 -1.78773 49.6844 -1.71863C49.2652 -1.58031 48.6387 -1.377 47.8481 -1.13035C46.2609 -0.635237 44.0427 0.0249875 41.5325 0.6823C36.215 2.07471 30.6736 3.15796 27 3.15796V26.0151C33.8087 26.0151 41.7672 24.2495 47.3292 22.7931C50.2586 22.026 52.825 21.2618 54.6625 20.6886C55.5842 20.4011 56.33 20.1593 56.8551 19.986C57.1178 19.8993 57.3258 19.8296 57.4735 19.7797C57.5474 19.7548 57.6062 19.7348 57.6493 19.72C57.6709 19.7127 57.6885 19.7066 57.7021 19.7019C57.7089 19.6996 57.7147 19.6976 57.7195 19.696C57.7219 19.6952 57.7241 19.6944 57.726 19.6938C57.7269 19.6934 57.7281 19.693 57.7286 19.6929C57.7298 19.6924 57.7309 19.692 54 8.88887ZM27 3.15796C23.3263 3.15796 17.7849 2.07471 12.4674 0.6823C9.95717 0.0249875 7.73904 -0.635237 6.15184 -1.13035C5.36118 -1.377 4.73467 -1.58031 4.3155 -1.71863C4.10609 -1.78773 3.94899 -1.84043 3.84961 -1.874C3.79994 -1.89078 3.76474 -1.90276 3.74471 -1.9096C3.73469 -1.91302 3.72848 -1.91515 3.72613 -1.91595C3.72496 -1.91636 3.72476 -1.91643 3.72554 -1.91616C3.72593 -1.91602 3.72657 -1.91581 3.72745 -1.9155C3.72789 -1.91535 3.72874 -1.91506 3.72896 -1.91498C3.72987 -1.91467 3.73084 -1.91433 -4.673e-05 8.88887C-3.73093 19.692 -3.72983 19.6924 -3.72868 19.6929C-3.72821 19.693 -3.72698 19.6934 -3.72603 19.6938C-3.72415 19.6944 -3.72201 19.6952 -3.71961 19.696C-3.71482 19.6976 -3.70901 19.6996 -3.7022 19.7019C-3.68858 19.7066 -3.67095 19.7127 -3.6494 19.72C-3.60629 19.7348 -3.54745 19.7548 -3.47359 19.7797C-3.32589 19.8296 -3.11788 19.8993 -2.85516 19.986C-2.33008 20.1593 -1.58425 20.4011 -0.662589 20.6886C1.17485 21.2618 3.74125 22.026 6.67073 22.7931C12.2327 24.2495 20.1913 26.0151 27 26.0151V3.15796Z"
fill="var(--primary-color)"
/>
</g>
</svg>
<h4 class="font-medium text-3xl text-surface-900 dark:text-surface-0">SAKAI</h4>
</a>
</div>
<div class="col-span-12 md:col-span-10">
<div class="grid grid-cols-12 gap-8 text-center md:text-left">
<div class="col-span-12 md:col-span-3">
<h4 class="font-medium text-2xl leading-normal mb-4 text-surface-900 dark:text-surface-0">Company</h4>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">About Us</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">News</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Investor Relations</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Careers</a>
<a class="leading-normal text-xl block cursor-pointer text-surface-700 dark:text-surface-100">Media Kit</a>
</div>
<div class="col-span-12 md:col-span-3">
<h4 class="font-medium text-2xl leading-normal mb-4 text-surface-900 dark:text-surface-0">Resources</h4>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Get Started</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Learn</a>
<a class="leading-normal text-xl block cursor-pointer text-surface-700 dark:text-surface-100">Case Studies</a>
</div>
<div class="col-span-12 md:col-span-3">
<h4 class="font-medium text-2xl leading-normal mb-4 text-surface-900 dark:text-surface-0">Community</h4>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Discord</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Events<img src="/demo/images/landing/new-badge.svg" class="ml-2" /></a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">FAQ</a>
<a class="leading-normal text-xl block cursor-pointer text-surface-700 dark:text-surface-100">Blog</a>
</div>
<div class="col-span-12 md:col-span-3">
<h4 class="font-medium text-2xl leading-normal mb-4 text-surface-900 dark:text-surface-0">Legal</h4>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Brand Policy</a>
<a class="leading-normal text-xl block cursor-pointer mb-2 text-surface-700 dark:text-surface-100">Privacy Policy</a>
<a class="leading-normal text-xl block cursor-pointer text-surface-700 dark:text-surface-100">Terms of Service</a>
</div>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/components/landing/HeroWidget.vue
================================================
<template>
<div
id="hero"
class="flex flex-col pt-6 px-6 lg:px-20 overflow-hidden"
style="background: linear-gradient(0deg, rgba(255, 255, 255, 0.2), rgba(255, 255, 255, 0.2)), radial-gradient(77.36% 256.97% at 77.36% 57.52%, rgb(238, 239, 175) 0%, rgb(195, 227, 250) 100%); clip-path: ellipse(150% 87% at 93% 13%)"
>
<div class="mx-6 md:mx-20 mt-0 md:mt-6">
<h1 class="text-6xl font-bold text-gray-900 leading-tight"><span class="font-light block">Eu sem integer</span>eget magna fermentum</h1>
<p class="font-normal text-2xl leading-normal md:mt-4 text-gray-700">Sed blandit libero volutpat sed cras. Fames ac turpis egestas integer. Placerat in egestas erat...</p>
<Button label="Get Started" as="router-link" to="/" rounded class="text-xl! mt-8 px-4!"></Button>
</div>
<div class="flex justify-center md:justify-end">
<img src="/demo/images/landing/screen-1.png" alt="Hero Image" class="w-9/12 md:w-auto" />
</div>
</div>
</template>
================================================
FILE: src/components/landing/HighlightsWidget.vue
================================================
<template>
<div id="highlights" class="py-6 px-6 lg:px-20 mx-0 my-12 lg:mx-20">
<div class="text-center">
<div class="text-surface-900 dark:text-surface-0 font-normal mb-2 text-4xl">Powerful Everywhere</div>
<span class="text-muted-color text-2xl">Amet consectetur adipiscing elit...</span>
</div>
<div class="grid grid-cols-12 gap-4 mt-20 pb-2 md:pb-20">
<div class="flex justify-center col-span-12 lg:col-span-6 bg-purple-100 p-0 order-1 lg:order-none" style="border-radius: 8px">
<img src="/demo/images/landing/mockup.svg" class="w-11/12" alt="mockup mobile" />
</div>
<div class="col-span-12 lg:col-span-6 my-auto flex flex-col lg:items-end text-center lg:text-right gap-4">
<div class="flex items-center justify-center bg-purple-200 self-center lg:self-end" style="width: 4.2rem; height: 4.2rem; border-radius: 10px">
<i class="pi pi-fw pi-mobile text-4xl! text-purple-700"></i>
</div>
<div class="leading-none text-surface-900 dark:text-surface-0 text-3xl font-normal">Congue Quisque Egestas</div>
<span class="text-surface-700 dark:text-surface-100 text-2xl leading-normal ml-0 md:ml-2" style="max-width: 650px"
>Lectus arcu bibendum at varius vel pharetra vel turpis nunc. Eget aliquet nibh praesent tristique magna sit amet purus gravida. Sit amet mattis vulputate enim nulla aliquet.</span
>
</div>
</div>
<div class="grid grid-cols-12 gap-4 my-20 pt-2 md:pt-20">
<div class="col-span-12 lg:col-span-6 my-auto flex flex-col text-center lg:text-left lg:items-start gap-4">
<div class="flex items-center justify-center bg-yellow-200 self-center lg:self-start" style="width: 4.2rem; height: 4.2rem; border-radius: 10px">
<i class="pi pi-fw pi-desktop text-3xl! text-yellow-700"></i>
</div>
<div class="leading-none text-surface-900 dark:text-surface-0 text-3xl font-normal">Celerisque Eu Ultrices</div>
<span class="text-surface-700 dark:text-surface-100 text-2xl leading-normal mr-0 md:mr-2" style="max-width: 650px"
>Adipiscing commodo elit at imperdiet dui. Viverra nibh cras pulvinar mattis nunc sed blandit libero. Suspendisse in est ante in. Mauris pharetra et ultrices neque ornare aenean euismod elementum nisi.</span
>
</div>
<div class="flex justify-end order-1 sm:order-2 col-span-12 lg:col-span-6 bg-yellow-100 p-0" style="border-radius: 8px">
<img src="/demo/images/landing/mockup-desktop.svg" class="w-11/12" alt="mockup" />
</div>
</div>
</div>
</template>
================================================
FILE: src/components/landing/PricingWidget.vue
================================================
<template>
<div id="pricing" class="py-6 px-6 lg:px-20 my-2 md:my-6">
<div class="text-center mb-6">
<div class="text-surface-900 dark:text-surface-0 font-normal mb-2 text-4xl">Matchless Pricing</div>
<span class="text-muted-color text-2xl">Amet consectetur adipiscing elit...</span>
</div>
<div class="grid grid-cols-12 gap-4 justify-between mt-20 md:mt-0">
<div class="col-span-12 lg:col-span-4 p-0 md:p-4">
<div class="p-4 flex flex-col border-surface-200 dark:border-surface-600 pricing-card cursor-pointer border-2 hover:border-primary duration-300 transition-all" style="border-radius: 10px">
<div class="text-surface-900 dark:text-surface-0 text-center my-8 text-3xl">Free</div>
<img src="/demo/images/landing/free.svg" class="w-10/12 mx-auto" alt="free" />
<div class="my-8 flex flex-col items-center gap-4">
<div class="flex items-center">
<span class="text-5xl font-bold mr-2 text-surface-900 dark:text-surface-0">$0</span>
<span class="text-surface-600 dark:text-surface-200">per month</span>
</div>
<Button label="Get Started" class="p-button-rounded border-0 ml-4 font-light leading-tight bg-blue-500 text-white"></Button>
</div>
<Divider class="w-full bg-surface-200"></Divider>
<ul class="my-8 list-none p-0 flex text-surface-900 dark:text-surface-0 flex-col px-8">
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Responsive Layout</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Unlimited Push Messages</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">50 Support Ticket</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Free Shipping</span>
</li>
</ul>
</div>
</div>
<div class="col-span-12 lg:col-span-4 p-0 md:p-4 mt-6 md:mt-0">
<div class="p-4 flex flex-col border-surface-200 dark:border-surface-600 pricing-card cursor-pointer border-2 hover:border-primary duration-300 transition-all" style="border-radius: 10px">
<div class="text-surface-900 dark:text-surface-0 text-center my-8 text-3xl">Startup</div>
<img src="/demo/images/landing/startup.svg" class="w-10/12 mx-auto" alt="startup" />
<div class="my-8 flex flex-col items-center gap-4">
<div class="flex items-center">
<span class="text-5xl font-bold mr-2 text-surface-900 dark:text-surface-0">$1</span>
<span class="text-surface-600 dark:text-surface-200">per month</span>
</div>
<Button label="Get Started" class="p-button-rounded border-0 ml-4 font-light leading-tight bg-blue-500 text-white"></Button>
</div>
<Divider class="w-full bg-surface-200"></Divider>
<ul class="my-8 list-none p-0 flex text-surface-900 dark:text-surface-0 flex-col px-8">
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Responsive Layout</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Unlimited Push Messages</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">50 Support Ticket</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Free Shipping</span>
</li>
</ul>
</div>
</div>
<div class="col-span-12 lg:col-span-4 p-0 md:p-4 mt-6 md:mt-0">
<div class="p-4 flex flex-col border-surface-200 dark:border-surface-600 pricing-card cursor-pointer border-2 hover:border-primary duration-300 transition-all" style="border-radius: 10px">
<div class="text-surface-900 dark:text-surface-0 text-center my-8 text-3xl">Enterprise</div>
<img src="/demo/images/landing/enterprise.svg" class="w-10/12 mx-auto" alt="enterprise" />
<div class="my-8 flex flex-col items-center gap-4">
<div class="flex items-center">
<span class="text-5xl font-bold mr-2 text-surface-900 dark:text-surface-0">$5</span>
<span class="text-surface-600 dark:text-surface-200">per month</span>
</div>
<Button label="Get Started" class="p-button-rounded border-0 ml-4 font-light leading-tight bg-blue-500 text-white"></Button>
</div>
<Divider class="w-full bg-surface-200"></Divider>
<ul class="my-8 list-none p-0 flex text-surface-900 dark:text-surface-0 flex-col px-8">
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Responsive Layout</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Unlimited Push Messages</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">50 Support Ticket</span>
</li>
<li class="py-2">
<i class="pi pi-fw pi-check text-xl text-cyan-500 mr-2"></i>
<span class="text-xl leading-normal">Free Shipping</span>
</li>
</ul>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/components/landing/TopbarWidget.vue
================================================
<script setup>
function smoothScroll(id) {
document.body.click();
const element = document.getElementById(id);
if (element) {
element.scrollIntoView({
behavior: 'smooth',
block: 'start'
});
}
}
</script>
<template>
<a class="flex items-center" href="#">
<svg viewBox="0 0 54 40" fill="none" xmlns="http://www.w3.org/2000/svg" class="h-12 mr-2">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.1637 19.2467C17.1566 19.4033 17.1529 19.561 17.1529 19.7194C17.1529 25.3503 21.7203 29.915 27.3546 29.915C32.9887 29.915 37.5561 25.3503 37.5561 19.7194C37.5561 19.5572 37.5524 19.3959 37.5449 19.2355C38.5617 19.0801 39.5759 18.9013 40.5867 18.6994L40.6926 18.6782C40.7191 19.0218 40.7326 19.369 40.7326 19.7194C40.7326 27.1036 34.743 33.0896 27.3546 33.0896C19.966 33.0896 13.9765 27.1036 13.9765 19.7194C13.9765 19.374 13.9896 19.0316 14.0154 18.6927L14.0486 18.6994C15.0837 18.9062 16.1223 19.0886 17.1637 19.2467ZM33.3284 11.4538C31.6493 10.2396 29.5855 9.52381 27.3546 9.52381C25.1195 9.52381 23.0524 10.2421 21.3717 11.4603C20.0078 11.3232 18.6475 11.1387 17.2933 10.907C19.7453 8.11308 23.3438 6.34921 27.3546 6.34921C31.36 6.34921 34.9543 8.10844 37.4061 10.896C36.0521 11.1292 34.692 11.3152 33.3284 11.4538ZM43.826 18.0518C43.881 18.6003 43.9091 19.1566 43.9091 19.7194C43.9091 28.8568 36.4973 36.2642 27.3546 36.2642C18.2117 36.2642 10.8 28.8568 10.8 19.7194C10.8 19.1615 10.8276 18.61 10.8816 18.0663L7.75383 17.4411C7.66775 18.1886 7.62354 18.9488 7.62354 19.7194C7.62354 30.6102 16.4574 39.4388 27.3546 39.4388C38.2517 39.4388 47.0855 30.6102 47.0855 19.7194C47.0855 18.9439 47.0407 18.1789 46.9536 17.4267L43.826 18.0518ZM44.2613 9.54743L40.9084 10.2176C37.9134 5.95821 32.9593 3.1746 27.3546 3.1746C21.7442 3.1746 16.7856 5.96385 13.7915 10.2305L10.4399 9.56057C13.892 3.83178 20.1756 0 27.3546 0C34.5281 0 40.8075 3.82591 44.2613 9.54743Z"
fill="var(--primary-color)"
/>
<mask id="mask0_1413_1551" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="8" width="54" height="11">
<path d="M27 18.3652C10.5114 19.1944 0 8.88892 0 8.88892C0 8.88892 16.5176 14.5866 27 14.5866C37.4824 14.5866 54 8.88892 54 8.88892C54 8.88892 43.4886 17.5361 27 18.3652Z" fill="var(--primary-color)" />
</mask>
<g mask="url(#mask0_1413_1551)">
<path
d="M-4.673e-05 8.88887L3.73084 -1.91434L-8.00806 17.0473L-4.673e-05 8.88887ZM27 18.3652L26.4253 6.95109L27 18.3652ZM54 8.88887L61.2673 17.7127L50.2691 -1.91434L54 8.88887ZM-4.673e-05 8.88887C-8.00806 17.0473 -8.00469 17.0505 -8.00132 17.0538C-8.00018 17.055 -7.99675 17.0583 -7.9944 17.0607C-7.98963 17.0653 -7.98474 17.0701 -7.97966 17.075C-7.96949 17.0849 -7.95863 17.0955 -7.94707 17.1066C-7.92401 17.129 -7.89809 17.1539 -7.86944 17.1812C-7.8122 17.236 -7.74377 17.3005 -7.66436 17.3743C-7.50567 17.5218 -7.30269 17.7063 -7.05645 17.9221C-6.56467 18.3532 -5.89662 18.9125 -5.06089 19.5534C-3.39603 20.83 -1.02575 22.4605 1.98012 24.0457C7.97874 27.2091 16.7723 30.3226 27.5746 29.7793L26.4253 6.95109C20.7391 7.23699 16.0326 5.61231 12.6534 3.83024C10.9703 2.94267 9.68222 2.04866 8.86091 1.41888C8.45356 1.10653 8.17155 0.867278 8.0241 0.738027C7.95072 0.673671 7.91178 0.637576 7.90841 0.634492C7.90682 0.63298 7.91419 0.639805 7.93071 0.65557C7.93897 0.663455 7.94952 0.673589 7.96235 0.686039C7.96883 0.692262 7.97582 0.699075 7.98338 0.706471C7.98719 0.710167 7.99113 0.714014 7.99526 0.718014C7.99729 0.720008 8.00047 0.723119 8.00148 0.724116C8.00466 0.727265 8.00796 0.730446 -4.673e-05 8.88887ZM27.5746 29.7793C37.6904 29.2706 45.9416 26.3684 51.6602 23.6054C54.5296 22.2191 56.8064 20.8465 58.4186 19.7784C59.2265 19.2431 59.873 18.7805 60.3494 18.4257C60.5878 18.2482 60.7841 18.0971 60.9374 17.977C61.014 17.9169 61.0799 17.8645 61.1349 17.8203C61.1624 17.7981 61.1872 17.7781 61.2093 17.7602C61.2203 17.7512 61.2307 17.7427 61.2403 17.7348C61.2452 17.7308 61.2499 17.727 61.2544 17.7233C61.2566 17.7215 61.2598 17.7188 61.261 17.7179C61.2642 17.7153 61.2673 17.7127 54 8.88887C46.7326 0.0650536 46.7357 0.0625219 46.7387 0.0600241C46.7397 0.0592345 46.7427 0.0567658 46.7446 0.0551857C46.7485 0.0520238 46.7521 0.0489887 46.7557 0.0460799C46.7628 0.0402623 46.7694 0.0349487 46.7753 0.0301318C46.7871 0.0204986 46.7966 0.0128495 46.8037 0.00712562C46.818 -0.00431848 46.8228 -0.00808311 46.8184 -0.00463784C46.8096 0.00228345 46.764 0.0378652 46.6828 0.0983779C46.5199 0.219675 46.2165 0.439161 45.7812 0.727519C44.9072 1.30663 43.5257 2.14765 41.7061 3.02677C38.0469 4.79468 32.7981 6.63058 26.4253 6.95109L27.5746 29.7793ZM54 8.88887C50.2691 -1.91433 50.27 -1.91467 50.271 -1.91498C50.2712 -1.91506 50.272 -1.91535 50.2724 -1.9155C50.2733 -1.91581 50.274 -1.91602 50.2743 -1.91616C50.2752 -1.91643 50.275 -1.91636 50.2738 -1.91595C50.2714 -1.91515 50.2652 -1.91302 50.2552 -1.9096C50.2351 -1.90276 50.1999 -1.89078 50.1503 -1.874C50.0509 -1.84043 49.8938 -1.78773 49.6844 -1.71863C49.2652 -1.58031 48.6387 -1.377 47.8481 -1.13035C46.2609 -0.635237 44.0427 0.0249875 41.5325 0.6823C36.215 2.07471 30.6736 3.15796 27 3.15796V26.0151C33.8087 26.0151 41.7672 24.2495 47.3292 22.7931C50.2586 22.026 52.825 21.2618 54.6625 20.6886C55.5842 20.4011 56.33 20.1593 56.8551 19.986C57.1178 19.8993 57.3258 19.8296 57.4735 19.7797C57.5474 19.7548 57.6062 19.7348 57.6493 19.72C57.6709 19.7127 57.6885 19.7066 57.7021 19.7019C57.7089 19.6996 57.7147 19.6976 57.7195 19.696C57.7219 19.6952 57.7241 19.6944 57.726 19.6938C57.7269 19.6934 57.7281 19.693 57.7286 19.6929C57.7298 19.6924 57.7309 19.692 54 8.88887ZM27 3.15796C23.3263 3.15796 17.7849 2.07471 12.4674 0.6823C9.95717 0.0249875 7.73904 -0.635237 6.15184 -1.13035C5.36118 -1.377 4.73467 -1.58031 4.3155 -1.71863C4.10609 -1.78773 3.94899 -1.84043 3.84961 -1.874C3.79994 -1.89078 3.76474 -1.90276 3.74471 -1.9096C3.73469 -1.91302 3.72848 -1.91515 3.72613 -1.91595C3.72496 -1.91636 3.72476 -1.91643 3.72554 -1.91616C3.72593 -1.91602 3.72657 -1.91581 3.72745 -1.9155C3.72789 -1.91535 3.72874 -1.91506 3.72896 -1.91498C3.72987 -1.91467 3.73084 -1.91433 -4.673e-05 8.88887C-3.73093 19.692 -3.72983 19.6924 -3.72868 19.6929C-3.72821 19.693 -3.72698 19.6934 -3.72603 19.6938C-3.72415 19.6944 -3.72201 19.6952 -3.71961 19.696C-3.71482 19.6976 -3.70901 19.6996 -3.7022 19.7019C-3.68858 19.7066 -3.67095 19.7127 -3.6494 19.72C-3.60629 19.7348 -3.54745 19.7548 -3.47359 19.7797C-3.32589 19.8296 -3.11788 19.8993 -2.85516 19.986C-2.33008 20.1593 -1.58425 20.4011 -0.662589 20.6886C1.17485 21.2618 3.74125 22.026 6.67073 22.7931C12.2327 24.2495 20.1913 26.0151 27 26.0151V3.15796Z"
fill="var(--primary-color)"
/>
</g>
</svg>
<span class="text-surface-900 dark:text-surface-0 font-medium text-2xl leading-normal mr-20">SAKAI</span>
</a>
<Button
class="lg:hidden!"
text
severity="secondary"
rounded
v-styleclass="{ selector: '@next', enterFromClass: 'hidden', enterActiveClass: 'animate-scalein', leaveToClass: 'hidden', leaveActiveClass: 'animate-fadeout', hideOnOutsideClick: true }"
>
<i class="pi pi-bars text-2xl!"></i>
</Button>
<div class="items-center bg-surface-0 dark:bg-surface-900 grow justify-between hidden lg:flex absolute lg:static w-full left-0 top-full px-12 lg:px-0 z-20 rounded-border">
<ul class="list-none p-0 m-0 flex lg:items-center select-none flex-col lg:flex-row cursor-pointer gap-8">
<li>
<a @click="smoothScroll('hero')" class="px-0 py-4 text-surface-900 dark:text-surface-0 font-medium text-xl">
<span>Home</span>
</a>
</li>
<li>
<a @click="smoothScroll('features')" class="px-0 py-4 text-surface-900 dark:text-surface-0 font-medium text-xl">
<span>Features</span>
</a>
</li>
<li>
<a @click="smoothScroll('highlights')" class="px-0 py-4 text-surface-900 dark:text-surface-0 font-medium text-xl">
<span>Highlights</span>
</a>
</li>
<li>
<a @click="smoothScroll('pricing')" class="px-0 py-4 text-surface-900 dark:text-surface-0 font-medium text-xl">
<span>Pricing</span>
</a>
</li>
</ul>
<div class="flex border-t lg:border-t-0 border-surface py-4 lg:py-0 mt-4 lg:mt-0 gap-2">
<Button label="Login" text as="router-link" to="/auth/login" rounded></Button>
<Button label="Register" to="/auth/login" rounded></Button>
</div>
</div>
</template>
================================================
FILE: src/layout/AppConfigurator.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { $t, updatePreset, updateSurfacePalette } from '@primeuix/themes';
import Aura from '@primeuix/themes/aura';
import Lara from '@primeuix/themes/lara';
import Nora from '@primeuix/themes/nora';
import { ref } from 'vue';
const { layoutConfig, isDarkTheme, changeMenuMode } = useLayout();
const presets = {
Aura,
Lara,
Nora
};
const preset = ref(layoutConfig.preset);
const presetOptions = ref(Object.keys(presets));
const menuMode = ref(layoutConfig.menuMode);
const menuModeOptions = ref([
{ label: 'Static', value: 'static' },
{ label: 'Overlay', value: 'overlay' }
]);
const primaryColors = ref([
{ name: 'noir', palette: {} },
{ name: 'emerald', palette: { 50: '#ecfdf5', 100: '#d1fae5', 200: '#a7f3d0', 300: '#6ee7b7', 400: '#34d399', 500: '#10b981', 600: '#059669', 700: '#047857', 800: '#065f46', 900: '#064e3b', 950: '#022c22' } },
{ name: 'green', palette: { 50: '#f0fdf4', 100: '#dcfce7', 200: '#bbf7d0', 300: '#86efac', 400: '#4ade80', 500: '#22c55e', 600: '#16a34a', 700: '#15803d', 800: '#166534', 900: '#14532d', 950: '#052e16' } },
{ name: 'lime', palette: { 50: '#f7fee7', 100: '#ecfccb', 200: '#d9f99d', 300: '#bef264', 400: '#a3e635', 500: '#84cc16', 600: '#65a30d', 700: '#4d7c0f', 800: '#3f6212', 900: '#365314', 950: '#1a2e05' } },
{ name: 'orange', palette: { 50: '#fff7ed', 100: '#ffedd5', 200: '#fed7aa', 300: '#fdba74', 400: '#fb923c', 500: '#f97316', 600: '#ea580c', 700: '#c2410c', 800: '#9a3412', 900: '#7c2d12', 950: '#431407' } },
{ name: 'amber', palette: { 50: '#fffbeb', 100: '#fef3c7', 200: '#fde68a', 300: '#fcd34d', 400: '#fbbf24', 500: '#f59e0b', 600: '#d97706', 700: '#b45309', 800: '#92400e', 900: '#78350f', 950: '#451a03' } },
{ name: 'yellow', palette: { 50: '#fefce8', 100: '#fef9c3', 200: '#fef08a', 300: '#fde047', 400: '#facc15', 500: '#eab308', 600: '#ca8a04', 700: '#a16207', 800: '#854d0e', 900: '#713f12', 950: '#422006' } },
{ name: 'teal', palette: { 50: '#f0fdfa', 100: '#ccfbf1', 200: '#99f6e4', 300: '#5eead4', 400: '#2dd4bf', 500: '#14b8a6', 600: '#0d9488', 700: '#0f766e', 800: '#115e59', 900: '#134e4a', 950: '#042f2e' } },
{ name: 'cyan', palette: { 50: '#ecfeff', 100: '#cffafe', 200: '#a5f3fc', 300: '#67e8f9', 400: '#22d3ee', 500: '#06b6d4', 600: '#0891b2', 700: '#0e7490', 800: '#155e75', 900: '#164e63', 950: '#083344' } },
{ name: 'sky', palette: { 50: '#f0f9ff', 100: '#e0f2fe', 200: '#bae6fd', 300: '#7dd3fc', 400: '#38bdf8', 500: '#0ea5e9', 600: '#0284c7', 700: '#0369a1', 800: '#075985', 900: '#0c4a6e', 950: '#082f49' } },
{ name: 'blue', palette: { 50: '#eff6ff', 100: '#dbeafe', 200: '#bfdbfe', 300: '#93c5fd', 400: '#60a5fa', 500: '#3b82f6', 600: '#2563eb', 700: '#1d4ed8', 800: '#1e40af', 900: '#1e3a8a', 950: '#172554' } },
{ name: 'indigo', palette: { 50: '#eef2ff', 100: '#e0e7ff', 200: '#c7d2fe', 300: '#a5b4fc', 400: '#818cf8', 500: '#6366f1', 600: '#4f46e5', 700: '#4338ca', 800: '#3730a3', 900: '#312e81', 950: '#1e1b4b' } },
{ name: 'violet', palette: { 50: '#f5f3ff', 100: '#ede9fe', 200: '#ddd6fe', 300: '#c4b5fd', 400: '#a78bfa', 500: '#8b5cf6', 600: '#7c3aed', 700: '#6d28d9', 800: '#5b21b6', 900: '#4c1d95', 950: '#2e1065' } },
{ name: 'purple', palette: { 50: '#faf5ff', 100: '#f3e8ff', 200: '#e9d5ff', 300: '#d8b4fe', 400: '#c084fc', 500: '#a855f7', 600: '#9333ea', 700: '#7e22ce', 800: '#6b21a8', 900: '#581c87', 950: '#3b0764' } },
{ name: 'fuchsia', palette: { 50: '#fdf4ff', 100: '#fae8ff', 200: '#f5d0fe', 300: '#f0abfc', 400: '#e879f9', 500: '#d946ef', 600: '#c026d3', 700: '#a21caf', 800: '#86198f', 900: '#701a75', 950: '#4a044e' } },
{ name: 'pink', palette: { 50: '#fdf2f8', 100: '#fce7f3', 200: '#fbcfe8', 300: '#f9a8d4', 400: '#f472b6', 500: '#ec4899', 600: '#db2777', 700: '#be185d', 800: '#9d174d', 900: '#831843', 950: '#500724' } },
{ name: 'rose', palette: { 50: '#fff1f2', 100: '#ffe4e6', 200: '#fecdd3', 300: '#fda4af', 400: '#fb7185', 500: '#f43f5e', 600: '#e11d48', 700: '#be123c', 800: '#9f1239', 900: '#881337', 950: '#4c0519' } }
]);
const surfaces = ref([
{
name: 'slate',
palette: { 0: '#ffffff', 50: '#f8fafc', 100: '#f1f5f9', 200: '#e2e8f0', 300: '#cbd5e1', 400: '#94a3b8', 500: '#64748b', 600: '#475569', 700: '#334155', 800: '#1e293b', 900: '#0f172a', 950: '#020617' }
},
{
name: 'gray',
palette: { 0: '#ffffff', 50: '#f9fafb', 100: '#f3f4f6', 200: '#e5e7eb', 300: '#d1d5db', 400: '#9ca3af', 500: '#6b7280', 600: '#4b5563', 700: '#374151', 800: '#1f2937', 900: '#111827', 950: '#030712' }
},
{
name: 'zinc',
palette: { 0: '#ffffff', 50: '#fafafa', 100: '#f4f4f5', 200: '#e4e4e7', 300: '#d4d4d8', 400: '#a1a1aa', 500: '#71717a', 600: '#52525b', 700: '#3f3f46', 800: '#27272a', 900: '#18181b', 950: '#09090b' }
},
{
name: 'neutral',
palette: { 0: '#ffffff', 50: '#fafafa', 100: '#f5f5f5', 200: '#e5e5e5', 300: '#d4d4d4', 400: '#a3a3a3', 500: '#737373', 600: '#525252', 700: '#404040', 800: '#262626', 900: '#171717', 950: '#0a0a0a' }
},
{
name: 'stone',
palette: { 0: '#ffffff', 50: '#fafaf9', 100: '#f5f5f4', 200: '#e7e5e4', 300: '#d6d3d1', 400: '#a8a29e', 500: '#78716c', 600: '#57534e', 700: '#44403c', 800: '#292524', 900: '#1c1917', 950: '#0c0a09' }
},
{
name: 'soho',
palette: { 0: '#ffffff', 50: '#f4f4f4', 100: '#e8e9e9', 200: '#d2d2d4', 300: '#bbbcbe', 400: '#a5a5a9', 500: '#8e8f93', 600: '#77787d', 700: '#616268', 800: '#4a4b52', 900: '#34343d', 950: '#1d1e27' }
},
{
name: 'viva',
palette: { 0: '#ffffff', 50: '#f3f3f3', 100: '#e7e7e8', 200: '#cfd0d0', 300: '#b7b8b9', 400: '#9fa1a1', 500: '#87898a', 600: '#6e7173', 700: '#565a5b', 800: '#3e4244', 900: '#262b2c', 950: '#0e1315' }
},
{
name: 'ocean',
palette: { 0: '#ffffff', 50: '#fbfcfc', 100: '#F7F9F8', 200: '#EFF3F2', 300: '#DADEDD', 400: '#B1B7B6', 500: '#828787', 600: '#5F7274', 700: '#415B61', 800: '#29444E', 900: '#183240', 950: '#0c1920' }
}
]);
function getPresetExt() {
const color = primaryColors.value.find((c) => c.name === layoutConfig.primary);
if (color.name === 'noir') {
return {
semantic: {
primary: {
50: '{surface.50}',
100: '{surface.100}',
200: '{surface.200}',
300: '{surface.300}',
400: '{surface.400}',
500: '{surface.500}',
600: '{surface.600}',
700: '{surface.700}',
800: '{surface.800}',
900: '{surface.900}',
950: '{surface.950}'
},
colorScheme: {
light: {
primary: {
color: '{primary.950}',
contrastColor: '#ffffff',
hoverColor: '{primary.800}',
activeColor: '{primary.700}'
},
highlight: {
background: '{primary.950}',
focusBackground: '{primary.700}',
color: '#ffffff',
focusColor: '#ffffff'
}
},
dark: {
primary: {
color: '{primary.50}',
contrastColor: '{primary.950}',
hoverColor: '{primary.200}',
activeColor: '{primary.300}'
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.300}',
color: '{primary.950}',
focusColor: '{primary.950}'
}
}
}
}
};
} else {
return {
semantic: {
primary: color.palette,
colorScheme: {
light: {
primary: {
color: '{primary.500}',
contrastColor: '#ffffff',
hoverColor: '{primary.600}',
activeColor: '{primary.700}'
},
highlight: {
background: '{primary.50}',
focusBackground: '{primary.100}',
color: '{primary.700}',
focusColor: '{primary.800}'
}
},
dark: {
primary: {
color: '{primary.400}',
contrastColor: '{surface.900}',
hoverColor: '{primary.300}',
activeColor: '{primary.200}'
},
highlight: {
background: 'color-mix(in srgb, {primary.400}, transparent 84%)',
focusBackground: 'color-mix(in srgb, {primary.400}, transparent 76%)',
color: 'rgba(255,255,255,.87)',
focusColor: 'rgba(255,255,255,.87)'
}
}
}
}
};
}
}
function updateColors(type, color) {
if (type === 'primary') {
layoutConfig.primary = color.name;
} else if (type === 'surface') {
layoutConfig.surface = color.name;
}
applyTheme(type, color);
}
function applyTheme(type, color) {
if (type === 'primary') {
updatePreset(getPresetExt());
} else if (type === 'surface') {
updateSurfacePalette(color.palette);
}
}
function onPresetChange() {
layoutConfig.preset = preset.value;
const presetValue = presets[preset.value];
const surfacePalette = surfaces.value.find((s) => s.name === layoutConfig.surface)?.palette;
$t().preset(presetValue).preset(getPresetExt()).surfacePalette(surfacePalette).use({ useDefaultOptions: true });
}
</script>
<template>
<div
class="config-panel hidden absolute top-[3.25rem] right-0 w-64 p-4 bg-surface-0 dark:bg-surface-900 border border-surface rounded-border origin-top shadow-[0px_3px_5px_rgba(0,0,0,0.02),0px_0px_2px_rgba(0,0,0,0.05),0px_1px_4px_rgba(0,0,0,0.08)]"
>
<div class="flex flex-col gap-4">
<div>
<span class="text-sm text-muted-color font-semibold">Primary</span>
<div class="pt-2 flex gap-2 flex-wrap justify-between">
<button
v-for="primaryColor of primaryColors"
:key="primaryColor.name"
type="button"
:title="primaryColor.name"
@click="updateColors('primary', primaryColor)"
:class="['border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1', { 'outline-primary': layoutConfig.primary === primaryColor.name }]"
:style="{ backgroundColor: `${primaryColor.name === 'noir' ? 'var(--text-color)' : primaryColor.palette['500']}` }"
></button>
</div>
</div>
<div>
<span class="text-sm text-muted-color font-semibold">Surface</span>
<div class="pt-2 flex gap-2 flex-wrap justify-between">
<button
v-for="surface of surfaces"
:key="surface.name"
type="button"
:title="surface.name"
@click="updateColors('surface', surface)"
:class="[
'border-none w-5 h-5 rounded-full p-0 cursor-pointer outline-none outline-offset-1',
{ 'outline-primary': layoutConfig.surface ? layoutConfig.surface === surface.name : isDarkTheme ? surface.name === 'zinc' : surface.name === 'slate' }
]"
:style="{ backgroundColor: `${surface.palette['500']}` }"
></button>
</div>
</div>
<div class="flex flex-col gap-2">
<span class="text-sm text-muted-color font-semibold">Presets</span>
<SelectButton v-model="preset" @change="onPresetChange" :options="presetOptions" :allowEmpty="false" />
</div>
<div class="flex flex-col gap-2">
<span class="text-sm text-muted-color font-semibold">Menu Mode</span>
<SelectButton v-model="menuMode" @change="changeMenuMode" :options="menuModeOptions" :allowEmpty="false" optionLabel="label" optionValue="value" />
</div>
</div>
</div>
</template>
================================================
FILE: src/layout/AppFooter.vue
================================================
<script setup></script>
<template>
<div class="layout-footer">
SAKAI by
<a href="https://primevue.org" target="_blank" rel="noopener noreferrer" class="text-primary font-bold hover:underline">PrimeVue</a>
</div>
</template>
================================================
FILE: src/layout/AppLayout.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { computed } from 'vue';
import AppFooter from './AppFooter.vue';
import AppSidebar from './AppSidebar.vue';
import AppTopbar from './AppTopbar.vue';
const { layoutConfig, layoutState, hideMobileMenu } = useLayout();
const containerClass = computed(() => {
return {
'layout-overlay': layoutConfig.menuMode === 'overlay',
'layout-static': layoutConfig.menuMode === 'static',
'layout-overlay-active': layoutState.overlayMenuActive,
'layout-mobile-active': layoutState.mobileMenuActive,
'layout-static-inactive': layoutState.staticMenuInactive
};
});
</script>
<template>
<div class="layout-wrapper" :class="containerClass">
<AppTopbar />
<AppSidebar />
<div class="layout-main-container">
<div class="layout-main">
<router-view />
</div>
<AppFooter />
</div>
<div class="layout-mask animate-fadein" @click="hideMobileMenu" />
</div>
<Toast />
</template>
================================================
FILE: src/layout/AppMenu.vue
================================================
<script setup>
import { ref } from 'vue';
import AppMenuItem from './AppMenuItem.vue';
const model = ref([
{
label: 'Home',
items: [
{
label: 'Dashboard',
icon: 'pi pi-fw pi-home',
to: '/'
}
]
},
{
label: 'UI Components',
path: '/uikit',
items: [
{
label: 'Form Layout',
icon: 'pi pi-fw pi-id-card',
to: '/uikit/formlayout'
},
{
label: 'Input',
icon: 'pi pi-fw pi-check-square',
to: '/uikit/input'
},
{
label: 'Button',
icon: 'pi pi-fw pi-mobile',
to: '/uikit/button',
class: 'rotated-icon'
},
{
label: 'Table',
icon: 'pi pi-fw pi-table',
to: '/uikit/table'
},
{
label: 'List',
icon: 'pi pi-fw pi-list',
to: '/uikit/list'
},
{
label: 'Tree',
icon: 'pi pi-fw pi-share-alt',
to: '/uikit/tree'
},
{
label: 'Panel',
icon: 'pi pi-fw pi-tablet',
to: '/uikit/panel'
},
{
label: 'Overlay',
icon: 'pi pi-fw pi-clone',
to: '/uikit/overlay'
},
{
label: 'Media',
icon: 'pi pi-fw pi-image',
to: '/uikit/media'
},
{
label: 'Menu',
icon: 'pi pi-fw pi-bars',
to: '/uikit/menu'
},
{
label: 'Message',
icon: 'pi pi-fw pi-comment',
to: '/uikit/message'
},
{
label: 'File',
icon: 'pi pi-fw pi-file',
to: '/uikit/file'
},
{
label: 'Chart',
icon: 'pi pi-fw pi-chart-bar',
to: '/uikit/charts'
},
{
label: 'Timeline',
icon: 'pi pi-fw pi-calendar',
to: '/uikit/timeline'
},
{
label: 'Misc',
icon: 'pi pi-fw pi-circle',
to: '/uikit/misc'
}
]
},
{
label: 'Prime Blocks',
icon: 'pi pi-fw pi-prime',
path: '/blocks',
items: [
{
label: 'Free Blocks',
icon: 'pi pi-fw pi-eye',
to: '/blocks/free'
},
{
label: 'All Blocks',
icon: 'pi pi-fw pi-globe',
url: 'https://blocks.primevue.org/',
target: '_blank'
}
]
},
{
label: 'Pages',
icon: 'pi pi-fw pi-briefcase',
path: '/pages',
items: [
{
label: 'Landing',
icon: 'pi pi-fw pi-globe',
to: '/landing'
},
{
label: 'Auth',
icon: 'pi pi-fw pi-user',
path: '/auth',
items: [
{
label: 'Login',
icon: 'pi pi-fw pi-sign-in',
to: '/auth/login'
},
{
label: 'Error',
icon: 'pi pi-fw pi-times-circle',
to: '/auth/error'
},
{
label: 'Access Denied',
icon: 'pi pi-fw pi-lock',
to: '/auth/access'
}
]
},
{
label: 'Crud',
icon: 'pi pi-fw pi-pencil',
to: '/pages/crud'
},
{
label: 'Not Found',
icon: 'pi pi-fw pi-exclamation-circle',
to: '/pages/notfound'
},
{
label: 'Empty',
icon: 'pi pi-fw pi-circle-off',
to: '/pages/empty'
}
]
},
{
label: 'Hierarchy',
icon: 'pi pi-fw pi-align-left',
path: '/hierarchy',
items: [
{
label: 'Submenu 1',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_1',
items: [
{
label: 'Submenu 1.1',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_1_1',
items: [
{
label: 'Submenu 1.1.1',
icon: 'pi pi-fw pi-align-left'
},
{
label: 'Submenu 1.1.2',
icon: 'pi pi-fw pi-align-left'
},
{
label: 'Submenu 1.1.3',
icon: 'pi pi-fw pi-align-left'
}
]
},
{
label: 'Submenu 1.2',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_1_2',
items: [
{
label: 'Submenu 1.2.1',
icon: 'pi pi-fw pi-align-left'
}
]
}
]
},
{
label: 'Submenu 2',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_2',
items: [
{
label: 'Submenu 2.1',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_2_1',
items: [
{
label: 'Submenu 2.1.1',
icon: 'pi pi-fw pi-align-left'
},
{
label: 'Submenu 2.1.2',
icon: 'pi pi-fw pi-align-left'
}
]
},
{
label: 'Submenu 2.2',
icon: 'pi pi-fw pi-align-left',
path: '/submenu_2_2',
items: [
{
label: 'Submenu 2.2.1',
icon: 'pi pi-fw pi-align-left'
}
]
}
]
}
]
},
{
label: 'Get Started',
path: '/start',
items: [
{
label: 'Documentation',
icon: 'pi pi-fw pi-book',
to: '/start/documentation'
},
{
label: 'View Source',
icon: 'pi pi-fw pi-github',
url: 'https://github.com/primefaces/sakai-vue',
target: '_blank'
}
]
}
]);
</script>
<template>
<ul class="layout-menu">
<template v-for="(item, i) in model" :key="item">
<app-menu-item v-if="!item.separator" :item="item" :index="i"></app-menu-item>
<li v-if="item.separator" class="menu-separator"></li>
</template>
</ul>
</template>
<style lang="scss" scoped></style>
================================================
FILE: src/layout/AppMenuItem.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { computed } from 'vue';
const { layoutState, isDesktop } = useLayout();
const props = defineProps({
item: {
type: Object,
default: () => ({})
},
root: {
type: Boolean,
default: true
},
parentPath: {
type: String,
default: null
}
});
const fullPath = computed(() => (props.item.path ? (props.parentPath ? props.parentPath + props.item.path : props.item.path) : null));
const isActive = computed(() => {
return props.item.path ? layoutState.activePath?.startsWith(fullPath.value) : layoutState.activePath === props.item.to;
});
const itemClick = (event, item) => {
if (item.disabled) {
event.preventDefault();
return;
}
if (item.command) {
item.command({ originalEvent: event, item: item });
}
if (item.items) {
if (isActive.value) {
layoutState.activePath = layoutState.activePath.replace(item.path, '');
} else {
layoutState.activePath = fullPath.value;
layoutState.menuHoverActive = true;
}
} else {
layoutState.overlayMenuActive = false;
layoutState.mobileMenuActive = false;
layoutState.menuHoverActive = false;
}
};
const onMouseEnter = () => {
if (isDesktop() && props.root && props.item.items && layoutState.menuHoverActive) {
layoutState.activePath = fullPath.value;
}
};
</script>
<template>
<li :class="{ 'layout-root-menuitem': root, 'active-menuitem': isActive }">
<div v-if="root && item.visible !== false" class="layout-menuitem-root-text">{{ item.label }}</div>
<a v-if="(!item.to || item.items) && item.visible !== false" :href="item.url" @click="itemClick($event, item)" :class="item.class" :target="item.target" tabindex="0" @mouseenter="onMouseEnter">
<i :class="item.icon" class="layout-menuitem-icon" />
<span class="layout-menuitem-text">{{ item.label }}</span>
<i class="pi pi-fw pi-angle-down layout-submenu-toggler" v-if="item.items" />
</a>
<router-link v-if="item.to && !item.items && item.visible !== false" @click="itemClick($event, item)" exactActiveClass="active-route" :class="item.class" tabindex="0" :to="item.to" @mouseenter="onMouseEnter">
<i :class="item.icon" class="layout-menuitem-icon" />
<span class="layout-menuitem-text">{{ item.label }}</span>
<i class="pi pi-fw pi-angle-down layout-submenu-toggler" v-if="item.items" />
</router-link>
<Transition v-if="item.items && item.visible !== false" name="layout-submenu">
<ul v-show="root ? true : isActive" class="layout-submenu">
<app-menu-item v-for="child in item.items" :key="child.label + '_' + (child.to || child.path)" :item="child" :root="false" :parentPath="fullPath" />
</ul>
</Transition>
</li>
</template>
================================================
FILE: src/layout/AppSidebar.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { onBeforeUnmount, ref, watch } from 'vue';
import { useRoute } from 'vue-router';
import AppMenu from './AppMenu.vue';
const { layoutState, isDesktop, hasOpenOverlay } = useLayout();
const route = useRoute();
const sidebarRef = ref(null);
let outsideClickListener = null;
watch(
() => route.path,
(newPath) => {
if (isDesktop()) layoutState.activePath = null;
else layoutState.activePath = newPath;
layoutState.overlayMenuActive = false;
layoutState.mobileMenuActive = false;
layoutState.menuHoverActive = false;
},
{ immediate: true }
);
watch(hasOpenOverlay, (newVal) => {
if (isDesktop()) {
if (newVal) bindOutsideClickListener();
else unbindOutsideClickListener();
}
});
const bindOutsideClickListener = () => {
if (!outsideClickListener) {
outsideClickListener = (event) => {
if (isOutsideClicked(event)) {
layoutState.overlayMenuActive = false;
}
};
document.addEventListener('click', outsideClickListener);
}
};
const unbindOutsideClickListener = () => {
if (outsideClickListener) {
document.removeEventListener('click', outsideClickListener);
outsideClickListener = null;
}
};
const isOutsideClicked = (event) => {
const topbarButtonEl = document.querySelector('.layout-menu-button');
return !(sidebarRef.value.isSameNode(event.target) || sidebarRef.value.contains(event.target) || topbarButtonEl?.isSameNode(event.target) || topbarButtonEl?.contains(event.target));
};
onBeforeUnmount(() => {
unbindOutsideClickListener();
});
</script>
<template>
<div ref="sidebarRef" class="layout-sidebar">
<AppMenu />
</div>
</template>
================================================
FILE: src/layout/AppTopbar.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import AppConfigurator from './AppConfigurator.vue';
const { toggleMenu, toggleDarkMode, isDarkTheme } = useLayout();
</script>
<template>
<div class="layout-topbar">
<div class="layout-topbar-logo-container">
<button class="layout-menu-button layout-topbar-action" @click="toggleMenu">
<i class="pi pi-bars"></i>
</button>
<router-link to="/" class="layout-topbar-logo">
<svg viewBox="0 0 54 40" fill="none" xmlns="http://www.w3.org/2000/svg">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.1637 19.2467C17.1566 19.4033 17.1529 19.561 17.1529 19.7194C17.1529 25.3503 21.7203 29.915 27.3546 29.915C32.9887 29.915 37.5561 25.3503 37.5561 19.7194C37.5561 19.5572 37.5524 19.3959 37.5449 19.2355C38.5617 19.0801 39.5759 18.9013 40.5867 18.6994L40.6926 18.6782C40.7191 19.0218 40.7326 19.369 40.7326 19.7194C40.7326 27.1036 34.743 33.0896 27.3546 33.0896C19.966 33.0896 13.9765 27.1036 13.9765 19.7194C13.9765 19.374 13.9896 19.0316 14.0154 18.6927L14.0486 18.6994C15.0837 18.9062 16.1223 19.0886 17.1637 19.2467ZM33.3284 11.4538C31.6493 10.2396 29.5855 9.52381 27.3546 9.52381C25.1195 9.52381 23.0524 10.2421 21.3717 11.4603C20.0078 11.3232 18.6475 11.1387 17.2933 10.907C19.7453 8.11308 23.3438 6.34921 27.3546 6.34921C31.36 6.34921 34.9543 8.10844 37.4061 10.896C36.0521 11.1292 34.692 11.3152 33.3284 11.4538ZM43.826 18.0518C43.881 18.6003 43.9091 19.1566 43.9091 19.7194C43.9091 28.8568 36.4973 36.2642 27.3546 36.2642C18.2117 36.2642 10.8 28.8568 10.8 19.7194C10.8 19.1615 10.8276 18.61 10.8816 18.0663L7.75383 17.4411C7.66775 18.1886 7.62354 18.9488 7.62354 19.7194C7.62354 30.6102 16.4574 39.4388 27.3546 39.4388C38.2517 39.4388 47.0855 30.6102 47.0855 19.7194C47.0855 18.9439 47.0407 18.1789 46.9536 17.4267L43.826 18.0518ZM44.2613 9.54743L40.9084 10.2176C37.9134 5.95821 32.9593 3.1746 27.3546 3.1746C21.7442 3.1746 16.7856 5.96385 13.7915 10.2305L10.4399 9.56057C13.892 3.83178 20.1756 0 27.3546 0C34.5281 0 40.8075 3.82591 44.2613 9.54743Z"
fill="var(--primary-color)"
/>
<mask id="mask0_1413_1551" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="8" width="54" height="11">
<path d="M27 18.3652C10.5114 19.1944 0 8.88892 0 8.88892C0 8.88892 16.5176 14.5866 27 14.5866C37.4824 14.5866 54 8.88892 54 8.88892C54 8.88892 43.4886 17.5361 27 18.3652Z" fill="var(--primary-color)" />
</mask>
<g mask="url(#mask0_1413_1551)">
<path
d="M-4.673e-05 8.88887L3.73084 -1.91434L-8.00806 17.0473L-4.673e-05 8.88887ZM27 18.3652L26.4253 6.95109L27 18.3652ZM54 8.88887L61.2673 17.7127L50.2691 -1.91434L54 8.88887ZM-4.673e-05 8.88887C-8.00806 17.0473 -8.00469 17.0505 -8.00132 17.0538C-8.00018 17.055 -7.99675 17.0583 -7.9944 17.0607C-7.98963 17.0653 -7.98474 17.0701 -7.97966 17.075C-7.96949 17.0849 -7.95863 17.0955 -7.94707 17.1066C-7.92401 17.129 -7.89809 17.1539 -7.86944 17.1812C-7.8122 17.236 -7.74377 17.3005 -7.66436 17.3743C-7.50567 17.5218 -7.30269 17.7063 -7.05645 17.9221C-6.56467 18.3532 -5.89662 18.9125 -5.06089 19.5534C-3.39603 20.83 -1.02575 22.4605 1.98012 24.0457C7.97874 27.2091 16.7723 30.3226 27.5746 29.7793L26.4253 6.95109C20.7391 7.23699 16.0326 5.61231 12.6534 3.83024C10.9703 2.94267 9.68222 2.04866 8.86091 1.41888C8.45356 1.10653 8.17155 0.867278 8.0241 0.738027C7.95072 0.673671 7.91178 0.637576 7.90841 0.634492C7.90682 0.63298 7.91419 0.639805 7.93071 0.65557C7.93897 0.663455 7.94952 0.673589 7.96235 0.686039C7.96883 0.692262 7.97582 0.699075 7.98338 0.706471C7.98719 0.710167 7.99113 0.714014 7.99526 0.718014C7.99729 0.720008 8.00047 0.723119 8.00148 0.724116C8.00466 0.727265 8.00796 0.730446 -4.673e-05 8.88887ZM27.5746 29.7793C37.6904 29.2706 45.9416 26.3684 51.6602 23.6054C54.5296 22.2191 56.8064 20.8465 58.4186 19.7784C59.2265 19.2431 59.873 18.7805 60.3494 18.4257C60.5878 18.2482 60.7841 18.0971 60.9374 17.977C61.014 17.9169 61.0799 17.8645 61.1349 17.8203C61.1624 17.7981 61.1872 17.7781 61.2093 17.7602C61.2203 17.7512 61.2307 17.7427 61.2403 17.7348C61.2452 17.7308 61.2499 17.727 61.2544 17.7233C61.2566 17.7215 61.2598 17.7188 61.261 17.7179C61.2642 17.7153 61.2673 17.7127 54 8.88887C46.7326 0.0650536 46.7357 0.0625219 46.7387 0.0600241C46.7397 0.0592345 46.7427 0.0567658 46.7446 0.0551857C46.7485 0.0520238 46.7521 0.0489887 46.7557 0.0460799C46.7628 0.0402623 46.7694 0.0349487 46.7753 0.0301318C46.7871 0.0204986 46.7966 0.0128495 46.8037 0.00712562C46.818 -0.00431848 46.8228 -0.00808311 46.8184 -0.00463784C46.8096 0.00228345 46.764 0.0378652 46.6828 0.0983779C46.5199 0.219675 46.2165 0.439161 45.7812 0.727519C44.9072 1.30663 43.5257 2.14765 41.7061 3.02677C38.0469 4.79468 32.7981 6.63058 26.4253 6.95109L27.5746 29.7793ZM54 8.88887C50.2691 -1.91433 50.27 -1.91467 50.271 -1.91498C50.2712 -1.91506 50.272 -1.91535 50.2724 -1.9155C50.2733 -1.91581 50.274 -1.91602 50.2743 -1.91616C50.2752 -1.91643 50.275 -1.91636 50.2738 -1.91595C50.2714 -1.91515 50.2652 -1.91302 50.2552 -1.9096C50.2351 -1.90276 50.1999 -1.89078 50.1503 -1.874C50.0509 -1.84043 49.8938 -1.78773 49.6844 -1.71863C49.2652 -1.58031 48.6387 -1.377 47.8481 -1.13035C46.2609 -0.635237 44.0427 0.0249875 41.5325 0.6823C36.215 2.07471 30.6736 3.15796 27 3.15796V26.0151C33.8087 26.0151 41.7672 24.2495 47.3292 22.7931C50.2586 22.026 52.825 21.2618 54.6625 20.6886C55.5842 20.4011 56.33 20.1593 56.8551 19.986C57.1178 19.8993 57.3258 19.8296 57.4735 19.7797C57.5474 19.7548 57.6062 19.7348 57.6493 19.72C57.6709 19.7127 57.6885 19.7066 57.7021 19.7019C57.7089 19.6996 57.7147 19.6976 57.7195 19.696C57.7219 19.6952 57.7241 19.6944 57.726 19.6938C57.7269 19.6934 57.7281 19.693 57.7286 19.6929C57.7298 19.6924 57.7309 19.692 54 8.88887ZM27 3.15796C23.3263 3.15796 17.7849 2.07471 12.4674 0.6823C9.95717 0.0249875 7.73904 -0.635237 6.15184 -1.13035C5.36118 -1.377 4.73467 -1.58031 4.3155 -1.71863C4.10609 -1.78773 3.94899 -1.84043 3.84961 -1.874C3.79994 -1.89078 3.76474 -1.90276 3.74471 -1.9096C3.73469 -1.91302 3.72848 -1.91515 3.72613 -1.91595C3.72496 -1.91636 3.72476 -1.91643 3.72554 -1.91616C3.72593 -1.91602 3.72657 -1.91581 3.72745 -1.9155C3.72789 -1.91535 3.72874 -1.91506 3.72896 -1.91498C3.72987 -1.91467 3.73084 -1.91433 -4.673e-05 8.88887C-3.73093 19.692 -3.72983 19.6924 -3.72868 19.6929C-3.72821 19.693 -3.72698 19.6934 -3.72603 19.6938C-3.72415 19.6944 -3.72201 19.6952 -3.71961 19.696C-3.71482 19.6976 -3.70901 19.6996 -3.7022 19.7019C-3.68858 19.7066 -3.67095 19.7127 -3.6494 19.72C-3.60629 19.7348 -3.54745 19.7548 -3.47359 19.7797C-3.32589 19.8296 -3.11788 19.8993 -2.85516 19.986C-2.33008 20.1593 -1.58425 20.4011 -0.662589 20.6886C1.17485 21.2618 3.74125 22.026 6.67073 22.7931C12.2327 24.2495 20.1913 26.0151 27 26.0151V3.15796Z"
fill="var(--primary-color)"
/>
</g>
</svg>
<span>SAKAI</span>
</router-link>
</div>
<div class="layout-topbar-actions">
<div class="layout-config-menu">
<button type="button" class="layout-topbar-action" @click="toggleDarkMode">
<i :class="['pi', { 'pi-moon': isDarkTheme, 'pi-sun': !isDarkTheme }]"></i>
</button>
<div class="relative">
<button
v-styleclass="{ selector: '@next', enterFromClass: 'hidden', enterActiveClass: 'p-anchored-overlay-enter-active', leaveToClass: 'hidden', leaveActiveClass: 'p-anchored-overlay-leave-active', hideOnOutsideClick: true }"
type="button"
class="layout-topbar-action layout-topbar-action-highlight"
>
<i class="pi pi-palette"></i>
</button>
<AppConfigurator />
</div>
</div>
<button
class="layout-topbar-menu-button layout-topbar-action"
v-styleclass="{ selector: '@next', enterFromClass: 'hidden', enterActiveClass: 'p-anchored-overlay-enter-active', leaveToClass: 'hidden', leaveActiveClass: 'p-anchored-overlay-leave-active', hideOnOutsideClick: true }"
>
<i class="pi pi-ellipsis-v"></i>
</button>
<div class="layout-topbar-menu hidden lg:block">
<div class="layout-topbar-menu-content">
<button type="button" class="layout-topbar-action">
<i class="pi pi-calendar"></i>
<span>Calendar</span>
</button>
<button type="button" class="layout-topbar-action">
<i class="pi pi-inbox"></i>
<span>Messages</span>
</button>
<button type="button" class="layout-topbar-action">
<i class="pi pi-user"></i>
<span>Profile</span>
</button>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/layout/composables/layout.js
================================================
import { computed, reactive } from 'vue';
const layoutConfig = reactive({
preset: 'Aura',
primary: 'emerald',
surface: null,
darkTheme: false,
menuMode: 'static'
});
const layoutState = reactive({
staticMenuInactive: false,
overlayMenuActive: false,
profileSidebarVisible: false,
configSidebarVisible: false,
sidebarExpanded: false,
menuHoverActive: false,
activeMenuItem: null,
activePath: null
});
export function useLayout() {
const toggleDarkMode = () => {
if (!document.startViewTransition) {
executeDarkModeToggle();
return;
}
document.startViewTransition(() => executeDarkModeToggle(event));
};
const executeDarkModeToggle = () => {
layoutConfig.darkTheme = !layoutConfig.darkTheme;
document.documentElement.classList.toggle('app-dark');
};
const toggleMenu = () => {
if (isDesktop()) {
if (layoutConfig.menuMode === 'static') {
layoutState.staticMenuInactive = !layoutState.staticMenuInactive;
}
if (layoutConfig.menuMode === 'overlay') {
layoutState.overlayMenuActive = !layoutState.overlayMenuActive;
}
} else {
layoutState.mobileMenuActive = !layoutState.mobileMenuActive;
}
};
const toggleConfigSidebar = () => {
layoutState.configSidebarVisible = !layoutState.configSidebarVisible;
};
const hideMobileMenu = () => {
layoutState.mobileMenuActive = false;
};
const changeMenuMode = (event) => {
layoutConfig.menuMode = event.value;
layoutState.staticMenuInactive = false;
layoutState.mobileMenuActive = false;
layoutState.sidebarExpanded = false;
layoutState.menuHoverActive = false;
layoutState.anchored = false;
};
const isDarkTheme = computed(() => layoutConfig.darkTheme);
const isDesktop = () => window.innerWidth > 991;
const hasOpenOverlay = computed(() => layoutState.overlayMenuActive);
return {
layoutConfig,
layoutState,
isDarkTheme,
toggleDarkMode,
toggleConfigSidebar,
toggleMenu,
hideMobileMenu,
changeMenuMode,
isDesktop,
hasOpenOverlay
};
}
================================================
FILE: src/router/index.js
================================================
import AppLayout from '@/layout/AppLayout.vue';
import { createRouter, createWebHistory } from 'vue-router';
const router = createRouter({
history: createWebHistory(),
routes: [
{
path: '/',
component: AppLayout,
children: [
{
path: '/',
name: 'dashboard',
component: () => import('@/views/Dashboard.vue')
},
{
path: '/uikit/formlayout',
name: 'formlayout',
component: () => import('@/views/uikit/FormLayout.vue')
},
{
path: '/uikit/input',
name: 'input',
component: () => import('@/views/uikit/InputDoc.vue')
},
{
path: '/uikit/button',
name: 'button',
component: () => import('@/views/uikit/ButtonDoc.vue')
},
{
path: '/uikit/table',
name: 'table',
component: () => import('@/views/uikit/TableDoc.vue')
},
{
path: '/uikit/list',
name: 'list',
component: () => import('@/views/uikit/ListDoc.vue')
},
{
path: '/uikit/tree',
name: 'tree',
component: () => import('@/views/uikit/TreeDoc.vue')
},
{
path: '/uikit/panel',
name: 'panel',
component: () => import('@/views/uikit/PanelsDoc.vue')
},
{
path: '/uikit/overlay',
name: 'overlay',
component: () => import('@/views/uikit/OverlayDoc.vue')
},
{
path: '/uikit/media',
name: 'media',
component: () => import('@/views/uikit/MediaDoc.vue')
},
{
path: '/uikit/message',
name: 'message',
component: () => import('@/views/uikit/MessagesDoc.vue')
},
{
path: '/uikit/file',
name: 'file',
component: () => import('@/views/uikit/FileDoc.vue')
},
{
path: '/uikit/menu',
name: 'menu',
component: () => import('@/views/uikit/MenuDoc.vue')
},
{
path: '/uikit/charts',
name: 'charts',
component: () => import('@/views/uikit/ChartDoc.vue')
},
{
path: '/uikit/misc',
name: 'misc',
component: () => import('@/views/uikit/MiscDoc.vue')
},
{
path: '/uikit/timeline',
name: 'timeline',
component: () => import('@/views/uikit/TimelineDoc.vue')
},
{
path: '/blocks/free',
name: 'blocks',
meta: {
breadcrumb: ['Prime Blocks', 'Free Blocks']
},
component: () => import('@/views/utilities/Blocks.vue')
},
{
path: '/pages/empty',
name: 'empty',
component: () => import('@/views/pages/Empty.vue')
},
{
path: '/pages/crud',
name: 'crud',
component: () => import('@/views/pages/Crud.vue')
},
{
path: '/start/documentation',
name: 'documentation',
component: () => import('@/views/pages/Documentation.vue')
}
]
},
{
path: '/landing',
name: 'landing',
component: () => import('@/views/pages/Landing.vue')
},
{
path: '/pages/notfound',
name: 'notfound',
component: () => import('@/views/pages/NotFound.vue')
},
{
path: '/auth/login',
name: 'login',
component: () => import('@/views/pages/auth/Login.vue')
},
{
path: '/auth/access',
name: 'accessDenied',
component: () => import('@/views/pages/auth/Access.vue')
},
{
path: '/auth/error',
name: 'error',
component: () => import('@/views/pages/auth/Error.vue')
}
]
});
export default router;
================================================
FILE: src/service/CountryService.js
================================================
export const CountryService = {
getData() {
return [
{ name: 'Afghanistan', code: 'AF' },
{ name: 'Albania', code: 'AL' },
{ name: 'Algeria', code: 'DZ' },
{ name: 'American Samoa', code: 'AS' },
{ name: 'Andorra', code: 'AD' },
{ name: 'Angola', code: 'AO' },
{ name: 'Anguilla', code: 'AI' },
{ name: 'Antarctica', code: 'AQ' },
{ name: 'Antigua and Barbuda', code: 'AG' },
{ name: 'Argentina', code: 'AR' },
{ name: 'Armenia', code: 'AM' },
{ name: 'Aruba', code: 'AW' },
{ name: 'Australia', code: 'AU' },
{ name: 'Austria', code: 'AT' },
{ name: 'Azerbaijan', code: 'AZ' },
{ name: 'Bahamas', code: 'BS' },
{ name: 'Bahrain', code: 'BH' },
{ name: 'Bangladesh', code: 'BD' },
{ name: 'Barbados', code: 'BB' },
{ name: 'Belarus', code: 'BY' },
{ name: 'Belgium', code: 'BE' },
{ name: 'Belize', code: 'BZ' },
{ name: 'Benin', code: 'BJ' },
{ name: 'Bermuda', code: 'BM' },
{ name: 'Bhutan', code: 'BT' },
{ name: 'Bolivia', code: 'BO' },
{ name: 'Bosnia and Herzegovina', code: 'BA' },
{ name: 'Botswana', code: 'BW' },
{ name: 'Bouvet Island', code: 'BV' },
{ name: 'Brazil', code: 'BR' },
{ name: 'British Indian Ocean Territory', code: 'IO' },
{ name: 'Brunei Darussalam', code: 'BN' },
{ name: 'Bulgaria', code: 'BG' },
{ name: 'Burkina Faso', code: 'BF' },
{ name: 'Burundi', code: 'BI' },
{ name: 'Cambodia', code: 'KH' },
{ name: 'Cameroon', code: 'CM' },
{ name: 'Canada', code: 'CA' },
{ name: 'Cape Verde', code: 'CV' },
{ name: 'Cayman Islands', code: 'KY' },
{ name: 'Central African Republic', code: 'CF' },
{ name: 'Chad', code: 'TD' },
{ name: 'Chile', code: 'CL' },
{ name: 'China', code: 'CN' },
{ name: 'Christmas Island', code: 'CX' },
{ name: 'Cocos (Keeling) Islands', code: 'CC' },
{ name: 'Colombia', code: 'CO' },
{ name: 'Comoros', code: 'KM' },
{ name: 'Congo', code: 'CG' },
{ name: 'Congo, The Democratic Republic of the', code: 'CD' },
{ name: 'Cook Islands', code: 'CK' },
{ name: 'Costa Rica', code: 'CR' },
{ name: 'Cote D"Ivoire', code: 'CI' },
{ name: 'Croatia', code: 'HR' },
{ name: 'Cuba', code: 'CU' },
{ name: 'Cyprus', code: 'CY' },
{ name: 'Czech Republic', code: 'CZ' },
{ name: 'Denmark', code: 'DK' },
{ name: 'Djibouti', code: 'DJ' },
{ name: 'Dominica', code: 'DM' },
{ name: 'Dominican Republic', code: 'DO' },
{ name: 'Ecuador', code: 'EC' },
{ name: 'Egypt', code: 'EG' },
{ name: 'El Salvador', code: 'SV' },
{ name: 'Equatorial Guinea', code: 'GQ' },
{ name: 'Eritrea', code: 'ER' },
{ name: 'Estonia', code: 'EE' },
{ name: 'Ethiopia', code: 'ET' },
{ name: 'Falkland Islands (Malvinas)', code: 'FK' },
{ name: 'Faroe Islands', code: 'FO' },
{ name: 'Fiji', code: 'FJ' },
{ name: 'Finland', code: 'FI' },
{ name: 'France', code: 'FR' },
{ name: 'French Guiana', code: 'GF' },
{ name: 'French Polynesia', code: 'PF' },
{ name: 'French Southern Territories', code: 'TF' },
{ name: 'Gabon', code: 'GA' },
{ name: 'Gambia', code: 'GM' },
{ name: 'Georgia', code: 'GE' },
{ name: 'Germany', code: 'DE' },
{ name: 'Ghana', code: 'GH' },
{ name: 'Gibraltar', code: 'GI' },
{ name: 'Greece', code: 'GR' },
{ name: 'Greenland', code: 'GL' },
{ name: 'Grenada', code: 'GD' },
{ name: 'Guadeloupe', code: 'GP' },
{ name: 'Guam', code: 'GU' },
{ name: 'Guatemala', code: 'GT' },
{ name: 'Guernsey', code: 'GG' },
{ name: 'Guinea', code: 'GN' },
{ name: 'Guinea-Bissau', code: 'GW' },
{ name: 'Guyana', code: 'GY' },
{ name: 'Haiti', code: 'HT' },
{ name: 'Heard Island and Mcdonald Islands', code: 'HM' },
{ name: 'Holy See (Vatican City State)', code: 'VA' },
{ name: 'Honduras', code: 'HN' },
{ name: 'Hong Kong', code: 'HK' },
{ name: 'Hungary', code: 'HU' },
{ name: 'Iceland', code: 'IS' },
{ name: 'India', code: 'IN' },
{ name: 'Indonesia', code: 'ID' },
{ name: 'Iran, Islamic Republic Of', code: 'IR' },
{ name: 'Iraq', code: 'IQ' },
{ name: 'Ireland', code: 'IE' },
{ name: 'Isle of Man', code: 'IM' },
{ name: 'Israel', code: 'IL' },
{ name: 'Italy', code: 'IT' },
{ name: 'Jamaica', code: 'JM' },
{ name: 'Japan', code: 'JP' },
{ name: 'Jersey', code: 'JE' },
{ name: 'Jordan', code: 'JO' },
{ name: 'Kazakhstan', code: 'KZ' },
{ name: 'Kenya', code: 'KE' },
{ name: 'Kiribati', code: 'KI' },
{ name: 'Korea, Democratic People"S Republic of', code: 'KP' },
{ name: 'Korea, Republic of', code: 'KR' },
{ name: 'Kuwait', code: 'KW' },
{ name: 'Kyrgyzstan', code: 'KG' },
{ name: 'Lao People"S Democratic Republic', code: 'LA' },
{ name: 'Latvia', code: 'LV' },
{ name: 'Lebanon', code: 'LB' },
{ name: 'Lesotho', code: 'LS' },
{ name: 'Liberia', code: 'LR' },
{ name: 'Libyan Arab Jamahiriya', code: 'LY' },
{ name: 'Liechtenstein', code: 'LI' },
{ name: 'Lithuania', code: 'LT' },
{ name: 'Luxembourg', code: 'LU' },
{ name: 'Macao', code: 'MO' },
{ name: 'Macedonia, The Former Yugoslav Republic of', code: 'MK' },
{ name: 'Madagascar', code: 'MG' },
{ name: 'Malawi', code: 'MW' },
{ name: 'Malaysia', code: 'MY' },
{ name: 'Maldives', code: 'MV' },
{ name: 'Mali', code: 'ML' },
{ name: 'Malta', code: 'MT' },
{ name: 'Marshall Islands', code: 'MH' },
{ name: 'Martinique', code: 'MQ' },
{ name: 'Mauritania', code: 'MR' },
{ name: 'Mauritius', code: 'MU' },
{ name: 'Mayotte', code: 'YT' },
{ name: 'Mexico', code: 'MX' },
{ name: 'Micronesia, Federated States of', code: 'FM' },
{ name: 'Moldova, Republic of', code: 'MD' },
{ name: 'Monaco', code: 'MC' },
{ name: 'Mongolia', code: 'MN' },
{ name: 'Montserrat', code: 'MS' },
{ name: 'Morocco', code: 'MA' },
{ name: 'Mozambique', code: 'MZ' },
{ name: 'Myanmar', code: 'MM' },
{ name: 'Namibia', code: 'NA' },
{ name: 'Nauru', code: 'NR' },
{ name: 'Nepal', code: 'NP' },
{ name: 'Netherlands', code: 'NL' },
{ name: 'Netherlands Antilles', code: 'AN' },
{ name: 'New Caledonia', code: 'NC' },
{ name: 'New Zealand', code: 'NZ' },
{ name: 'Nicaragua', code: 'NI' },
{ name: 'Niger', code: 'NE' },
{ name: 'Nigeria', code: 'NG' },
{ name: 'Niue', code: 'NU' },
{ name: 'Norfolk Island', code: 'NF' },
{ name: 'Northern Mariana Islands', code: 'MP' },
{ name: 'Norway', code: 'NO' },
{ name: 'Oman', code: 'OM' },
{ name: 'Pakistan', code: 'PK' },
{ name: 'Palau', code: 'PW' },
{ name: 'Palestinian Territory, Occupied', code: 'PS' },
{ name: 'Panama', code: 'PA' },
{ name: 'Papua New Guinea', code: 'PG' },
{ name: 'Paraguay', code: 'PY' },
{ name: 'Peru', code: 'PE' },
{ name: 'Philippines', code: 'PH' },
{ name: 'Pitcairn', code: 'PN' },
{ name: 'Poland', code: 'PL' },
{ name: 'Portugal', code: 'PT' },
{ name: 'Puerto Rico', code: 'PR' },
{ name: 'Qatar', code: 'QA' },
{ name: 'Reunion', code: 'RE' },
{ name: 'Romania', code: 'RO' },
{ name: 'Russian Federation', code: 'RU' },
{ name: 'RWANDA', code: 'RW' },
{ name: 'Saint Helena', code: 'SH' },
{ name: 'Saint Kitts and Nevis', code: 'KN' },
{ name: 'Saint Lucia', code: 'LC' },
{ name: 'Saint Pierre and Miquelon', code: 'PM' },
{ name: 'Saint Vincent and the Grenadines', code: 'VC' },
{ name: 'Samoa', code: 'WS' },
{ name: 'San Marino', code: 'SM' },
{ name: 'Sao Tome and Principe', code: 'ST' },
{ name: 'Saudi Arabia', code: 'SA' },
{ name: 'Senegal', code: 'SN' },
{ name: 'Serbia and Montenegro', code: 'CS' },
{ name: 'Seychelles', code: 'SC' },
{ name: 'Sierra Leone', code: 'SL' },
{ name: 'Singapore', code: 'SG' },
{ name: 'Slovakia', code: 'SK' },
{ name: 'Slovenia', code: 'SI' },
{ name: 'Solomon Islands', code: 'SB' },
{ name: 'Somalia', code: 'SO' },
{ name: 'South Africa', code: 'ZA' },
{ name: 'South Georgia and the South Sandwich Islands', code: 'GS' },
{ name: 'Spain', code: 'ES' },
{ name: 'Sri Lanka', code: 'LK' },
{ name: 'Sudan', code: 'SD' },
{ name: 'Suriname', code: 'SR' },
{ name: 'Svalbard and Jan Mayen', code: 'SJ' },
{ name: 'Swaziland', code: 'SZ' },
{ name: 'Sweden', code: 'SE' },
{ name: 'Switzerland', code: 'CH' },
{ name: 'Syrian Arab Republic', code: 'SY' },
{ name: 'Taiwan, Province of China', code: 'TW' },
{ name: 'Tajikistan', code: 'TJ' },
{ name: 'Tanzania, United Republic of', code: 'TZ' },
{ name: 'Thailand', code: 'TH' },
{ name: 'Timor-Leste', code: 'TL' },
{ name: 'Togo', code: 'TG' },
{ name: 'Tokelau', code: 'TK' },
{ name: 'Tonga', code: 'TO' },
{ name: 'Trinidad and Tobago', code: 'TT' },
{ name: 'Tunisia', code: 'TN' },
{ name: 'Turkey', code: 'TR' },
{ name: 'Turkmenistan', code: 'TM' },
{ name: 'Turks and Caicos Islands', code: 'TC' },
{ name: 'Tuvalu', code: 'TV' },
{ name: 'Uganda', code: 'UG' },
{ name: 'Ukraine', code: 'UA' },
{ name: 'United Arab Emirates', code: 'AE' },
{ name: 'United Kingdom', code: 'GB' },
{ name: 'United States', code: 'US' },
{ name: 'United States Minor Outlying Islands', code: 'UM' },
{ name: 'Uruguay', code: 'UY' },
{ name: 'Uzbekistan', code: 'UZ' },
{ name: 'Vanuatu', code: 'VU' },
{ name: 'Venezuela', code: 'VE' },
{ name: 'Viet Nam', code: 'VN' },
{ name: 'Virgin Islands, British', code: 'VG' },
{ name: 'Virgin Islands, U.S.', code: 'VI' },
{ name: 'Wallis and Futuna', code: 'WF' },
{ name: 'Western Sahara', code: 'EH' },
{ name: 'Yemen', code: 'YE' },
{ name: 'Zambia', code: 'ZM' },
{ name: 'Zimbabwe', code: 'ZW' }
];
},
getCountries() {
return Promise.resolve(this.getData());
}
};
================================================
FILE: src/service/NodeService.js
================================================
export const NodeService = {
getTreeNodesData() {
return [
{
key: '0',
label: 'Documents',
data: 'Documents Folder',
icon: 'pi pi-fw pi-inbox',
children: [
{
key: '0-0',
label: 'Work',
data: 'Work Folder',
icon: 'pi pi-fw pi-cog',
children: [
{ key: '0-0-0', label: 'Expenses.doc', icon: 'pi pi-fw pi-file', data: 'Expenses Document' },
{ key: '0-0-1', label: 'Resume.doc', icon: 'pi pi-fw pi-file', data: 'Resume Document' }
]
},
{
key: '0-1',
label: 'Home',
data: 'Home Folder',
icon: 'pi pi-fw pi-home',
children: [{ key: '0-1-0', label: 'Invoices.txt', icon: 'pi pi-fw pi-file', data: 'Invoices for this month' }]
}
]
},
{
key: '1',
label: 'Events',
data: 'Events Folder',
icon: 'pi pi-fw pi-calendar',
children: [
{ key: '1-0', label: 'Meeting', icon: 'pi pi-fw pi-calendar-plus', data: 'Meeting' },
{ key: '1-1', label: 'Product Launch', icon: 'pi pi-fw pi-calendar-plus', data: 'Product Launch' },
{ key: '1-2', label: 'Report Review', icon: 'pi pi-fw pi-calendar-plus', data: 'Report Review' }
]
},
{
key: '2',
label: 'Movies',
data: 'Movies Folder',
icon: 'pi pi-fw pi-star-fill',
children: [
{
key: '2-0',
icon: 'pi pi-fw pi-star-fill',
label: 'Al Pacino',
data: 'Pacino Movies',
children: [
{ key: '2-0-0', label: 'Scarface', icon: 'pi pi-fw pi-video', data: 'Scarface Movie' },
{ key: '2-0-1', label: 'Serpico', icon: 'pi pi-fw pi-video', data: 'Serpico Movie' }
]
},
{
key: '2-1',
label: 'Robert De Niro',
icon: 'pi pi-fw pi-star-fill',
data: 'De Niro Movies',
children: [
{ key: '2-1-0', label: 'Goodfellas', icon: 'pi pi-fw pi-video', data: 'Goodfellas Movie' },
{ key: '2-1-1', label: 'Untouchables', icon: 'pi pi-fw pi-video', data: 'Untouchables Movie' }
]
}
]
}
];
},
getTreeTableNodesData() {
return [
{
key: '0',
data: {
name: 'Applications',
size: '100kb',
type: 'Folder'
},
children: [
{
key: '0-0',
data: {
name: 'Vue',
size: '25kb',
type: 'Folder'
},
children: [
{
key: '0-0-0',
data: {
name: 'vue.app',
size: '10kb',
type: 'Application'
}
},
{
key: '0-0-1',
data: {
name: 'native.app',
size: '10kb',
type: 'Application'
}
},
{
key: '0-0-2',
data: {
name: 'mobile.app',
size: '5kb',
type: 'Application'
}
}
]
},
{
key: '0-1',
data: {
name: 'editor.app',
size: '25kb',
type: 'Application'
}
},
{
key: '0-2',
data: {
name: 'settings.app',
size: '50kb',
type: 'Application'
}
}
]
},
{
key: '1',
data: {
name: 'Cloud',
size: '20kb',
type: 'Folder'
},
children: [
{
key: '1-0',
data: {
name: 'backup-1.zip',
size: '10kb',
type: 'Zip'
}
},
{
key: '1-1',
data: {
name: 'backup-2.zip',
size: '10kb',
type: 'Zip'
}
}
]
},
{
key: '2',
data: {
name: 'Desktop',
size: '150kb',
type: 'Folder'
},
children: [
{
key: '2-0',
data: {
name: 'note-meeting.txt',
size: '50kb',
type: 'Text'
}
},
{
key: '2-1',
data: {
name: 'note-todo.txt',
size: '100kb',
type: 'Text'
}
}
]
},
{
key: '3',
data: {
name: 'Documents',
size: '75kb',
type: 'Folder'
},
children: [
{
key: '3-0',
data: {
name: 'Work',
size: '55kb',
type: 'Folder'
},
children: [
{
key: '3-0-0',
data: {
name: 'Expenses.doc',
size: '30kb',
type: 'Document'
}
},
{
key: '3-0-1',
data: {
name: 'Resume.doc',
size: '25kb',
type: 'Resume'
}
}
]
},
{
key: '3-1',
data: {
name: 'Home',
size: '20kb',
type: 'Folder'
},
children: [
{
key: '3-1-0',
data: {
name: 'Invoices',
size: '20kb',
type: 'Text'
}
}
]
}
]
},
{
key: '4',
data: {
name: 'Downloads',
size: '25kb',
type: 'Folder'
},
children: [
{
key: '4-0',
data: {
name: 'Spanish',
size: '10kb',
type: 'Folder'
},
children: [
{
key: '4-0-0',
data: {
name: 'tutorial-a1.txt',
size: '5kb',
type: 'Text'
}
},
{
key: '4-0-1',
data: {
name: 'tutorial-a2.txt',
size: '5kb',
type: 'Text'
}
}
]
},
{
key: '4-1',
data: {
name: 'Travel',
size: '15kb',
type: 'Text'
},
children: [
{
key: '4-1-0',
data: {
name: 'Hotel.pdf',
size: '10kb',
type: 'PDF'
}
},
{
key: '4-1-1',
data: {
name: 'Flight.pdf',
size: '5kb',
type: 'PDF'
}
}
]
}
]
},
{
key: '5',
data: {
name: 'Main',
size: '50kb',
type: 'Folder'
},
children: [
{
key: '5-0',
data: {
name: 'bin',
size: '50kb',
type: 'Link'
}
},
{
key: '5-1',
data: {
name: 'etc',
size: '100kb',
type: 'Link'
}
},
{
key: '5-2',
data: {
name: 'var',
size: '100kb',
type: 'Link'
}
}
]
},
{
key: '6',
data: {
name: 'Other',
size: '5kb',
type: 'Folder'
},
children: [
{
key: '6-0',
data: {
name: 'todo.txt',
size: '3kb',
type: 'Text'
}
},
{
key: '6-1',
data: {
name: 'logo.png',
size: '2kb',
type: 'Picture'
}
}
]
},
{
key: '7',
data: {
name: 'Pictures',
size: '150kb',
type: 'Folder'
},
children: [
{
key: '7-0',
data: {
name: 'barcelona.jpg',
size: '90kb',
type: 'Picture'
}
},
{
key: '7-1',
data: {
name: 'primevue.png',
size: '30kb',
type: 'Picture'
}
},
{
key: '7-2',
data: {
name: 'prime.jpg',
size: '30kb',
type: 'Picture'
}
}
]
},
{
key: '8',
data: {
name: 'Videos',
size: '1500kb',
type: 'Folder'
},
children: [
{
key: '8-0',
data: {
name: 'primefaces.mkv',
size: '1000kb',
type: 'Video'
}
},
{
key: '8-1',
data: {
name: 'intro.avi',
size: '500kb',
type: 'Video'
}
}
]
}
];
},
getTreeTableNodes() {
return Promise.resolve(this.getTreeTableNodesData());
},
getTreeNodes() {
return Promise.resolve(this.getTreeNodesData());
}
};
================================================
FILE: src/service/PhotoService.js
================================================
export const PhotoService = {
getData() {
return [
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria1.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria1s.jpg',
alt: 'Description for Image 1',
title: 'Title 1'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria2.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria2s.jpg',
alt: 'Description for Image 2',
title: 'Title 2'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria3.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria3s.jpg',
alt: 'Description for Image 3',
title: 'Title 3'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria4.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria4s.jpg',
alt: 'Description for Image 4',
title: 'Title 4'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria5.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria5s.jpg',
alt: 'Description for Image 5',
title: 'Title 5'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria6.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria6s.jpg',
alt: 'Description for Image 6',
title: 'Title 6'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria7.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria7s.jpg',
alt: 'Description for Image 7',
title: 'Title 7'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria8.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria8s.jpg',
alt: 'Description for Image 8',
title: 'Title 8'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria9.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria9s.jpg',
alt: 'Description for Image 9',
title: 'Title 9'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria10.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria10s.jpg',
alt: 'Description for Image 10',
title: 'Title 10'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria11.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria11s.jpg',
alt: 'Description for Image 11',
title: 'Title 11'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria12.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria12s.jpg',
alt: 'Description for Image 12',
title: 'Title 12'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria13.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria13s.jpg',
alt: 'Description for Image 13',
title: 'Title 13'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria14.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria14s.jpg',
alt: 'Description for Image 14',
title: 'Title 14'
},
{
itemImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria15.jpg',
thumbnailImageSrc: 'https://primefaces.org/cdn/primevue/images/galleria/galleria15s.jpg',
alt: 'Description for Image 15',
title: 'Title 15'
}
];
},
getImages() {
return Promise.resolve(this.getData());
}
};
================================================
FILE: src/service/ProductService.js
================================================
export const ProductService = {
getProductsData() {
return [
{
id: '1000',
code: 'f230fh0g3',
name: 'Bamboo Watch',
description: 'Product Description',
image: 'bamboo-watch.jpg',
price: 65,
category: 'Accessories',
quantity: 24,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1001',
code: 'nvklal433',
name: 'Black Watch',
description: 'Product Description',
image: 'black-watch.jpg',
price: 72,
category: 'Accessories',
quantity: 61,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1002',
code: 'zz21cz3c1',
name: 'Blue Band',
description: 'Product Description',
image: 'blue-band.jpg',
price: 79,
category: 'Fitness',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 3
},
{
id: '1003',
code: '244wgerg2',
name: 'Blue T-Shirt',
description: 'Product Description',
image: 'blue-t-shirt.jpg',
price: 29,
category: 'Clothing',
quantity: 25,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1004',
code: 'h456wer53',
name: 'Bracelet',
description: 'Product Description',
image: 'bracelet.jpg',
price: 15,
category: 'Accessories',
quantity: 73,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1005',
code: 'av2231fwg',
name: 'Brown Purse',
description: 'Product Description',
image: 'brown-purse.jpg',
price: 120,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4
},
{
id: '1006',
code: 'bib36pfvm',
name: 'Chakra Bracelet',
description: 'Product Description',
image: 'chakra-bracelet.jpg',
price: 32,
category: 'Accessories',
quantity: 5,
inventoryStatus: 'LOWSTOCK',
rating: 3
},
{
id: '1007',
code: 'mbvjkgip5',
name: 'Galaxy Earrings',
description: 'Product Description',
image: 'galaxy-earrings.jpg',
price: 34,
category: 'Accessories',
quantity: 23,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1008',
code: 'vbb124btr',
name: 'Game Controller',
description: 'Product Description',
image: 'game-controller.jpg',
price: 99,
category: 'Electronics',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 4
},
{
id: '1009',
code: 'cm230f032',
name: 'Gaming Set',
description: 'Product Description',
image: 'gaming-set.jpg',
price: 299,
category: 'Electronics',
quantity: 63,
inventoryStatus: 'INSTOCK',
rating: 3
},
{
id: '1010',
code: 'plb34234v',
name: 'Gold Phone Case',
description: 'Product Description',
image: 'gold-phone-case.jpg',
price: 24,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4
},
{
id: '1011',
code: '4920nnc2d',
name: 'Green Earbuds',
description: 'Product Description',
image: 'green-earbuds.jpg',
price: 89,
category: 'Electronics',
quantity: 23,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1012',
code: '250vm23cc',
name: 'Green T-Shirt',
description: 'Product Description',
image: 'green-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 74,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1013',
code: 'fldsmn31b',
name: 'Grey T-Shirt',
description: 'Product Description',
image: 'grey-t-shirt.jpg',
price: 48,
category: 'Clothing',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 3
},
{
id: '1014',
code: 'waas1x2as',
name: 'Headphones',
description: 'Product Description',
image: 'headphones.jpg',
price: 175,
category: 'Electronics',
quantity: 8,
inventoryStatus: 'LOWSTOCK',
rating: 5
},
{
id: '1015',
code: 'vb34btbg5',
name: 'Light Green T-Shirt',
description: 'Product Description',
image: 'light-green-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 34,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1016',
code: 'k8l6j58jl',
name: 'Lime Band',
description: 'Product Description',
image: 'lime-band.jpg',
price: 79,
category: 'Fitness',
quantity: 12,
inventoryStatus: 'INSTOCK',
rating: 3
},
{
id: '1017',
code: 'v435nn85n',
name: 'Mini Speakers',
description: 'Product Description',
image: 'mini-speakers.jpg',
price: 85,
category: 'Clothing',
quantity: 42,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1018',
code: '09zx9c0zc',
name: 'Painted Phone Case',
description: 'Product Description',
image: 'painted-phone-case.jpg',
price: 56,
category: 'Accessories',
quantity: 41,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1019',
code: 'mnb5mb2m5',
name: 'Pink Band',
description: 'Product Description',
image: 'pink-band.jpg',
price: 79,
category: 'Fitness',
quantity: 63,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1020',
code: 'r23fwf2w3',
name: 'Pink Purse',
description: 'Product Description',
image: 'pink-purse.jpg',
price: 110,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4
},
{
id: '1021',
code: 'pxpzczo23',
name: 'Purple Band',
description: 'Product Description',
image: 'purple-band.jpg',
price: 79,
category: 'Fitness',
quantity: 6,
inventoryStatus: 'LOWSTOCK',
rating: 3
},
{
id: '1022',
code: '2c42cb5cb',
name: 'Purple Gemstone Necklace',
description: 'Product Description',
image: 'purple-gemstone-necklace.jpg',
price: 45,
category: 'Accessories',
quantity: 62,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1023',
code: '5k43kkk23',
name: 'Purple T-Shirt',
description: 'Product Description',
image: 'purple-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 5
},
{
id: '1024',
code: 'lm2tny2k4',
name: 'Shoes',
description: 'Product Description',
image: 'shoes.jpg',
price: 64,
category: 'Clothing',
quantity: 0,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1025',
code: 'nbm5mv45n',
name: 'Sneakers',
description: 'Product Description',
image: 'sneakers.jpg',
price: 78,
category: 'Clothing',
quantity: 52,
inventoryStatus: 'INSTOCK',
rating: 4
},
{
id: '1026',
code: 'zx23zc42c',
name: 'Teal T-Shirt',
description: 'Product Description',
image: 'teal-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 3,
inventoryStatus: 'LOWSTOCK',
rating: 3
},
{
id: '1027',
code: 'acvx872gc',
name: 'Yellow Earbuds',
description: 'Product Description',
image: 'yellow-earbuds.jpg',
price: 89,
category: 'Electronics',
quantity: 35,
inventoryStatus: 'INSTOCK',
rating: 3
},
{
id: '1028',
code: 'tx125ck42',
name: 'Yoga Mat',
description: 'Product Description',
image: 'yoga-mat.jpg',
price: 20,
category: 'Fitness',
quantity: 15,
inventoryStatus: 'INSTOCK',
rating: 5
},
{
id: '1029',
code: 'gwuby345v',
name: 'Yoga Set',
description: 'Product Description',
image: 'yoga-set.jpg',
price: 20,
category: 'Fitness',
quantity: 25,
inventoryStatus: 'INSTOCK',
rating: 8
}
];
},
getProductsWithOrdersData() {
return [
{
id: '1000',
code: 'f230fh0g3',
name: 'Bamboo Watch',
description: 'Product Description',
image: 'bamboo-watch.jpg',
price: 65,
category: 'Accessories',
quantity: 24,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: [
{
id: '1000-0',
productCode: 'f230fh0g3',
date: '2020-09-13',
amount: 65,
quantity: 1,
customer: 'David James',
status: 'PENDING'
},
{
id: '1000-1',
productCode: 'f230fh0g3',
date: '2020-05-14',
amount: 130,
quantity: 2,
customer: 'Leon Rodrigues',
status: 'DELIVERED'
},
{
id: '1000-2',
productCode: 'f230fh0g3',
date: '2019-01-04',
amount: 65,
quantity: 1,
customer: 'Juan Alejandro',
status: 'RETURNED'
},
{
id: '1000-3',
productCode: 'f230fh0g3',
date: '2020-09-13',
amount: 195,
quantity: 3,
customer: 'Claire Morrow',
status: 'CANCELLED'
}
]
},
{
id: '1001',
code: 'nvklal433',
name: 'Black Watch',
description: 'Product Description',
image: 'black-watch.jpg',
price: 72,
category: 'Accessories',
quantity: 61,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1001-0',
productCode: 'nvklal433',
date: '2020-05-14',
amount: 72,
quantity: 1,
customer: 'Maisha Jefferson',
status: 'DELIVERED'
},
{
id: '1001-1',
productCode: 'nvklal433',
date: '2020-02-28',
amount: 144,
quantity: 2,
customer: 'Octavia Murillo',
status: 'PENDING'
}
]
},
{
id: '1002',
code: 'zz21cz3c1',
name: 'Blue Band',
description: 'Product Description',
image: 'blue-band.jpg',
price: 79,
category: 'Fitness',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 3,
orders: [
{
id: '1002-0',
productCode: 'zz21cz3c1',
date: '2020-07-05',
amount: 79,
quantity: 1,
customer: 'Stacey Leja',
status: 'DELIVERED'
},
{
id: '1002-1',
productCode: 'zz21cz3c1',
date: '2020-02-06',
amount: 79,
quantity: 1,
customer: 'Ashley Wickens',
status: 'DELIVERED'
}
]
},
{
id: '1003',
code: '244wgerg2',
name: 'Blue T-Shirt',
description: 'Product Description',
image: 'blue-t-shirt.jpg',
price: 29,
category: 'Clothing',
quantity: 25,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: []
},
{
id: '1004',
code: 'h456wer53',
name: 'Bracelet',
description: 'Product Description',
image: 'bracelet.jpg',
price: 15,
category: 'Accessories',
quantity: 73,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1004-0',
productCode: 'h456wer53',
date: '2020-09-05',
amount: 60,
quantity: 4,
customer: 'Mayumi Misaki',
status: 'PENDING'
},
{
id: '1004-1',
productCode: 'h456wer53',
date: '2019-04-16',
amount: 2,
quantity: 30,
customer: 'Francesco Salvatore',
status: 'DELIVERED'
}
]
},
{
id: '1005',
code: 'av2231fwg',
name: 'Brown Purse',
description: 'Product Description',
image: 'brown-purse.jpg',
price: 120,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4,
orders: [
{
id: '1005-0',
productCode: 'av2231fwg',
date: '2020-01-25',
amount: 120,
quantity: 1,
customer: 'Isabel Sinclair',
status: 'RETURNED'
},
{
id: '1005-1',
productCode: 'av2231fwg',
date: '2019-03-12',
amount: 240,
quantity: 2,
customer: 'Lionel Clifford',
status: 'DELIVERED'
},
{
id: '1005-2',
productCode: 'av2231fwg',
date: '2019-05-05',
amount: 120,
quantity: 1,
customer: 'Cody Chavez',
status: 'DELIVERED'
}
]
},
{
id: '1006',
code: 'bib36pfvm',
name: 'Chakra Bracelet',
description: 'Product Description',
image: 'chakra-bracelet.jpg',
price: 32,
category: 'Accessories',
quantity: 5,
inventoryStatus: 'LOWSTOCK',
rating: 3,
orders: [
{
id: '1006-0',
productCode: 'bib36pfvm',
date: '2020-02-24',
amount: 32,
quantity: 1,
customer: 'Arvin Darci',
status: 'DELIVERED'
},
{
id: '1006-1',
productCode: 'bib36pfvm',
date: '2020-01-14',
amount: 64,
quantity: 2,
customer: 'Izzy Jones',
status: 'PENDING'
}
]
},
{
id: '1007',
code: 'mbvjkgip5',
name: 'Galaxy Earrings',
description: 'Product Description',
image: 'galaxy-earrings.jpg',
price: 34,
category: 'Accessories',
quantity: 23,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: [
{
id: '1007-0',
productCode: 'mbvjkgip5',
date: '2020-06-19',
amount: 34,
quantity: 1,
customer: 'Jennifer Smith',
status: 'DELIVERED'
}
]
},
{
id: '1008',
code: 'vbb124btr',
name: 'Game Controller',
description: 'Product Description',
image: 'game-controller.jpg',
price: 99,
category: 'Electronics',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 4,
orders: [
{
id: '1008-0',
productCode: 'vbb124btr',
date: '2020-01-05',
amount: 99,
quantity: 1,
customer: 'Jeanfrancois David',
status: 'DELIVERED'
},
{
id: '1008-1',
productCode: 'vbb124btr',
date: '2020-01-19',
amount: 198,
quantity: 2,
customer: 'Ivar Greenwood',
status: 'RETURNED'
}
]
},
{
id: '1009',
code: 'cm230f032',
name: 'Gaming Set',
description: 'Product Description',
image: 'gaming-set.jpg',
price: 299,
category: 'Electronics',
quantity: 63,
inventoryStatus: 'INSTOCK',
rating: 3,
orders: [
{
id: '1009-0',
productCode: 'cm230f032',
date: '2020-06-24',
amount: 299,
quantity: 1,
customer: 'Kadeem Mujtaba',
status: 'PENDING'
},
{
id: '1009-1',
productCode: 'cm230f032',
date: '2020-05-11',
amount: 299,
quantity: 1,
customer: 'Ashley Wickens',
status: 'DELIVERED'
},
{
id: '1009-2',
productCode: 'cm230f032',
date: '2019-02-07',
amount: 299,
quantity: 1,
customer: 'Julie Johnson',
status: 'DELIVERED'
},
{
id: '1009-3',
productCode: 'cm230f032',
date: '2020-04-26',
amount: 299,
quantity: 1,
customer: 'Tony Costa',
status: 'CANCELLED'
}
]
},
{
id: '1010',
code: 'plb34234v',
name: 'Gold Phone Case',
description: 'Product Description',
image: 'gold-phone-case.jpg',
price: 24,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4,
orders: [
{
id: '1010-0',
productCode: 'plb34234v',
date: '2020-02-04',
amount: 24,
quantity: 1,
customer: 'James Butt',
status: 'DELIVERED'
},
{
id: '1010-1',
productCode: 'plb34234v',
date: '2020-05-05',
amount: 48,
quantity: 2,
customer: 'Josephine Darakjy',
status: 'DELIVERED'
}
]
},
{
id: '1011',
code: '4920nnc2d',
name: 'Green Earbuds',
description: 'Product Description',
image: 'green-earbuds.jpg',
price: 89,
category: 'Electronics',
quantity: 23,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1011-0',
productCode: '4920nnc2d',
date: '2020-06-01',
amount: 89,
quantity: 1,
customer: 'Art Venere',
status: 'DELIVERED'
}
]
},
{
id: '1012',
code: '250vm23cc',
name: 'Green T-Shirt',
description: 'Product Description',
image: 'green-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 74,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: [
{
id: '1012-0',
productCode: '250vm23cc',
date: '2020-02-05',
amount: 49,
quantity: 1,
customer: 'Lenna Paprocki',
status: 'DELIVERED'
},
{
id: '1012-1',
productCode: '250vm23cc',
date: '2020-02-15',
amount: 49,
quantity: 1,
customer: 'Donette Foller',
status: 'PENDING'
}
]
},
{
id: '1013',
code: 'fldsmn31b',
name: 'Grey T-Shirt',
description: 'Product Description',
image: 'grey-t-shirt.jpg',
price: 48,
category: 'Clothing',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 3,
orders: [
{
id: '1013-0',
productCode: 'fldsmn31b',
date: '2020-04-01',
amount: 48,
quantity: 1,
customer: 'Simona Morasca',
status: 'DELIVERED'
}
]
},
{
id: '1014',
code: 'waas1x2as',
name: 'Headphones',
description: 'Product Description',
image: 'headphones.jpg',
price: 175,
category: 'Electronics',
quantity: 8,
inventoryStatus: 'LOWSTOCK',
rating: 5,
orders: [
{
id: '1014-0',
productCode: 'waas1x2as',
date: '2020-05-15',
amount: 175,
quantity: 1,
customer: 'Lenna Paprocki',
status: 'DELIVERED'
},
{
id: '1014-1',
productCode: 'waas1x2as',
date: '2020-01-02',
amount: 175,
quantity: 1,
customer: 'Donette Foller',
status: 'CANCELLED'
}
]
},
{
id: '1015',
code: 'vb34btbg5',
name: 'Light Green T-Shirt',
description: 'Product Description',
image: 'light-green-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 34,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1015-0',
productCode: 'vb34btbg5',
date: '2020-07-02',
amount: 98,
quantity: 2,
customer: 'Mitsue Tollner',
status: 'DELIVERED'
}
]
},
{
id: '1016',
code: 'k8l6j58jl',
name: 'Lime Band',
description: 'Product Description',
image: 'lime-band.jpg',
price: 79,
category: 'Fitness',
quantity: 12,
inventoryStatus: 'INSTOCK',
rating: 3,
orders: []
},
{
id: '1017',
code: 'v435nn85n',
name: 'Mini Speakers',
description: 'Product Description',
image: 'mini-speakers.jpg',
price: 85,
category: 'Clothing',
quantity: 42,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1017-0',
productCode: 'v435nn85n',
date: '2020-07-12',
amount: 85,
quantity: 1,
customer: 'Minna Amigon',
status: 'DELIVERED'
}
]
},
{
id: '1018',
code: '09zx9c0zc',
name: 'Painted Phone Case',
description: 'Product Description',
image: 'painted-phone-case.jpg',
price: 56,
category: 'Accessories',
quantity: 41,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: [
{
id: '1018-0',
productCode: '09zx9c0zc',
date: '2020-07-01',
amount: 56,
quantity: 1,
customer: 'Abel Maclead',
status: 'DELIVERED'
},
{
id: '1018-1',
productCode: '09zx9c0zc',
date: '2020-05-02',
amount: 56,
quantity: 1,
customer: 'Minna Amigon',
status: 'RETURNED'
}
]
},
{
id: '1019',
code: 'mnb5mb2m5',
name: 'Pink Band',
description: 'Product Description',
image: 'pink-band.jpg',
price: 79,
category: 'Fitness',
quantity: 63,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: []
},
{
id: '1020',
code: 'r23fwf2w3',
name: 'Pink Purse',
description: 'Product Description',
image: 'pink-purse.jpg',
price: 110,
category: 'Accessories',
quantity: 0,
inventoryStatus: 'OUTOFSTOCK',
rating: 4,
orders: [
{
id: '1020-0',
productCode: 'r23fwf2w3',
date: '2020-05-29',
amount: 110,
quantity: 1,
customer: 'Kiley Caldarera',
status: 'DELIVERED'
},
{
id: '1020-1',
productCode: 'r23fwf2w3',
date: '2020-02-11',
amount: 220,
quantity: 2,
customer: 'Graciela Ruta',
status: 'DELIVERED'
}
]
},
{
id: '1021',
code: 'pxpzczo23',
name: 'Purple Band',
description: 'Product Description',
image: 'purple-band.jpg',
price: 79,
category: 'Fitness',
quantity: 6,
inventoryStatus: 'LOWSTOCK',
rating: 3,
orders: [
{
id: '1021-0',
productCode: 'pxpzczo23',
date: '2020-02-02',
amount: 79,
quantity: 1,
customer: 'Cammy Albares',
status: 'DELIVERED'
}
]
},
{
id: '1022',
code: '2c42cb5cb',
name: 'Purple Gemstone Necklace',
description: 'Product Description',
image: 'purple-gemstone-necklace.jpg',
price: 45,
category: 'Accessories',
quantity: 62,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1022-0',
productCode: '2c42cb5cb',
date: '2020-06-29',
amount: 45,
quantity: 1,
customer: 'Mattie Poquette',
status: 'DELIVERED'
},
{
id: '1022-1',
productCode: '2c42cb5cb',
date: '2020-02-11',
amount: 135,
quantity: 3,
customer: 'Meaghan Garufi',
status: 'DELIVERED'
}
]
},
{
id: '1023',
code: '5k43kkk23',
name: 'Purple T-Shirt',
description: 'Product Description',
image: 'purple-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 2,
inventoryStatus: 'LOWSTOCK',
rating: 5,
orders: [
{
id: '1023-0',
productCode: '5k43kkk23',
date: '2020-04-15',
amount: 49,
quantity: 1,
customer: 'Gladys Rim',
status: 'RETURNED'
}
]
},
{
id: '1024',
code: 'lm2tny2k4',
name: 'Shoes',
description: 'Product Description',
image: 'shoes.jpg',
price: 64,
category: 'Clothing',
quantity: 0,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: []
},
{
id: '1025',
code: 'nbm5mv45n',
name: 'Sneakers',
description: 'Product Description',
image: 'sneakers.jpg',
price: 78,
category: 'Clothing',
quantity: 52,
inventoryStatus: 'INSTOCK',
rating: 4,
orders: [
{
id: '1025-0',
productCode: 'nbm5mv45n',
date: '2020-02-19',
amount: 78,
quantity: 1,
customer: 'Yuki Whobrey',
status: 'DELIVERED'
},
{
id: '1025-1',
productCode: 'nbm5mv45n',
date: '2020-05-21',
amount: 78,
quantity: 1,
customer: 'Fletcher Flosi',
status: 'PENDING'
}
]
},
{
id: '1026',
code: 'zx23zc42c',
name: 'Teal T-Shirt',
description: 'Product Description',
image: 'teal-t-shirt.jpg',
price: 49,
category: 'Clothing',
quantity: 3,
inventoryStatus: 'LOWSTOCK',
rating: 3,
orders: [
{
id: '1026-0',
productCode: 'zx23zc42c',
date: '2020-04-24',
amount: 98,
quantity: 2,
customer: 'Bette Nicka',
status: 'DELIVERED'
}
]
},
{
id: '1027',
code: 'acvx872gc',
name: 'Yellow Earbuds',
description: 'Product Description',
image: 'yellow-earbuds.jpg',
price: 89,
category: 'Electronics',
quantity: 35,
inventoryStatus: 'INSTOCK',
rating: 3,
orders: [
{
id: '1027-0',
productCode: 'acvx872gc',
date: '2020-01-29',
amount: 89,
quantity: 1,
customer: 'Veronika Inouye',
status: 'DELIVERED'
},
{
id: '1027-1',
productCode: 'acvx872gc',
date: '2020-06-11',
amount: 89,
quantity: 1,
customer: 'Willard Kolmetz',
status: 'DELIVERED'
}
]
},
{
id: '1028',
code: 'tx125ck42',
name: 'Yoga Mat',
description: 'Product Description',
image: 'yoga-mat.jpg',
price: 20,
category: 'Fitness',
quantity: 15,
inventoryStatus: 'INSTOCK',
rating: 5,
orders: []
},
{
id: '1029',
code: 'gwuby345v',
name: 'Yoga Set',
description: 'Product Description',
image: 'yoga-set.jpg',
price: 20,
category: 'Fitness',
quantity: 25,
inventoryStatus: 'INSTOCK',
rating: 8,
orders: [
{
id: '1029-0',
productCode: 'gwuby345v',
date: '2020-02-14',
amount: 4,
quantity: 80,
customer: 'Maryann Royster',
status: 'DELIVERED'
}
]
}
];
},
getProductsMini() {
return Promise.resolve(this.getProductsData().slice(0, 5));
},
getProductsSmall() {
return Promise.resolve(this.getProductsData().slice(0, 10));
},
getProducts() {
return Promise.resolve(this.getProductsData());
},
getProductsWithOrdersSmall() {
return Promise.resolve(this.getProductsWithOrdersData().slice(0, 10));
},
getProductsWithOrders() {
return Promise.resolve(this.getProductsWithOrdersData());
}
};
================================================
FILE: src/views/Dashboard.vue
================================================
<script setup>
import BestSellingWidget from '@/components/dashboard/BestSellingWidget.vue';
import NotificationsWidget from '@/components/dashboard/NotificationsWidget.vue';
import RecentSalesWidget from '@/components/dashboard/RecentSalesWidget.vue';
import RevenueStreamWidget from '@/components/dashboard/RevenueStreamWidget.vue';
import StatsWidget from '@/components/dashboard/StatsWidget.vue';
</script>
<template>
<div class="grid grid-cols-12 gap-8">
<StatsWidget />
<div class="col-span-12 xl:col-span-6">
<RecentSalesWidget />
<BestSellingWidget />
</div>
<div class="col-span-12 xl:col-span-6">
<RevenueStreamWidget />
<NotificationsWidget />
</div>
</div>
</template>
================================================
FILE: src/views/pages/Crud.vue
================================================
<script setup>
import { ProductService } from '@/service/ProductService';
import { FilterMatchMode } from '@primevue/core/api';
import { useToast } from 'primevue/usetoast';
import { onMounted, ref } from 'vue';
onMounted(() => {
ProductService.getProducts().then((data) => (products.value = data));
});
const toast = useToast();
const dt = ref();
const products = ref();
const productDialog = ref(false);
const deleteProductDialog = ref(false);
const deleteProductsDialog = ref(false);
const product = ref({});
const selectedProducts = ref();
const filters = ref({
global: { value: null, matchMode: FilterMatchMode.CONTAINS }
});
const submitted = ref(false);
const statuses = ref([
{ label: 'INSTOCK', value: 'instock' },
{ label: 'LOWSTOCK', value: 'lowstock' },
{ label: 'OUTOFSTOCK', value: 'outofstock' }
]);
function formatCurrency(value) {
if (value) return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
return;
}
function openNew() {
product.value = {};
submitted.value = false;
productDialog.value = true;
}
function hideDialog() {
productDialog.value = false;
submitted.value = false;
}
function saveProduct() {
submitted.value = true;
if (product?.value.name?.trim()) {
if (product.value.id) {
product.value.inventoryStatus = product.value.inventoryStatus.value ? product.value.inventoryStatus.value : product.value.inventoryStatus;
products.value[findIndexById(product.value.id)] = product.value;
toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Updated', life: 3000 });
} else {
product.value.id = createId();
product.value.code = createId();
product.value.image = 'product-placeholder.svg';
product.value.inventoryStatus = product.value.inventoryStatus ? product.value.inventoryStatus.value : 'INSTOCK';
products.value.push(product.value);
toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Created', life: 3000 });
}
productDialog.value = false;
product.value = {};
}
}
function editProduct(prod) {
product.value = { ...prod };
productDialog.value = true;
}
function confirmDeleteProduct(prod) {
product.value = prod;
deleteProductDialog.value = true;
}
function deleteProduct() {
products.value = products.value.filter((val) => val.id !== product.value.id);
deleteProductDialog.value = false;
product.value = {};
toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Deleted', life: 3000 });
}
function findIndexById(id) {
let index = -1;
for (let i = 0; i < products.value.length; i++) {
if (products.value[i].id === id) {
index = i;
break;
}
}
return index;
}
function createId() {
let id = '';
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
for (var i = 0; i < 5; i++) {
id += chars.charAt(Math.floor(Math.random() * chars.length));
}
return id;
}
function exportCSV() {
dt.value.exportCSV();
}
function confirmDeleteSelected() {
deleteProductsDialog.value = true;
}
function deleteSelectedProducts() {
products.value = products.value.filter((val) => !selectedProducts.value.includes(val));
deleteProductsDialog.value = false;
selectedProducts.value = null;
toast.add({ severity: 'success', summary: 'Successful', detail: 'Products Deleted', life: 3000 });
}
function getStatusLabel(status) {
switch (status) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
</script>
<template>
<div>
<div class="card">
<Toolbar class="mb-6">
<template #start>
<Button label="New" icon="pi pi-plus" severity="secondary" class="mr-2" @click="openNew" />
<Button label="Delete" icon="pi pi-trash" severity="secondary" @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
</template>
<template #end>
<Button label="Export" icon="pi pi-upload" severity="secondary" @click="exportCSV($event)" />
</template>
</Toolbar>
<DataTable
ref="dt"
v-model:selection="selectedProducts"
:value="products"
dataKey="id"
:paginator="true"
:rows="10"
:filters="filters"
paginatorTemplate="FirstPageLink PrevPageLink PageLinks NextPageLink LastPageLink CurrentPageReport RowsPerPageDropdown"
:rowsPerPageOptions="[5, 10, 25]"
currentPageReportTemplate="Showing {first} to {last} of {totalRecords} products"
>
<template #header>
<div class="flex flex-wrap gap-2 items-center justify-between">
<h4 class="m-0">Manage Products</h4>
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters['global'].value" placeholder="Search..." />
</IconField>
</div>
</template>
<Column selectionMode="multiple" style="width: 3rem" :exportable="false"></Column>
<Column field="code" header="Code" sortable style="min-width: 12rem"></Column>
<Column field="name" header="Name" sortable style="min-width: 16rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="rounded" style="width: 64px" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category" sortable style="min-width: 10rem"></Column>
<Column field="rating" header="Reviews" sortable style="min-width: 12rem">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" :readonly="true" />
</template>
</Column>
<Column field="inventoryStatus" header="Status" sortable style="min-width: 12rem">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStatusLabel(slotProps.data.inventoryStatus)" />
</template>
</Column>
<Column :exportable="false" style="min-width: 12rem">
<template #body="slotProps">
<Button icon="pi pi-pencil" outlined rounded class="mr-2" @click="editProduct(slotProps.data)" />
<Button icon="pi pi-trash" outlined rounded severity="danger" @click="confirmDeleteProduct(slotProps.data)" />
</template>
</Column>
</DataTable>
</div>
<Dialog v-model:visible="productDialog" :style="{ width: '450px' }" header="Product Details" :modal="true">
<div class="flex flex-col gap-6">
<img v-if="product.image" :src="`https://primefaces.org/cdn/primevue/images/product/${product.image}`" :alt="product.image" class="block m-auto pb-4" />
<div>
<label for="name" class="block font-bold mb-3">Name</label>
<InputText id="name" v-model.trim="product.name" required="true" autofocus :invalid="submitted && !product.name" fluid />
<small v-if="submitted && !product.name" class="text-red-500">Name is required.</small>
</div>
<div>
<label for="description" class="block font-bold mb-3">Description</label>
<Textarea id="description" v-model="product.description" required="true" rows="3" cols="20" fluid />
</div>
<div>
<label for="inventoryStatus" class="block font-bold mb-3">Inventory Status</label>
<Select id="inventoryStatus" v-model="product.inventoryStatus" :options="statuses" optionLabel="label" placeholder="Select a Status" fluid></Select>
</div>
<div>
<span class="block font-bold mb-4">Category</span>
<div class="grid grid-cols-12 gap-4">
<div class="flex items-center gap-2 col-span-6">
<RadioButton id="category1" v-model="product.category" name="category" value="Accessories" />
<label for="category1">Accessories</label>
</div>
<div class="flex items-center gap-2 col-span-6">
<RadioButton id="category2" v-model="product.category" name="category" value="Clothing" />
<label for="category2">Clothing</label>
</div>
<div class="flex items-center gap-2 col-span-6">
<RadioButton id="category3" v-model="product.category" name="category" value="Electronics" />
<label for="category3">Electronics</label>
</div>
<div class="flex items-center gap-2 col-span-6">
<RadioButton id="category4" v-model="product.category" name="category" value="Fitness" />
<label for="category4">Fitness</label>
</div>
</div>
</div>
<div class="grid grid-cols-12 gap-4">
<div class="col-span-6">
<label for="price" class="block font-bold mb-3">Price</label>
<InputNumber id="price" v-model="product.price" mode="currency" currency="USD" locale="en-US" fluid />
</div>
<div class="col-span-6">
<label for="quantity" class="block font-bold mb-3">Quantity</label>
<InputNumber id="quantity" v-model="product.quantity" integeronly fluid />
</div>
</div>
</div>
<template #footer>
<Button label="Cancel" icon="pi pi-times" text @click="hideDialog" />
<Button label="Save" icon="pi pi-check" @click="saveProduct" />
</template>
</Dialog>
<Dialog v-model:visible="deleteProductDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
<div class="flex items-center gap-4">
<i class="pi pi-exclamation-triangle text-3xl!" />
<span v-if="product"
>Are you sure you want to delete <b>{{ product.name }}</b
>?</span
>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" text @click="deleteProductDialog = false" />
<Button label="Yes" icon="pi pi-check" @click="deleteProduct" />
</template>
</Dialog>
<Dialog v-model:visible="deleteProductsDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
<div class="flex items-center gap-4">
<i class="pi pi-exclamation-triangle text-3xl!" />
<span v-if="product">Are you sure you want to delete the selected products?</span>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" text @click="deleteProductsDialog = false" />
<Button label="Yes" icon="pi pi-check" text @click="deleteSelectedProducts" />
</template>
</Dialog>
</div>
</template>
================================================
FILE: src/views/pages/Documentation.vue
================================================
<template>
<div class="card">
<div class="font-semibold text-2xl mb-4">Documentation</div>
<div class="font-semibold text-xl mb-4">Get Started</div>
<p class="text-lg mb-4">
Sakai is an application template for Vue based on the <a href="https://github.com/vuejs/create-vue" class="font-medium text-primary hover:underline">create-vue</a>, the recommended way to start a <strong>Vite-powered</strong> Vue
projects. To get started, clone the <a href="https://github.com/primefaces/sakai-vue" class="font-medium text-primary hover:underline">repository</a> from GitHub and install the dependencies with npm or yarn.
</p>
<pre class="app-code">
<code>git clone https://github.com/primefaces/sakai-vue
npm install
npm run dev</code></pre>
<p class="text-lg mb-4">Navigate to <i class="bg-highlight px-2 py-1 rounded-border not-italic text-base">http://localhost:5173/</i> to view the application in your local environment.</p>
<pre class="app-code"><code>npm run dev</code></pre>
<div class="font-semibold text-xl mb-4">Structure</div>
<p class="text-lg mb-4">Templates consists of a couple folders, demos and layout have been separated so that you can easily remove what is not necessary for your application.</p>
<ul class="leading-normal list-disc pl-8 text-lg mb-4">
<li><span class="text-primary font-medium">src/layout</span>: Main layout files, needs to be present.</li>
<li><span class="text-primary font-medium">src/views</span>: Demo pages like Dashboard.</li>
<li><span class="text-primary font-medium">public/demo</span>: Assets used in demos</li>
<li><span class="text-primary font-medium">src/assets/demo</span>: Styles used in demos</li>
<li><span class="text-primary font-medium">src/assets/layout</span>: SCSS files of the main layout</li>
</ul>
<div class="font-semibold text-xl mb-4">Menu</div>
<p class="text-lg mb-4">
Main menu is defined at <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">src/layout/AppMenu.vue</span> file. Update the <i class="bg-highlight px-2 py-1 rounded-border not-italic text-base">model</i> property to
define your own menu items.
</p>
<div class="font-semibold text-xl mb-4">Layout Composable</div>
<p class="text-lg mb-4">
The <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">src/layout/composables/layout.js</span> is a composable that manages the layout state changes including dark mode, PrimeVue theme, menu modes and states. If you
change the initial values like the preset or colors, make sure to apply them at PrimeVue config at main.js as well.
</p>
<div class="font-semibold text-xl mb-4">Tailwind CSS</div>
<p class="text-lg mb-4">The demo pages are developed with Tailwind CSS however the core application shell mainly uses custom CSS.</p>
<div class="font-semibold text-xl mb-4">Variables</div>
<p class="text-lg mb-4">
CSS variables used in the template derive their values from the PrimeVue styled mode presets, use the files under <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">assets/layout/_variables.scss</span> to customize
according to your requirements.
</p>
<div class="font-semibold text-xl mb-4">Add Sakai-Vue to a Nuxt Project</div>
<p class="text-lg mb-4">To get started, create a Nuxt project.</p>
<pre class="app-code">
<code>npx nuxi@latest init sakai-nuxt</code></pre>
<p class="text-lg mb-4">Add Prime related libraries to the project.</p>
<pre class="app-code">
<code>npm install primevue @primevue/themes tailwindcss-primeui primeicons
npm install --save-dev @primevue/nuxt-module</code></pre>
<p class="text-lg mb-4">Add PrimeVue-Nuxt module to <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">nuxt.config.js</span></p>
<pre class="app-code">
<code>modules: [
'@primevue/nuxt-module',
]</code></pre>
<p class="text-lg mb-4">Install <a href="https://tailwindcss.com/docs/guides/nuxtjs" class="font-medium text-primary hover:underline">Tailwind CSS</a> with Nuxt using official documentation.</p>
<p class="text-lg mb-4">
Add <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">tailwindcss-primeui</span> package as a plugin to <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">tailwind.config.js</span>
</p>
<pre class="app-code">
<code>plugins: [require('tailwindcss-primeui')]</code></pre>
<p class="text-lg mb-4">Add PrimeVue to in <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">nuxt.config.js</span></p>
<pre class="app-code">
<code>import Aura from '@primevue/themes/aura';
primevue: {
options: {
theme: {
preset: Aura,
options: {
darkModeSelector: '.app-dark'
}
}
}
}</code></pre>
<p class="text-lg mb-4">
Copy <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">src/assets</span> folder and paste them to <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">assets</span> folder to your Nuxt project.
And add to <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">nuxt.config.js</span>
</p>
<pre class="app-code">
<code>css: ['~/assets/tailwind.css', '~/assets/styles.scss']</code></pre>
<p class="text-lg mb-4">Change <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">app.vue</span></p>
<pre class="app-code">
<code>&lt;template&gt;
&lt;NuxtLayout&gt;
&lt;NuxtPage /&gt;
&lt;/NuxtLayout&gt;
&lt;/template&gt;</code></pre>
<p class="text-lg mb-4">Create <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">layouts/default.vue</span> and paste this code:</p>
<pre class="app-code">
<code>&lt;script setup&gt;
import AppLayout from './AppLayout.vue';
&lt;/script&gt;
&lt;template&gt;
&lt;AppLayout /&gt;
&lt;/template&gt;</code></pre>
<p class="text-lg mb-4">
Create <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">layouts</span> folder and copy <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">src/layout</span> folder and paste them. And then
create <span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">composables/use-layout.vue</span> and replace it with
<span class="bg-highlight px-2 py-1 rounded-border not-italic text-base">src/layout/composables/layout.js</span>. Then remove this line:
</p>
<pre class="app-code">
<code>import { useLayout } from '@/layout/composables/layout';</code></pre>
<p class="text-lg mb-4">As a final step, copy the following folders:</p>
<ul class="leading-normal list-disc pl-8 text-lg mb-4">
<li><span class="text-primary font-medium">public/demo</span> <i class="pi pi-arrow-right text-sm! mr-1"></i> <span class="text-primary font-medium">public</span></li>
<li><span class="text-primary font-medium">src/components</span> <i class="pi pi-arrow-right text-sm! mr-1"></i> <span class="text-primary font-medium">components</span></li>
<li><span class="text-primary font-medium">src/service</span> <i class="pi pi-arrow-right text-sm! mr-1"></i> <span class="text-primary font-medium">service</span></li>
<li><span class="text-primary font-medium">src/views/uikit</span> <i class="pi pi-arrow-right text-sm! mr-1"></i> <span class="text-primary font-medium">pages/uikit</span></li>
<li><span class="text-primary font-medium">src/views/pages</span> <i class="pi pi-arrow-right text-sm! mr-1"></i> <span class="text-primary font-medium">pages</span></li>
</ul>
</div>
</template>
<style lang="scss" scoped>
@media screen and (max-width: 991px) {
.video-container {
position: relative;
width: 100%;
height: 0;
padding-bottom: 56.25%;
iframe {
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
}
}
}
</style>
================================================
FILE: src/views/pages/Empty.vue
================================================
<template>
<div className="card">
<div class="font-semibold text-xl mb-4">Empty Page</div>
<p>Use this page to start from scratch and place your custom content.</p>
</div>
</template>
================================================
FILE: src/views/pages/Landing.vue
================================================
<script setup lang="ts">
import FeaturesWidget from '@/components/landing/FeaturesWidget.vue';
import FooterWidget from '@/components/landing/FooterWidget.vue';
import HeroWidget from '@/components/landing/HeroWidget.vue';
import HighlightsWidget from '@/components/landing/HighlightsWidget.vue';
import PricingWidget from '@/components/landing/PricingWidget.vue';
import TopbarWidget from '@/components/landing/TopbarWidget.vue';
</script>
<template>
<div class="bg-surface-0 dark:bg-surface-900">
<div id="home" class="landing-wrapper overflow-hidden">
<div class="py-6 px-6 mx-0 md:mx-12 lg:mx-20 lg:px-20 flex items-center justify-between relative lg:static">
<TopbarWidget />
</div>
<HeroWidget />
<FeaturesWidget />
<HighlightsWidget />
<PricingWidget />
<FooterWidget />
</div>
</div>
</template>
================================================
FILE: src/views/pages/NotFound.vue
================================================
<script setup>
import FloatingConfigurator from '@/components/FloatingConfigurator.vue';
</script>
<template>
<FloatingConfigurator />
<div class="flex items-center justify-center min-h-screen overflow-hidden">
<div class="flex flex-col items-center justify-center">
<svg width="54" height="40" viewBox="0 0 54 40" fill="none" xmlns="http://www.w3.org/2000/svg" class="mb-8 w-32 shrink-0">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.1637 19.2467C17.1566 19.4033 17.1529 19.561 17.1529 19.7194C17.1529 25.3503 21.7203 29.915 27.3546 29.915C32.9887 29.915 37.5561 25.3503 37.5561 19.7194C37.5561 19.5572 37.5524 19.3959 37.5449 19.2355C38.5617 19.0801 39.5759 18.9013 40.5867 18.6994L40.6926 18.6782C40.7191 19.0218 40.7326 19.369 40.7326 19.7194C40.7326 27.1036 34.743 33.0896 27.3546 33.0896C19.966 33.0896 13.9765 27.1036 13.9765 19.7194C13.9765 19.374 13.9896 19.0316 14.0154 18.6927L14.0486 18.6994C15.0837 18.9062 16.1223 19.0886 17.1637 19.2467ZM33.3284 11.4538C31.6493 10.2396 29.5855 9.52381 27.3546 9.52381C25.1195 9.52381 23.0524 10.2421 21.3717 11.4603C20.0078 11.3232 18.6475 11.1387 17.2933 10.907C19.7453 8.11308 23.3438 6.34921 27.3546 6.34921C31.36 6.34921 34.9543 8.10844 37.4061 10.896C36.0521 11.1292 34.692 11.3152 33.3284 11.4538ZM43.826 18.0518C43.881 18.6003 43.9091 19.1566 43.9091 19.7194C43.9091 28.8568 36.4973 36.2642 27.3546 36.2642C18.2117 36.2642 10.8 28.8568 10.8 19.7194C10.8 19.1615 10.8276 18.61 10.8816 18.0663L7.75383 17.4411C7.66775 18.1886 7.62354 18.9488 7.62354 19.7194C7.62354 30.6102 16.4574 39.4388 27.3546 39.4388C38.2517 39.4388 47.0855 30.6102 47.0855 19.7194C47.0855 18.9439 47.0407 18.1789 46.9536 17.4267L43.826 18.0518ZM44.2613 9.54743L40.9084 10.2176C37.9134 5.95821 32.9593 3.1746 27.3546 3.1746C21.7442 3.1746 16.7856 5.96385 13.7915 10.2305L10.4399 9.56057C13.892 3.83178 20.1756 0 27.3546 0C34.5281 0 40.8075 3.82591 44.2613 9.54743Z"
fill="var(--primary-color)"
/>
<mask id="mask0_1413_1551" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="8" width="54" height="11">
<path d="M27 18.3652C10.5114 19.1944 0 8.88892 0 8.88892C0 8.88892 16.5176 14.5866 27 14.5866C37.4824 14.5866 54 8.88892 54 8.88892C54 8.88892 43.4886 17.5361 27 18.3652Z" fill="var(--primary-color)" />
</mask>
<g mask="url(#mask0_1413_1551)">
<path
d="M-4.673e-05 8.88887L3.73084 -1.91434L-8.00806 17.0473L-4.673e-05 8.88887ZM27 18.3652L26.4253 6.95109L27 18.3652ZM54 8.88887L61.2673 17.7127L50.2691 -1.91434L54 8.88887ZM-4.673e-05 8.88887C-8.00806 17.0473 -8.00469 17.0505 -8.00132 17.0538C-8.00018 17.055 -7.99675 17.0583 -7.9944 17.0607C-7.98963 17.0653 -7.98474 17.0701 -7.97966 17.075C-7.96949 17.0849 -7.95863 17.0955 -7.94707 17.1066C-7.92401 17.129 -7.89809 17.1539 -7.86944 17.1812C-7.8122 17.236 -7.74377 17.3005 -7.66436 17.3743C-7.50567 17.5218 -7.30269 17.7063 -7.05645 17.9221C-6.56467 18.3532 -5.89662 18.9125 -5.06089 19.5534C-3.39603 20.83 -1.02575 22.4605 1.98012 24.0457C7.97874 27.2091 16.7723 30.3226 27.5746 29.7793L26.4253 6.95109C20.7391 7.23699 16.0326 5.61231 12.6534 3.83024C10.9703 2.94267 9.68222 2.04866 8.86091 1.41888C8.45356 1.10653 8.17155 0.867278 8.0241 0.738027C7.95072 0.673671 7.91178 0.637576 7.90841 0.634492C7.90682 0.63298 7.91419 0.639805 7.93071 0.65557C7.93897 0.663455 7.94952 0.673589 7.96235 0.686039C7.96883 0.692262 7.97582 0.699075 7.98338 0.706471C7.98719 0.710167 7.99113 0.714014 7.99526 0.718014C7.99729 0.720008 8.00047 0.723119 8.00148 0.724116C8.00466 0.727265 8.00796 0.730446 -4.673e-05 8.88887ZM27.5746 29.7793C37.6904 29.2706 45.9416 26.3684 51.6602 23.6054C54.5296 22.2191 56.8064 20.8465 58.4186 19.7784C59.2265 19.2431 59.873 18.7805 60.3494 18.4257C60.5878 18.2482 60.7841 18.0971 60.9374 17.977C61.014 17.9169 61.0799 17.8645 61.1349 17.8203C61.1624 17.7981 61.1872 17.7781 61.2093 17.7602C61.2203 17.7512 61.2307 17.7427 61.2403 17.7348C61.2452 17.7308 61.2499 17.727 61.2544 17.7233C61.2566 17.7215 61.2598 17.7188 61.261 17.7179C61.2642 17.7153 61.2673 17.7127 54 8.88887C46.7326 0.0650536 46.7357 0.0625219 46.7387 0.0600241C46.7397 0.0592345 46.7427 0.0567658 46.7446 0.0551857C46.7485 0.0520238 46.7521 0.0489887 46.7557 0.0460799C46.7628 0.0402623 46.7694 0.0349487 46.7753 0.0301318C46.7871 0.0204986 46.7966 0.0128495 46.8037 0.00712562C46.818 -0.00431848 46.8228 -0.00808311 46.8184 -0.00463784C46.8096 0.00228345 46.764 0.0378652 46.6828 0.0983779C46.5199 0.219675 46.2165 0.439161 45.7812 0.727519C44.9072 1.30663 43.5257 2.14765 41.7061 3.02677C38.0469 4.79468 32.7981 6.63058 26.4253 6.95109L27.5746 29.7793ZM54 8.88887C50.2691 -1.91433 50.27 -1.91467 50.271 -1.91498C50.2712 -1.91506 50.272 -1.91535 50.2724 -1.9155C50.2733 -1.91581 50.274 -1.91602 50.2743 -1.91616C50.2752 -1.91643 50.275 -1.91636 50.2738 -1.91595C50.2714 -1.91515 50.2652 -1.91302 50.2552 -1.9096C50.2351 -1.90276 50.1999 -1.89078 50.1503 -1.874C50.0509 -1.84043 49.8938 -1.78773 49.6844 -1.71863C49.2652 -1.58031 48.6387 -1.377 47.8481 -1.13035C46.2609 -0.635237 44.0427 0.0249875 41.5325 0.6823C36.215 2.07471 30.6736 3.15796 27 3.15796V26.0151C33.8087 26.0151 41.7672 24.2495 47.3292 22.7931C50.2586 22.026 52.825 21.2618 54.6625 20.6886C55.5842 20.4011 56.33 20.1593 56.8551 19.986C57.1178 19.8993 57.3258 19.8296 57.4735 19.7797C57.5474 19.7548 57.6062 19.7348 57.6493 19.72C57.6709 19.7127 57.6885 19.7066 57.7021 19.7019C57.7089 19.6996 57.7147 19.6976 57.7195 19.696C57.7219 19.6952 57.7241 19.6944 57.726 19.6938C57.7269 19.6934 57.7281 19.693 57.7286 19.6929C57.7298 19.6924 57.7309 19.692 54 8.88887ZM27 3.15796C23.3263 3.15796 17.7849 2.07471 12.4674 0.6823C9.95717 0.0249875 7.73904 -0.635237 6.15184 -1.13035C5.36118 -1.377 4.73467 -1.58031 4.3155 -1.71863C4.10609 -1.78773 3.94899 -1.84043 3.84961 -1.874C3.79994 -1.89078 3.76474 -1.90276 3.74471 -1.9096C3.73469 -1.91302 3.72848 -1.91515 3.72613 -1.91595C3.72496 -1.91636 3.72476 -1.91643 3.72554 -1.91616C3.72593 -1.91602 3.72657 -1.91581 3.72745 -1.9155C3.72789 -1.91535 3.72874 -1.91506 3.72896 -1.91498C3.72987 -1.91467 3.73084 -1.91433 -4.673e-05 8.88887C-3.73093 19.692 -3.72983 19.6924 -3.72868 19.6929C-3.72821 19.693 -3.72698 19.6934 -3.72603 19.6938C-3.72415 19.6944 -3.72201 19.6952 -3.71961 19.696C-3.71482 19.6976 -3.70901 19.6996 -3.7022 19.7019C-3.68858 19.7066 -3.67095 19.7127 -3.6494 19.72C-3.60629 19.7348 -3.54745 19.7548 -3.47359 19.7797C-3.32589 19.8296 -3.11788 19.8993 -2.85516 19.986C-2.33008 20.1593 -1.58425 20.4011 -0.662589 20.6886C1.17485 21.2618 3.74125 22.026 6.67073 22.7931C12.2327 24.2495 20.1913 26.0151 27 26.0151V3.15796Z"
fill="var(--primary-color)"
/>
</g>
</svg>
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, color-mix(in srgb, var(--primary-color), transparent 60%) 10%, var(--surface-ground) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20 flex flex-col items-center" style="border-radius: 53px">
<span class="text-primary font-bold text-3xl">404</span>
<h1 class="text-surface-900 dark:text-surface-0 font-bold text-3xl lg:text-5xl mb-2">Not Found</h1>
<div class="text-surface-600 dark:text-surface-200 mb-8">Requested resource is not available.</div>
<router-link to="/" class="w-full flex items-center py-8 border-surface-300 dark:border-surface-500 border-b">
<span class="flex justify-center items-center border-2 border-primary text-primary rounded-border" style="height: 3.5rem; width: 3.5rem">
<i class="pi pi-fw pi-table text-2xl!"></i>
</span>
<span class="ml-6 flex flex-col">
<span class="text-surface-900 dark:text-surface-0 lg:text-xl font-medium mb-0 block">Frequently Asked Questions</span>
<span class="text-surface-600 dark:text-surface-200 lg:text-xl">Ultricies mi quis hendrerit dolor.</span>
</span>
</router-link>
<router-link to="/" class="w-full flex items-center py-8 border-surface-300 dark:border-surface-500 border-b">
<span class="flex justify-center items-center border-2 border-primary text-primary rounded-border" style="height: 3.5rem; width: 3.5rem">
<i class="pi pi-fw pi-question-circle text-2xl!"></i>
</span>
<span class="ml-6 flex flex-col">
<span class="text-surface-900 dark:text-surface-0 lg:text-xl font-medium mb-0">Solution Center</span>
<span class="text-surface-600 dark:text-surface-200 lg:text-xl">Phasellus faucibus scelerisque eleifend.</span>
</span>
</router-link>
<router-link to="/" class="w-full flex items-center mb-8 py-8 border-surface-300 dark:border-surface-500 border-b">
<span class="flex justify-center items-center border-2 border-primary text-primary rounded-border" style="height: 3.5rem; width: 3.5rem">
<i class="pi pi-fw pi-unlock text-2xl!"></i>
</span>
<span class="ml-6 flex flex-col">
<span class="text-surface-900 dark:text-surface-0 lg:text-xl font-medium mb-0">Permission Manager</span>
<span class="text-surface-600 dark:text-surface-200 lg:text-xl">Accumsan in nisl nisi scelerisque</span>
</span>
</router-link>
<Button as="router-link" label="Go to Dashboard" to="/" />
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/pages/auth/Access.vue
================================================
<script setup>
import FloatingConfigurator from '@/components/FloatingConfigurator.vue';
</script>
<template>
<FloatingConfigurator />
<div class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
<div class="flex flex-col items-center justify-center">
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, rgba(247, 149, 48, 0.4) 10%, rgba(247, 149, 48, 0) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20 flex flex-col items-center" style="border-radius: 53px">
<div class="gap-4 flex flex-col items-center">
<div class="flex justify-center items-center border-2 border-orange-500 rounded-full" style="width: 3.2rem; height: 3.2rem">
<i class="text-orange-500 pi pi-fw pi-lock text-2xl!"></i>
</div>
<h1 class="text-surface-900 dark:text-surface-0 font-bold text-4xl lg:text-5xl mb-2">Access Denied</h1>
<span class="text-muted-color mb-8">You do not have the necessary permisions. Please contact admins.</span>
<img src="/demo/images/access/asset-access.svg" alt="Access denied" class="mb-8" width="80%" />
<div class="col-span-12 mt-8 text-center">
<Button as="router-link" label="Go to Dashboard" to="/" severity="warn" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/pages/auth/Error.vue
================================================
<script setup>
import FloatingConfigurator from '@/components/FloatingConfigurator.vue';
</script>
<template>
<FloatingConfigurator />
<div class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
<div class="flex flex-col items-center justify-center">
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, rgba(233, 30, 99, 0.4) 10%, rgba(33, 150, 243, 0) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20 flex flex-col items-center" style="border-radius: 53px">
<div class="gap-4 flex flex-col items-center">
<div class="flex justify-center items-center border-2 border-pink-500 rounded-full" style="height: 3.2rem; width: 3.2rem">
<i class="pi pi-fw pi-exclamation-circle text-2xl! text-pink-500"></i>
</div>
<h1 class="text-surface-900 dark:text-surface-0 font-bold text-5xl mb-2">Error Occured</h1>
<span class="text-muted-color mb-8">Requested resource is not available.</span>
<img src="/demo/images/error/asset-error.svg" alt="Error" class="mb-8" width="80%" />
<div class="col-span-12 mt-8 text-center">
<Button as="router-link" label="Go to Dashboard" to="/" severity="danger" />
</div>
</div>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/pages/auth/Login.vue
================================================
<script setup>
import FloatingConfigurator from '@/components/FloatingConfigurator.vue';
import { ref } from 'vue';
const email = ref('');
const password = ref('');
const checked = ref(false);
</script>
<template>
<FloatingConfigurator />
<div class="bg-surface-50 dark:bg-surface-950 flex items-center justify-center min-h-screen min-w-[100vw] overflow-hidden">
<div class="flex flex-col items-center justify-center">
<div style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, var(--primary-color) 10%, rgba(33, 150, 243, 0) 30%)">
<div class="w-full bg-surface-0 dark:bg-surface-900 py-20 px-8 sm:px-20" style="border-radius: 53px">
<div class="text-center mb-8">
<svg viewBox="0 0 54 40" fill="none" xmlns="http://www.w3.org/2000/svg" class="mb-8 w-16 shrink-0 mx-auto">
<path
fill-rule="evenodd"
clip-rule="evenodd"
d="M17.1637 19.2467C17.1566 19.4033 17.1529 19.561 17.1529 19.7194C17.1529 25.3503 21.7203 29.915 27.3546 29.915C32.9887 29.915 37.5561 25.3503 37.5561 19.7194C37.5561 19.5572 37.5524 19.3959 37.5449 19.2355C38.5617 19.0801 39.5759 18.9013 40.5867 18.6994L40.6926 18.6782C40.7191 19.0218 40.7326 19.369 40.7326 19.7194C40.7326 27.1036 34.743 33.0896 27.3546 33.0896C19.966 33.0896 13.9765 27.1036 13.9765 19.7194C13.9765 19.374 13.9896 19.0316 14.0154 18.6927L14.0486 18.6994C15.0837 18.9062 16.1223 19.0886 17.1637 19.2467ZM33.3284 11.4538C31.6493 10.2396 29.5855 9.52381 27.3546 9.52381C25.1195 9.52381 23.0524 10.2421 21.3717 11.4603C20.0078 11.3232 18.6475 11.1387 17.2933 10.907C19.7453 8.11308 23.3438 6.34921 27.3546 6.34921C31.36 6.34921 34.9543 8.10844 37.4061 10.896C36.0521 11.1292 34.692 11.3152 33.3284 11.4538ZM43.826 18.0518C43.881 18.6003 43.9091 19.1566 43.9091 19.7194C43.9091 28.8568 36.4973 36.2642 27.3546 36.2642C18.2117 36.2642 10.8 28.8568 10.8 19.7194C10.8 19.1615 10.8276 18.61 10.8816 18.0663L7.75383 17.4411C7.66775 18.1886 7.62354 18.9488 7.62354 19.7194C7.62354 30.6102 16.4574 39.4388 27.3546 39.4388C38.2517 39.4388 47.0855 30.6102 47.0855 19.7194C47.0855 18.9439 47.0407 18.1789 46.9536 17.4267L43.826 18.0518ZM44.2613 9.54743L40.9084 10.2176C37.9134 5.95821 32.9593 3.1746 27.3546 3.1746C21.7442 3.1746 16.7856 5.96385 13.7915 10.2305L10.4399 9.56057C13.892 3.83178 20.1756 0 27.3546 0C34.5281 0 40.8075 3.82591 44.2613 9.54743Z"
fill="var(--primary-color)"
/>
<mask id="mask0_1413_1551" style="mask-type: alpha" maskUnits="userSpaceOnUse" x="0" y="8" width="54" height="11">
<path d="M27 18.3652C10.5114 19.1944 0 8.88892 0 8.88892C0 8.88892 16.5176 14.5866 27 14.5866C37.4824 14.5866 54 8.88892 54 8.88892C54 8.88892 43.4886 17.5361 27 18.3652Z" fill="var(--primary-color)" />
</mask>
<g mask="url(#mask0_1413_1551)">
<path
d="M-4.673e-05 8.88887L3.73084 -1.91434L-8.00806 17.0473L-4.673e-05 8.88887ZM27 18.3652L26.4253 6.95109L27 18.3652ZM54 8.88887L61.2673 17.7127L50.2691 -1.91434L54 8.88887ZM-4.673e-05 8.88887C-8.00806 17.0473 -8.00469 17.0505 -8.00132 17.0538C-8.00018 17.055 -7.99675 17.0583 -7.9944 17.0607C-7.98963 17.0653 -7.98474 17.0701 -7.97966 17.075C-7.96949 17.0849 -7.95863 17.0955 -7.94707 17.1066C-7.92401 17.129 -7.89809 17.1539 -7.86944 17.1812C-7.8122 17.236 -7.74377 17.3005 -7.66436 17.3743C-7.50567 17.5218 -7.30269 17.7063 -7.05645 17.9221C-6.56467 18.3532 -5.89662 18.9125 -5.06089 19.5534C-3.39603 20.83 -1.02575 22.4605 1.98012 24.0457C7.97874 27.2091 16.7723 30.3226 27.5746 29.7793L26.4253 6.95109C20.7391 7.23699 16.0326 5.61231 12.6534 3.83024C10.9703 2.94267 9.68222 2.04866 8.86091 1.41888C8.45356 1.10653 8.17155 0.867278 8.0241 0.738027C7.95072 0.673671 7.91178 0.637576 7.90841 0.634492C7.90682 0.63298 7.91419 0.639805 7.93071 0.65557C7.93897 0.663455 7.94952 0.673589 7.96235 0.686039C7.96883 0.692262 7.97582 0.699075 7.98338 0.706471C7.98719 0.710167 7.99113 0.714014 7.99526 0.718014C7.99729 0.720008 8.00047 0.723119 8.00148 0.724116C8.00466 0.727265 8.00796 0.730446 -4.673e-05 8.88887ZM27.5746 29.7793C37.6904 29.2706 45.9416 26.3684 51.6602 23.6054C54.5296 22.2191 56.8064 20.8465 58.4186 19.7784C59.2265 19.2431 59.873 18.7805 60.3494 18.4257C60.5878 18.2482 60.7841 18.0971 60.9374 17.977C61.014 17.9169 61.0799 17.8645 61.1349 17.8203C61.1624 17.7981 61.1872 17.7781 61.2093 17.7602C61.2203 17.7512 61.2307 17.7427 61.2403 17.7348C61.2452 17.7308 61.2499 17.727 61.2544 17.7233C61.2566 17.7215 61.2598 17.7188 61.261 17.7179C61.2642 17.7153 61.2673 17.7127 54 8.88887C46.7326 0.0650536 46.7357 0.0625219 46.7387 0.0600241C46.7397 0.0592345 46.7427 0.0567658 46.7446 0.0551857C46.7485 0.0520238 46.7521 0.0489887 46.7557 0.0460799C46.7628 0.0402623 46.7694 0.0349487 46.7753 0.0301318C46.7871 0.0204986 46.7966 0.0128495 46.8037 0.00712562C46.818 -0.00431848 46.8228 -0.00808311 46.8184 -0.00463784C46.8096 0.00228345 46.764 0.0378652 46.6828 0.0983779C46.5199 0.219675 46.2165 0.439161 45.7812 0.727519C44.9072 1.30663 43.5257 2.14765 41.7061 3.02677C38.0469 4.79468 32.7981 6.63058 26.4253 6.95109L27.5746 29.7793ZM54 8.88887C50.2691 -1.91433 50.27 -1.91467 50.271 -1.91498C50.2712 -1.91506 50.272 -1.91535 50.2724 -1.9155C50.2733 -1.91581 50.274 -1.91602 50.2743 -1.91616C50.2752 -1.91643 50.275 -1.91636 50.2738 -1.91595C50.2714 -1.91515 50.2652 -1.91302 50.2552 -1.9096C50.2351 -1.90276 50.1999 -1.89078 50.1503 -1.874C50.0509 -1.84043 49.8938 -1.78773 49.6844 -1.71863C49.2652 -1.58031 48.6387 -1.377 47.8481 -1.13035C46.2609 -0.635237 44.0427 0.0249875 41.5325 0.6823C36.215 2.07471 30.6736 3.15796 27 3.15796V26.0151C33.8087 26.0151 41.7672 24.2495 47.3292 22.7931C50.2586 22.026 52.825 21.2618 54.6625 20.6886C55.5842 20.4011 56.33 20.1593 56.8551 19.986C57.1178 19.8993 57.3258 19.8296 57.4735 19.7797C57.5474 19.7548 57.6062 19.7348 57.6493 19.72C57.6709 19.7127 57.6885 19.7066 57.7021 19.7019C57.7089 19.6996 57.7147 19.6976 57.7195 19.696C57.7219 19.6952 57.7241 19.6944 57.726 19.6938C57.7269 19.6934 57.7281 19.693 57.7286 19.6929C57.7298 19.6924 57.7309 19.692 54 8.88887ZM27 3.15796C23.3263 3.15796 17.7849 2.07471 12.4674 0.6823C9.95717 0.0249875 7.73904 -0.635237 6.15184 -1.13035C5.36118 -1.377 4.73467 -1.58031 4.3155 -1.71863C4.10609 -1.78773 3.94899 -1.84043 3.84961 -1.874C3.79994 -1.89078 3.76474 -1.90276 3.74471 -1.9096C3.73469 -1.91302 3.72848 -1.91515 3.72613 -1.91595C3.72496 -1.91636 3.72476 -1.91643 3.72554 -1.91616C3.72593 -1.91602 3.72657 -1.91581 3.72745 -1.9155C3.72789 -1.91535 3.72874 -1.91506 3.72896 -1.91498C3.72987 -1.91467 3.73084 -1.91433 -4.673e-05 8.88887C-3.73093 19.692 -3.72983 19.6924 -3.72868 19.6929C-3.72821 19.693 -3.72698 19.6934 -3.72603 19.6938C-3.72415 19.6944 -3.72201 19.6952 -3.71961 19.696C-3.71482 19.6976 -3.70901 19.6996 -3.7022 19.7019C-3.68858 19.7066 -3.67095 19.7127 -3.6494 19.72C-3.60629 19.7348 -3.54745 19.7548 -3.47359 19.7797C-3.32589 19.8296 -3.11788 19.8993 -2.85516 19.986C-2.33008 20.1593 -1.58425 20.4011 -0.662589 20.6886C1.17485 21.2618 3.74125 22.026 6.67073 22.7931C12.2327 24.2495 20.1913 26.0151 27 26.0151V3.15796Z"
fill="var(--primary-color)"
/>
</g>
</svg>
<div class="text-surface-900 dark:text-surface-0 text-3xl font-medium mb-4">Welcome to PrimeLand!</div>
<span class="text-muted-color font-medium">Sign in to continue</span>
</div>
<div>
<label for="email1" class="block text-surface-900 dark:text-surface-0 text-xl font-medium mb-2">Email</label>
<InputText id="email1" type="text" placeholder="Email address" class="w-full md:w-[30rem] mb-8" v-model="email" />
<label for="password1" class="block text-surface-900 dark:text-surface-0 font-medium text-xl mb-2">Password</label>
<Password id="password1" v-model="password" placeholder="Password" :toggleMask="true" class="mb-4" fluid :feedback="false"></Password>
<div class="flex items-center justify-between mt-2 mb-8 gap-8">
<div class="flex items-center">
<Checkbox v-model="checked" id="rememberme1" binary class="mr-2"></Checkbox>
<label for="rememberme1">Remember me</label>
</div>
<span class="font-medium no-underline ml-2 text-right cursor-pointer text-primary">Forgot password?</span>
</div>
<Button label="Sign In" class="w-full" as="router-link" to="/"></Button>
</div>
</div>
</div>
</div>
</div>
</template>
<style scoped>
.pi-eye {
transform: scale(1.6);
margin-right: 1rem;
}
.pi-eye-slash {
transform: scale(1.6);
margin-right: 1rem;
}
</style>
================================================
FILE: src/views/uikit/ButtonDoc.vue
================================================
<script setup>
import { ref } from 'vue';
const items = ref([
{
label: 'Update',
icon: 'pi pi-refresh'
},
{
label: 'Delete',
icon: 'pi pi-times'
},
{
separator: true
},
{
label: 'Home',
icon: 'pi pi-home'
}
]);
const loading = ref([false, false, false]);
function load(index) {
loading.value[index] = true;
setTimeout(() => (loading.value[index] = false), 1000);
}
</script>
<template>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Default</div>
<div class="flex flex-wrap gap-2">
<Button label="Submit"></Button>
<Button label="Disabled" :disabled="true"></Button>
<Button label="Link" class="p-button-link" />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Severities</div>
<div class="flex flex-wrap gap-2">
<Button label="Primary" />
<Button label="Secondary" severity="secondary" />
<Button label="Success" severity="success" />
<Button label="Info" severity="info" />
<Button label="Warn" severity="warn" />
<Button label="Help" severity="help" />
<Button label="Danger" severity="danger" />
<Button label="Contrast" severity="contrast" />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Text</div>
<div class="flex flex-wrap gap-2">
<Button label="Primary" text />
<Button label="Secondary" severity="secondary" text />
<Button label="Success" severity="success" text />
<Button label="Info" severity="info" text />
<Button label="Warn" severity="warn" text />
<Button label="Help" severity="help" text />
<Button label="Danger" severity="danger" text />
<Button label="Plain" plain text />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Outlined</div>
<div class="flex flex-wrap gap-2">
<Button label="Primary" outlined />
<Button label="Secondary" severity="secondary" outlined />
<Button label="Success" severity="success" outlined />
<Button label="Info" severity="info" outlined />
<Button label="warn" severity="warn" outlined />
<Button label="Help" severity="help" outlined />
<Button label="Danger" severity="danger" outlined />
<Button label="Contrast" severity="contrast" outlined />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Group</div>
<div class="flex flex-wrap gap-2">
<ButtonGroup>
<Button label="Save" icon="pi pi-check" />
<Button label="Delete" icon="pi pi-trash" />
<Button label="Cancel" icon="pi pi-times" />
</ButtonGroup>
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">SplitButton</div>
<div class="flex flex-wrap gap-2">
<SplitButton label="Save" :model="items"></SplitButton>
<SplitButton label="Save" :model="items" severity="secondary"></SplitButton>
<SplitButton label="Save" :model="items" severity="success"></SplitButton>
<SplitButton label="Save" :model="items" severity="info"></SplitButton>
<SplitButton label="Save" :model="items" severity="warn"></SplitButton>
<SplitButton label="Save" :model="items" severity="help"></SplitButton>
<SplitButton label="Save" :model="items" severity="danger"></SplitButton>
<SplitButton label="Save" :model="items" severity="contrast"></SplitButton>
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Templating</div>
<div class="flex flex-wrap gap-2">
<Button type="button">
<img alt="logo" src="/demo/images/logo-white.svg" style="width: 1.5rem" />
</Button>
<Button type="button" outlined severity="success">
<img alt="logo" src="/demo/images/logo.svg" style="width: 1.5rem" />
<span class="ml-2 text-bold">PrimeVue</span>
</Button>
</div>
</div>
</div>
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Icons</div>
<div class="flex flex-wrap gap-2">
<Button icon="pi pi-star-fill" class="mr-2 mb-2"></Button>
<Button label="Bookmark" icon="pi pi-bookmark" class="mr-2 mb-2"></Button>
<Button label="Bookmark" icon="pi pi-bookmark" iconPos="right" class="mr-2 mb-2"></Button>
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Raised</div>
<div class="flex flex-wrap gap-2">
<Button label="Primary" raised />
<Button label="Secondary" severity="secondary" raised />
<Button label="Success" severity="success" raised />
<Button label="Info" severity="info" raised />
<Button label="Warn" severity="warn" raised />
<Button label="Help" severity="help" raised />
<Button label="Danger" severity="danger" raised />
<Button label="Contrast" severity="contrast" raised />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Rounded</div>
<div class="flex flex-wrap gap-2">
<Button label="Primary" rounded />
<Button label="Secondary" severity="secondary" rounded />
<Button label="Success" severity="success" rounded />
<Button label="Info" severity="info" rounded />
<Button label="Warn" severity="warn" rounded />
<Button label="Help" severity="help" rounded />
<Button label="Danger" severity="danger" rounded />
<Button label="Contrast" severity="contrast" rounded />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Rounded Icons</div>
<div class="flex flex-wrap gap-2">
<Button icon="pi pi-check" rounded />
<Button icon="pi pi-bookmark" severity="secondary" rounded />
<Button icon="pi pi-search" severity="success" rounded />
<Button icon="pi pi-user" severity="info" rounded />
<Button icon="pi pi-bell" severity="warn" rounded />
<Button icon="pi pi-heart" severity="help" rounded />
<Button icon="pi pi-times" severity="danger" rounded />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Rounded Text</div>
<div class="flex flex-wrap gap-2">
<Button icon="pi pi-check" text raised rounded />
<Button icon="pi pi-bookmark" severity="secondary" text raised rounded />
<Button icon="pi pi-search" severity="success" text raised rounded />
<Button icon="pi pi-user" severity="info" text raised rounded />
<Button icon="pi pi-bell" severity="warn" text raised rounded />
<Button icon="pi pi-heart" severity="help" text raised rounded />
<Button icon="pi pi-times" severity="danger" text raised rounded />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Rounded Outlined</div>
<div class="flex flex-wrap gap-2">
<Button icon="pi pi-check" rounded outlined />
<Button icon="pi pi-bookmark" severity="secondary" rounded outlined />
<Button icon="pi pi-search" severity="success" rounded outlined />
<Button icon="pi pi-user" severity="info" rounded outlined />
<Button icon="pi pi-bell" severity="warn" rounded outlined />
<Button icon="pi pi-heart" severity="help" rounded outlined />
<Button icon="pi pi-times" severity="danger" rounded outlined />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Loading</div>
<div class="flex flex-wrap gap-2">
<Button type="button" class="mr-2 mb-2" label="Search" icon="pi pi-search" :loading="loading[0]" @click="load(0)" />
<Button type="button" class="mr-2 mb-2" label="Search" icon="pi pi-search" iconPos="right" :loading="loading[1]" @click="load(1)" />
<Button type="button" class="mr-2 mb-2" icon="pi pi-search" :loading="loading[2]" @click="load(2)" />
<Button type="button" class="mr-2 mb-2" label="Search" :loading="loading[3]" @click="load(3)" />
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/ChartDoc.vue
================================================
<script setup>
import { useLayout } from '@/layout/composables/layout';
import { onMounted, ref, watch } from 'vue';
const { layoutConfig, isDarkTheme } = useLayout();
const lineData = ref(null);
const pieData = ref(null);
const polarData = ref(null);
const barData = ref(null);
const radarData = ref(null);
const lineOptions = ref(null);
const pieOptions = ref(null);
const polarOptions = ref(null);
const barOptions = ref(null);
const radarOptions = ref(null);
onMounted(() => {
setColorOptions();
});
function setColorOptions() {
const documentStyle = getComputedStyle(document.documentElement);
const textColor = documentStyle.getPropertyValue('--text-color');
const textColorSecondary = documentStyle.getPropertyValue('--text-color-secondary');
const surfaceBorder = documentStyle.getPropertyValue('--surface-border');
barData.value = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'My First dataset',
backgroundColor: documentStyle.getPropertyValue('--p-primary-500'),
borderColor: documentStyle.getPropertyValue('--p-primary-500'),
data: [65, 59, 80, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
backgroundColor: documentStyle.getPropertyValue('--p-primary-200'),
borderColor: documentStyle.getPropertyValue('--p-primary-200'),
data: [28, 48, 40, 19, 86, 27, 90]
}
]
};
barOptions.value = {
plugins: {
legend: {
labels: {
fontColor: textColor
}
}
},
scales: {
x: {
ticks: {
color: textColorSecondary,
font: {
weight: 500
}
},
grid: {
display: false,
drawBorder: false
}
},
y: {
ticks: {
color: textColorSecondary
},
grid: {
color: surfaceBorder,
drawBorder: false
}
}
}
};
pieData.value = {
labels: ['A', 'B', 'C'],
datasets: [
{
data: [540, 325, 702],
backgroundColor: [documentStyle.getPropertyValue('--p-indigo-500'), documentStyle.getPropertyValue('--p-purple-500'), documentStyle.getPropertyValue('--p-teal-500')],
hoverBackgroundColor: [documentStyle.getPropertyValue('--p-indigo-400'), documentStyle.getPropertyValue('--p-purple-400'), documentStyle.getPropertyValue('--p-teal-400')]
}
]
};
pieOptions.value = {
plugins: {
legend: {
labels: {
usePointStyle: true,
color: textColor
}
}
}
};
lineData.value = {
labels: ['January', 'February', 'March', 'April', 'May', 'June', 'July'],
datasets: [
{
label: 'First Dataset',
data: [65, 59, 80, 81, 56, 55, 40],
fill: false,
backgroundColor: documentStyle.getPropertyValue('--p-primary-500'),
borderColor: documentStyle.getPropertyValue('--p-primary-500'),
tension: 0.4
},
{
label: 'Second Dataset',
data: [28, 48, 40, 19, 86, 27, 90],
fill: false,
backgroundColor: documentStyle.getPropertyValue('--p-primary-200'),
borderColor: documentStyle.getPropertyValue('--p-primary-200'),
tension: 0.4
}
]
};
lineOptions.value = {
plugins: {
legend: {
labels: {
fontColor: textColor
}
}
},
scales: {
x: {
ticks: {
color: textColorSecondary
},
grid: {
color: surfaceBorder,
drawBorder: false
}
},
y: {
ticks: {
color: textColorSecondary
},
grid: {
color: surfaceBorder,
drawBorder: false
}
}
}
};
polarData.value = {
datasets: [
{
data: [11, 16, 7, 3],
backgroundColor: [documentStyle.getPropertyValue('--p-indigo-500'), documentStyle.getPropertyValue('--p-purple-500'), documentStyle.getPropertyValue('--p-teal-500'), documentStyle.getPropertyValue('--p-orange-500')],
label: 'My dataset'
}
],
labels: ['Indigo', 'Purple', 'Teal', 'Orange']
};
polarOptions.value = {
plugins: {
legend: {
labels: {
color: textColor
}
}
},
scales: {
r: {
grid: {
color: surfaceBorder
}
}
}
};
radarData.value = {
labels: ['Eating', 'Drinking', 'Sleeping', 'Designing', 'Coding', 'Cycling', 'Running'],
datasets: [
{
label: 'My First dataset',
borderColor: documentStyle.getPropertyValue('--p-indigo-400'),
pointBackgroundColor: documentStyle.getPropertyValue('--p-indigo-400'),
pointBorderColor: documentStyle.getPropertyValue('--p-indigo-400'),
pointHoverBackgroundColor: textColor,
pointHoverBorderColor: documentStyle.getPropertyValue('--p-indigo-400'),
data: [65, 59, 90, 81, 56, 55, 40]
},
{
label: 'My Second dataset',
borderColor: documentStyle.getPropertyValue('--p-purple-400'),
pointBackgroundColor: documentStyle.getPropertyValue('--p-purple-400'),
pointBorderColor: documentStyle.getPropertyValue('--p-purple-400'),
pointHoverBackgroundColor: textColor,
pointHoverBorderColor: documentStyle.getPropertyValue('--p-purple-400'),
data: [28, 48, 40, 19, 96, 27, 100]
}
]
};
radarOptions.value = {
plugins: {
legend: {
labels: {
fontColor: textColor
}
}
},
scales: {
r: {
grid: {
color: textColorSecondary
}
}
}
};
}
watch(
[() => layoutConfig.primary, () => layoutConfig.surface, isDarkTheme],
() => {
setColorOptions();
},
{ immediate: true }
);
</script>
<template>
<Fluid class="grid grid-cols-12 gap-8">
<div class="col-span-12 xl:col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Linear</div>
<Chart type="line" :data="lineData" :options="lineOptions"></Chart>
</div>
</div>
<div class="col-span-12 xl:col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Bar</div>
<Chart type="bar" :data="barData" :options="barOptions"></Chart>
</div>
</div>
<div class="col-span-12 xl:col-span-6">
<div class="card flex flex-col items-center">
<div class="font-semibold text-xl mb-4">Pie</div>
<Chart type="pie" :data="pieData" :options="pieOptions"></Chart>
</div>
</div>
<div class="col-span-12 xl:col-span-6">
<div class="card flex flex-col items-center">
<div class="font-semibold text-xl mb-4">Doughnut</div>
<Chart type="doughnut" :data="pieData" :options="pieOptions"></Chart>
</div>
</div>
<div class="col-span-12 xl:col-span-6">
<div class="card flex flex-col items-center">
<div class="font-semibold text-xl mb-4">Polar Area</div>
<Chart type="polarArea" :data="polarData" :options="polarOptions"></Chart>
</div>
</div>
<div class="col-span-12 xl:col-span-6">
<div class="card flex flex-col items-center">
<div class="font-semibold text-xl mb-4">Radar</div>
<Chart type="radar" :data="radarData" :options="radarOptions"></Chart>
</div>
</div>
</Fluid>
</template>
================================================
FILE: src/views/uikit/FileDoc.vue
================================================
<script setup>
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const fileupload = ref();
function upload() {
fileupload.value.upload();
}
function onUpload() {
toast.add({ severity: 'info', summary: 'Success', detail: 'File Uploaded', life: 3000 });
}
</script>
<template>
<div class="grid grid-cols-12 gap-8">
<div class="col-span-full lg:col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Advanced</div>
<FileUpload name="demo[]" @uploader="onUpload" :multiple="true" accept="image/*" :maxFileSize="1000000" customUpload />
</div>
</div>
<div class="col-span-full lg:col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Basic</div>
<div class="card flex flex-col gap-6 items-center justify-center">
<Toast />
<FileUpload ref="fileupload" mode="basic" name="demo[]" accept="image/*" :maxFileSize="1000000" @uploader="onUpload" customUpload />
<Button label="Upload" @click="upload" severity="secondary" />
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/FormLayout.vue
================================================
<script setup>
import { ref } from 'vue';
const dropdownItems = ref([
{ name: 'Option 1', code: 'Option 1' },
{ name: 'Option 2', code: 'Option 2' },
{ name: 'Option 3', code: 'Option 3' }
]);
const dropdownItem = ref(null);
</script>
<template>
<Fluid>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Vertical</div>
<div class="flex flex-col gap-2">
<label for="name1">Name</label>
<InputText id="name1" type="text" />
</div>
<div class="flex flex-col gap-2">
<label for="email1">Email</label>
<InputText id="email1" type="text" />
</div>
<div class="flex flex-col gap-2">
<label for="age1">Age</label>
<InputText id="age1" type="text" />
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Vertical Grid</div>
<div class="flex flex-wrap gap-4">
<div class="flex flex-col grow basis-0 gap-2">
<label for="name2">Name</label>
<InputText id="name2" type="text" />
</div>
<div class="flex flex-col grow basis-0 gap-2">
<label for="email2">Email</label>
<InputText id="email2" type="text" />
</div>
</div>
</div>
</div>
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Horizontal</div>
<div class="grid grid-cols-12 gap-2">
<label for="name3" class="flex items-center col-span-12 mb-2 md:col-span-2 md:mb-0">Name</label>
<div class="col-span-12 md:col-span-10">
<InputText id="name3" type="text" />
</div>
</div>
<div class="grid grid-cols-12 gap-2">
<label for="email3" class="flex items-center col-span-12 mb-2 md:col-span-2 md:mb-0">Email</label>
<div class="col-span-12 md:col-span-10">
<InputText id="email3" type="text" />
</div>
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Inline</div>
<div class="flex flex-wrap items-start gap-4">
<div class="field">
<label for="firstname1" class="sr-only">Firstname</label>
<InputText id="firstname1" type="text" placeholder="Firstname" />
</div>
<div class="field">
<label for="lastname1" class="sr-only">Lastname</label>
<InputText id="lastname1" type="text" placeholder="Lastname" />
</div>
<Button label="Submit" :fluid="false"></Button>
</div>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Help Text</div>
<div class="flex flex-wrap gap-2">
<label for="username">Username</label>
<InputText id="username" type="text" />
<small>Enter your username to reset your password.</small>
</div>
</div>
</div>
</div>
<div class="flex mt-8">
<div class="card flex flex-col gap-4 w-full">
<div class="font-semibold text-xl">Advanced</div>
<div class="flex flex-col md:flex-row gap-4">
<div class="flex flex-wrap gap-2 w-full">
<label for="firstname2">Firstname</label>
<InputText id="firstname2" type="text" />
</div>
<div class="flex flex-wrap gap-2 w-full">
<label for="lastname2">Lastname</label>
<InputText id="lastname2" type="text" />
</div>
</div>
<div class="flex flex-wrap">
<label for="address">Address</label>
<Textarea id="address" rows="4" />
</div>
<div class="flex flex-col md:flex-row gap-4">
<div class="flex flex-wrap gap-2 w-full">
<label for="state">State</label>
<Select id="state" v-model="dropdownItem" :options="dropdownItems" optionLabel="name" placeholder="Select One" class="w-full"></Select>
</div>
<div class="flex flex-wrap gap-2 w-full">
<label for="zip">Zip</label>
<InputText id="zip" type="text" />
</div>
</div>
</div>
</div>
</Fluid>
</template>
================================================
FILE: src/views/uikit/InputDoc.vue
================================================
<script setup>
import { CountryService } from '@/service/CountryService';
import { NodeService } from '@/service/NodeService';
import { onMounted, ref } from 'vue';
const floatValue = ref(null);
const autoValue = ref(null);
const selectedAutoValue = ref(null);
const autoFilteredValue = ref([]);
const calendarValue = ref(null);
const inputNumberValue = ref(null);
const sliderValue = ref(50);
const ratingValue = ref(null);
const colorValue = ref('#1976D2');
const radioValue = ref(null);
const checkboxValue = ref([]);
const switchValue = ref(false);
const listboxValues = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
const listboxValue = ref(null);
const dropdownValues = ref([
{ name: 'New York', code: 'NY' },
{ name: 'Rome', code: 'RM' },
{ name: 'London', code: 'LDN' },
{ name: 'Istanbul', code: 'IST' },
{ name: 'Paris', code: 'PRS' }
]);
const dropdownValue = ref(null);
const multiselectValues = ref([
{ name: 'Australia', code: 'AU' },
{ name: 'Brazil', code: 'BR' },
{ name: 'China', code: 'CN' },
{ name: 'Egypt', code: 'EG' },
{ name: 'France', code: 'FR' },
{ name: 'Germany', code: 'DE' },
{ name: 'India', code: 'IN' },
{ name: 'Japan', code: 'JP' },
{ name: 'Spain', code: 'ES' },
{ name: 'United States', code: 'US' }
]);
const multiselectValue = ref(null);
const toggleValue = ref(false);
const selectButtonValue = ref(null);
const selectButtonValues = ref([{ name: 'Option 1' }, { name: 'Option 2' }, { name: 'Option 3' }]);
const knobValue = ref(50);
const inputGroupValue = ref(false);
const treeSelectNodes = ref(null);
const selectedNode = ref(null);
onMounted(() => {
CountryService.getCountries().then((data) => (autoValue.value = data));
NodeService.getTreeNodes().then((data) => (treeSelectNodes.value = data));
});
function searchCountry(event) {
setTimeout(() => {
if (!event.query.trim().length) {
autoFilteredValue.value = [...autoValue.value];
} else {
autoFilteredValue.value = autoValue.value.filter((country) => {
return country.name.toLowerCase().startsWith(event.query.toLowerCase());
});
}
}, 250);
}
</script>
<template>
<Fluid class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">InputText</div>
<div class="flex flex-col md:flex-row gap-4">
<InputText type="text" placeholder="Default" />
<InputText type="text" placeholder="Disabled" :disabled="true" />
<InputText type="text" placeholder="Invalid" invalid />
</div>
<div class="font-semibold text-xl">Icons</div>
<IconField>
<InputIcon class="pi pi-user" />
<InputText type="text" placeholder="Username" />
</IconField>
<IconField iconPosition="left">
<InputText type="text" placeholder="Search" />
<InputIcon class="pi pi-search" />
</IconField>
<div class="font-semibold text-xl">Float Label</div>
<FloatLabel>
<InputText id="username" type="text" v-model="floatValue" />
<label for="username">Username</label>
</FloatLabel>
<div class="font-semibold text-xl">Textarea</div>
<Textarea placeholder="Your Message" :autoResize="true" rows="3" cols="30" />
<div class="font-semibold text-xl">AutoComplete</div>
<AutoComplete v-model="selectedAutoValue" :suggestions="autoFilteredValue" optionLabel="name" placeholder="Search" dropdown multiple display="chip" @complete="searchCountry($event)" />
<div class="font-semibold text-xl">DatePicker</div>
<DatePicker :showIcon="true" :showButtonBar="true" v-model="calendarValue"></DatePicker>
<div class="font-semibold text-xl">InputNumber</div>
<InputNumber v-model="inputNumberValue" showButtons mode="decimal"></InputNumber>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Slider</div>
<InputText v-model.number="sliderValue" />
<Slider v-model="sliderValue" />
<div class="flex flex-row mt-6">
<div class="flex flex-col gap-4 w-1/2">
<div class="font-semibold text-xl">Rating</div>
<Rating v-model="ratingValue" />
</div>
<div class="flex flex-col gap-4 w-1/2">
<div class="font-semibold text-xl">ColorPicker</div>
<ColorPicker style="width: 2rem" v-model="colorValue" />
</div>
</div>
<div class="font-semibold text-xl">Knob</div>
<Knob v-model="knobValue" :step="10" :min="-50" :max="50" valueTemplate="{value}%" />
</div>
</div>
<div class="md:w-1/2">
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">RadioButton</div>
<div class="flex flex-col md:flex-row gap-4">
<div class="flex items-center">
<RadioButton id="option1" name="option" value="Chicago" v-model="radioValue" />
<label for="option1" class="leading-none ml-2">Chicago</label>
</div>
<div class="flex items-center">
<RadioButton id="option2" name="option" value="Los Angeles" v-model="radioValue" />
<label for="option2" class="leading-none ml-2">Los Angeles</label>
</div>
<div class="flex items-center">
<RadioButton id="option3" name="option" value="New York" v-model="radioValue" />
<label for="option3" class="leading-none ml-2">New York</label>
</div>
</div>
<div class="font-semibold text-xl">Checkbox</div>
<div class="flex flex-col md:flex-row gap-4">
<div class="flex items-center">
<Checkbox id="checkOption1" name="option" value="Chicago" v-model="checkboxValue" />
<label for="checkOption1" class="ml-2">Chicago</label>
</div>
<div class="flex items-center">
<Checkbox id="checkOption2" name="option" value="Los Angeles" v-model="checkboxValue" />
<label for="checkOption2" class="ml-2">Los Angeles</label>
</div>
<div class="flex items-center">
<Checkbox id="checkOption3" name="option" value="New York" v-model="checkboxValue" />
<label for="checkOption3" class="ml-2">New York</label>
</div>
</div>
<div class="font-semibold text-xl">ToggleSwitch</div>
<ToggleSwitch v-model="switchValue" />
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">Listbox</div>
<Listbox v-model="listboxValue" :options="listboxValues" optionLabel="name" :filter="true" />
<div class="font-semibold text-xl">Select</div>
<Select v-model="dropdownValue" :options="dropdownValues" optionLabel="name" placeholder="Select" />
<div class="font-semibold text-xl">MultiSelect</div>
<MultiSelect v-model="multiselectValue" :options="multiselectValues" optionLabel="name" placeholder="Select Countries" :filter="true">
<template #value="slotProps">
<div class="inline-flex items-center py-1 px-2 bg-primary text-primary-contrast rounded-border mr-2" v-for="option of slotProps.value" :key="option.code">
<span :class="'mr-2 flag flag-' + option.code.toLowerCase()" style="width: 18px; height: 12px" />
<div>{{ option.name }}</div>
</div>
<template v-if="!slotProps.value || slotProps.value.length === 0">
<div class="p-1">Select Countries</div>
</template>
</template>
<template #option="slotProps">
<div class="flex items-center">
<span :class="'mr-2 flag flag-' + slotProps.option.code.toLowerCase()" style="width: 18px; height: 12px" />
<div>{{ slotProps.option.name }}</div>
</div>
</template>
</MultiSelect>
<div class="font-semibold text-xl">TreeSelect</div>
<TreeSelect v-model="selectedNode" :options="treeSelectNodes" placeholder="Select Item"></TreeSelect>
</div>
<div class="card flex flex-col gap-4">
<div class="font-semibold text-xl">ToggleButton</div>
<ToggleButton v-model="toggleValue" onLabel="Yes" offLabel="No" :style="{ width: '10em' }" />
<div class="font-semibold text-xl">SelectButton</div>
<SelectButton v-model="selectButtonValue" :options="selectButtonValues" optionLabel="name" />
</div>
</div>
</Fluid>
<Fluid class="flex mt-8">
<div class="card flex flex-col gap-4 w-full">
<div class="font-semibold text-xl">InputGroup</div>
<div class="flex flex-col md:flex-row gap-4">
<InputGroup>
<InputGroupAddon>
<i class="pi pi-user"></i>
</InputGroupAddon>
<InputText placeholder="Username" />
</InputGroup>
<InputGroup>
<InputGroupAddon>
<i class="pi pi-clock"></i>
</InputGroupAddon>
<InputGroupAddon>
<i class="pi pi-star-fill"></i>
</InputGroupAddon>
<InputNumber placeholder="Price" />
<InputGroupAddon>$</InputGroupAddon>
<InputGroupAddon>.00</InputGroupAddon>
</InputGroup>
</div>
<div class="flex flex-col md:flex-row gap-4">
<InputGroup>
<Button label="Search" />
<InputText placeholder="Keyword" />
</InputGroup>
<InputGroup>
<InputGroupAddon>
<Checkbox v-model="inputGroupValue" :binary="true" />
</InputGroupAddon>
<InputText placeholder="Confirm" />
</InputGroup>
</div>
</div>
</Fluid>
</template>
================================================
FILE: src/views/uikit/ListDoc.vue
================================================
<script setup>
import { ProductService } from '@/service/ProductService';
import { onMounted, ref } from 'vue';
const products = ref(null);
const picklistProducts = ref(null);
const orderlistProducts = ref(null);
const options = ref(['list', 'grid']);
const layout = ref('list');
onMounted(() => {
ProductService.getProductsSmall().then((data) => {
products.value = data.slice(0, 6);
picklistProducts.value = [data, []];
orderlistProducts.value = data;
});
});
function getSeverity(product) {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warning';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
</script>
<template>
<div class="flex flex-col">
<div class="card">
<div class="font-semibold text-xl">DataView</div>
<DataView :value="products" :layout="layout">
<template #header>
<div class="flex justify-end">
<SelectButton v-model="layout" :options="options" :allowEmpty="false">
<template #option="{ option }">
<i :class="[option === 'list' ? 'pi pi-bars' : 'pi pi-table']" />
</template>
</SelectButton>
</div>
</template>
<template #list="slotProps">
<div class="flex flex-col">
<div v-for="(item, index) in slotProps.items" :key="index">
<div class="flex flex-col sm:flex-row sm:items-center p-6 gap-4" :class="{ 'border-t border-surface': index !== 0 }">
<div class="md:w-40 relative">
<img class="block xl:block mx-auto rounded w-full" :src="`https://primefaces.org/cdn/primevue/images/product/${item.image}`" :alt="item.name" />
<Tag :value="item.inventoryStatus" :severity="getSeverity(item)" class="absolute dark:bg-surface-900!" style="left: 4px; top: 4px"></Tag>
</div>
<div class="flex flex-col md:flex-row justify-between md:items-center flex-1 gap-6">
<div class="flex flex-row md:flex-col justify-between items-start gap-2">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ item.category }}</span>
<div class="text-lg font-medium mt-2">{{ item.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div
class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style="
border-radius: 30px;
box-shadow:
0px 1px 2px 0px rgba(0, 0, 0, 0.04),
0px 1px 2px 0px rgba(0, 0, 0, 0.06);
"
>
<span class="text-surface-900 font-medium text-sm">{{ item.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex flex-col md:items-end gap-8">
<span class="text-xl font-semibold">${{ item.price }}</span>
<div class="flex flex-row-reverse md:flex-row gap-2">
<Button icon="pi pi-heart" outlined></Button>
<Button icon="pi pi-shopping-cart" label="Buy Now" :disabled="item.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto md:flex-initial whitespace-nowrap"></Button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<template #grid="slotProps">
<div class="grid grid-cols-12 gap-4">
<div v-for="(item, index) in slotProps.items" :key="index" class="col-span-12 sm:col-span-6 lg:col-span-4 p-2">
<div class="p-6 border border-surface-200 dark:border-surface-700 bg-surface-0 dark:bg-surface-900 rounded flex flex-col">
<div class="bg-surface-50 flex justify-center rounded p-4">
<div class="relative mx-auto">
<img class="rounded w-full" :src="`https://primefaces.org/cdn/primevue/images/product/${item.image}`" :alt="item.name" style="max-width: 300px" />
<Tag :value="item.inventoryStatus" :severity="getSeverity(item)" class="absolute dark:bg-surface-900!" style="left: 4px; top: 4px"></Tag>
</div>
</div>
<div class="pt-6">
<div class="flex flex-row justify-between items-start gap-2">
<div>
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ item.category }}</span>
<div class="text-lg font-medium mt-1">{{ item.name }}</div>
</div>
<div class="bg-surface-100 p-1" style="border-radius: 30px">
<div
class="bg-surface-0 flex items-center gap-2 justify-center py-1 px-2"
style="
border-radius: 30px;
box-shadow:
0px 1px 2px 0px rgba(0, 0, 0, 0.04),
0px 1px 2px 0px rgba(0, 0, 0, 0.06);
"
>
<span class="text-surface-900 font-medium text-sm">{{ item.rating }}</span>
<i class="pi pi-star-fill text-yellow-500"></i>
</div>
</div>
</div>
<div class="flex flex-col gap-6 mt-6">
<span class="text-2xl font-semibold">${{ item.price }}</span>
<div class="flex gap-2">
<Button icon="pi pi-shopping-cart" label="Buy Now" :disabled="item.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap"></Button>
<Button icon="pi pi-heart" outlined></Button>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
</DataView>
</div>
<div class="flex flex-col lg:flex-row gap-8">
<div class="lg:w-2/3">
<div class="card">
<div class="font-semibold text-xl mb-4">PickList</div>
<PickList v-model="picklistProducts" breakpoint="1400px" dataKey="id">
<template #option="{ option }">
{{ option.name }}
</template>
</PickList>
</div>
</div>
<div class="lg:w-1/3">
<div class="card">
<div class="font-semibold text-xl mb-4">OrderList</div>
<OrderList v-model="orderlistProducts" breakpoint="1400px" dataKey="id" pt:pcList:root="w-full">
<template #option="{ option }">
{{ option.name }}
</template>
</OrderList>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/MediaDoc.vue
================================================
<script setup>
import { PhotoService } from '@/service/PhotoService';
import { ProductService } from '@/service/ProductService';
import { onMounted, ref } from 'vue';
const products = ref([]);
const images = ref([]);
const galleriaResponsiveOptions = ref([
{
breakpoint: '1024px',
numVisible: 5
},
{
breakpoint: '960px',
numVisible: 4
},
{
breakpoint: '768px',
numVisible: 3
},
{
breakpoint: '560px',
numVisible: 1
}
]);
const carouselResponsiveOptions = ref([
{
breakpoint: '1024px',
numVisible: 3,
numScroll: 3
},
{
breakpoint: '768px',
numVisible: 2,
numScroll: 2
},
{
breakpoint: '560px',
numVisible: 1,
numScroll: 1
}
]);
onMounted(() => {
ProductService.getProductsSmall().then((data) => (products.value = data));
PhotoService.getImages().then((data) => (images.value = data));
});
function getSeverity(status) {
switch (status) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warning';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">Carousel</div>
<Carousel :value="products" :numVisible="3" :numScroll="3" :responsiveOptions="carouselResponsiveOptions">
<template #item="slotProps">
<div class="border border-surface-200 dark:border-surface-700 rounded m-2 p-4">
<div class="mb-4">
<div class="relative mx-auto">
<img :src="'https://primefaces.org/cdn/primevue/images/product/' + slotProps.data.image" :alt="slotProps.data.name" class="w-full rounded" />
<div class="dark:bg-surface-900 absolute rounded-border" style="left: 5px; top: 5px">
<Tag :value="slotProps.data.inventoryStatus" :severity="getSeverity(slotProps.data.inventoryStatus)" />
</div>
</div>
</div>
<div class="mb-4 font-medium">{{ slotProps.data.name }}</div>
<div class="flex justify-between items-center">
<div class="mt-0 font-semibold text-xl">${{ slotProps.data.price }}</div>
<span>
<Button icon="pi pi-heart" severity="secondary" outlined />
<Button icon="pi pi-shopping-cart" class="ml-2" />
</span>
</div>
</div>
</template>
</Carousel>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Image</div>
<Image src="https://primefaces.org/cdn/primevue/images/galleria/galleria10.jpg" alt="Image" width="250" />
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Galleria</div>
<Galleria :value="images" :responsiveOptions="galleriaResponsiveOptions" :numVisible="5" containerStyle="max-width: 640px">
<template #item="slotProps">
<img :src="slotProps.item.itemImageSrc" :alt="slotProps.item.alt" style="width: 100%" />
</template>
<template #thumbnail="slotProps">
<img :src="slotProps.item.thumbnailImageSrc" :alt="slotProps.item.alt" />
</template>
</Galleria>
</div>
</template>
================================================
FILE: src/views/uikit/MenuDoc.vue
================================================
<script setup>
import { ref } from 'vue';
const menu = ref(null);
const contextMenu = ref(null);
const nestedMenuitems = ref([
{
label: 'Customers',
icon: 'pi pi-fw pi-table',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-user-plus',
items: [
{
label: 'Customer',
icon: 'pi pi-fw pi-plus'
},
{
label: 'Duplicate',
icon: 'pi pi-fw pi-copy'
}
]
},
{
label: 'Edit',
icon: 'pi pi-fw pi-user-edit'
}
]
},
{
label: 'Orders',
icon: 'pi pi-fw pi-shopping-cart',
items: [
{
label: 'View',
icon: 'pi pi-fw pi-list'
},
{
label: 'Search',
icon: 'pi pi-fw pi-search'
}
]
},
{
label: 'Shipments',
icon: 'pi pi-fw pi-envelope',
items: [
{
label: 'Tracker',
icon: 'pi pi-fw pi-compass'
},
{
label: 'Map',
icon: 'pi pi-fw pi-map-marker'
},
{
label: 'Manage',
icon: 'pi pi-fw pi-pencil'
}
]
},
{
label: 'Profile',
icon: 'pi pi-fw pi-user',
items: [
{
label: 'Settings',
icon: 'pi pi-fw pi-cog'
},
{
label: 'Billing',
icon: 'pi pi-fw pi-file'
}
]
},
{
label: 'Quit',
icon: 'pi pi-fw pi-sign-out'
}
]);
const breadcrumbHome = ref({ icon: 'pi pi-home', to: '/' });
const breadcrumbItems = ref([{ label: 'Computer' }, { label: 'Notebook' }, { label: 'Accessories' }, { label: 'Backpacks' }, { label: 'Item' }]);
const tieredMenuItems = ref([
{
label: 'Customers',
icon: 'pi pi-fw pi-table',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-user-plus',
items: [
{
label: 'Customer',
icon: 'pi pi-fw pi-plus'
},
{
label: 'Duplicate',
icon: 'pi pi-fw pi-copy'
}
]
},
{
label: 'Edit',
icon: 'pi pi-fw pi-user-edit'
}
]
},
{
label: 'Orders',
icon: 'pi pi-fw pi-shopping-cart',
items: [
{
label: 'View',
icon: 'pi pi-fw pi-list'
},
{
label: 'Search',
icon: 'pi pi-fw pi-search'
}
]
},
{
label: 'Shipments',
icon: 'pi pi-fw pi-envelope',
items: [
{
label: 'Tracker',
icon: 'pi pi-fw pi-compass'
},
{
label: 'Map',
icon: 'pi pi-fw pi-map-marker'
},
{
label: 'Manage',
icon: 'pi pi-fw pi-pencil'
}
]
},
{
label: 'Profile',
icon: 'pi pi-fw pi-user',
items: [
{
label: 'Settings',
icon: 'pi pi-fw pi-cog'
},
{
label: 'Billing',
icon: 'pi pi-fw pi-file'
}
]
},
{
separator: true
},
{
label: 'Quit',
icon: 'pi pi-fw pi-sign-out'
}
]);
const overlayMenuItems = ref([
{
label: 'Save',
icon: 'pi pi-save'
},
{
label: 'Update',
icon: 'pi pi-refresh'
},
{
label: 'Delete',
icon: 'pi pi-trash'
},
{
separator: true
},
{
label: 'Home',
icon: 'pi pi-home'
}
]);
const menuitems = ref([
{
label: 'Customers',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-plus'
},
{
label: 'Edit',
icon: 'pi pi-fw pi-user-edit'
}
]
},
{
label: 'Orders',
items: [
{
label: 'View',
icon: 'pi pi-fw pi-list'
},
{
label: 'Search',
icon: 'pi pi-fw pi-search'
}
]
}
]);
const contextMenuItems = ref([
{
label: 'Save',
icon: 'pi pi-save'
},
{
label: 'Update',
icon: 'pi pi-refresh'
},
{
label: 'Delete',
icon: 'pi pi-trash'
},
{
separator: true
},
{
label: 'Options',
icon: 'pi pi-cog'
}
]);
const megamenuItems = ref([
{
label: 'Fashion',
icon: 'pi pi-fw pi-tag',
items: [
[
{
label: 'Woman',
items: [{ label: 'Woman Item' }, { label: 'Woman Item' }, { label: 'Woman Item' }]
},
{
label: 'Men',
items: [{ label: 'Men Item' }, { label: 'Men Item' }, { label: 'Men Item' }]
}
],
[
{
label: 'Kids',
items: [{ label: 'Kids Item' }, { label: 'Kids Item' }]
},
{
label: 'Luggage',
items: [{ label: 'Luggage Item' }, { label: 'Luggage Item' }, { label: 'Luggage Item' }]
}
]
]
},
{
label: 'Electronics',
icon: 'pi pi-fw pi-desktop',
items: [
[
{
label: 'Computer',
items: [{ label: 'Computer Item' }, { label: 'Computer Item' }]
},
{
label: 'Camcorder',
items: [{ label: 'Camcorder Item' }, { label: 'Camcorder Item' }, { label: 'Camcorder Item' }]
}
],
[
{
label: 'TV',
items: [{ label: 'TV Item' }, { label: 'TV Item' }]
},
{
label: 'Audio',
items: [{ label: 'Audio Item' }, { label: 'Audio Item' }, { label: 'Audio Item' }]
}
],
[
{
label: 'Sports.7',
items: [{ label: 'Sports.7.1' }, { label: 'Sports.7.2' }]
}
]
]
},
{
label: 'Furniture',
icon: 'pi pi-fw pi-image',
items: [
[
{
label: 'Living Room',
items: [{ label: 'Living Room Item' }, { label: 'Living Room Item' }]
},
{
label: 'Kitchen',
items: [{ label: 'Kitchen Item' }, { label: 'Kitchen Item' }, { label: 'Kitchen Item' }]
}
],
[
{
label: 'Bedroom',
items: [{ label: 'Bedroom Item' }, { label: 'Bedroom Item' }]
},
{
label: 'Outdoor',
items: [{ label: 'Outdoor Item' }, { label: 'Outdoor Item' }, { label: 'Outdoor Item' }]
}
]
]
},
{
label: 'Sports',
icon: 'pi pi-fw pi-star',
items: [
[
{
label: 'Basketball',
items: [{ label: 'Basketball Item' }, { label: 'Basketball Item' }]
},
{
label: 'Football',
items: [{ label: 'Football Item' }, { label: 'Football Item' }, { label: 'Football Item' }]
}
],
[
{
label: 'Tennis',
items: [{ label: 'Tennis Item' }, { label: 'Tennis Item' }]
}
]
]
}
]);
const panelMenuitems = ref([
{
label: 'Customers',
icon: 'pi pi-fw pi-table',
items: [
{
label: 'New',
icon: 'pi pi-fw pi-user-plus',
items: [
{
label: 'Customer',
icon: 'pi pi-fw pi-plus'
},
{
label: 'Duplicate',
icon: 'pi pi-fw pi-copy'
}
]
},
{
label: 'Edit',
icon: 'pi pi-fw pi-user-edit'
}
]
},
{
label: 'Orders',
icon: 'pi pi-fw pi-shopping-cart',
items: [
{
label: 'View',
icon: 'pi pi-fw pi-list'
},
{
label: 'Search',
icon: 'pi pi-fw pi-search'
}
]
},
{
label: 'Shipments',
icon: 'pi pi-fw pi-envelope',
items: [
{
label: 'Tracker',
icon: 'pi pi-fw pi-compass'
},
{
label: 'Map',
icon: 'pi pi-fw pi-map-marker'
},
{
label: 'Manage',
icon: 'pi pi-fw pi-pencil'
}
]
},
{
label: 'Profile',
icon: 'pi pi-fw pi-user',
items: [
{
label: 'Settings',
icon: 'pi pi-fw pi-cog'
},
{
label: 'Billing',
icon: 'pi pi-fw pi-file'
}
]
}
]);
function toggleMenu(event) {
menu.value.toggle(event);
}
function onContextRightClick(event) {
contextMenu.value.show(event);
}
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">Menubar</div>
<Menubar :model="nestedMenuitems">
<template #end>
<IconField iconPosition="left">
<InputIcon class="pi pi-search" />
<InputText type="text" placeholder="Search" />
</IconField>
</template>
</Menubar>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Breadcrumb</div>
<Breadcrumb :home="breadcrumbHome" :model="breadcrumbItems" />
</div>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Steps</div>
<Stepper value="1">
<StepList>
<Step value="1">Header I</Step>
<Step value="2">Header II</Step>
<Step value="3">Header III</Step>
</StepList>
</Stepper>
</div>
</div>
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">TabMenu</div>
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
</Tabs>
</div>
</div>
</div>
<div class="flex flex-col md:flex-row gap-8 mt-6">
<div class="md:w-1/3">
<div class="card">
<div class="font-semibold text-xl mb-4">Tiered Menu</div>
<TieredMenu :model="tieredMenuItems" />
</div>
</div>
<div class="md:w-1/3">
<div class="card">
<div class="font-semibold text-xl mb-4">Plain Menu</div>
<Menu :model="menuitems" />
</div>
</div>
<div class="md:w-1/3">
<div class="card">
<div class="font-semibold text-xl mb-4">Overlay Menu</div>
<Menu ref="menu" :model="overlayMenuItems" :popup="true" />
<Button type="button" label="Options" icon="pi pi-angle-down" @click="toggleMenu" style="width: auto" />
</div>
<div class="card" @contextmenu="onContextRightClick">
<div class="font-semibold text-xl mb-4">Context Menu</div>
Right click to display.
<ContextMenu ref="contextMenu" :model="contextMenuItems" />
</div>
</div>
</div>
<div class="flex flex-col md:flex-row gap-8 mt-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">MegaMenu | Horizontal</div>
<MegaMenu :model="megamenuItems" />
<div class="font-semibold text-xl mb-4 mt-8">MegaMenu | Vertical</div>
<MegaMenu :model="megamenuItems" orientation="vertical" />
</div>
</div>
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">PanelMenu</div>
<PanelMenu :model="panelMenuitems" />
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/MessagesDoc.vue
================================================
<script setup>
import { useToast } from 'primevue/usetoast';
import { ref } from 'vue';
const toast = useToast();
const message = ref([]);
const username = ref(null);
const email = ref(null);
function showSuccess() {
toast.add({ severity: 'success', summary: 'Success Message', detail: 'Message Detail', life: 3000 });
}
function showInfo() {
toast.add({ severity: 'info', summary: 'Info Message', detail: 'Message Detail', life: 3000 });
}
function showWarn() {
toast.add({ severity: 'warn', summary: 'Warn Message', detail: 'Message Detail', life: 3000 });
}
function showError() {
toast.add({ severity: 'error', summary: 'Error Message', detail: 'Message Detail', life: 3000 });
}
</script>
<template>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Toast</div>
<div class="flex flex-wrap gap-2">
<Button @click="showSuccess()" label="Success" severity="success" />
<Button @click="showInfo()" label="Info" severity="info" />
<Button @click="showWarn()" label="Warn" severity="warn" />
<Button @click="showError()" label="Error" severity="danger" />
</div>
<div class="font-semibold text-xl mt-4 mb-4">Inline</div>
<div class="flex flex-wrap mb-4 gap-2">
<InputText v-model="username" placeholder="Username" aria-label="username" invalid />
<Message severity="error">Username is required</Message>
</div>
<div class="flex flex-wrap gap-2">
<InputText v-model="email" placeholder="Email" aria-label="email" invalid />
<Message severity="error" icon="pi pi-times-circle" />
</div>
</div>
</div>
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Message</div>
<div class="flex flex-col gap-4 mb-4">
<Message severity="success">Success Message</Message>
<Message severity="info">Info Message</Message>
<Message severity="warn">Warn Message</Message>
<Message severity="error">Error Message</Message>
<Message severity="secondary">Secondary Message</Message>
<Message severity="contrast">Contrast Message</Message>
</div>
<transition-group name="p-message" tag="div">
<Message v-for="msg of message" :severity="msg.severity" :key="msg.content">{{ msg.content }}</Message>
</transition-group>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/MiscDoc.vue
================================================
<script setup>
import { onBeforeUnmount, onMounted, ref } from 'vue';
const value = ref(0);
let interval = null;
function startProgress() {
interval = setInterval(() => {
let newValue = value.value + Math.floor(Math.random() * 10) + 1;
if (newValue >= 100) {
newValue = 100;
}
value.value = newValue;
}, 2000);
}
function endProgress() {
clearInterval(interval);
interval = null;
}
onMounted(() => {
startProgress();
});
onBeforeUnmount(() => {
endProgress();
});
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">ProgressBar</div>
<div class="flex flex-col md:flex-row gap-4">
<div class="md:w-1/2">
<ProgressBar :value="value"></ProgressBar>
</div>
<div class="md:w-1/2">
<ProgressBar :value="50" :showValue="false"></ProgressBar>
</div>
</div>
</div>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Badge</div>
<div class="flex gap-2">
<Badge :value="2"></Badge>
<Badge :value="8" severity="success"></Badge>
<Badge :value="4" severity="info"></Badge>
<Badge :value="12" severity="Warn"></Badge>
<Badge :value="3" severity="danger"></Badge>
</div>
<div class="font-semibold my-4">Overlay</div>
<div class="flex gap-6">
<OverlayBadge value="2">
<i class="pi pi-bell" style="font-size: 2rem" />
</OverlayBadge>
<OverlayBadge value="4" severity="danger">
<i class="pi pi-calendar" style="font-size: 2rem" />
</OverlayBadge>
<OverlayBadge severity="danger">
<i class="pi pi-envelope" style="font-size: 2rem" />
</OverlayBadge>
</div>
<div class="font-semibold my-4">Button</div>
<div class="flex gap-2">
<Button label="Emails" badge="8" class="mr-2"></Button>
<Button label="Messages" icon="pi pi-users" severity="warn" badge="8" badgeClass="p-badge-danger"></Button>
</div>
<div class="font-semibold my-4">Sizes</div>
<div class="flex items-start gap-2">
<Badge :value="2"></Badge>
<Badge :value="4" size="large" severity="warn"></Badge>
<Badge :value="6" size="xlarge" severity="success"></Badge>
</div>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Avatar</div>
<div class="font-semibold mb-4">Group</div>
<AvatarGroup>
<Avatar :image="'https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png'" size="large" shape="circle"></Avatar>
<Avatar :image="'https://primefaces.org/cdn/primevue/images/avatar/asiyajavayant.png'" size="large" shape="circle"></Avatar>
<Avatar :image="'https://primefaces.org/cdn/primevue/images/avatar/onyamalimba.png'" size="large" shape="circle"></Avatar>
<Avatar :image="'https://primefaces.org/cdn/primevue/images/avatar/ionibowcher.png'" size="large" shape="circle"></Avatar>
<Avatar :image="'https://primefaces.org/cdn/primevue/images/avatar/xuxuefeng.png'" size="large" shape="circle"></Avatar>
<Avatar label="+2" shape="circle" size="large" :style="{ 'background-color': '#9c27b0', color: '#ffffff' }"></Avatar>
</AvatarGroup>
<div class="font-semibold my-4">Label - Circle</div>
<Avatar label="P" class="mr-2" size="xlarge" shape="circle"></Avatar>
<Avatar label="V" class="mr-2" size="large" :style="{ 'background-color': '#2196F3', color: '#ffffff' }" shape="circle"></Avatar>
<Avatar label="U" class="mr-2" :style="{ 'background-color': '#9c27b0', color: '#ffffff' }" shape="circle"></Avatar>
<div class="font-semibold my-4">Icon - Badge</div>
<OverlayBadge value="4" severity="danger" class="inline-flex">
<Avatar label="U" size="xlarge" />
</OverlayBadge>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">ScrollTop</div>
<ScrollPanel :style="{ width: '250px', height: '200px' }">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Vitae et leo duis ut diam. Ultricies mi quis hendrerit dolor magna eget est lorem. Amet consectetur
adipiscing elit ut. Nam libero justo laoreet sit amet. Pharetra massa massa ultricies mi quis hendrerit dolor magna. Est ultricies integer quis auctor elit sed vulputate. Consequat ac felis donec et. Tellus orci ac auctor
augue mauris. Semper feugiat nibh sed pulvinar proin gravida hendrerit lectus a. Tincidunt arcu non sodales neque sodales. Metus aliquam eleifend mi in nulla posuere sollicitudin aliquam ultrices. Sodales ut etiam sit amet
nisl purus. Cursus sit amet dictum sit amet. Tristique senectus et netus et malesuada fames ac turpis egestas. Et tortor consequat id porta nibh venenatis cras sed. Diam maecenas ultricies mi eget mauris. Eget egestas purus
viverra accumsan in nisl nisi. Suscipit adipiscing bibendum est ultricies integer. Mattis aliquam faucibus purus in massa tempor nec.
</p>
<ScrollTop target="parent" :threshold="100" icon="pi pi-arrow-up"></ScrollTop>
</ScrollPanel>
</div>
</div>
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Tag</div>
<div class="font-semibold mb-4">Default</div>
<div class="flex gap-2">
<Tag value="Primary"></Tag>
<Tag severity="success" value="Success"></Tag>
<Tag severity="info" value="Info"></Tag>
<Tag severity="warn" value="Warn"></Tag>
<Tag severity="danger" value="Danger"></Tag>
</div>
<div class="font-semibold my-4">Pills</div>
<div class="flex gap-2">
<Tag value="Primary" :rounded="true"></Tag>
<Tag severity="success" value="Success" :rounded="true"></Tag>
<Tag severity="info" value="Info" :rounded="true"></Tag>
<Tag severity="warn" value="Warn" :rounded="true"></Tag>
<Tag severity="danger" value="Danger" :rounded="true"></Tag>
</div>
<div class="font-semibold my-4">Icons</div>
<div class="flex gap-2">
<Tag icon="pi pi-user" value="Primary"></Tag>
<Tag icon="pi pi-check" severity="success" value="Success"></Tag>
<Tag icon="pi pi-info-circle" severity="info" value="Info"></Tag>
<Tag con="pi pi-exclamation-triangle" severity="warn" value="Warn"></Tag>
<Tag icon="pi pi-times" severity="danger" value="Danger"></Tag>
</div>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Chip</div>
<div class="font-semibold mb-4">Basic</div>
<div class="flex items-center flex-col sm:flex-row">
<Chip label="Action" class="mr-2 mb-2"></Chip>
<Chip label="Comedy" class="mr-2 mb-2"></Chip>
<Chip label="Mystery" class="mr-2 mb-2"></Chip>
<Chip label="Thriller" :removable="true" class="mb-2"></Chip>
</div>
<div class="font-semibold my-4">Icon</div>
<div class="flex items-center flex-col sm:flex-row">
<Chip label="Apple" icon="pi pi-apple" class="mr-2 mb-2"></Chip>
<Chip label="Facebook" icon="pi pi-facebook" class="mr-2 mb-2"></Chip>
<Chip label="Google" icon="pi pi-google" class="mr-2 mb-2"></Chip>
<Chip label="Microsoft" icon="pi pi-microsoft" :removable="true" class="mb-2"></Chip>
</div>
<div class="font-semibold my-4">Image</div>
<div class="flex items-center flex-col sm:flex-row">
<Chip label="Amy Elsner" :image="'https://primefaces.org/cdn/primevue/images/avatar/amyelsner.png'" class="mr-2 mb-2"></Chip>
<Chip label="Asiya Javayant" :image="'https://primefaces.org/cdn/primevue/images/avatar/asiyajavayant.png'" class="mr-2 mb-2"></Chip>
<Chip label="Onyama Limba" :image="'https://primefaces.org/cdn/primevue/images/avatar/onyamalimba.png'" class="mr-2 mb-2"></Chip>
</div>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Skeleton</div>
<div class="rounded-border border border-surface p-6">
<div class="flex mb-4">
<Skeleton shape="circle" size="4rem" class="mr-2"></Skeleton>
<div>
<Skeleton width="10rem" class="mb-2"></Skeleton>
<Skeleton width="5rem" class="mb-2"></Skeleton>
<Skeleton height=".5rem"></Skeleton>
</div>
</div>
<Skeleton width="100%" height="150px"></Skeleton>
<div class="flex justify-between mt-4">
<Skeleton width="4rem" height="2rem"></Skeleton>
<Skeleton width="4rem" height="2rem"></Skeleton>
</div>
</div>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/OverlayDoc.vue
================================================
<script setup>
import { ProductService } from '@/service/ProductService';
import { useConfirm } from 'primevue/useconfirm';
import { useToast } from 'primevue/usetoast';
import { onMounted, ref } from 'vue';
const display = ref(false);
const displayConfirmation = ref(false);
const visibleLeft = ref(false);
const visibleRight = ref(false);
const visibleTop = ref(false);
const visibleBottom = ref(false);
const visibleFull = ref(false);
const products = ref(null);
const selectedProduct = ref(null);
const op = ref(null);
const popup = ref(null);
const toast = useToast();
const confirmPopup = useConfirm();
onMounted(() => {
ProductService.getProductsSmall().then((data) => (products.value = data));
});
function open() {
display.value = true;
}
function close() {
display.value = false;
}
function openConfirmation() {
displayConfirmation.value = true;
}
function closeConfirmation() {
displayConfirmation.value = false;
}
function toggleDataTable(event) {
op.value.toggle(event);
}
function onProductSelect(event) {
op.value.hide();
toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
}
function confirm(event) {
confirmPopup.require({
target: event.target,
message: 'Are you sure you want to proceed?',
icon: 'pi pi-exclamation-triangle',
rejectProps: {
label: 'Cancel',
severity: 'secondary',
outlined: true
},
acceptProps: {
label: 'Save'
},
accept: () => {
toast.add({ severity: 'info', summary: 'Confirmed', detail: 'You have accepted', life: 3000 });
},
reject: () => {
toast.add({ severity: 'info', summary: 'Rejected', detail: 'You have rejected', life: 3000 });
}
});
}
</script>
<template>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Dialog</div>
<Dialog header="Dialog" v-model:visible="display" :breakpoints="{ '960px': '75vw' }" :style="{ width: '30vw' }" :modal="true">
<p class="leading-normal m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est laborum.
</p>
<template #footer>
<Button label="Save" @click="close" />
</template>
</Dialog>
<Button label="Show" style="width: auto" @click="open" />
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Popover</div>
<div class="flex flex-wrap gap-2">
<Button type="button" label="Show" @click="toggleDataTable" />
<Popover ref="op" id="overlay_panel" style="width: 450px">
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
<Column field="name" header="Name" sortable style="min-width: 12rem"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
</template>
</Column>
<Column field="price" header="Price" sortable style="min-width: 8rem">
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
</Column>
</DataTable>
</Popover>
</div>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Tooltip</div>
<div class="inline-flex gap-4">
<InputText type="text" placeholder="Username" v-tooltip="'Your username'" />
<Button type="button" label="Save" v-tooltip="'Click to proceed'" />
</div>
</div>
</div>
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Drawer</div>
<Drawer v-model:visible="visibleLeft" header="Drawer">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Drawer>
<Drawer v-model:visible="visibleRight" header="Drawer" position="right">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Drawer>
<Drawer v-model:visible="visibleTop" header="Drawer" position="top">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Drawer>
<Drawer v-model:visible="visibleBottom" header="Drawer" position="bottom">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Drawer>
<Drawer v-model:visible="visibleFull" header="Drawer" position="full">
<p>
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat.
</p>
</Drawer>
<Button icon="pi pi-arrow-right" @click="visibleLeft = true" style="margin-right: 0.25em" />
<Button icon="pi pi-arrow-left" @click="visibleRight = true" style="margin-right: 0.25em" />
<Button icon="pi pi-arrow-down" @click="visibleTop = true" style="margin-right: 0.25em" />
<Button icon="pi pi-arrow-up" @click="visibleBottom = true" style="margin-right: 0.25em" />
<Button icon="pi pi-external-link" @click="visibleFull = true" />
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">ConfirmPopup</div>
<ConfirmPopup></ConfirmPopup>
<Button ref="popup" @click="confirm($event)" icon="pi pi-check" label="Confirm" class="mr-2"></Button>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">ConfirmDialog</div>
<Button label="Delete" icon="pi pi-trash" severity="danger" style="width: auto" @click="openConfirmation" />
<Dialog header="Confirmation" v-model:visible="displayConfirmation" :style="{ width: '350px' }" :modal="true">
<div class="flex items-center justify-center">
<i class="pi pi-exclamation-triangle mr-4" style="font-size: 2rem" />
<span>Are you sure you want to proceed?</span>
</div>
<template #footer>
<Button label="No" icon="pi pi-times" @click="closeConfirmation" text severity="secondary" />
<Button label="Yes" icon="pi pi-check" @click="closeConfirmation" severity="danger" outlined autofocus />
</template>
</Dialog>
</div>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/PanelsDoc.vue
================================================
<script setup>
import { ref } from 'vue';
const items = ref([
{
label: 'Save',
icon: 'pi pi-check'
},
{
label: 'Update',
icon: 'pi pi-upload'
},
{
label: 'Delete',
icon: 'pi pi-trash'
},
{
label: 'Home Page',
icon: 'pi pi-home'
}
]);
const cardMenu = ref([
{ label: 'Save', icon: 'pi pi-fw pi-check' },
{ label: 'Update', icon: 'pi pi-fw pi-refresh' },
{ label: 'Delete', icon: 'pi pi-fw pi-trash' }
]);
const menuRef = ref(null);
function toggle() {
menuRef.value.toggle(event);
}
</script>
<template>
<div class="flex flex-col">
<div class="card">
<div class="font-semibold text-xl mb-4">Toolbar</div>
<Toolbar>
<template #start>
<Button icon="pi pi-plus" class="mr-2" severity="secondary" text />
<Button icon="pi pi-print" class="mr-2" severity="secondary" text />
<Button icon="pi pi-upload" severity="secondary" text />
</template>
<template #center>
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText placeholder="Search" />
</IconField>
</template>
<template #end> <SplitButton label="Save" :model="items"></SplitButton></template>
</Toolbar>
</div>
<div class="flex flex-col md:flex-row gap-8">
<div class="md:w-1/2">
<div class="card">
<div class="font-semibold text-xl mb-4">Accordion</div>
<Accordion value="0">
<AccordionPanel value="0">
<AccordionHeader>Header I</AccordionHeader>
<AccordionContent>
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.
</p>
</AccordionContent>
</AccordionPanel>
<AccordionPanel value="1">
<AccordionHeader>Header II</AccordionHeader>
<AccordionContent>
<p class="m-0">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt
explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non
numquam eius modi.
</p>
</AccordionContent>
</AccordionPanel>
<AccordionPanel value="2">
<AccordionHeader>Header III</AccordionHeader>
<AccordionContent>
<p class="m-0">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique
sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil
impedit quo minus.
</p>
</AccordionContent>
</AccordionPanel>
</Accordion>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Tabs</div>
<Tabs value="0">
<TabList>
<Tab value="0">Header I</Tab>
<Tab value="1">Header II</Tab>
<Tab value="2">Header III</Tab>
</TabList>
<TabPanels>
<TabPanel value="0">
<p class="m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
commodo consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit
anim id est laborum.
</p>
</TabPanel>
<TabPanel value="1">
<p class="m-0">
Sed ut perspiciatis unde omnis iste natus error sit voluptatem accusantium doloremque laudantium, totam rem aperiam, eaque ipsa quae ab illo inventore veritatis et quasi architecto beatae vitae dicta sunt
explicabo. Nemo enim ipsam voluptatem quia voluptas sit aspernatur aut odit aut fugit, sed quia consequuntur magni dolores eos qui ratione voluptatem sequi nesciunt. Consectetur, adipisci velit, sed quia non
numquam eius modi.
</p>
</TabPanel>
<TabPanel value="2">
<p class="m-0">
At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non provident, similique
sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga. Et harum quidem rerum facilis est et expedita distinctio. Nam libero tempore, cum soluta nobis est eligendi optio cumque nihil
impedit quo minus.
</p>
</TabPanel>
</TabPanels>
</Tabs>
</div>
</div>
<div class="md:w-1/2 mt-6 md:mt-0">
<div class="card">
<div class="font-semibold text-xl mb-4">Panel</div>
<Panel header="Header" :toggleable="true">
<p class="leading-normal m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</Panel>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Fieldset</div>
<Fieldset legend="Legend" :toggleable="true">
<p class="leading-normal m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</Fieldset>
</div>
<Card>
<template v-slot:title>
<div class="flex items-center justify-between mb-0">
<div class="font-semibold text-xl mb-4">Card</div>
<Button icon="pi pi-plus" class="p-button-text" @click="toggle" />
</div>
<Menu id="config_menu" ref="menuRef" :model="cardMenu" :popup="true" />
</template>
<template v-slot:content>
<p class="leading-normal m-0">
Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea commodo
consequat. Duis aute irure dolor in reprehenderit in voluptate velit esse cillum dolore eu fugiat nulla pariatur. Excepteur sint occaecat cupidatat non proident, sunt in culpa qui officia deserunt mollit anim id est
laborum.
</p>
</template>
</Card>
</div>
</div>
<div class="card mt-8">
<div class="font-semibold text-xl mb-4">Divider</div>
<div class="flex flex-col md:flex-row">
<div class="w-full md:w-5/12 flex flex-col items-center justify-center gap-3 py-5">
<div class="flex flex-col gap-2">
<label for="username">Username</label>
<InputText id="username" type="text" />
</div>
<div class="flex flex-col gap-2">
<label for="password">Password</label>
<InputText id="password" type="password" />
</div>
<div class="flex">
<Button label="Login" icon="pi pi-user" class="w-full max-w-[17.35rem] mx-auto"></Button>
</div>
</div>
<div class="w-full md:w-2/12">
<Divider layout="vertical" class="hidden! md:flex!"><b>OR</b></Divider>
<Divider layout="horizontal" class="flex! md:hidden!" align="center"><b>OR</b></Divider>
</div>
<div class="w-full md:w-5/12 flex items-center justify-center py-5">
<Button label="Sign Up" icon="pi pi-user-plus" severity="success" class="w-full max-w-[17.35rem] mx-auto"></Button>
</div>
</div>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Splitter</div>
<Splitter style="height: 300px" class="mb-8">
<SplitterPanel :size="30" :minSize="10">
<div className="h-full flex items-center justify-center">Panel 1</div>
</SplitterPanel>
<SplitterPanel :size="70">
<Splitter layout="vertical">
<SplitterPanel :size="15">
<div className="h-full flex items-center justify-center">Panel 2</div>
</SplitterPanel>
<SplitterPanel :size="50">
<div className="h-full flex items-center justify-center">Panel 3</div>
</SplitterPanel>
</Splitter>
</SplitterPanel>
</Splitter>
</div>
</div>
</template>
================================================
FILE: src/views/uikit/TableDoc.vue
================================================
<script setup>
import { CustomerService } from '@/service/CustomerService';
import { ProductService } from '@/service/ProductService';
import { FilterMatchMode, FilterOperator } from '@primevue/core/api';
import { onBeforeMount, reactive, ref } from 'vue';
const customers1 = ref(null);
const customers2 = ref(null);
const customers3 = ref(null);
const filters1 = ref(null);
const loading1 = ref(null);
const balanceFrozen = ref(false);
const products = ref(null);
const expandedRows = ref([]);
const statuses = reactive(['unqualified', 'qualified', 'new', 'negotiation', 'renewal', 'proposal']);
const representatives = reactive([
{ name: 'Amy Elsner', image: 'amyelsner.png' },
{ name: 'Anna Fali', image: 'annafali.png' },
{ name: 'Asiya Javayant', image: 'asiyajavayant.png' },
{ name: 'Bernardo Dominic', image: 'bernardodominic.png' },
{ name: 'Elwin Sharvill', image: 'elwinsharvill.png' },
{ name: 'Ioni Bowcher', image: 'ionibowcher.png' },
{ name: 'Ivan Magalhaes', image: 'ivanmagalhaes.png' },
{ name: 'Onyama Limba', image: 'onyamalimba.png' },
{ name: 'Stephen Shaw', image: 'stephenshaw.png' },
{ name: 'XuXue Feng', image: 'xuxuefeng.png' }
]);
function getOrderSeverity(order) {
switch (order.status) {
case 'DELIVERED':
return 'success';
case 'CANCELLED':
return 'danger';
case 'PENDING':
return 'warn';
case 'RETURNED':
return 'info';
default:
return null;
}
}
function getSeverity(status) {
switch (status) {
case 'unqualified':
return 'danger';
case 'qualified':
return 'success';
case 'new':
return 'info';
case 'negotiation':
return 'warn';
case 'renewal':
return null;
}
}
function getStockSeverity(product) {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
}
onBeforeMount(() => {
ProductService.getProductsWithOrdersSmall().then((data) => (products.value = data));
CustomerService.getCustomersLarge().then((data) => {
customers1.value = data;
loading1.value = false;
customers1.value.forEach((customer) => (customer.date = new Date(customer.date)));
});
CustomerService.getCustomersLarge().then((data) => (customers2.value = data));
CustomerService.getCustomersMedium().then((data) => (customers3.value = data));
initFilters1();
});
function initFilters1() {
filters1.value = {
global: { value: null, matchMode: FilterMatchMode.CONTAINS },
name: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
'country.name': { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.STARTS_WITH }] },
representative: { value: null, matchMode: FilterMatchMode.IN },
date: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.DATE_IS }] },
balance: { operator: FilterOperator.AND, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
status: { operator: FilterOperator.OR, constraints: [{ value: null, matchMode: FilterMatchMode.EQUALS }] },
activity: { value: [0, 100], matchMode: FilterMatchMode.BETWEEN },
verified: { value: null, matchMode: FilterMatchMode.EQUALS }
};
}
function expandAll() {
expandedRows.value = products.value.reduce((acc, p) => (acc[p.id] = true) && acc, {});
}
function collapseAll() {
expandedRows.value = null;
}
function formatCurrency(value) {
return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
}
function formatDate(value) {
return value.toLocaleDateString('en-US', {
day: '2-digit',
month: '2-digit',
year: 'numeric'
});
}
function calculateCustomerTotal(name) {
let total = 0;
if (customers3.value) {
for (let customer of customers3.value) {
if (customer.representative.name === name) {
total++;
}
}
}
return total;
}
</script>
<template>
<div class="card">
<div class="font-semibold text-xl mb-4">Filtering</div>
<DataTable
:value="customers1"
:paginator="true"
:rows="10"
dataKey="id"
:rowHover="true"
v-model:filters="filters1"
filterDisplay="menu"
:loading="loading1"
:filters="filters1"
:globalFilterFields="['name', 'country.name', 'representative.name', 'balance', 'status']"
showGridlines
>
<template #header>
<div class="flex justify-between">
<Button type="button" icon="pi pi-filter-slash" label="Clear" outlined @click="clearFilter()" />
<IconField>
<InputIcon>
<i class="pi pi-search" />
</InputIcon>
<InputText v-model="filters1['global'].value" placeholder="Keyword Search" />
</IconField>
</div>
</template>
<template #empty> No customers found. </template>
<template #loading> Loading customers data. Please wait. </template>
<Column field="name" header="Name" style="min-width: 12rem">
<template #body="{ data }">
{{ data.name }}
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by name" />
</template>
</Column>
<Column header="Country" filterField="country.name" style="min-width: 12rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${data.country.code}`" style="width: 24px" />
<span>{{ data.country.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<InputText v-model="filterModel.value" type="text" placeholder="Search by country" />
</template>
<template #filterclear="{ filterCallback }">
<Button type="button" icon="pi pi-times" @click="filterCallback()" severity="secondary"></Button>
</template>
<template #filterapply="{ filterCallback }">
<Button type="button" icon="pi pi-check" @click="filterCallback()" severity="success"></Button>
</template>
</Column>
<Column header="Agent" filterField="representative" :showFilterMatchModes="false" :filterMenuStyle="{ width: '14rem' }" style="min-width: 14rem">
<template #body="{ data }">
<div class="flex items-center gap-2">
<img :alt="data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${data.representative.image}`" style="width: 32px" />
<span>{{ data.representative.name }}</span>
</div>
</template>
<template #filter="{ filterModel }">
<MultiSelect v-model="filterModel.value" :options="representatives" optionLabel="name" placeholder="Any">
<template #option="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.option.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.option.image}`" style="width: 32px" />
<span>{{ slotProps.option.name }}</span>
</div>
</template>
</MultiSelect>
</template>
</Column>
<Column header="Date" filterField="date" dataType="date" style="min-width: 10rem">
<template #body="{ data }">
{{ formatDate(data.date) }}
</template>
<template #filter="{ filterModel }">
<DatePicker v-model="filterModel.value" dateFormat="mm/dd/yy" placeholder="mm/dd/yyyy" />
</template>
</Column>
<Column header="Balance" filterField="balance" dataType="numeric" style="min-width: 10rem">
<template #body="{ data }">
{{ formatCurrency(data.balance) }}
</template>
<template #filter="{ filterModel }">
<InputNumber v-model="filterModel.value" mode="currency" currency="USD" locale="en-US" />
</template>
</Column>
<Column header="Status" field="status" :filterMenuStyle="{ width: '14rem' }" style="min-width: 12rem">
<template #body="{ data }">
<Tag :value="data.status" :severity="getSeverity(data.status)" />
</template>
<template #filter="{ filterModel }">
<Select v-model="filterModel.value" :options="statuses" placeholder="Select One" showClear>
<template #option="slotProps">
<Tag :value="slotProps.option" :severity="getSeverity(slotProps.option)" />
</template>
</Select>
</template>
</Column>
<Column field="activity" header="Activity" :showFilterMatchModes="false" style="min-width: 12rem">
<template #body="{ data }">
<ProgressBar :value="data.activity" :showValue="false" style="height: 6px"></ProgressBar>
</template>
<template #filter="{ filterModel }">
<Slider v-model="filterModel.value" range class="m-4"></Slider>
<div class="flex items-center justify-between px-2">
<span>{{ filterModel.value ? filterModel.value[0] : 0 }}</span>
<span>{{ filterModel.value ? filterModel.value[1] : 100 }}</span>
</div>
</template>
</Column>
<Column field="verified" header="Verified" dataType="boolean" bodyClass="text-center" style="min-width: 8rem">
<template #body="{ data }">
<i class="pi" :class="{ 'pi-check-circle text-green-500 ': data.verified, 'pi-times-circle text-red-500': !data.verified }"></i>
</template>
<template #filter="{ filterModel }">
<label for="verified-filter" class="font-bold"> Verified </label>
<Checkbox v-model="filterModel.value" :indeterminate="filterModel.value === null" binary inputId="verified-filter" />
</template>
</Column>
</DataTable>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Frozen Columns</div>
<ToggleButton v-model="balanceFrozen" onIcon="pi pi-lock" offIcon="pi pi-lock-open" onLabel="Balance" offLabel="Balance" />
<DataTable :value="customers2" scrollable scrollHeight="400px" class="mt-6">
<Column field="name" header="Name" style="min-width: 200px" frozen class="font-bold"></Column>
<Column field="id" header="Id" style="min-width: 100px"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country.name" header="Country" style="min-width: 200px"></Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px"></Column>
<Column field="activity" header="Activity" style="min-width: 200px"></Column>
<Column field="representative.name" header="Representative" style="min-width: 200px"></Column>
<Column field="balance" header="Balance" style="min-width: 200px" alignFrozen="right" :frozen="balanceFrozen">
<template #body="{ data }">
<span class="font-bold">{{ formatCurrency(data.balance) }}</span>
</template>
</Column>
</DataTable>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Row Expansion</div>
<DataTable v-model:expandedRows="expandedRows" :value="products" dataKey="id" tableStyle="min-width: 60rem">
<template #header>
<div class="flex flex-wrap justify-end gap-2">
<Button text icon="pi pi-plus" label="Expand All" @click="expandAll" />
<Button text icon="pi pi-minus" label="Collapse All" @click="collapseAll" />
</div>
</template>
<Column expander style="width: 5rem" />
<Column field="name" header="Name"></Column>
<Column header="Image">
<template #body="slotProps">
<img :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.data.image}`" :alt="slotProps.data.image" class="shadow-lg" width="64" />
</template>
</Column>
<Column field="price" header="Price">
<template #body="slotProps">
{{ formatCurrency(slotProps.data.price) }}
</template>
</Column>
<Column field="category" header="Category"></Column>
<Column field="rating" header="Reviews">
<template #body="slotProps">
<Rating :modelValue="slotProps.data.rating" readonly />
</template>
</Column>
<Column header="Status">
<template #body="slotProps">
<Tag :value="slotProps.data.inventoryStatus" :severity="getStockSeverity(slotProps.data)" />
</template>
</Column>
<template #expansion="slotProps">
<div class="p-4">
<h5>Orders for {{ slotProps.data.name }}</h5>
<DataTable :value="slotProps.data.orders">
<Column field="id" header="Id" sortable></Column>
<Column field="customer" header="Customer" sortable></Column>
<Column field="date" header="Date" sortable></Column>
<Column field="amount" header="Amount" sortable>
<template #body="slotProps">
{{ formatCurrency(slotProps.data.amount) }}
</template>
</Column>
<Column field="status" header="Status" sortable>
<template #body="slotProps">
<Tag :value="slotProps.data.status.toLowerCase()" :severity="getOrderSeverity(slotProps.data)" />
</template>
</Column>
<Column headerStyle="width:4rem">
<template #body>
<Button icon="pi pi-search" />
</template>
</Column>
</DataTable>
</div>
</template>
</DataTable>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">Grouping</div>
<DataTable :value="customers3" rowGroupMode="subheader" groupRowsBy="representative.name" sortMode="single" sortField="representative.name" :sortOrder="1" scrollable scrollHeight="400px" tableStyle="min-width: 50rem">
<template #groupheader="slotProps">
<div class="flex items-center gap-2">
<img :alt="slotProps.data.representative.name" :src="`https://primefaces.org/cdn/primevue/images/avatar/${slotProps.data.representative.image}`" width="32" style="vertical-align: middle" />
<span>{{ slotProps.data.representative.name }}</span>
</div>
</template>
<Column field="representative.name" header="Representative"></Column>
<Column field="name" header="Name" style="min-width: 200px"></Column>
<Column field="country" header="Country" style="min-width: 200px">
<template #body="slotProps">
<div class="flex items-center gap-2">
<img alt="flag" src="https://primefaces.org/cdn/primevue/images/flag/flag_placeholder.png" :class="`flag flag-${slotProps.data.country.code}`" style="width: 24px" />
<span>{{ slotProps.data.country.name }}</span>
</div>
</template>
</Column>
<Column field="company" header="Company" style="min-width: 200px"></Column>
<Column field="status" header="Status" style="min-width: 200px">
<template #body="slotProps">
<Tag :value="slotProps.data.status" :severity="getSeverity(slotProps.data.status)" />
</template>
</Column>
<Column field="date" header="Date" style="min-width: 200px"></Column>
<template #groupfooter="slotProps">
<div class="flex justify-end font-bold w-full">Total Customers: {{ calculateCustomerTotal(slotProps.data.representative.name) }}</div>
</template>
</DataTable>
</div>
</template>
<style scoped lang="scss">
:deep(.p-datatable-frozen-tbody) {
font-weight: bold;
}
:deep(.p-datatable-scrollable .p-frozen-column) {
font-weight: bold;
}
</style>
================================================
FILE: src/views/uikit/TimelineDoc.vue
================================================
<script setup>
import { ref } from 'vue';
const events = ref([
{
status: 'Ordered',
date: '15/10/2020 10:30',
icon: 'pi pi-shopping-cart',
color: '#9C27B0',
image: 'game-controller.jpg'
},
{
status: 'Processing',
date: '15/10/2020 14:00',
icon: 'pi pi-cog',
color: '#673AB7'
},
{
status: 'Shipped',
date: '15/10/2020 16:15',
icon: 'pi pi-envelope',
color: '#FF9800'
},
{
status: 'Delivered',
date: '16/10/2020 10:00',
icon: 'pi pi-check',
color: '#607D8B'
}
]);
const horizontalEvents = ref(['2020', '2021', '2022', '2023']);
</script>
<template>
<div class="grid grid-cols-12 gap-8">
<div class="col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Left Align</div>
<Timeline :value="events">
<template #content="slotProps">
{{ slotProps.item.status }}
</template>
</Timeline>
</div>
</div>
<div class="col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Right Align</div>
<Timeline :value="events" align="right">
<template #content="slotProps">
{{ slotProps.item.status }}
</template>
</Timeline>
</div>
</div>
<div class="col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Alternate Align</div>
<Timeline :value="events" align="alternate">
<template #content="slotProps">
{{ slotProps.item.status }}
</template>
</Timeline>
</div>
</div>
<div class="col-span-6">
<div class="card">
<div class="font-semibold text-xl mb-4">Opposite Content</div>
<Timeline :value="events">
<template #opposite="slotProps">
<small class="text-muted-color">{{ slotProps.item.date }}</small>
</template>
<template #content="slotProps">
{{ slotProps.item.status }}
</template>
</Timeline>
</div>
</div>
<div class="col-span-full">
<div class="card">
<div class="font-semibold text-xl mb-4">Templating</div>
<Timeline :value="events" align="alternate" class="customized-timeline">
<template #marker="slotProps">
<span class="flex w-8 h-8 items-center justify-center text-white rounded-full z-10 shadow-sm" :style="{ backgroundColor: slotProps.item.color }">
<i :class="slotProps.item.icon"></i>
</span>
</template>
<template #content="slotProps">
<Card class="mt-4">
<template #title>
{{ slotProps.item.status }}
</template>
<template #subtitle>
{{ slotProps.item.date }}
</template>
<template #content>
<img v-if="slotProps.item.image" :src="`https://primefaces.org/cdn/primevue/images/product/${slotProps.item.image}`" :alt="slotProps.item.name" width="200" class="shadow-sm" />
<p>
Lorem ipsum dolor sit amet, consectetur adipisicing elit. Inventore sed consequuntur error repudiandae numquam deserunt quisquam repellat libero asperiores earum nam nobis, culpa ratione quam perferendis esse,
cupiditate neque quas!
</p>
<Button label="Read more" text></Button>
</template>
</Card>
</template>
</Timeline>
</div>
</div>
<div class="col-span-full">
<div class="card">
<div class="font-semibold text-xl mb-4">Horizontal</div>
<div class="font-semibold mb-2">Top Align</div>
<Timeline :value="horizontalEvents" layout="horizontal" align="top">
<template #content="slotProps">
{{ slotProps.item }}
</template>
</Timeline>
<div class="font-semibold mt-4 mb-2">Bottom Align</div>
<Timeline :value="horizontalEvents" layout="horizontal" align="bottom">
<template #content="slotProps">
{{ slotProps.item }}
</template>
</Timeline>
<div class="font-semibold mt-4 mb-2">Alternate Align</div>
<Timeline :value="horizontalEvents" layout="horizontal" align="alternate">
<template #opposite> &nbsp; </template>
<template #content="slotProps">
{{ slotProps.item }}
</template>
</Timeline>
</div>
</div>
</div>
</template>
<style lang="scss" scoped>
@media screen and (max-width: 960px) {
::v-deep(.customized-timeline) {
.p-timeline-event:nth-child(even) {
flex-direction: row !important;
.p-timeline-event-content {
text-align: left !important;
}
}
.p-timeline-event-opposite {
flex: 0;
}
.p-card {
margin-top: 1rem;
}
}
}
</style>
================================================
FILE: src/views/uikit/TreeDoc.vue
================================================
<script setup>
import { NodeService } from '@/service/NodeService';
import { onMounted, ref } from 'vue';
const treeValue = ref(null);
const selectedTreeValue = ref(null);
const treeTableValue = ref(null);
const selectedTreeTableValue = ref(null);
onMounted(() => {
NodeService.getTreeNodes().then((data) => (treeValue.value = data));
NodeService.getTreeTableNodes().then((data) => (treeTableValue.value = data));
});
</script>
<template>
<div class="card">
<div class="font-semibold text-xl">Tree</div>
<Tree :value="treeValue" selectionMode="checkbox" v-model:selectionKeys="selectedTreeValue"></Tree>
</div>
<div class="card">
<div class="font-semibold text-xl mb-4">TreeTable</div>
<TreeTable :value="treeTableValue" selectionMode="checkbox" v-model:selectionKeys="selectedTreeTableValue">
<Column field="name" header="Name" :expander="true"></Column>
<Column field="size" header="Size"></Column>
<Column field="type" header="Type"></Column>
</TreeTable>
</div>
</template>