Merge branch 'prod'
commit
dcd66c1515
|
@ -7,9 +7,9 @@
|
|||
<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-200 dark:border-surface-700': index !== 0 }">
|
||||
<div class="flex flex-col sm:flex-row sm:items-center gap-4">
|
||||
<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" />
|
||||
<img class="rounded w-36" :src="`https://primefaces.org/cdn/primevue/images/product/${item.image}`" :alt="item.name" />
|
||||
<div class="dark:bg-surface-900 absolute rounded-border" style="left: 4px; top: 4px">
|
||||
<Tag :value="item.inventoryStatus" :severity="getSeverity(item)"></Tag>
|
||||
</div>
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
<template>
|
||||
<DocSectionText v-bind="$attrs">
|
||||
<p>Uploading implementation can be overridden by enabling <i>customUpload</i> property and defining a custom <i>uploader</i> handler event.</p>
|
||||
<p>Uploading implementation can be overridden by enabling <i>customUpload</i> property. This sample, displays the image on the client side with a grayscale filter.</p>
|
||||
</DocSectionText>
|
||||
<div class="card flex justify-center">
|
||||
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
|
||||
<div class="card flex flex-col items-center gap-6">
|
||||
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
|
||||
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
|
||||
</div>
|
||||
<DocSectionCode :code="code" />
|
||||
</template>
|
||||
|
@ -12,30 +13,37 @@
|
|||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: null,
|
||||
code: {
|
||||
basic: `
|
||||
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
|
||||
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
|
||||
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
|
||||
`,
|
||||
options: `
|
||||
<template>
|
||||
<div class="card flex justify-center">
|
||||
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
|
||||
<div class="card flex flex-col items-center gap-6">
|
||||
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
|
||||
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
src: null
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
async customBase64Uploader(event) {
|
||||
onFileSelect(event) {
|
||||
const file = event.files[0];
|
||||
const reader = new FileReader();
|
||||
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
|
||||
reader.onloadend = function () {
|
||||
const base64data = reader.result;
|
||||
reader.onload = async (e) => {
|
||||
this.src = e.target.result;
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -43,39 +51,42 @@ export default {
|
|||
`,
|
||||
composition: `
|
||||
<template>
|
||||
<div class="card flex justify-center">
|
||||
<FileUpload mode="basic" name="demo[]" url="/api/upload" accept="image/*" customUpload @uploader="customBase64Uploader" />
|
||||
<div class="card flex flex-col items-center gap-6">
|
||||
<FileUpload mode="basic" @select="onFileSelect" customUpload auto severity="secondary" class="p-button-outlined" />
|
||||
<img v-if="src" :src="src" alt="Image" class="shadow-md rounded-xl w-full sm:w-64" style="filter: grayscale(100%)" />
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
const customBase64Uploader = async (event) => {
|
||||
import { ref } from "vue";
|
||||
|
||||
const src = ref(null);
|
||||
|
||||
function onFileSelect(event) {
|
||||
const file = event.files[0];
|
||||
const reader = new FileReader();
|
||||
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
reader.onload = async (e) => {
|
||||
src.value = e.target.result;
|
||||
};
|
||||
|
||||
reader.onloadend = function () {
|
||||
const base64data = reader.result;
|
||||
};
|
||||
};
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
<\/script>
|
||||
`
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
async customBase64Uploader(event) {
|
||||
onFileSelect(event) {
|
||||
const file = event.files[0];
|
||||
const reader = new FileReader();
|
||||
let blob = await fetch(file.objectURL).then((r) => r.blob()); //blob:url
|
||||
|
||||
reader.readAsDataURL(blob);
|
||||
|
||||
reader.onloadend = function () {
|
||||
const base64data = reader.result;
|
||||
reader.onload = async (e) => {
|
||||
this.src = e.target.result;
|
||||
};
|
||||
|
||||
reader.readAsDataURL(file);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -1,34 +1,55 @@
|
|||
<template>
|
||||
<DocSectionText v-bind="$attrs">
|
||||
<p>An example that displays a DataTable inside a popup to select an item.</p>
|
||||
<p>Place the Popover outside of the data iteration components to avoid rendering it multiple times.</p>
|
||||
</DocSectionText>
|
||||
|
||||
<div class="card flex flex-col items-center gap-4">
|
||||
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
|
||||
|
||||
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
|
||||
<div class="relative">
|
||||
<img :src="`https://primefaces.org/cdn/primevue/images/product/${selectedProduct.image}`" :alt="selectedProduct.name" class="w-full sm:w-80" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-4 mb-2">
|
||||
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
|
||||
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
|
||||
</div>
|
||||
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
|
||||
</div>
|
||||
|
||||
<Popover ref="op" appendTo="body">
|
||||
<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">
|
||||
<div class="card">
|
||||
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
|
||||
<Column field="id" header="Id" class="w-1/6"></Column>
|
||||
<Column field="code" header="Code" class="w-1/6"></Column>
|
||||
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
|
||||
<Column field="price" header="Price" sortable class="w-1/6">
|
||||
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
|
||||
</Column>
|
||||
<Column header="Image" class="w-1/6">
|
||||
<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 header="Details" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<Popover ref="op">
|
||||
<div v-if="selectedProduct" class="rounded flex flex-col">
|
||||
<div class="flex justify-center rounded">
|
||||
<div class="relative mx-auto">
|
||||
<img class="rounded w-44 sm:w-64" :src="`https://primefaces.org/cdn/primevue/images/product/${selectedProduct.image}`" :alt="selectedProduct.name" />
|
||||
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex flex-row justify-between items-start gap-2 mb-4">
|
||||
<div>
|
||||
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
|
||||
<div class="text-lg font-medium mt-1">{{ selectedProduct.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">{{ selectedProduct.rating }}</span>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Button icon="pi pi-shopping-cart" :label="`Buy Now | \$${selectedProduct.price}`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
|
||||
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
<DocSectionCode :code="code" :service="['ProductService']" />
|
||||
|
@ -43,67 +64,103 @@ export default {
|
|||
selectedProduct: null,
|
||||
code: {
|
||||
basic: `
|
||||
<Toast />
|
||||
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
|
||||
|
||||
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
|
||||
<div class="relative">
|
||||
<img :src="\`/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-16 shadow-sm" class="w-full sm:w-80" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-4 mb-2">
|
||||
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
|
||||
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
|
||||
</div>
|
||||
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
|
||||
</div>
|
||||
|
||||
<Popover ref="op" appendTo="body">
|
||||
<DataTable v-model:selection="selectedProduct" :value="products" selectionMode="single" :paginator="true" :rows="5" @row-select="onProductSelect">
|
||||
<Column field="name" header="Name" sortable style="width: 50%"></Column>
|
||||
<Column header="Image" style="width: 20%">
|
||||
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
|
||||
<Column field="id" header="Id" class="w-1/6"></Column>
|
||||
<Column field="code" header="Code" class="w-1/6"></Column>
|
||||
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
|
||||
<Column field="price" header="Price" sortable class="w-1/6">
|
||||
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
|
||||
</Column>
|
||||
<Column header="Image" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
<img :src="\`/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
|
||||
<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="width: 30%">
|
||||
<Column header="Details" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
$ {{ slotProps.data.price }}
|
||||
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<Popover ref="op">
|
||||
<div v-if="selectedProduct" class="rounded flex flex-col">
|
||||
<div class="flex justify-center rounded">
|
||||
<div class="relative mx-auto">
|
||||
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
|
||||
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex flex-row justify-between items-start gap-2 mb-4">
|
||||
<div>
|
||||
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
|
||||
<div class="text-lg font-medium mt-1">{{ selectedProduct.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">{{ selectedProduct.rating }}</span>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
|
||||
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
`,
|
||||
options: `
|
||||
<template>
|
||||
<div class="card flex flex-col items-center gap-4">
|
||||
<Toast />
|
||||
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
|
||||
|
||||
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
|
||||
<div class="relative">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-full sm:w-80" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-4 mb-2">
|
||||
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
|
||||
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
|
||||
</div>
|
||||
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
|
||||
</div>
|
||||
|
||||
<Popover ref="op" appendTo="body">
|
||||
<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">
|
||||
<div class="card">
|
||||
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
|
||||
<Column field="id" header="Id" class="w-1/6"></Column>
|
||||
<Column field="code" header="Code" class="w-1/6"></Column>
|
||||
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
|
||||
<Column field="price" header="Price" sortable class="w-1/6">
|
||||
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
|
||||
</Column>
|
||||
<Column header="Image" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
|
||||
<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">
|
||||
<Column header="Details" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
$ {{ slotProps.data.price }}
|
||||
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<Popover ref="op">
|
||||
<div v-if="selectedProduct" class="rounded flex flex-col">
|
||||
<div class="flex justify-center rounded">
|
||||
<div class="relative mx-auto">
|
||||
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
|
||||
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex flex-row justify-between items-start gap-2 mb-4">
|
||||
<div>
|
||||
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
|
||||
<div class="text-lg font-medium mt-1">{{ selectedProduct.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">{{ selectedProduct.rating }}</span>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
|
||||
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -119,17 +176,40 @@ export default {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
ProductService.getProductsSmall()
|
||||
.then((data) => (this.products = data))
|
||||
.then(() => (this.selectedProduct = this.products[0]));
|
||||
ProductService.getProductsSmall().then((data) => (this.products = data));
|
||||
},
|
||||
methods: {
|
||||
toggle(event) {
|
||||
this.$refs.op.toggle(event);
|
||||
},
|
||||
onProductSelect(event) {
|
||||
displayProduct(event, product) {
|
||||
if (this.selectedProduct?.id === product.id) {
|
||||
this.$refs.op.hide();
|
||||
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
|
||||
this.selectedProduct = null;
|
||||
} else {
|
||||
this.selectedProduct = product;
|
||||
this.$refs.op.show(event);
|
||||
|
||||
// will not be needed with v4.0.6 as Popover will auto align
|
||||
if (this.$refs.op.container) {
|
||||
this.$refs.op.alignOverlay();
|
||||
}
|
||||
}
|
||||
},
|
||||
hidePopover() {
|
||||
this.$refs.op.hide();
|
||||
},
|
||||
getSeverity(product) {
|
||||
switch (product.inventoryStatus) {
|
||||
case 'INSTOCK':
|
||||
return 'success';
|
||||
|
||||
case 'LOWSTOCK':
|
||||
return 'warn';
|
||||
|
||||
case 'OUTOFSTOCK':
|
||||
return 'danger';
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
@ -137,35 +217,53 @@ export default {
|
|||
`,
|
||||
composition: `
|
||||
<template>
|
||||
<div class="card flex flex-col items-center gap-4">
|
||||
<Toast />
|
||||
<Button type="button" icon="pi pi-search" :label="selectedProduct ? selectedProduct.name : 'Select a Product'" @click="toggle" aria-haspopup="true" aria-controls="overlay_panel" />
|
||||
|
||||
<div v-if="selectedProduct" class="p-8 bg-surface-0 dark:bg-surface-900 rounded border border-surface-200 dark:border-surface-700">
|
||||
<div class="relative">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" class="w-full sm:w-80" />
|
||||
</div>
|
||||
<div class="flex items-center justify-between mt-4 mb-2">
|
||||
<span class="font-semibold text-xl">{{ selectedProduct.name }}</span>
|
||||
<span class="text-xl ml-4">{{ '$' + selectedProduct.price }}</span>
|
||||
</div>
|
||||
<span class="text-surface-500 dark:text-surface-400">{{ selectedProduct.category }}</span>
|
||||
</div>
|
||||
|
||||
<Popover ref="op" appendTo="body">
|
||||
<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">
|
||||
<div class="card">
|
||||
<DataTable :value="products" :rows="5" paginator tableStyle="min-width: 50rem">
|
||||
<Column field="id" header="Id" class="w-1/6"></Column>
|
||||
<Column field="code" header="Code" class="w-1/6"></Column>
|
||||
<Column field="name" header="Name" class="w-1/6" bodyClass="whitespace-nowrap"></Column>
|
||||
<Column field="price" header="Price" sortable class="w-1/6">
|
||||
<template #body="slotProps"> $ {{ slotProps.data.price }} </template>
|
||||
</Column>
|
||||
<Column header="Image" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="slotProps.data.image" class="w-16 shadow-sm" />
|
||||
<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">
|
||||
<Column header="Details" class="w-1/6">
|
||||
<template #body="slotProps">
|
||||
$ {{ slotProps.data.price }}
|
||||
<Button type="button" @click="displayProduct($event, slotProps.data)" icon="pi pi-search" severity="secondary" rounded></Button>
|
||||
</template>
|
||||
</Column>
|
||||
</DataTable>
|
||||
|
||||
<Popover ref="op">
|
||||
<div v-if="selectedProduct" class="rounded flex flex-col">
|
||||
<div class="flex justify-center rounded">
|
||||
<div class="relative mx-auto">
|
||||
<img class="rounded w-44 sm:w-64" :src="\`https://primefaces.org/cdn/primevue/images/product/\${selectedProduct.image}\`" :alt="selectedProduct.name" />
|
||||
<Tag :value="selectedProduct.inventoryStatus" :severity="getSeverity(selectedProduct)" class="absolute dark:!bg-surface-900" style="left: 4px; top: 4px"></Tag>
|
||||
</div>
|
||||
</div>
|
||||
<div class="pt-4">
|
||||
<div class="flex flex-row justify-between items-start gap-2 mb-4">
|
||||
<div>
|
||||
<span class="font-medium text-surface-500 dark:text-surface-400 text-sm">{{ selectedProduct.category }}</span>
|
||||
<div class="text-lg font-medium mt-1">{{ selectedProduct.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">{{ selectedProduct.rating }}</span>
|
||||
<i class="pi pi-star-fill text-yellow-500"></i>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex gap-2">
|
||||
<Button icon="pi pi-shopping-cart" :label="\`Buy Now | \\$\${selectedProduct.price}\`" :disabled="selectedProduct.inventoryStatus === 'OUTOFSTOCK'" class="flex-auto whitespace-nowrap" @click="hidePopover"></Button>
|
||||
<Button icon="pi pi-heart" outlined @click="hidePopover"></Button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
@ -176,23 +274,46 @@ import { useToast } from "primevue/usetoast";
|
|||
import { ProductService } from '@/service/ProductService';
|
||||
|
||||
onMounted(() => {
|
||||
ProductService.getProductsSmall()
|
||||
.then((data) => (products.value = data))
|
||||
.then(() => (selectedProduct.value = products.value[0]));
|
||||
ProductService.getProductsSmall().then((data) => (products.value = data));
|
||||
});
|
||||
|
||||
const toast = useToast();
|
||||
const op = ref();
|
||||
const products = ref();
|
||||
const selectedProduct = ref();
|
||||
|
||||
const toggle = (event) => {
|
||||
op.value.toggle(event);
|
||||
};
|
||||
|
||||
const onProductSelect = (event) => {
|
||||
const displayProduct = (event, product) => {
|
||||
if (selectedProduct.value?.id === product.id) {
|
||||
op.value.hide();
|
||||
toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
|
||||
selectedProduct.value = null;
|
||||
} else {
|
||||
selectedProduct.value = product;
|
||||
op.value.show(event);
|
||||
|
||||
// will not be needed with v4.0.6 as Popover will auto align
|
||||
if (op.value.container) {
|
||||
op.value.alignOverlay();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const hidePopover = () => {
|
||||
op.value.hide();
|
||||
}
|
||||
|
||||
const getSeverity = (product) => {
|
||||
switch (product.inventoryStatus) {
|
||||
case 'INSTOCK':
|
||||
return 'success';
|
||||
|
||||
case 'LOWSTOCK':
|
||||
return 'warn';
|
||||
|
||||
case 'OUTOFSTOCK':
|
||||
return 'danger';
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
<\/script>
|
||||
`,
|
||||
|
@ -216,17 +337,39 @@ const onProductSelect = (event) => {
|
|||
};
|
||||
},
|
||||
mounted() {
|
||||
ProductService.getProductsSmall()
|
||||
.then((data) => (this.products = data))
|
||||
.then(() => (this.selectedProduct = this.products[0]));
|
||||
ProductService.getProductsSmall().then((data) => (this.products = data));
|
||||
},
|
||||
methods: {
|
||||
toggle(event) {
|
||||
this.$refs.op.toggle(event);
|
||||
},
|
||||
onProductSelect(event) {
|
||||
displayProduct(event, product) {
|
||||
if (this.selectedProduct?.id === product.id) {
|
||||
this.$refs.op.hide();
|
||||
this.$toast.add({ severity: 'info', summary: 'Product Selected', detail: event.data.name, life: 3000 });
|
||||
this.selectedProduct = null;
|
||||
} else {
|
||||
this.selectedProduct = product;
|
||||
this.$refs.op.show(event);
|
||||
|
||||
if (this.$refs.op.container) {
|
||||
this.$refs.op.alignOverlay();
|
||||
}
|
||||
}
|
||||
},
|
||||
hidePopover() {
|
||||
this.$refs.op.hide();
|
||||
},
|
||||
getSeverity(product) {
|
||||
switch (product.inventoryStatus) {
|
||||
case 'INSTOCK':
|
||||
return 'success';
|
||||
|
||||
case 'LOWSTOCK':
|
||||
return 'warn';
|
||||
|
||||
case 'OUTOFSTOCK':
|
||||
return 'danger';
|
||||
|
||||
default:
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
|
|
@ -0,0 +1,165 @@
|
|||
<template>
|
||||
<DocSectionText v-bind="$attrs">
|
||||
<p>In this sample, data is retrieved from the content inside the popover.</p>
|
||||
</DocSectionText>
|
||||
<div class="card flex justify-center">
|
||||
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
|
||||
|
||||
<Popover ref="op">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<span class="font-medium block mb-2">Team Members</span>
|
||||
<ul class="list-none p-0 m-0 flex flex-col">
|
||||
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
|
||||
<img :src="`https://primefaces.org/cdn/primevue/images/avatar/${member.image}`" style="width: 32px" />
|
||||
<div>
|
||||
<span class="font-medium">{{ member.name }}</span>
|
||||
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
<DocSectionCode :code="code" />
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectedMember: null,
|
||||
members: [
|
||||
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
|
||||
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
|
||||
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
|
||||
],
|
||||
code: {
|
||||
basic: `
|
||||
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
|
||||
|
||||
<Popover ref="op">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<span class="font-medium block mb-2">Team Members</span>
|
||||
<ul class="list-none p-0 m-0 flex flex-col">
|
||||
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
|
||||
<div>
|
||||
<span class="font-medium">{{ member.name }}</span>
|
||||
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
`,
|
||||
options: `
|
||||
<template>
|
||||
<div class="card flex justify-center">
|
||||
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
|
||||
|
||||
<Popover ref="op">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<span class="font-medium block mb-2">Team Members</span>
|
||||
<ul class="list-none p-0 m-0 flex flex-col">
|
||||
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
|
||||
<div>
|
||||
<span class="font-medium">{{ member.name }}</span>
|
||||
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
selectedMember: null,
|
||||
members: [
|
||||
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
|
||||
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
|
||||
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
|
||||
]
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
toggle(event) {
|
||||
this.$refs.op.toggle(event);
|
||||
},
|
||||
selectMember(member) {
|
||||
this.selectedMember = member;
|
||||
this.$refs.op.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
<\/script>
|
||||
`,
|
||||
composition: `
|
||||
<template>
|
||||
<div class="card flex justify-center">
|
||||
<Button type="button" :label="selectedMember ? selectedMember.name : 'Select Member'" @click="toggle" class="min-w-48" />
|
||||
|
||||
<Popover ref="op">
|
||||
<div class="flex flex-col gap-4">
|
||||
<div>
|
||||
<span class="font-medium block mb-2">Team Members</span>
|
||||
<ul class="list-none p-0 m-0 flex flex-col">
|
||||
<li v-for="member in members" :key="member.name" class="flex items-center gap-2 px-2 py-3 hover:bg-emphasis cursor-pointer rounded-border" @click="selectMember(member)">
|
||||
<img :src="\`https://primefaces.org/cdn/primevue/images/avatar/\${member.image}\`" style="width: 32px" />
|
||||
<div>
|
||||
<span class="font-medium">{{ member.name }}</span>
|
||||
<div class="text-sm text-surface-500 dark:text-surface-400">{{ member.email }}</div>
|
||||
</div>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
</div>
|
||||
</Popover>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script setup>
|
||||
import { ref } from "vue";
|
||||
|
||||
const op = ref();
|
||||
const selectedMember = ref(null);
|
||||
const members = ref([
|
||||
{ name: 'Amy Elsner', image: 'amyelsner.png', email: 'amy@email.com', role: 'Owner' },
|
||||
{ name: 'Bernardo Dominic', image: 'bernardodominic.png', email: 'bernardo@email.com', role: 'Editor' },
|
||||
{ name: 'Ioni Bowcher', image: 'ionibowcher.png', email: 'ioni@email.com', role: 'Viewer' }
|
||||
]);
|
||||
|
||||
const toggle = (event) => {
|
||||
op.value.toggle(event);
|
||||
}
|
||||
|
||||
const selectMember = (member) => {
|
||||
selectedMember.value = member;
|
||||
op.value.hide();
|
||||
}
|
||||
<\/script>
|
||||
`
|
||||
}
|
||||
};
|
||||
},
|
||||
methods: {
|
||||
toggle(event) {
|
||||
this.$refs.op.toggle(event);
|
||||
},
|
||||
selectMember(member) {
|
||||
this.selectedMember = member;
|
||||
this.$refs.op.hide();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
|
@ -16,6 +16,7 @@ import BasicDoc from '@/doc/popover/BasicDoc.vue';
|
|||
import DataTableDoc from '@/doc/popover/DataTableDoc.vue';
|
||||
import ImportDoc from '@/doc/popover/ImportDoc.vue';
|
||||
import PTComponent from '@/doc/popover/pt/index.vue';
|
||||
import SelectDataDoc from '@/doc/popover/SelectDataDoc.vue';
|
||||
import ThemingDoc from '@/doc/popover/theming/index.vue';
|
||||
|
||||
export default {
|
||||
|
@ -32,6 +33,11 @@ export default {
|
|||
label: 'Basic',
|
||||
component: BasicDoc
|
||||
},
|
||||
{
|
||||
id: 'selectdata',
|
||||
label: 'Select Data',
|
||||
component: SelectDataDoc
|
||||
},
|
||||
{
|
||||
id: 'datatable',
|
||||
label: 'DataTable',
|
||||
|
|
|
@ -67,15 +67,24 @@
|
|||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">New Components</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Layout, Typography, Tab orientations, Navigation Drawer.</p>
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Form Library</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Built-in form library with validations.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-blue-500 rounded" style="width: 25%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Components</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">New Carousel, Tab Orientations, Updated Menu, Navigation Drawer...</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Form Library</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Built-in form library with validations.</p>
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Headless Mode</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Headless component kit with Tailwind CSS.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
</div>
|
||||
|
@ -94,11 +103,9 @@
|
|||
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-blue-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Advanced Suite ... 2025</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Gantt Chart, Flow Chart, Sheet, Calendar, Timeline, Editor.</p>
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">PrimeVue+ Suite | 2025</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Gantt Chart, Flow Chart, Sheet, PDF Viewer, Calendar, Timeline, Editor.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-blue-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
</div>
|
||||
|
@ -113,7 +120,7 @@
|
|||
<h2 class="text-lg font-bold mt-0 mb-2">New Figma Tokens - Phase 1</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Update tokens to sync with the new styled mode.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-indigo-500 rounded" style="width: 50%; height: 4px"></div>
|
||||
<div class="bg-indigo-500 rounded" style="width: 100%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -122,9 +129,11 @@
|
|||
<h2 class="text-lg font-bold mt-0 mb-2">New Figma Tokens - Phase 2</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Update tokens to sync with the new styled mode.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-indigo-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
<div class="bg-indigo-500 rounded" style="width: 50%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-indigo-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Figma to Theme API</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Build a Figma plugin to generate themes from UI Kit.</p>
|
||||
|
@ -133,7 +142,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
</div>
|
||||
<div class="flex gap-4 border-b border-surface-200 dark:border-surface-700 pb-4">
|
||||
<div class="shrink-0 p-4 bg-teal-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">SHOWCASE</div>
|
||||
|
@ -144,7 +152,7 @@
|
|||
<h2 class="text-lg font-bold mt-0 mb-2">Documentation</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Interactive component viewer to explore tokens and pt sections.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
<div class="bg-teal-500 rounded" style="width: 25%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -159,37 +167,37 @@
|
|||
<h2 class="text-lg font-bold mt-0 mb-2">V4 Update</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Update all templates to PrimeVue v4, replace PrimeFlex demos with Tailwind.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
<div class="bg-violet-500 rounded" style="width: 100%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-violet-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Genesis</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Brand new template application.</p>
|
||||
<p class="mt-0 mb-4 leading-normal">Brand new multi-purpose template.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-teal-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
</div>
|
||||
<div class="flex gap-4 border-b border-surface-200 dark:border-surface-700 pb-4">
|
||||
<div class="shrink-0 p-4 bg-orange-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">PrimeBlocks</div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-orange-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Tailwind Blocks</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Migrate Blocks to Tailwind CSS.</p>
|
||||
<p class="mt-0 mb-4 leading-normal">Migrate Blocks to v4 and Tailwind CSS.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-orange-500 rounded" style="width: 50%; height: 4px"></div>
|
||||
<div class="bg-orange-500 rounded" style="width: 90%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-orange-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">Online App</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Implement a SaaS app to access the blocks instead of an offline download.</p>
|
||||
<p class="mt-0 mb-4 leading-normal">Implement an app to access the blocks instead of an offline download.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-orange-500 rounded" style="width: 0%; height: 4px"></div>
|
||||
<div class="bg-orange-500 rounded" style="width: 90%; height: 4px"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -199,7 +207,7 @@
|
|||
<div class="shrink-0 p-4 bg-pink-500 text-white rounded font-bold text-lg flex items-center justify-center w-56">Design</div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-pink-500 border-l-8">
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">New UI Theme</h2>
|
||||
<h2 class="text-lg font-bold mt-0 mb-2">New Aura Theme</h2>
|
||||
<p class="mt-0 mb-4 leading-normal">Brand new default theme with a modern and attractive design.</p>
|
||||
<div class="bg-surface-200 rounded">
|
||||
<div class="bg-pink-500 rounded" style="width: 100%; height: 4px"></div>
|
||||
|
@ -207,6 +215,7 @@
|
|||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="flex-1 flex gap-4 flex-col">
|
||||
<div class="p-4 bg-surface-0 dark:bg-surface-900 rounded border-pink-500 border-l-8">
|
||||
|
@ -218,7 +227,6 @@
|
|||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="flex-1 flex gap-4 flex-col"></div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
|
Loading…
Reference in New Issue