Change PrimeVue ChatApp ShowCase from Options API to Composition API.
Last active
May 1, 2025 06:18
-
-
Save wcheek/254757146372e33bc0b53cc83d0184ab to your computer and use it in GitHub Desktop.
PrimeVue ChatApp ShowCase Options API to Composition API Conversion
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div | |
class="flex-1 h-full overflow-y-auto overflow-x-clip overflow-hidden flex border border-surface rounded-2xl" | |
> | |
<div class="w-4/12 xl:w-3/12 min-w-40 overflow-auto flex flex-col gap-6"> | |
<div | |
class="flex flex-col gap-6 pt-3 pb-2 -mb-2 px-5 sticky top-0 bg-surface-0 dark:bg-surface-950 z-10" | |
> | |
<div class="flex items-center justify-between gap-6 text-color"> | |
<div class="text-2xl font-medium lead">Chats</div> | |
<Button icon="pi pi-plus" text /> | |
</div> | |
</div> | |
<div class="px-5"> | |
<IconField iconPosition="left"> | |
<InputIcon class="pi pi-search"> </InputIcon> | |
<InputText v-model="search" placeholder="Search" class="w-full" /> | |
</IconField> | |
</div> | |
<div class="w-full px-5"> | |
<SelectButton | |
v-model="value" | |
:options="options" | |
aria-labelledby="basic" | |
:pt="{ | |
root: { | |
class: 'w-full', | |
}, | |
pcbutton: { | |
root: { | |
class: 'flex-1', | |
}, | |
}, | |
}" | |
/> | |
</div> | |
<div class="flex-1 flex flex-col"> | |
<div | |
v-for="chat in chats" | |
:key="chat.name" | |
class="flex items-center gap-2 p-4 cursor-pointer hover:bg-emphasis transition-all" | |
:class="{ | |
'bg-emphasis': chat.name === activeChat, | |
}" | |
> | |
<div class="relative"> | |
<div | |
v-if="chat.active !== undefined" | |
class="absolute top-0 right-0 p-[1px] bg-surface-0 dark:bg-surface-950 rounded-full flex items-center justify-center" | |
> | |
<Badge | |
:severity="chat.active ? 'success' : 'danger'" | |
class="p-1.5" | |
></Badge> | |
</div> | |
<Avatar | |
v-bind=" | |
chat.image ? { image: chat.image } : { label: chat.capName } | |
" | |
:class="{ | |
'!bg-primary-100 !text-primary-950': !chat.image, | |
}" | |
class="text-base font-medium flex" | |
size="large" | |
shape="circle" | |
/> | |
</div> | |
<div class="flex-1"> | |
<div class="flex items-start gap-1 justify-between"> | |
<div class="text-color font-medium leading-6"> | |
{{ chat.name }} | |
</div> | |
<div class="text-sm text-muted-color leading-5"> | |
{{ chat.time }} | |
</div> | |
</div> | |
<div class="flex items-center gap-5 justify-between mt-1"> | |
<div class="text-muted-color text-sm leading-5 line-clamp-1"> | |
{{ chat.lastMessage }} | |
</div> | |
<Badge | |
v-if="chat.unreadMessageCount > 0" | |
:value="chat.unreadMessageCount" | |
severity="contrast" | |
></Badge> | |
</div> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div class="w-8/12 xl:w-6/12 border-x border-surface flex flex-col"> | |
<div class="flex items-center p-4 gap-7 border-b border-surface"> | |
<div class="flex items-center"> | |
<Avatar | |
image="https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png" | |
class="mr-2 av" | |
size="large" | |
shape="circle" | |
/> | |
<div class="flex-1"> | |
<div | |
class="text-color leading-6 cursor-pointer hover:text-muted-color-emphasis transition-colors" | |
> | |
PrimeTek | |
</div> | |
<div class="text-muted-color leading-5 line-clamp-1 mt-1"> | |
Cody Fisher, Esther Howard, Jerome Bell, Kristin Watson, Ronald | |
Richards, Darrell Steward | |
</div> | |
</div> | |
</div> | |
<div class="flex items-center gap-2"> | |
<Button icon="pi pi-phone" text /> | |
<Button icon="pi pi-search" text /> | |
<Button | |
type="button" | |
icon="pi pi-ellipsis-h" | |
text | |
@click="toggle" | |
aria-haspopup="true" | |
aria-controls="overlay_menu" | |
/> | |
<Menu ref="menu" id="overlay_menu" :model="menuItems" :popup="true" /> | |
</div> | |
</div> | |
<div class="flex-1 overflow-y-auto flex flex-col gap-8 py-8 px-6"> | |
<div | |
v-for="message in chatMessages" | |
:key="message.id" | |
class="flex items-start min-w-64 w-fit max-w-[60%]" | |
:class="{ 'ml-auto mr-0 flex-row-reverse': message.type === 'sent' }" | |
> | |
<div | |
class="flex items-center gap-2 sticky top-0 transition-all" | |
:class="{ | |
'flex-row-reverse': message.type === 'sent', | |
}" | |
> | |
<Avatar | |
v-bind=" | |
message.image | |
? { image: message.image } | |
: { label: message.capName } | |
" | |
:class="{ | |
'bg-primary-100 text-primary-950': !message.image, | |
}" | |
class="w-10 h-10 text-sm font-medium" | |
shape="circle" | |
/> | |
<div> | |
<svg | |
:class=" | |
message.type === 'received' | |
? 'fill-surface-100 dark:fill-surface-800' | |
: 'fill-primary rotate-180' | |
" | |
class="" | |
xmlns="http://www.w3.org/2000/svg" | |
width="7" | |
height="11" | |
viewBox="0 0 7 11" | |
fill="none" | |
> | |
<path | |
d="M1.79256 7.09551C0.516424 6.31565 0.516426 4.46224 1.79256 3.68238L7 0.500055L7 10.2778L1.79256 7.09551Z" | |
/> | |
</svg> | |
</div> | |
</div> | |
<div | |
:class=" | |
message.type === 'received' | |
? 'flex-1 bg-surface-100 dark:bg-surface-800 px-2 py-1 rounded-lg' | |
: 'flex-1 bg-primary px-2 py-1 rounded-lg' | |
" | |
> | |
<p | |
:class=" | |
message.type === 'received' | |
? 'text-color leading-6 mb-0' | |
: 'text-primary-contrast leading-6 mb-0' | |
" | |
> | |
{{ message.message }} | |
</p> | |
<div | |
v-if="message.attachment" | |
:class=" | |
message.type === 'received' | |
? 'bg-surface-200 dark:bg-surface-700' | |
: 'bg-primary-emphasis' | |
" | |
class="mt-2 w-full rounded-lg mb-0.5 hover:opacity-75 transition-all" | |
> | |
<img | |
class="w-full h-auto block cursor-pointer" | |
:src="message.attachment" | |
alt="Message Image" | |
/> | |
</div> | |
</div> | |
</div> | |
</div> | |
<div | |
class="p-4 border-t border-surface flex items-end justify-between gap-2" | |
> | |
<div class="flex items-end gap-1 flex-1"> | |
<Button icon="pi pi-face-smile" text /> | |
<Button icon="pi pi-paperclip" text /> | |
<Textarea | |
class="ml-1 flex-1 border-0 shadow-none max-h-32 min-h-9 bg-emphasis overflow-auto" | |
autoResize | |
rows="1" | |
placeholder="Write your message..." | |
/> | |
</div> | |
<Button icon="pi pi-send" /> | |
</div> | |
</div> | |
<div class="w-3/12 xl:block hidden min-w-40 py-6 px-3 overflow-auto"> | |
<div class="flex flex-col items-center justify-center"> | |
<Avatar | |
image="https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png" | |
class="w-32 h-32" | |
size="xlarge" | |
shape="circle" | |
/> | |
<div class="leading-6 font-medium text-color mt-4 w-full text-center"> | |
PrimeTek | |
</div> | |
<div class="leading-5 text-sm text-muted-color mt-1 w-full text-center"> | |
@primetek | |
</div> | |
<div class="flex items-center justify-center flex-wrap gap-1 mt-4"> | |
<Button | |
icon="pi pi-phone text-muted-color" | |
severity="secondary" | |
text | |
/> | |
<Button | |
icon="pi pi-video text-muted-color" | |
severity="secondary" | |
text | |
/> | |
<Button | |
icon="pi pi-sign-in text-muted-color" | |
severity="secondary" | |
text | |
/> | |
<Button | |
icon="pi pi-info-circle text-muted-color" | |
severity="secondary" | |
text | |
/> | |
<Button | |
type="button" | |
icon="pi pi-ellipsis-v text-muted-color" | |
severity="secondary" | |
text | |
@click="toggle" | |
aria-haspopup="true" | |
aria-controls="overlay_menu" | |
/> | |
<Menu ref="menu" id="overlay_menu" :model="menuItems" :popup="true" /> | |
</div> | |
</div> | |
<div class="flex flex-col gap-4 mt-4"> | |
<div class="flex items-center gap-2"> | |
<i class="pi pi-bell text-color"></i> | |
<div class="leading-6 font-medium text-color flex-1"> | |
Notification | |
</div> | |
<ToggleSwitch v-model="notification" /> | |
</div> | |
<div class="flex items-center gap-2"> | |
<i class="pi pi-volume-down text-color"></i> | |
<div class="leading-6 font-medium text-color flex-1">Sound</div> | |
<ToggleSwitch v-model="sound" /> | |
</div> | |
<div class="flex items-center gap-2"> | |
<i class="pi pi-download text-color"></i> | |
<div class="leading-6 font-medium text-color flex-1"> | |
Save to downloads | |
</div> | |
<ToggleSwitch v-model="download" /> | |
</div> | |
</div> | |
<div class="mt-6"> | |
<div class="flex items-center gap-2"> | |
<div class="flex-1 text-color leading-6 font-medium">Members</div> | |
<Button | |
label="See All" | |
class="text-sm py-0.5 px-2 text-muted-color" | |
text | |
/> | |
</div> | |
<div class="mt-4 flex flex-col gap-4"> | |
<div | |
v-for="member in members" | |
:key="member.name" | |
class="flex items-center gap-2 cursor-pointer" | |
> | |
<Avatar | |
v-bind=" | |
member.image | |
? { image: member.image } | |
: { label: member.capName } | |
" | |
:class="{ | |
'bg-orange-100 text-orange-950': !member.image, | |
}" | |
class="font-medium text-xs" | |
shape="circle" | |
/> | |
<div | |
class="text-sm text-color hover:text-muted-color-emphasis transition-colors font-medium leading-5 flex-1" | |
> | |
{{ member.name }} | |
</div> | |
<i class="pi pi-chevron-right text-xs text-muted-color"></i> | |
</div> | |
</div> | |
</div> | |
<div class="mt-5"> | |
<SelectButton | |
v-model="media" | |
:options="mediaOptions" | |
:pt="{ | |
root: { | |
class: 'w-full', | |
}, | |
pcbutton: { | |
root: { | |
class: 'flex-1', | |
}, | |
}, | |
}" | |
/> | |
<div class="mt-3 mb-5 grid grid-cols-3 gap-2"> | |
<div | |
v-for="(media, index) in chatMedia" | |
:key="index" | |
class="bg-emphasis hover:opacity-70 transition-all flex-1 aspect-square rounded-lg border border-surface cursor-pointer" | |
> | |
<img | |
class="w-full h-full object-cover block" | |
:src="media" | |
alt="Media Image" | |
/> | |
</div> | |
<div | |
class="bg-emphasis hover:opacity-70 transition-all flex-1 aspect-square rounded-lg border border-surface cursor-pointer flex items-center justify-center" | |
> | |
<span class="text-muted-color font-medium">99+</span> | |
</div> | |
</div> | |
<Button | |
label="Show more" | |
icon="pi pi-arrow-right" | |
iconPos="right" | |
outlined | |
class="w-full text-left" | |
:pt="{ | |
root: { | |
class: 'justify-between', | |
}, | |
}" | |
/> | |
</div> | |
</div> | |
</div> | |
</template> | |
<script setup lang="ts"> | |
const search = ref(""); | |
const download = ref(false); | |
const notification = ref(true); | |
const sound = ref(false); | |
const value = ref("Chat"); | |
const value2 = ref(""); | |
const options = ref(["Chat", "Call"]); | |
const media = ref("Media"); | |
const mediaOptions = ref(["Media", "Link", "Docs"]); | |
const activeChat = ref("PrimeTek Team"); | |
const menuItems = ref([ | |
{ | |
label: "Group Info", | |
icon: "pi pi-info-circle", | |
}, | |
{ | |
label: "Leave group", | |
icon: "pi pi-sign-out", | |
}, | |
]); | |
const chats = ref([ | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg", | |
name: "Cody Fisher", | |
capName: "CF", | |
active: true, | |
unreadMessageCount: 8, | |
time: "12.30", | |
lastMessage: | |
"Hey there! I've heard about PrimeVue. Any cool tips for getting started?", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar-primetek.png", | |
name: "PrimeTek Team", | |
capName: "PT", | |
active: undefined, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: "Let's implement PrimeVue. Elevating our UI game! 🚀", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png", | |
name: "Jerome Bell", | |
capName: "JB", | |
active: true, | |
unreadMessageCount: 4, | |
time: "11.15", | |
lastMessage: | |
"Absolutely! PrimeVue's documentation is gold—simplifies our UI work.", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar12.jpg", | |
name: "Robert Fox", | |
capName: "RF", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"Interesting! PrimeVue sounds amazing. What's your favorite feature?", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar13.jpg", | |
name: "Esther Howard", | |
capName: "EH", | |
active: true, | |
unreadMessageCount: 9, | |
time: "11.15", | |
lastMessage: | |
"Quick one, team! Anyone using PrimeVue for mobile app development?", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar9.jpg", | |
name: "Darlene Robertson", | |
capName: "DR", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"Just explored PrimeVue's themes. Can we talk about those stunning designs? 😍", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png", | |
name: "Ralph Edwards", | |
capName: "RE", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"PrimeVue is a game-changer, right? What are your thoughts, folks?", | |
}, | |
{ | |
image: "", | |
name: "Ronald Richards", | |
capName: "RR", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"Jumping in! PrimeVue's community forum is buzzing. Any engaging discussions?", | |
}, | |
{ | |
image: "", | |
name: "Kristin Watson", | |
capName: "KW", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"Sharing a quick win-PrimeVue tutorials are leveling up my UI skills. 👩💻", | |
}, | |
{ | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar7.png", | |
name: "Darrell Steward", | |
capName: "DS", | |
active: false, | |
unreadMessageCount: 0, | |
time: "11.15", | |
lastMessage: | |
"Reflecting on PrimeVue's impact on our workflow. What's your take?", | |
}, | |
]); | |
const chatMessages = ref([ | |
{ | |
id: 1, | |
attachment: "", | |
name: "", | |
image: "", | |
capName: "OS", | |
type: "received", | |
message: "Awesome! What's the standout feature?", | |
}, | |
{ | |
id: 2, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png", | |
capName: "A", | |
type: "received", | |
message: "PrimeVue rocks! Simplifies UI dev with versatile components.", | |
}, | |
{ | |
id: 3, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg", | |
capName: "A", | |
type: "received", | |
message: "Intriguing! Tell us more about its impact.", | |
}, | |
{ | |
id: 4, | |
attachment: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/message-image.png", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png", | |
capName: "A", | |
type: "received", | |
message: | |
"It's design-neutral and compatible with Tailwind. Features accessible, high-grade components!", | |
}, | |
{ | |
id: 5, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png", | |
capName: "A", | |
type: "sent", | |
message: "Customizable themes, responsive design – UI excellence!", | |
}, | |
{ | |
id: 6, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png", | |
capName: "A", | |
type: "received", | |
message: "Love it! Fast-tracking our development is key.", | |
}, | |
{ | |
id: 7, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png", | |
capName: "A", | |
type: "received", | |
message: "Documentation rocks too – smooth integration for all.", | |
}, | |
{ | |
id: 8, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png", | |
capName: "B", | |
type: "sent", | |
message: | |
"The flexibility and ease of use are truly impressive. Have you explored the new components?", | |
}, | |
{ | |
id: 9, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar12.jpg", | |
capName: "C", | |
type: "received", | |
message: | |
"Absolutely, the new calendar component has saved us a ton of development time!", | |
}, | |
{ | |
id: 10, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar13.jpg", | |
capName: "D", | |
type: "received", | |
message: | |
"And the accessibility features are top-notch. It's great to see a library focusing on inclusivity.", | |
}, | |
{ | |
id: 11, | |
attachment: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/message-image.png", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png", | |
capName: "E", | |
type: "sent", | |
message: | |
"I couldn't agree more. Plus, the documentation is incredibly thorough, which makes onboarding new team members a breeze.", | |
}, | |
{ | |
id: 12, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar6.png", | |
capName: "F", | |
type: "received", | |
message: | |
"Do you have any tips for optimizing performance when using multiple complex components?", | |
}, | |
{ | |
id: 13, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg", | |
capName: "G", | |
type: "received", | |
message: | |
"Yes! Lazy loading and code splitting can make a huge difference, especially in larger applications.", | |
}, | |
{ | |
id: 14, | |
attachment: "", | |
name: "", | |
image: "", | |
capName: "HS", | |
type: "received", | |
message: | |
"I've also found that leveraging the component's internal state management capabilities can help streamline data flow and improve performance.", | |
}, | |
{ | |
id: 15, | |
attachment: "", | |
name: "", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png", | |
capName: "H", | |
type: "sent", | |
message: | |
"That's great advice. It's amazing how much detail and thought has gone into making PrimeVue such a powerful tool for developers.", | |
}, | |
]); | |
const chatMedia = ref([ | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image1.png", | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image2.png", | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image3.png", | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image4.png", | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/chat-image5.png", | |
]); | |
const members = ref([ | |
{ | |
name: "Robin Jonas", | |
capName: "RJ", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar2.png", | |
}, | |
{ | |
name: "Cameron Williamson", | |
capName: "CW", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar11.jpg", | |
}, | |
{ | |
name: "Eleanor Pena", | |
capName: "EP", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar5.png", | |
}, | |
{ | |
name: "Arlene McCoy", | |
capName: "AM", | |
image: | |
"https://www.primefaces.org/cdn/primevue/images/landing/apps/avatar8.png", | |
}, | |
{ name: "Dianne Russell", capName: "DR", image: "" }, | |
]); | |
const menu = ref(); | |
function toggle(event: any) { | |
menu.value.toggle(event); | |
} | |
</script> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment