All pages added
This commit is contained in:
@@ -103,6 +103,21 @@ const router = createRouter({
|
||||
path: '/utilities/icons',
|
||||
name: 'icons',
|
||||
component: () => import('@/views/utilities/Icons.vue')
|
||||
},
|
||||
{
|
||||
path: '/pages/timeline',
|
||||
name: 'timeline',
|
||||
component: () => import('@/views/pages/Timeline.vue')
|
||||
},
|
||||
{
|
||||
path: '/pages/empty',
|
||||
name: 'empty',
|
||||
component: () => import('@/views/pages/Empty.vue')
|
||||
},
|
||||
{
|
||||
path: '/documentation',
|
||||
name: 'documentation',
|
||||
component: () => import('@/views/utilities/Documentation.vue')
|
||||
}
|
||||
]
|
||||
},
|
||||
@@ -111,6 +126,12 @@ const router = createRouter({
|
||||
name: 'landing',
|
||||
component: () => import('@/views/pages/Landing.vue')
|
||||
},
|
||||
{
|
||||
path: '/pages/notfound',
|
||||
name: 'notfound',
|
||||
component: () => import('@/views/pages/NotFound.vue')
|
||||
},
|
||||
|
||||
{
|
||||
path: '/auth/login',
|
||||
name: 'login',
|
||||
|
||||
308
src/views/pages/CrudDemo.vue
Normal file
308
src/views/pages/CrudDemo.vue
Normal file
@@ -0,0 +1,308 @@
|
||||
<template>
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<Toast />
|
||||
<Toolbar class="mb-4">
|
||||
<template v-slot:start>
|
||||
<div class="my-2">
|
||||
<Button label="New" icon="pi pi-plus" class="p-button-success mr-2" @click="openNew" />
|
||||
<Button label="Delete" icon="pi pi-trash" class="p-button-danger" @click="confirmDeleteSelected" :disabled="!selectedProducts || !selectedProducts.length" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<template v-slot:end>
|
||||
<FileUpload mode="basic" accept="image/*" :maxFileSize="1000000" label="Import" chooseLabel="Import" class="mr-2 inline-block" />
|
||||
<Button label="Export" icon="pi pi-upload" class="p-button-help" @click="exportCSV($event)" />
|
||||
</template>
|
||||
</Toolbar>
|
||||
|
||||
<DataTable
|
||||
ref="dt"
|
||||
:value="products"
|
||||
v-model:selection="selectedProducts"
|
||||
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"
|
||||
responsiveLayout="scroll"
|
||||
>
|
||||
<template #header>
|
||||
<div class="flex flex-column md:flex-row md:justify-content-between md:align-items-center">
|
||||
<h5 class="m-0">Manage Products</h5>
|
||||
<span class="block mt-2 md:mt-0 p-input-icon-left">
|
||||
<i class="pi pi-search" />
|
||||
<InputText v-model="filters['global'].value" placeholder="Search..." />
|
||||
</span>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<Column selectionMode="multiple" headerStyle="width: 3rem"></Column>
|
||||
<Column field="code" header="Code" :sortable="true" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Code</span>
|
||||
{{ slotProps.data.code }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="name" header="Name" :sortable="true" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Name</span>
|
||||
{{ slotProps.data.name }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column header="Image" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Image</span>
|
||||
<img :src="'images/product/' + slotProps.data.image" :alt="slotProps.data.image" class="shadow-2" width="100" />
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="price" header="Price" :sortable="true" headerStyle="width:14%; min-width:8rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Price</span>
|
||||
{{ formatCurrency(slotProps.data.price) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="category" header="Category" :sortable="true" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Category</span>
|
||||
{{ formatCurrency(slotProps.data.category) }}
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="rating" header="Reviews" :sortable="true" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Rating</span>
|
||||
<Rating :modelValue="slotProps.data.rating" :readonly="true" :cancel="false" />
|
||||
</template>
|
||||
</Column>
|
||||
<Column field="inventoryStatus" header="Status" :sortable="true" headerStyle="width:14%; min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<span class="p-column-title">Status</span>
|
||||
<span :class="'product-badge status-' + (slotProps.data.inventoryStatus ? slotProps.data.inventoryStatus.toLowerCase() : '')">{{ slotProps.data.inventoryStatus }}</span>
|
||||
</template>
|
||||
</Column>
|
||||
<Column headerStyle="min-width:10rem;">
|
||||
<template #body="slotProps">
|
||||
<Button icon="pi pi-pencil" class="p-button-rounded p-button-success mr-2" @click="editProduct(slotProps.data)" />
|
||||
<Button icon="pi pi-trash" class="p-button-rounded p-button-warning mt-2" @click="confirmDeleteProduct(slotProps.data)" />
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<Dialog v-model:visible="productDialog" :style="{ width: '450px' }" header="Product Details" :modal="true" class="p-fluid">
|
||||
<img :src="'images/product/' + product.image" :alt="product.image" v-if="product.image" width="150" class="mt-0 mx-auto mb-5 block shadow-2" />
|
||||
<div class="field">
|
||||
<label for="name">Name</label>
|
||||
<InputText id="name" v-model.trim="product.name" required="true" autofocus :class="{ 'p-invalid': submitted && !product.name }" />
|
||||
<small class="p-invalid" v-if="submitted && !product.name">Name is required.</small>
|
||||
</div>
|
||||
<div class="field">
|
||||
<label for="description">Description</label>
|
||||
<Textarea id="description" v-model="product.description" required="true" rows="3" cols="20" />
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label for="inventoryStatus" class="mb-3">Inventory Status</label>
|
||||
<Dropdown id="inventoryStatus" v-model="product.inventoryStatus" :options="statuses" optionLabel="label" placeholder="Select a Status">
|
||||
<template #value="slotProps">
|
||||
<div v-if="slotProps.value && slotProps.value.value">
|
||||
<span :class="'product-badge status-' + slotProps.value.value">{{ slotProps.value.label }}</span>
|
||||
</div>
|
||||
<div v-else-if="slotProps.value && !slotProps.value.value">
|
||||
<span :class="'product-badge status-' + slotProps.value.toLowerCase()">{{ slotProps.value }}</span>
|
||||
</div>
|
||||
<span v-else>
|
||||
{{ slotProps.placeholder }}
|
||||
</span>
|
||||
</template>
|
||||
</Dropdown>
|
||||
</div>
|
||||
|
||||
<div class="field">
|
||||
<label class="mb-3">Category</label>
|
||||
<div class="formgrid grid">
|
||||
<div class="field-radiobutton col-6">
|
||||
<RadioButton id="category1" name="category" value="Accessories" v-model="product.category" />
|
||||
<label for="category1">Accessories</label>
|
||||
</div>
|
||||
<div class="field-radiobutton col-6">
|
||||
<RadioButton id="category2" name="category" value="Clothing" v-model="product.category" />
|
||||
<label for="category2">Clothing</label>
|
||||
</div>
|
||||
<div class="field-radiobutton col-6">
|
||||
<RadioButton id="category3" name="category" value="Electronics" v-model="product.category" />
|
||||
<label for="category3">Electronics</label>
|
||||
</div>
|
||||
<div class="field-radiobutton col-6">
|
||||
<RadioButton id="category4" name="category" value="Fitness" v-model="product.category" />
|
||||
<label for="category4">Fitness</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="formgrid grid">
|
||||
<div class="field col">
|
||||
<label for="price">Price</label>
|
||||
<InputNumber id="price" v-model="product.price" mode="currency" currency="USD" locale="en-US" />
|
||||
</div>
|
||||
<div class="field col">
|
||||
<label for="quantity">Quantity</label>
|
||||
<InputNumber id="quantity" v-model="product.quantity" integeronly />
|
||||
</div>
|
||||
</div>
|
||||
<template #footer>
|
||||
<Button label="Cancel" icon="pi pi-times" class="p-button-text" @click="hideDialog" />
|
||||
<Button label="Save" icon="pi pi-check" class="p-button-text" @click="saveProduct" />
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model:visible="deleteProductDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
|
||||
<div class="flex align-items-center justify-content-center">
|
||||
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
|
||||
<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" class="p-button-text" @click="deleteProductDialog = false" />
|
||||
<Button label="Yes" icon="pi pi-check" class="p-button-text" @click="deleteProduct" />
|
||||
</template>
|
||||
</Dialog>
|
||||
|
||||
<Dialog v-model:visible="deleteProductsDialog" :style="{ width: '450px' }" header="Confirm" :modal="true">
|
||||
<div class="flex align-items-center justify-content-center">
|
||||
<i class="pi pi-exclamation-triangle mr-3" style="font-size: 2rem" />
|
||||
<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" class="p-button-text" @click="deleteProductsDialog = false" />
|
||||
<Button label="Yes" icon="pi pi-check" class="p-button-text" @click="deleteSelectedProducts" />
|
||||
</template>
|
||||
</Dialog>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import { FilterMatchMode } from 'primevue/api';
|
||||
import ProductService from '../service/ProductService';
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
products: null,
|
||||
productDialog: false,
|
||||
deleteProductDialog: false,
|
||||
deleteProductsDialog: false,
|
||||
product: {},
|
||||
selectedProducts: null,
|
||||
filters: {},
|
||||
submitted: false,
|
||||
statuses: [
|
||||
{ label: 'INSTOCK', value: 'instock' },
|
||||
{ label: 'LOWSTOCK', value: 'lowstock' },
|
||||
{ label: 'OUTOFSTOCK', value: 'outofstock' }
|
||||
]
|
||||
};
|
||||
},
|
||||
productService: null,
|
||||
created() {
|
||||
this.productService = new ProductService();
|
||||
this.initFilters();
|
||||
},
|
||||
mounted() {
|
||||
this.productService.getProducts().then((data) => (this.products = data));
|
||||
},
|
||||
methods: {
|
||||
formatCurrency(value) {
|
||||
if (value) return value.toLocaleString('en-US', { style: 'currency', currency: 'USD' });
|
||||
return;
|
||||
},
|
||||
openNew() {
|
||||
this.product = {};
|
||||
this.submitted = false;
|
||||
this.productDialog = true;
|
||||
},
|
||||
hideDialog() {
|
||||
this.productDialog = false;
|
||||
this.submitted = false;
|
||||
},
|
||||
saveProduct() {
|
||||
this.submitted = true;
|
||||
if (this.product.name.trim()) {
|
||||
if (this.product.id) {
|
||||
this.product.inventoryStatus = this.product.inventoryStatus.value ? this.product.inventoryStatus.value : this.product.inventoryStatus;
|
||||
this.products[this.findIndexById(this.product.id)] = this.product;
|
||||
this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Updated', life: 3000 });
|
||||
} else {
|
||||
this.product.id = this.createId();
|
||||
this.product.code = this.createId();
|
||||
this.product.image = 'product-placeholder.svg';
|
||||
this.product.inventoryStatus = this.product.inventoryStatus ? this.product.inventoryStatus.value : 'INSTOCK';
|
||||
this.products.push(this.product);
|
||||
this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Created', life: 3000 });
|
||||
}
|
||||
this.productDialog = false;
|
||||
this.product = {};
|
||||
}
|
||||
},
|
||||
editProduct(product) {
|
||||
this.product = { ...product };
|
||||
this.productDialog = true;
|
||||
},
|
||||
confirmDeleteProduct(product) {
|
||||
this.product = product;
|
||||
this.deleteProductDialog = true;
|
||||
},
|
||||
deleteProduct() {
|
||||
this.products = this.products.filter((val) => val.id !== this.product.id);
|
||||
this.deleteProductDialog = false;
|
||||
this.product = {};
|
||||
this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Product Deleted', life: 3000 });
|
||||
},
|
||||
findIndexById(id) {
|
||||
let index = -1;
|
||||
for (let i = 0; i < this.products.length; i++) {
|
||||
if (this.products[i].id === id) {
|
||||
index = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
return index;
|
||||
},
|
||||
createId() {
|
||||
let id = '';
|
||||
var chars = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
|
||||
for (var i = 0; i < 5; i++) {
|
||||
id += chars.charAt(Math.floor(Math.random() * chars.length));
|
||||
}
|
||||
return id;
|
||||
},
|
||||
exportCSV() {
|
||||
this.$refs.dt.exportCSV();
|
||||
},
|
||||
confirmDeleteSelected() {
|
||||
this.deleteProductsDialog = true;
|
||||
},
|
||||
deleteSelectedProducts() {
|
||||
this.products = this.products.filter((val) => !this.selectedProducts.includes(val));
|
||||
this.deleteProductsDialog = false;
|
||||
this.selectedProducts = null;
|
||||
this.$toast.add({ severity: 'success', summary: 'Successful', detail: 'Products Deleted', life: 3000 });
|
||||
},
|
||||
initFilters() {
|
||||
this.filters = {
|
||||
global: { value: null, matchMode: FilterMatchMode.CONTAINS }
|
||||
};
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '../assets/demo/badges.scss';
|
||||
</style>
|
||||
10
src/views/pages/Empty.vue
Normal file
10
src/views/pages/Empty.vue
Normal file
@@ -0,0 +1,10 @@
|
||||
<template>
|
||||
<div className="grid">
|
||||
<div className="col-12">
|
||||
<div className="card">
|
||||
<h5>Empty Page</h5>
|
||||
<p>Use this page to start from scratch and place your custom content.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
55
src/views/pages/NotFound.vue
Normal file
55
src/views/pages/NotFound.vue
Normal file
@@ -0,0 +1,55 @@
|
||||
<template>
|
||||
<div class="surface-0 flex align-items-center justify-content-center min-h-screen min-w-screen overflow-hidden">
|
||||
<div class="grid justify-content-center p-2 lg:p-0" style="min-width: 80%">
|
||||
<div class="col-12 mt-5 xl:mt-0 text-center">
|
||||
<img src="layout/images/logo-blue.svg" alt="Sakai logo" class="mb-5" style="width: 81px; height: 60px" />
|
||||
</div>
|
||||
<div class="col-12 xl:col-6" style="border-radius: 56px; padding: 0.3rem; background: linear-gradient(180deg, rgba(33, 150, 243, 0.4) 10%, rgba(33, 150, 243, 0) 30%)">
|
||||
<div class="flex justify-content-center h-full w-full m-0 py-7 px-4" style="border-radius: 53px; background: linear-gradient(180deg, var(--surface-50) 38.9%, var(--surface-0))">
|
||||
<div class="grid flex-column align-items-center">
|
||||
<span class="text-blue-500 font-bold text-3xl">404</span>
|
||||
<h1 class="text-900 font-bold text-3xl lg:text-5xl mb-2">Looks like you are lost</h1>
|
||||
<span class="text-gray-600">Requested resource is not available.</span>
|
||||
<div class="col-12 flex align-items-center py-5 mt-6 border-300 border-bottom-1">
|
||||
<div class="flex justify-content-center align-items-center bg-cyan-400 border-round" style="height: 3.5rem; width: 3.5rem">
|
||||
<i class="pi pi-fw pi-table text-50 text-2xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<router-link to="/">
|
||||
<p class="text-900 lg:text-xl font-medium mb-0">Frequently Asked Questions</p>
|
||||
</router-link>
|
||||
<span class="text-gray-600 lg:text-xl">Ultricies mi quis hendrerit dolor.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 flex align-items-center py-5 border-300 border-bottom-1">
|
||||
<div class="flex justify-content-center align-items-center bg-orange-400 border-round" style="height: 3.5rem; width: 3.5rem">
|
||||
<i class="pi pi-fw pi-question-circle text-50 text-2xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<router-link to="/">
|
||||
<p class="text-900 lg:text-xl font-medium mb-0">Solution Center</p>
|
||||
</router-link>
|
||||
<span class="text-gray-600 lg:text-xl">Phasellus faucibus scelerisque eleifend.</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 flex align-items-center py-5 border-300 border-bottom-1">
|
||||
<div class="flex justify-content-center align-items-center bg-indigo-400 border-round" style="height: 3.5rem; width: 3.5rem">
|
||||
<i class="pi pi-fw pi-unlock text-50 text-2xl"></i>
|
||||
</div>
|
||||
<div class="ml-4">
|
||||
<router-link to="/">
|
||||
<p class="text-900 lg:text-xl font-medium mb-0">Permission Manager</p>
|
||||
</router-link>
|
||||
<span class="text-gray-600 lg:text-xl">Accumsan in nisl nisi scelerisque</span>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 mt-5 text-center">
|
||||
<i class="pi pi-fw pi-arrow-left text-blue-500 mr-2" style="vertical-align: center"></i>
|
||||
<router-link to="/" class="text-blue-500">Go to Dashboard</router-link>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
100
src/views/pages/Timeline.vue
Normal file
100
src/views/pages/Timeline.vue
Normal file
@@ -0,0 +1,100 @@
|
||||
<template>
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<h4>Timeline</h4>
|
||||
|
||||
<h5>Custom Timeline</h5>
|
||||
<Timeline :value="customEvents" align="alternate" class="customized-timeline">
|
||||
<template #marker="slotProps">
|
||||
<span class="flex w-2rem h-2rem align-items-center justify-content-center text-white border-circle z-1 shadow-2" :style="{ backgroundColor: slotProps.item.color }">
|
||||
<i :class="slotProps.item.icon"></i>
|
||||
</span>
|
||||
</template>
|
||||
<template #content="slotProps">
|
||||
<Card>
|
||||
<template #title>
|
||||
{{ slotProps.item.status }}
|
||||
</template>
|
||||
<template #subtitle>
|
||||
{{ slotProps.item.date }}
|
||||
</template>
|
||||
<template #content>
|
||||
<img v-if="slotProps.item.image" :src="'images/product/' + slotProps.item.image" :alt="slotProps.item.name" width="200" class="shadow-2 mb-3" />
|
||||
<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" class="p-button-text"></Button>
|
||||
</template>
|
||||
</Card>
|
||||
</template>
|
||||
</Timeline>
|
||||
|
||||
<h5 style="margin-top: 5em">Horizontal - Alternate Align</h5>
|
||||
<Timeline :value="horizontalEvents" layout="horizontal" align="alternate">
|
||||
<template #content="slotProps">
|
||||
{{ slotProps.item }}
|
||||
</template>
|
||||
<template #opposite> </template>
|
||||
</Timeline>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from 'vue';
|
||||
|
||||
const customEvents = 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>
|
||||
|
||||
<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>
|
||||
94
src/views/utilities/Documentation.vue
Normal file
94
src/views/utilities/Documentation.vue
Normal file
@@ -0,0 +1,94 @@
|
||||
<template>
|
||||
<div class="grid">
|
||||
<div class="col-12">
|
||||
<div class="card docs">
|
||||
<h3>Current Version</h3>
|
||||
<p>Vue 3 and PrimeVue 3</p>
|
||||
|
||||
<h5>Getting Started</h5>
|
||||
<p>
|
||||
Sakai is an application template for Vue based on the <a href="https://cli.vuejs.org/" class="font-medium">Vue CLI</a> that provides out-of-the-box standard tooling for Vue projects. To get started, clone the
|
||||
<a href="https://github.com/primefaces/sakai-vue" class="font-medium">repository</a> from GitHub and install the dependencies with npm or yarn.
|
||||
</p>
|
||||
<pre v-code.script><code>
|
||||
npm install
|
||||
|
||||
</code></pre>
|
||||
|
||||
or
|
||||
|
||||
<pre v-code.script><code>
|
||||
yarn
|
||||
|
||||
</code></pre>
|
||||
|
||||
<p>Next step is running the application using the serve script and navigate to <i>http://localhost:8080/</i> to view the application. That is it, you may now start with the development of your application using the Sakai template.</p>
|
||||
|
||||
<pre v-code.script><code>
|
||||
npm run serve
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h5>Vue CLI Scripts</h5>
|
||||
<p>Following commands are derived from create-app-app.</p>
|
||||
<pre v-code.script><code>
|
||||
"npm run serve": Starts the development server
|
||||
"npm run build": Builds the application for deployment.
|
||||
"npm run lint": Executes the lint checks.
|
||||
"npm run test:unit": Runs the tests.
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h5>Structure</h5>
|
||||
<p>
|
||||
Sakai consists of 2 main parts; the application layout and the resources. <i>App.vue</i> inside src folder is the main component containing the template for the base layout whereas required resources such as SASS structure for the
|
||||
layout are placed inside the <b>src/assets/</b> folder.
|
||||
</p>
|
||||
|
||||
<h5>Layout Components</h5>
|
||||
<p>
|
||||
Main layout is the template of the <i>App.vue</i>, it is divided into a couple of child components such as topbar, menu and footer. Here is template of the <i>App.vue</i> component that implements the logic such as menu state,
|
||||
layout modes and so on.
|
||||
</p>
|
||||
|
||||
<h5>Menu</h5>
|
||||
<p>
|
||||
Menu is a separate component defined in <i>AppMenu.vue</i> file based on PrimeVue MenuModel API. In order to define the menuitems, navigate to data section of <i>App.vue</i> file and define your own model as a nested structure
|
||||
using the <i>menu</i> property.
|
||||
</p>
|
||||
|
||||
<h5>Dependencies</h5>
|
||||
<p>Dependencies of Sakai are listed below and needs to be added to package.json.</p>
|
||||
|
||||
<pre v-code.script>
|
||||
<code>
|
||||
{
|
||||
"primevue": "~3.11.0",
|
||||
"primeicons": "~5.0.0",
|
||||
"primeflex": "~3.1.2",
|
||||
}
|
||||
|
||||
</code></pre>
|
||||
|
||||
<h5>PrimeVue Theme</h5>
|
||||
<p>Sakai uses the free Saga, Arya and Vela themes which are distributed within PrimeVue, however it can be used with any PrimeVue theme as well such as material, tailwind and bootstrap.</p>
|
||||
|
||||
<h5>SASS Variables</h5>
|
||||
<p>In case you'd like to customize the layout variables, open <i>_variables.scss</i> file under src/layout folder. Saving the changes will be reflected instantly at your browser.</p>
|
||||
|
||||
<h6>src/assets/_variables.scss</h6>
|
||||
<pre v-code.css>
|
||||
<code>
|
||||
$fontSize:1rem;
|
||||
$borderRadius:12px;
|
||||
$transitionDuration:.2s;
|
||||
|
||||
</code></pre>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style scoped lang="scss">
|
||||
@import '@/assets/demo/styles/documentation.scss';
|
||||
</style>
|
||||
Reference in New Issue
Block a user