Inplace provides an easy to do editing and display at the same time where clicking the output displays the actual content.
npx volt-vue add Inplace
import Dialog from '@/volt/Inplace.vue';
Inplace component requires display and content templates to define the content of each state.
<template>
<div class="card">
<Inplace>
<template #display> View Content </template>
<template #content>
<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. 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>
</Inplace>
</div>
</template>
<script setup lang="ts">
import Inplace from '@/volt/Inplace.vue';
</script>
The closeCallback switches the state back to display mode when called from an event.
<template>
<div class="card">
<Inplace>
<template #display>
{{ text || 'Click to Edit' }}
</template>
<template #content="{ closeCallback }">
<span class="inline-flex items-center gap-2">
<InputText v-model="text" autofocus />
<DangerButton icon="pi pi-times" text severity="danger" @click="closeCallback" />
</span>
</template>
</Inplace>
</div>
</template>
<script setup lang="ts">
import Inplace from '@/volt/Inplace.vue';
import InputText from '@/volt/InputText.vue';
import DangerButton from '@/volt/DangerButton.vue';
import { ref } from 'vue';
const text = ref(null);
</script>
Any content such as an image can be placed inside an Inplace.
<template>
<div class="card">
<Inplace>
<template #display>
<span class="inline-flex items-center gap-2">
<span class="pi pi-image"></span>
<span>View Photo</span>
</span>
</template>
<template #content>
<img class="w-full sm:w-80 shadow-2xl" alt="Nature" src="https://primefaces.org/cdn/primevue/images/nature/nature8.jpg" />
</template>
</Inplace>
</div>
</template>
<script setup lang="ts">
import Inplace from '@/volt/Inplace.vue';
</script>
The open event is used to initialize the content such as loading data in a lazy manner.
<template>
<div class="card">
<Inplace @open="loadData">
<template #display> View Data </template>
<template #content>
<DataView :value="products">
<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="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" />
<div class="absolute bg-black/70 rounded-border" style="left: 4px; top: 4px">
<Tag :value="item.inventoryStatus" :severity="getSeverity(item)"></Tag>
</div>
</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>
</DataView>
</template>
</Inplace>
</div>
</template>
<script setup lang="ts">
import { ProductService } from '@/service/ProductService';
import Button from '@/volt/Button.vue';
import DataView from '@/volt/DataView.vue';
import Tag from '@/volt/Tag.vue';
import Inplace from '@/volt/Inplace.vue';
import { ref } from 'vue';
const products = ref(null);
const loadData = () => {
ProductService.getProductsMini().then((data) => (products.value = data));
}
const getSeverity = (product) => {
switch (product.inventoryStatus) {
case 'INSTOCK':
return 'success';
case 'LOWSTOCK':
return 'warn';
case 'OUTOFSTOCK':
return 'danger';
default:
return null;
}
};
</script>