Modal
A modal is a secondary window that communicates or provides an action inside the same process. They’re incredibly useful for communicating additional information, collecting information, or directing users without forcing them to leave the page. When modals are used unnecessarily, they can become intrusive and annoying for the user. Nobody likes pop-ups.
Modal Stacked Left Aligned
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup> import { CheckCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-6 h-6 text-success-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Modal Stacked Left Aligned Horizontal
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup> import { CheckCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[544px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-0" > <template #header> <div class="flex gap-x-4"> <div> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-6 h-6 text-success-600" /> </div> </div> <div class="hidden md:flex md:flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-left">Blog post published</p> <p class="text-sm font-normal text-gray-600 text-left">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> </div> </template> <div class="flex flex-col gap-1 md:hidden"> <p class="text-lg font-semibold text-gray-900 text-left">Blog post published</p> <p class="text-sm font-normal text-gray-600 text-left">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <template #footer> <div class="flex flex-1 md:gap-4 md:flex-row"> <div class="w-12 h-12 hidden md:block" /> <div class="flex flex-1 gap-3 md:items-center flex-col-reverse md:flex-row"> <VCheckbox label="Don’t show again" labelClass="!font-medium !text-gray-700" /> <div class="flex flex-1 w-full gap-3 justify-end flex-col-reverse md:flex-row"> <VBtn>Cancel</VBtn> <VBtn color="primary">Confirm</VBtn> </div> </div> </div> </template> </VModal></template>
Warning Stacked Left Aligned
Unsaved changes
Do you want to save or discard changes?
<script setup> import { Save01Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-warning-100 border-8 border-warning-50 rounded-2xl"> <Save01Icon class="w-6 h-6 text-warning-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Unsaved changes</p> <p class="text-sm font-normal text-gray-600">Do you want to save or discard changes?</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Warning Stacked Left Aligned Horizontal
Unsaved changes
Do you want to save or discard changes?
Unsaved changes
Do you want to save or discard changes?
<script setup> import { Save01Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[544px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-0" > <template #header> <div class="flex gap-x-4"> <div> <div class="flex justify-center items-center w-12 h-12 bg-warning-100 border-8 border-warning-50 rounded-2xl"> <Save01Icon class="w-6 h-6 text-warning-600" /> </div> </div> <div class="hidden md:flex md:flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-left">Unsaved changes</p> <p class="text-sm font-normal text-gray-600 text-left">Do you want to save or discard changes?</p> </div> </div> </template> <div class="flex flex-col gap-1 md:hidden"> <p class="text-lg font-semibold text-gray-900 text-left">Unsaved changes</p> <p class="text-sm font-normal text-gray-600 text-left">Do you want to save or discard changes?</p> </div> <template #footer> <div class="flex flex-1 md:gap-4 md:flex-row"> <div class="w-12 h-12 hidden md:block" /> <div class="flex flex-1 gap-3 md:items-center flex-col-reverse md:flex-row"> <VCheckbox label="Don’t show again" labelClass="!font-medium !text-gray-700" /> <div class="flex flex-1 w-full gap-3 justify-end flex-col-reverse md:flex-row"> <VBtn>Cancel</VBtn> <VBtn color="primary">Confirm</VBtn> </div> </div> </div> </template> </VModal></template>
Destructive Stacked Left Aligned
Delete blog post
Are you sure you want to delete this post? This action cannot be undone.
<script setup> import { Trash01Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-error-100 border-8 border-error-50 rounded-2xl"> <Trash01Icon class="w-6 h-6 text-error-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Delete blog post</p> <p class="text-sm font-normal text-gray-600">Are you sure you want to delete this post? This action cannot be undone.</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="error" block>Delete</VBtn> </div> </template> </VModal></template>
Destructive Stacked Left Aligned Horizontal
Delete blog post
Are you sure you want to delete this post? This action cannot be undone.
Delete blog post
Are you sure you want to delete this post? This action cannot be undone.
<script setup> import { Trash01Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[544px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-0" > <template #header> <div class="flex gap-x-4"> <div> <div class="flex justify-center items-center w-12 h-12 bg-error-100 border-8 border-error-50 rounded-2xl"> <Trash01Icon class="w-6 h-6 text-error-600" /> </div> </div> <div class="hidden md:flex md:flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-left">Delete blog post</p> <p class="text-sm font-normal text-gray-600 text-left">Are you sure you want to delete this post? This action cannot be undone.</p> </div> </div> </template> <div class="flex flex-col gap-1 md:hidden"> <p class="text-lg font-semibold text-gray-900 text-left">Delete blog post</p> <p class="text-sm font-normal text-gray-600 text-left">Are you sure you want to delete this post? This action cannot be undone.</p> </div> <template #footer> <div class="flex flex-1 md:gap-4 md:flex-row"> <div class="w-12 h-12 hidden md:block" /> <div class="flex flex-1 gap-3 md:items-center flex-col-reverse md:flex-row"> <VCheckbox label="Don’t show again" labelClass="!font-medium !text-gray-700" /> <div class="flex flex-1 w-full gap-3 justify-end flex-col-reverse md:flex-row"> <VBtn>Cancel</VBtn> <VBtn color="error">Delete</VBtn> </div> </div> </div> </template> </VModal></template>
Checkboxes
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup> import { CheckCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-6 h-6 text-success-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div class="flex flex-col gap-y-3 mt-5"> <VCheckbox label="Share on Twitter" labelClass="!font-medium !text-gray-700 !mt-0" /> <VCheckbox label="Share on Medium" labelClass="!font-medium !text-gray-700 !mt-0" /> <VCheckbox label="Share on Facebook" labelClass="!font-medium !text-gray-700 !mt-0" /> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Toggles
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
Share on Twitter
@yourcompany
Share on Medium
yourcompany.medium.com
Share on Facebook
@yourcompany
<script setup> import { CheckCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-6 h-6 text-success-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div class="flex flex-col gap-y-3 mt-5"> <div v-for="item in [{ text: 'Share on Twitter', hint: '@yourcompany', }, { text: 'Share on Medium', hint: 'yourcompany.medium.com', }, { text: 'Share on Facebook', hint: '@yourcompany', }]" class="flex gap-x-2" > <VSwitch class="!w-fit" /> <div> <p class="text-sm font-medium text-gray-700">{{ item.text }}</p> <p class="text-sm font-normal text-gray-600">{{ item.hint }}</p> </div> </div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Dropdown
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup> import { CheckCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-6 h-6 text-success-600" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div class="flex flex-col mt-5"> <VSelect label="Team member" placeholder="Select" :items="[{ text: 'Olivia Rhye', value: 'Olivia Rhye', }]" shadow hideCheckIcon btnClass="!border !border-gray-300 !px-4 !py-3 !rounded-lg mt-2 !text-sm !font-medium" :style="{ '--v-select-border-color': '#D0D5DD', }" /> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal> </template>
Input Field
Project created
Please enter a name for this project.
<script setup> import { Flag05Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <Flag05Icon class="w-6 h-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div class="flex flex-col mt-5"> <VInput label="Project name" placeholder="e.g. Website design" /> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Access Request
Candice has requested edit access
One of your team has requested edit access to your project Website Design.
Candice Wu
candice@morphemelabs.com
<script setup> import { UserPlus01Icon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <UserPlus01Icon class="w-6 h-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div class="flex items-center gap-x-3 mt-5"> <VAvatar src="/avatar-2.png" :size="40" /> <div> <p class="text-sm font-semibold text-gray-700">Candice Wu</p> <p class="text-sm font-normal text-gray-600">candice@morphemelabs.com</p> </div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Email Invite
Candice has requested edit access
One of your team has requested edit access to your project Website Design.
<script setup> import { useForm, useFieldArray } from 'vee-validate'; import { UserPlus01Icon } from '@morphemeicons/vue/untitled'; const { handleSubmit } = useForm({ initialValues: { email: [''], }, }); const { push, fields } = useFieldArray('email');</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <UserPlus01Icon class="w-6 h-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Invite collaborators</p> <p class="text-sm font-normal text-gray-600">Your new project has been created. Invite colleagues to collaborate on this project.</p> </div> <form @submit="handleSubmit" class="space-y-3 mt-5"> <div v-for="(field, idx) in fields" :key="field.key" class="flex flex-col"> <VInput :label="idx == 0 ? 'Email Address' : ''" placeholder="you@morphemelabs.com" :name="`email[${idx}]`" type="url" wrapper-class="flex-1" /> </div> <VBtn type="button" color="primary" prefixIcon="ri:add-line" text flush @click="push('')">Add another</VBtn> </form> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Send invites</VBtn> </div> </template> </VModal></template>
Stacked With Team
You’ve been added to the team!
Thanks for accepting the invite. You’ve now been added to the team as an editor.
<template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 md:!p-6 !mt-6 md:!mt-8 border-t border-t-gray-200" bodyClass="!px-4 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full justify-center"> <VAvatarGroup spacing="xs" class="flex justify-center"> <VAvatar src="/avatar-1.png" size="48" class="mt-2 -mr-4" /> <VAvatar src="/avatar-2.png" size="56" class="z-[1]" /> <VAvatar src="/avatar-1.png" size="48" class="mt-2 -ml-4" /> </VAvatarGroup> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">You’ve been added to the team!</p> <p class="text-sm font-normal text-gray-600 text-center">Thanks for accepting the invite. You’ve now been added to the team as an editor.</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Get started</VBtn> </div> </template> </VModal></template>
Stacked With Team And Link
Invite your team
You’ve created a new project! Invite colleagues to collaborate on this project.
<script setup> import { Copy01Icon } from '@morphemeicons/vue/untitled'; const link = 'join.morphemelabs.com/project' const copyInput = () => { navigator.clipboard.writeText(link) }</script><template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 md:!p-6 !mt-6 md:!mt-8 border-t border-t-gray-200" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full justify-center"> <VAvatarGroup spacing="xs" class="flex justify-center"> <VAvatar src="/avatar-3.png" size="48" class="mt-2 -mr-4" /> <VAvatar src="/avatar-1.png" size="56" class="z-[1]" /> <VAvatar src="/avatar-4.png" size="48" class="mt-2 -ml-4" /> </VAvatarGroup> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Invite your team</p> <p class="text-sm font-normal text-gray-600 text-center">You’ve created a new project! Invite colleagues to collaborate on this project.</p> </div> <div class="flex items-end space-x-1"> <VInput :modelValue="link" label="Share link" readOnly wrapperClass="w-full" /> <VBtn icon text noRing @click="copyInput" > <Copy01Icon class="w-5 h-5 text-gray-500" /> </VBtn> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Continue</VBtn> </div> </template> </VModal></template>
Stacked With Team And invites
Invite your team
You’ve created a new project! Invite colleagues to collaborate on this project.
Candice Wu
candice
Admin
Demi Wilkinson
demi
Admin
Drew Cano
@drew
Editor
Natali Crag
@natali
Editor
<script setup>const team = [{ name: 'Candice Wu', nickName: 'candice', status: 'Admin', image: '/avatar-2.png'}, { name: 'Demi Wilkinson', nickName: 'demi', status: 'Admin', image: '/avatar-5.png'}, { name: 'Drew Cano', nickName: '@drew', status: 'Editor', image: '/avatar-6.png'}, { name: 'Natali Crag', nickName: '@natali', status: 'Editor', image: '/avatar-7.png'}]</script><template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 md:!p-6 !mt-6 md:!mt-8 border-t border-t-gray-200" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full justify-center"> <VAvatarGroup spacing="xs" class="flex justify-center"> <VAvatar src="/avatar-3.png" size="48" class="mt-2 -mr-4" /> <VAvatar src="/avatar-1.png" size="56" class="z-[1]" /> <VAvatar src="/avatar-4.png" size="48" class="mt-2 -ml-4" /> </VAvatarGroup> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Invite your team</p> <p class="text-sm font-normal text-gray-600 text-center">You’ve created a new project! Invite colleagues to collaborate on this project.</p> </div> <div class="space-y-3"> <div v-for="item in team" :key="item.nickname" class="flex items-center space-x-3"> <div class="flex flex-1 space-x-3 items-center"> <VCheckbox /> <VAvatar :src="item.image" :name="item.name" :maxInitial="1" size="xl" /> <div> <p class="text-sm font-semibold text-gray-700">{{ item.name }}</p> <p class="text-sm font-normal text-gray-600">{{ item.nickName }}</p> </div> </div> <div> <p class="text-xs font-medium text-gray-600">{{ item.status }}</p> </div> </div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Add to project</VBtn> </div> </template> </VModal></template>
Verification Code
Please check your email
We've sent a code to olivia@morphemelabs.com<script setup> import { Mail01Icon } from '@morphemeicons/vue/untitled'; const digits = reactive([]) const val = ref('') const count = ref(4) const otpCont = ref(null) if (val.value && val.value.length === count.value) { for (let i =0; i < count.value; i++) { digits[i] = val.value.charAt(i) } } else { for (let i =0; i < count.value; i++) { digits[i] = null; } } const handleKeyDown = (event, index) => { if (event.key !== "Tab" && event.key !== "ArrowRight" && event.key !== "ArrowLeft" ) { event.preventDefault(); } if (event.key === "Backspace") { digits[index] = null; if (index != 0) { (otpCont.value.children)[index-1].focus(); } return; } if ((new RegExp('^([0-9])$')).test(event.key)) { digits[index] = event.key; if (index != count.value - 1) { (otpCont.value.children)[index+1].focus(); } } }</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 md:!p-6 !mt-6 md:!mt-8 border-t border-t-gray-200" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full h-12"> <div class="absolute left-0 right-0 mx-auto flex justify-center items-center w-12 h-12 bg-primary-100 border-8 border-primary-50 rounded-2xl"> <Mail01Icon class="w-6 h-6 text-primary-600" /> </div> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Please check your email</p> <span class="text-sm font-normal text-gray-600 text-center"> We've sent a code to <span class="font-semibold">olivia@morphemelabs.com</span> </span> </div> <div class="flex flex-col space-y-4 mt-5"> <div ref="otpCont" class="grid grid-cols-4 gap-3"> <input type="number" v-for="(d, i) in digits" :key="i" v-model="digits[i]" :placeholder="i + 1" maxlength="1" @keydown="handleKeyDown($event, i)" class="!w-auto !h-16 md:!h-20 !text-display-lg !text-center text-primary-600 font-medium border-2 border-primary-600 rounded-lg" /> </div> <span class="text-sm font-normal text-gray-600"> Didn’t get a code? <VBtn text flush class="!text-gray-600 !font-normal !underline">Click to resend.</VBtn> </span> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Verify</VBtn> </div> </template> </VModal></template>
2 Factor Authentication Code
Set up two-factor authentication
To authorise transactions, please scan this QR code with your Google Authenticator App and enter the verification code below.
Verification code
-
<script setup> import { Lock01Icon } from '@morphemeicons/vue/untitled'; const digits = reactive([]) const val = ref('') const count = ref(6) const otpCont = ref(null) if (val.value && val.value.length === count.value) { for (let i =0; i < count.value; i++) { digits[i] = val.value.charAt(i) } } else { for (let i =0; i < count.value; i++) { digits[i] = null; } } const handleKeyDown = (event, index) => { if (event.key !== "Tab" ) { event.preventDefault(); } if (event.key === "Backspace") { digits[index] = null; if (index != 0) { (otpCont.value.children)[index-1].focus(); } return; } if ((new RegExp('^([0-9])$')).test(event.key)) { digits[index] = event.key; if (index != count.value - 1) { (otpCont.value.children)[index+1].focus(); } } }</script><template> <VModal modalClass="!w-full !max-w-[512px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 md:!p-6 !mt-6 md:!mt-8 border-t border-t-gray-200" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full h-12"> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg"> <Lock01Icon class="w-6 h-6 text-gray-700" /> </div> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Set up two-factor authentication</p> <p class="text-sm font-normal text-gray-600"> To authorise transactions, please scan this QR code with your Google Authenticator App and enter the verification code below. </p> </div> <div class="flex py-4 mt-5 bg-gray-50 justify-center"> <img src="/qr-code.png" alt="QR Code" class="w-24 h-24 md:w-32 md:h-32"> </div> <div class="flex flex-col mt-5"> <p class="text-sm font-semibold text-gray-700 mb-2">Verification code</p> <div ref="otpCont" class="relative flex justify-center space-x-2"> <input type="number" v-for="(d, i) in digits.slice(0, 3)" :key="i" v-model="digits[i]" :placeholder="i + 1" maxlength="1" @keydown="handleKeyDown($event, i)" class="!w-10 !h-14 md:!w-16 md:!h-16 !text-display-xs md:!text-display-lg !text-center text-primary-600 font-medium border border-gray-300 rounded-lg" :class="i == 2 && '!mr-3 md:!mr-5'" /> <input type="number" v-for="(d, i) in digits.slice(3, 6)" :key="i + 3" v-model="digits[i + 3]" :placeholder="i + 4" maxlength="1" @keydown="handleKeyDown($event, i + 3)" class="!w-10 !h-14 md:!w-16 md:!h-16 !text-display-xs md:!text-display-lg !text-center text-primary-600 font-medium border border-gray-300 rounded-lg" :class="i == 0 ? '!ml-3 md:!ml-5' : ''" /> <span class="absolute h-16 w-7 flex justify-center items-center !m-0"> <p class="!text-display-xs md:!text-display-xl font-medium text-gray-300 leading-none">-</p> </span> </div> <span class="text-sm font-normal text-gray-600 mt-4"> Didn’t get a code? <VBtn text flush class="!text-gray-600 !font-normal !underline">Click to resend.</VBtn> </span> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template><style>/* Chrome, Safari, Edge, Opera */input::-webkit-outer-spin-button,input::-webkit-inner-spin-button { -webkit-appearance: none; margin: 0;}/* Firefox */input[type=number] { -moz-appearance: textfield;}</style>
Centered Photo
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup> import { Copy01Icon } from '@morphemeicons/vue/untitled'; const link = 'join.morphemelabs.com/project' const copyInput = () => { navigator.clipboard.writeText(link) }</script><template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-5 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full justify-center"> <img src="/modal-centered-photo.png" alt="Dummy image"> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Blog post published</p> <p class="text-sm font-normal text-gray-600 text-center">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block @click="copyInput" > <Copy01Icon class="w-5 h-5" /> Copy link </VBtn> <VBtn color="primary" block>Finish</VBtn> </div> </template> </VModal></template>
Centered Carousel
Welcome to your dashboard
We’re glad to have you onboard. Here are some quick tips to get you up and running.
<script setup lang="ts">const images = [ { src: '/centered-carousel.png', alt: 'image 1' }, { src: '/centered-carousel.png', alt: 'image 1' }, { src: '/centered-carousel.png', alt: 'image 1' },]const index = ref(0)const onNext = () => { index.value = (index.value + 1) % images.length;}</script><template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="relative overflow-hidden"> <div class="flex transition transform ease delay-50" :style="{ transform: `translateX(${-index * 100}%)` }"> <div v-for="(image, i) in images" :key="i" class="flex flex-col shrink-0 w-full items-center justify-center"> <img :src="image.src" :alt="image.alt" class="w-full h-auto bg-gray-100 rounded-lg"> </div> </div> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Welcome to your dashboard</p> <p class="text-sm font-normal text-gray-600 text-center">We’re glad to have you onboard. Here are some quick tips to get you up and running.</p> </div> <div class="flex justify-center gap-x-4"> <div v-for="(image, i) in images" :class="index == i ? 'h-2.5 w-2.5 bg-primary-700 rounded-lg' : 'h-2.5 w-2.5 bg-gray-100 rounded-lg'"></div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Skip</VBtn> <VBtn color="primary" block @click="onNext">Next</VBtn> </div> </template> </VModal></template>
Payment Details
Update payment method
Update your card details.
<script setup>import { CreditCardShieldIcon } from '@morphemeicons/vue/untitled'const formatExpiryDate = (e) => { e.target.value = e.target.value.replace(/^(0[1-9]|1[0-2])$/g, '$1/').replace(/[^\d\/]$/g, '')}const formatCVV = (e) => { e.target.value = e.target.value.replace(/[^\d\/]$/g, '')}const formatCreditCardNumber = (e) => { e.target.value = e.target.value.replace(/(\d{4})(?=\d)/g, '$1 ').replace(/[^\d\/]$/g, '')}</script><template> <VModal modalClass="!w-full !max-w-[480px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex w-full items-start justify-between"> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <CreditCardShieldIcon class="h-6 w-6 text-gray-700" /> </div> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Update payment method</p> <p class="text-sm font-normal text-gray-600">Update your card details.</p> </div> <div class="flex flex-col md:grid grid-cols-3 gap-4 mt-5"> <div class="flex flex-col col-span-2 space-y-4"> <VInput label="Name on card" placeholder="Name" /> <VInput label="Card number" placeholder="1234 1234 1234 1234" maxlength="19" @keyup="formatCreditCardNumber($event)" > <template #prepend> <div class="flex items-center justify-center p-1.5 border border-gray-100 rounded h-6"> <img src="/master-card.png" alt="Master Card" class="h-3"> </div> </template> </VInput> </div> <div class="grid grid-cols-2 md:flex md:flex-col col-span-1 space-x-4 md:space-y-4 md:space-x-0"> <VInput label="Expiry" placeholder="MM/YYYY" maxlength="7" class="col-span-1" @keyup="formatExpiryDate($event)" /> <VInput label="CVV" placeholder="123" maxlength="3" @keyup="formatCVV($event)" class="col-span-1" /> </div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Update</VBtn> </div> </template> </VModal></template>
Payment Details Image
Update payment method
Update your card details.
Update payment method
Update your card details.
<script setup>const formatExpiryDate = (e) => { e.target.value = e.target.value.replace(/^(0[1-9]|1[0-2])$/g, '$1/').replace(/[^\d\/]$/g, '')}const formatCVV = (e) => { e.target.value = e.target.value.replace(/[^\d\/]$/g, '')}const formatCreditCardNumber = (e) => { e.target.value = e.target.value.replace(/(\d{4})(?=\d)/g, '$1 ').replace(/[^\d\/]$/g, '')}</script><template> <VModal hideXButton modalClass="!w-full !max-w-[480px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex flex-col w-full items-start justify-between"> <img src="/card-mockup.png" alt="Card Mockup" class="hidden md:block"> <p class="md:hidden text-lg font-semibold text-gray-900">Update payment method</p> <p class="md:hidden text-sm font-normal text-gray-600">Update your card details.</p> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="hidden md:flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Update payment method</p> <p class="text-sm font-normal text-gray-600">Update your card details.</p> </div> <div class="flex flex-col md:grid grid-cols-3 gap-4 md:mt-5"> <div class="flex flex-col col-span-2 space-y-4"> <VInput label="Name on card" placeholder="Name" /> <VInput label="Card number" placeholder="1234 1234 1234 1234" maxlength="19" @keyup="formatCreditCardNumber($event)" > <template #prepend> <div class="flex items-center justify-center p-1.5 border border-gray-100 rounded h-6"> <img src="/master-card.png" alt="Master Card" class="h-3"> </div> </template> </VInput> </div> <div class="grid grid-cols-2 md:flex md:flex-col col-span-1 space-x-4 md:space-y-4 md:space-x-0"> <VInput label="Expiry" placeholder="MM/YYYY" maxlength="7" class="col-span-1" @keyup="formatExpiryDate($event)" /> <VInput label="CVV" placeholder="123" maxlength="3" @keyup="formatCVV($event)" class="col-span-1" /> </div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Update</VBtn> </div> </template> </VModal></template>
Plan 01
Change your plan
Flexible pricing that grows with you.
<script setup>import { CreditCardRefreshIcon, LayersTwo01Icon, LayersThree01Icon, ZapIcon } from '@morphemeicons/vue/untitled';const items = ref([ { name: 'Basic plan', price: 10, description: 'Up to 10 users and 20GB individual data.', value: 1, }, { name: 'Business plan', price: 20, description: 'Up to 20 users and 40GB individual data.', value: 2, }, { name: 'Enterprise plan', price: 40, description: 'Unlimited users and unlimited individual data.', value: 3, }])</script><template> <VModal modalClass="!w-full !max-w-[480px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <CreditCardRefreshIcon class="h-6 w-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Change your plan</p> <p class="text-sm font-normal text-gray-600">Flexible pricing that grows with you.</p> </div> <VRadioGroup :items="items" :modelValue="1" class="!items-stretch mt-5" defaultClass="w-full flex-row-reverse justify-end !items-start p-4 bg-white border border-gray-200 rounded-lg" selectedClass="border-2 border-primary-600 !bg-primary-50" > <template #label="{item, selected}"> <div class="flex flex-1"> <div class="flex items-center justify-center w-8 h-8 bg-primary-100 border-4 border-primary-50 rounded-2xl mr-4 mix-blend-multiply"> <LayersTwo01Icon v-if="item.value == 1" class="w-4 h-4 text-primary-600" /> <LayersThree01Icon v-if="item.value == 2" class="w-4 h-4 text-primary-600" /> <ZapIcon v-if="item.value == 3" class="w-4 h-4 text-primary-600" /> </div> <div class="flex flex-1 flex-col space-y-1 mr-1"> <span class="text-sm font-medium text-gray-700"> {{ item.name }} <span class="font-normal text-gray-600" :class="selected == item.value && 'text-primary-700'">${{ item.price }}/month</span> </span> <p class="text-sm font-normal text-gray-600" :class="selected == item.value && 'text-primary-700'">{{ item.description }}</p> </div> </div> </template> </VRadioGroup> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Plan 02
Select plan
Simple and flexible per-user pricing.
<script setup>import { LayersTwo01Icon, CheckCircleIcon, MessageChatCircleIcon } from '@morphemeicons/vue/untitled';const items = ref([ { name: 'Basic plan', price: 10, paymentMethod: 'Billed annually', benefit: [ 'Basic features', 'Basic reporting', 'Up to 10 individual users', '20GB data per user', ], value: 1, }, { name: 'Business plan', price: 20, paymentMethod: 'Billed annually', benefit: [ 'Advanced features', 'Advanced reporting', 'Up to 20 individual users', '40GB data per user', ], value: 2, }])</script><template> <VModal modalClass="!w-full !max-w-[640px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !py-5 md:!px-6 md:!pt-6 border-b border-gray-200" bodyClass="!px-4 !pt-5 md:!p-6 md:!pb-8 !mt-0" footerClass="!p-4 !pt-6 md:!p-6 !mt-0 md:border-t md:border-gray-200" > <template #header> <div class="flex flex-1 flex-col md:flex-row space-y-3 md:space-x-4 md:space-y-0"> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <LayersTwo01Icon class="h-6 w-6 text-gray-700" /> </div> <div class="flex md:flex-1 flex-col space-y-1"> <p class="text-lg text-left font-semibold text-gray-900">Select plan</p> <p class="text-sm text-left font-normal text-gray-600">Simple and flexible per-user pricing.</p> </div> </div> </template> <div class="flex flex-col justify-center font-semibold"> <VRadioGroup :modelValue="1" :items="items" inline class="!hidden md:!flex !items-stretch" defaultClass="w-full flex-row-reverse justify-end !items-start p-5 bg-white border border-gray-200 rounded-lg" selectedClass="border-2 border-primary-600" > <template #label="{item, selected}"> <div class="flex flex-1 flex-col"> <p class="text-display-xs font-semibold text-gray-900">${{ item.price }}/mth</p> <p class="font-semibold text-gray-900 mt-2"> {{ item.name }} </p> <p class="text-sm font-normal text-gray-600 mt-0.5"> {{ item.paymentMethod }} </p> <div class="space-y-3 mt-5"> <div v-for="item in item.benefit" class="flex space-x-3"> <div> <CheckCircleIcon class="w-5 h-5 text-primary-600" /> </div> <p class="text-sm font-normal text-gray-600"> {{ item }} </p> </div> </div> </div> </template> </VRadioGroup> <VRadioGroup :modelValue="1" :items="items" class="md:!hidden !items-stretch" defaultClass="w-full flex-row-reverse justify-end !items-start p-5 bg-white border border-gray-200 rounded-lg" selectedClass="border-2 border-primary-600" > <template #label="{item, selected}"> <div class="flex flex-1 flex-col space-y-1"> <p class="text-display-xs font-semibold text-gray-900">${{ item.price }}/mth</p> <div class="flex justify-between space-x-2"> <p class="font-semibold text-gray-900"> {{ item.name }} </p> <p class="text-sm font-normal text-gray-600"> {{ item.paymentMethod }} </p> </div> </div> </template> </VRadioGroup> </div> <template #footer> <div class="flex flex-1 justify-between gap-3"> <VBtn class="!hidden md:!flex"> <template #prefix> <MessageChatCircleIcon class="w-5 h-5 text-gray-700" /> </template> Chat to us </VBtn> <div class="flex flex-1 justify-end gap-y-3 md:gap-x-3 flex-col-reverse md:flex-row"> <VBtn>Cancel</VBtn> <VBtn color="primary">Select plan</VBtn> </div> </div> </template> </VModal></template>
Plan 03
Change your payment method
Update your plan payment details.
<script setup>import { CurrencyDollarCircleIcon } from '@morphemeicons/vue/untitled';const items = ref([ { name: 'Visa', expiredDate: '06/2024', image: '/card-visa.png', value: 1, }, { name: 'Mastercard', expiredDate: '06/2024', image: '/card-mastercard.png', value: 2, }, { name: 'Apple Pay', expiredDate: '06/2024', image: '/card-apple-pay.png', value: 3, }])</script><template> <VModal modalClass="!w-full !max-w-[480px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <CurrencyDollarCircleIcon class="h-6 w-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Change your payment method</p> <p class="text-sm font-normal text-gray-600">Update your plan payment details.</p> </div> <VRadioGroup :items="items" :modelValue="1" class="!items-stretch mt-5" defaultClass="w-full flex-row-reverse justify-end !items-start p-4 bg-white border border-gray-200 rounded-lg" selectedClass="border-2 border-primary-600 !bg-primary-50" > <template #label="{item, selected}"> <div class="flex flex-1"> <img :src="item.image" :alt="item.image" class="h-8"> <div class="flex flex-1 flex-col mr-1 ml-3"> <p class="text-sm font-medium text-gray-700"> {{ item.name }} ending in 1234 </p> <p class="text-sm font-normal text-gray-600 mt-1" :class="selected == item.value && 'text-primary-600'"> Expiry {{ item.expiredDate }} </p> <div class="flex space-x-3 mt-2"> <VBtn text flush :class="selected == item.value && '!text-primary'">Set as default</VBtn> <VBtn text flush class="!text-primary-700">Edit</VBtn> </div> </div> </div> </template> </VRadioGroup> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
User Selection
Purchase seats
Select how many seats you need.
1
Price per seat
$10
Total
$10
<script setup>import { UsersCheckIcon, MinusIcon, PlusIcon } from '@morphemeicons/vue/untitled';const count = ref(1);const price = ref(10);const total = computed(() => count.value * price.value)const decrementCount = () => { count.value--;}const incrementCount = () => { count.value++;}</script><template> <VModal :modelValue="true" modalClass="!w-full !max-w-[480px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !py-5 md:!px-6 md:!pt-6 border-b border-gray-200" bodyClass="!px-4 !pt-5 !pb-6 md:!p-6 md:!pb-8 !mt-0" footerClass="!p-4 md:!pt-6 md:!p-6 !mt-0 border-t border-gray-200" > <template #header> <div class="flex flex-1 flex-col md:flex-row md:space-x-4"> <div class="hidden md:flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <UsersCheckIcon class="h-6 w-6 text-gray-700" /> </div> <div class="flex flex-1 flex-col space-y-1"> <p class="text-lg font-semibold text-gray-900 text-left">Purchase seats</p> <p class="text-sm font-normal text-gray-600 text-left">Select how many seats you need.</p> </div> </div> </template> <div class="flex flex-col justify-center font-semibold"> <div class="flex justify-center items-center gap-x-6 pb-3"> <VBtn icon :disabled="count < 1" @click="decrementCount" class="!hidden md:!flex"> <MinusIcon class="w-5 h-5" /> </VBtn> <VBtn size="sm" icon :disabled="count < 1" @click="decrementCount" class="md:!hidden"> <MinusIcon class="w-5 h-5" /> </VBtn> <p class="text-display-lg md:text-display-2xl font-semibold text-gray-900 leading-none"> {{ count }} </p> <VBtn icon @click="incrementCount" class="!hidden md:!flex"> <PlusIcon class="w-5 h-5" /> </VBtn> <VBtn size="sm" icon @click="incrementCount" class="md:!hidden"> <PlusIcon class="w-5 h-5" /> </VBtn> </div> <div class="grid grid-cols-2 gap-y-3 border-t border-gray-200 pt-3"> <p class="font-semibold text-gray-900">Price per seat</p> <p class="font-normal text-gray-600 text-right">$10</p> <p class="font-semibold text-gray-900">Total</p> <p class="font-normal text-gray-600 text-right">${{ total }}</p> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Purchase seats</VBtn> </div> </template> </VModal></template>
Form 01
Add experience
Share where you’ve worked on your profile.
<script setup>import { Flag05Icon, InfoCircleIcon, SearchLgIcon, Save01Icon } from '@morphemeicons/vue/untitled';const index = ref(0)const onNext = () => { index.value = index.value + 1;}</script><template> <VModal modalClass="!w-full !max-w-[640px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !py-5 md:!px-6 md:!pt-6" bodyClass="!px-4 !pt-0 !pb-0 md:!px-6 !mt-0" footerClass="!p-4 !pt-6 md:!p-6 !mt-0" > <template #header> <div class="flex flex-1 flex-col md:flex-row md:space-x-4"> <div class="hidden md:flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <Flag05Icon class="h-6 w-6 text-gray-700" /> </div> <div class="flex flex-1 flex-col space-y-1"> <p class="text-lg font-semibold text-gray-900 text-left">Add experience</p> <p class="text-sm font-normal text-gray-600 text-left">Share where you’ve worked on your profile.</p> </div> </div> </template> <div class="flex flex-col justify-center"> <form class="relative flex flex-col justify-center"> <div class="relative overflow-hidden"> <div class="flex md:flex-col transition transform ease delay-50 md:gap-4" :style="{ transform: `translateX(${-index * 100}%)` }"> <div class="flex flex-col shrink-0 w-full md:grid md:grid-cols-2 gap-4"> <div class="space-y-2 md:col-span-2"> <VInput label="Title*" placeholder="What is your title?" /> <VTooltip placement="right" class="flex"> <template #activator="{on}"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <VInput label="Company*" placeholder="Search for company" > <template #prepend> <SearchLgIcon class="w-5 h-5" /> </template> </VInput> <VInput label="Website*" placeholder="www.example.com" > <template #prepend> <div class="flex items-center h-full pr-3 border-r border-gray-200"> <p class="font-normal text-gray-600">https://</p> </div> </template> </VInput> <VInput label="Location*" placeholder="Search for city" > <template #prepend> <SearchLgIcon class="w-5 h-5" /> </template> </VInput> <VSelect label="Employment*" class="hidden md:block" /> </div> <div class="flex flex-col shrink-0 w-full space-y-4 md:space-y-0"> <VSelect label="Employment*" class="md:hidden" /> <div class="col-span-2"> <VTextarea label="Description*" placeholder="e.g. I joined Stripe’s Customer Success team to help them scale their checkout product. I focused mainly on onboarding new customers and resolving complaints." inputClass="h-28 px-3.5 py-3" /> <VTooltip placement="right" class="flex"> <template #activator="{on}"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> </div> </div> </div> </form> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block> <Save01Icon class="w-5 h-5" /> Save as draft </VBtn> <VBtn color="primary" block :class="index == 0 && '!hidden md:!flex'">Add experience</VBtn> <VBtn color="primary" @click="onNext" :class="index == 0 ? 'md:!hidden' : '!hidden md:!hidden'">Next</VBtn> </div> </template> </VModal></template>
Form 02
Add your company
Create your company profile for free in less than 5 minutes.
<script setup> import { Building05Icon, ImagePlusIcon, UploadCloud02Icon, } from '@morphemeicons/vue/untitled'; const previewUrl = ref(''); const fileInput = ref(); const openFileDialog = () => { fileInput.value.click(); }; const onFileChange = (event) => { const file = event.target.files[0]; const reader = new FileReader(); reader.onload = () => { previewUrl.value = reader.result; }; reader.readAsDataURL(file); };</script><template> <VModal modalClass="!w-full !max-w-[640px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !py-5 md:!px-6 md:!pt-6 border-b border-gray-200" bodyClass="!px-4 !pb-6 md:!pb-8 !pt-5 md:!pt-6 !mt-0" footerClass="!p-4 md:!p-6 !mt-0 border-t border-gray-200" > <template #header> <div class="relative flex w-full gap-x-4"> <div class="hidden md:flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs" > <Building05Icon class="h-6 w-6 text-gray-700" /> </div> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-left">Add your company</p> <p class="text-sm font-normal text-gray-600 text-left"> Create your company profile for free in less than 5 minutes. </p> </div> </div> </template> <div class="flex flex-col justify-center"> <form class="relative flex flex-col justify-center"> <div class="flex flex-col shrink-0 w-full gap-4"> <div class="flex flex-col space-y-2 md:grid md:grid-cols-3"> <label class="text-sm font-medium">Company name*</label> <VInput placeholder="e.g. Linear" wrapperClass="md:col-span-2" /> </div> <div class="flex flex-col space-y-2 md:grid md:grid-cols-3"> <label class="text-sm font-medium">Website URL*</label> <VInput placeholder="www.example.com" wrapperClass="md:col-span-2" /> </div> <div class="md:grid md:grid-cols-3 py-4 border-y border-gray-200"> <label class="hidden md:block text-sm font-medium">Profile image*</label> <div class="flex flex-row md:col-span-2"> {{ previewUrl }} <div v-if="!previewUrl" class="flex flex-1 gap-5" > <div class="flex items-center justify-center w-16 h-16 bg-gray-100 rounded-full"> <ImagePlusIcon class="w-8 h-8 text-gray-600 object-contain" /> </div> <div for="dropzone-file" class="flex md:flex-1 md:flex-col" > <div class="hidden md:flex self-start md:self-stretch w-full flex-col items-center justify-center border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-100 py-3 px-4 md:py-4"> <p class="mb-1 text-sm text-gray-600"> <span class="font-semibold text-primary-700"> Click to upload </span> or drag and drop </p> <p class="text-xs text-gray-600"> SVG, PNG, JPG or GIF (max. 800x400px) </p> </div> <div class="flex w-full md:hidden items-center space-x-2 border border-gray-200 rounded-lg cursor-pointer hover:bg-gray-100 py-3 px-4 md:py-4"> <UploadCloud02Icon class="h-5 w-5 text-gray-700" /> <p class="text-sm font-semibold text-gray-700">Upload photo</p> </div> <input id="dropzone-file" ref="fileInput" type="file" @change="onFileChange" class="hidden" /> </div> </div> <div v-else class="flex"> <div> <img :src="previewUrl" class="w-16 h-16 object-cover rounded-full" /> </div> <VBtn type="button" color="primary" size="sm" @click="openFileDialog" class="" > Change </VBtn> </div> </div> </div> <div class="flex flex-col md:grid grid-cols-3 space-y-2"> <label class="text-sm font-medium">Username*</label> <VInput placeholder="example" wrapperClass="col-span-2" prependClass="border-r border-gray-300" > <template #prepend> <p class="text-gray-600">morphemelabs.com/</p> </template> </VInput> </div> <div class="hidden md:grid grid-cols-3"> <label class="text-sm font-medium">Keywords*</label> <VTextarea placeholder="Add 1-10 keywords that help users find your company. For example, B2B, SaaS, marketplace, design..." wrapperClass="col-span-2" inputClass="!h-28 py-3 px-3.5" /> </div> <div class="hidden md:grid grid-cols-3"> <label class="text-sm font-medium">Description*</label> <VTextarea placeholder="Write a few sentences about the company..." wrapperClass="col-span-2" inputClass="!h-16 py-3 px-3.5" /> </div> </div> </form> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block > Add company </VBtn> </div> </template> </VModal></template>
Login
Log in to your account
Welcome back! Please enter your details.
<script setup>import { InfoCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!relative !items-start !gap-0" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" :xButtonProps="{ class: '!absolute right-0' }" > <template #header> <div class="flex flex-col items-center w-full"> <img src="/gits-logomark.png" alt="gits logo" class="w-8 h-8"> <p class="text-lg font-semibold text-gray-900 mt-4">Log in to your account</p> <p class="text-sm font-normal text-gray-600 mt-1">Welcome back! Please enter your details.</p> </div> </template> <form class="flex flex-col justify-center font-semibold"> <div> <VInput label="Email" placeholder="Enter your email" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <div class="mt-4"> <VInput type="password" label="Password" placeholder="Enter your password" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <div class="flex w-full justify-between mt-5"> <VCheckbox label="Remember for 30 days" /> <VBtn color="primary" flush text noRing>Forgot password</VBtn> </div> </form> <template #footer> <div class="flex flex-1 gap-3 flex-col"> <VBtn color="primary" block>Sign in</VBtn> <VBtn block> <img src="/google-logo.png" class="w-6 h-6" /> Sign in with Google </VBtn> </div> </template> </VModal></template>
Sign up 01
Sign up
Start your 30-day free trial.
<script setup>import { InfoCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" footerClass="!mt-6 md:!mt-8" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex flex-col w-full"> <img src="/gits-logomark.png" alt="gits logo" class="w-8 h-8"> <p class="text-lg font-semibold text-gray-900 text-left mt-3 md:mt-4">Sign up</p> <p class="text-sm font-normal text-gray-600 text-left mt-1">Start your 30-day free trial.</p> </div> </template> <form class="flex flex-col justify-center font-semibold space-y-4"> <div> <VInput label="Name*" placeholder="Enter your name" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <div> <VInput type="email" label="Email*" placeholder="Enter your email" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <div> <VInput type="password" label="Password*" placeholder="Enter your password" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on" class="!text-sm !font-normal !gap-x-1"> <InfoCircleIcon class="w-4 h-4" /> This is a hint text to help user. </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> </form> <template #footer> <div class="flex flex-1 gap-3 flex-col"> <VBtn color="primary" block>Sign in</VBtn> <VBtn block> <img src="/google-logo.png" class="w-6 h-6" /> Sign in with Google </VBtn> </div> </template> </VModal></template>
Sign up 02
Create an account
Start your free 30-day trial. Cancel anytime.
OR
<script setup>import { InfoCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!relative !items-start !gap-0" footerClass="!mt-6" bodyClass="!mt-3 md:!mt-4" :xButtonProps="{ class: '!absolute right-0' }" > <template #header> <div class="flex flex-col items-center w-full"> <img src="/gits-logomark.png" alt="gits logo" class="w-8 h-8"> <p class="text-lg font-semibold text-gray-900 mt-4">Create an account</p> <p class="text-sm font-normal text-gray-600 mt-1">Start your free 30-day trial. Cancel anytime.</p> </div> </template> <form class="flex flex-col justify-center font-semibold"> <div> <VInput placeholder="Enter your email" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> </form> <template #footer> <div class="flex flex-1 flex-col"> <VBtn color="primary" block>Get started</VBtn> <div class="my-5 flex w-full items-center before:mt-0.5 before:flex-1 before:border-t before:border-gray-200 after:mt-0.5 after:flex-1 after:border-t after:border-gray-200"> <p class="mx-2 mb-0 text-center font-medium text-gray-600"> OR </p> </div> <div class="space-y-3"> <VBtn block> <img src="~/assets/images/google-logo.png" alt="Google Logo" class="w-6 h-6"> Sign in with Google </VBtn> <VBtn block> <img src="~/assets/images/facebook-logo.png" alt="Facebook Logo" class="w-6 h-6"> Sign in with Facebook </VBtn> <VBtn block> <img src="~/assets/images/apple-logo.png" alt="Apple Logo" class="w-6 h-6"> Sign in with Apple </VBtn> </div> </div> </template> </VModal></template>
Link Field
Blog post published
This blog post has been published. Team members will be able to edit this post and republish changes.
<script setup lang="ts">import { CheckCircleIcon, InfoCircleIcon, Copy01Icon } from '@morphemeicons/vue/untitled';const link = 'www.gits.id/blog'const copyInput = () => { navigator.clipboard.writeText(link)}</script><template> <VModal modalClass="!w-full !max-w-[512px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!relative !items-start !gap-0" footerClass="!mt-6" bodyClass="!mt-3 md:!mt-4" > <template #header> <div class="flex w-full items-start justify-between"> <div class="flex justify-center items-center w-12 h-12 bg-success-100 border-8 border-success-50 rounded-2xl"> <CheckCircleIcon class="w-5 h-5 text-success-600" /> </div> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Blog post published</p> <p class="text-sm font-normal text-gray-600">This blog post has been published. Team members will be able to edit this post and republish changes.</p> </div> <div> <div class="flex items-end space-x-1"> <VInput :modelValue="link" label="Share link" readonly wrapperClass="w-full" /> <VBtn icon text noRing @click="copyInput" class="!text-gray-500"> <Copy01Icon class="w-5 h-5 text-gray-500" /> </VBtn> </div> <VTooltip placement="right" class="flex mt-2"> <template #activator="on"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Confirm</VBtn> </div> </template> </VModal></template>
Labels
Add labels to project
Labels help organize projects.
<script setup>import { Tag01Icon } from '@morphemeicons/vue/untitled';const items = [ { value: 1, text: 'Inprogress', }, { value: 2, text: 'Design', }, { value: 3, text: 'Web', },];</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" bodyClass="!mt-3 md:!mt-4" footerClass="!mt-6 md:!mt-8" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <Tag01Icon class="w-6 h-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Add labels to project</p> <p class="text-sm font-normal text-gray-600">Labels help organize projects.</p> </div> <VMultiSelect :items="items" placeholder="Search for label" /> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Add labels</VBtn> </div> </template> </VModal></template>
User Invites
Share with people
The following users have access to this project:
Candice Wu
candice@morphemelabs.com
Demi Wilkinson
demi@morphemelabs.com
Drew Cano
drew@morphemelabs.com
<script setup>import { UserPlus01Icon } from '@morphemeicons/vue/untitled';const team = [{ name: 'Candice Wu', email: 'candice@morphemelabs.com', status: 'Admin', image: '/avatar-2.png'}, { name: 'Demi Wilkinson', email: 'demi@morphemelabs.com', status: 'Admin', image: '/avatar-5.png'}, { name: 'Drew Cano', email: 'drew@morphemelabs.com', status: 'Editor', image: '/avatar-6.png'}]</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!items-start" bodyClass="!mt-3 md:!mt-4" footerClass="!mt-6 md:!mt-8" > <template #header> <div class="flex justify-center items-center w-12 h-12 border border-gray-200 rounded-lg shadow-xs"> <UserPlus01Icon class="w-6 h-6 text-gray-700" /> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900">Share with people</p> <p class="text-sm font-normal text-gray-600">The following users have access to this project:</p> </div> <div class="space-y-3"> <div v-for="item in team" :key="item.email" class="flex items-center space-x-3"> <div class="flex flex-1 space-x-3 items-center"> <VAvatar :src="item.image" :name="item.name" :maxInitial="1" size="xl" /> <div class="flex flex-col"> <p class="text-sm font-semibold text-gray-700">{{ item.name }}</p> <p class="text-sm font-normal text-gray-600 truncate">{{ item.email }}</p> </div> </div> <VBtn color="error" text flush>Remove</VBtn> </div> </div> <VMultiSelect label="Team member" :items="items" placeholder="Select team member" /> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Done</VBtn> </div> </template> </VModal></template>
Password Prompt
Please enter your password
Enter your password to make this change.
<script setup>import { Shield01Icon, InfoCircleIcon } from '@morphemeicons/vue/untitled';</script><template> <VModal modalClass="!w-full !max-w-[400px] !p-4 !pt-5 md:!p-6 shadow-xl !rounded-lg" headerClass="!relative !items-start" bodyClass="!mt-3 md:!mt-4" footerClass="!mt-6 md:!mt-8" :xButtonProps="{ class: '!absolute right-0' }" > <template #header> <div class="relative flex flex-col items-center w-full"> <div class="flex justify-center items-center w-12 h-12 bg-primary-100 border-8 border-primary-50 rounded-2xl"> <Shield01Icon class="w-6 h-6 text-primary-600" /> </div> <p class="text-lg font-semibold text-gray-900 mt-4">Please enter your password</p> <p class="text-sm font-normal text-gray-600 mt-1">Enter your password to make this change.</p> </div> </template> <form class="flex flex-col justify-center font-semibold space-y-4"> <div> <VInput type="email" label="Email or username" placeholder="Enter your email" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="{on}"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> <div> <VInput type="password" label="Password" placeholder="Enter your password" /> <VTooltip placement="right" class="flex mt-2"> <template #activator="{on}"> <VBtn text icon flush v-on="on"> <InfoCircleIcon class="w-4 h-4" /> </VBtn> </template> <span>Hello :)</span> </VTooltip> </div> </form> <template #footer> <div class="flex flex-1 flex-col-reverse md:flex-row gap-3"> <VBtn block>Cancel</VBtn> <VBtn color="primary" block>Verify</VBtn> </div> </template> </VModal></template>
Centered Video Carousel
Welcome to your dashboard
We’re glad to have you onboard. Here are some quick tips to get you up and running.
<script setup lang="ts">const videos = [ { src: '/example-video.mp4', alt: 'video 1' }, { src: '/example-video.mp4', alt: 'video 2' }, { src: '/example-video.mp4', alt: 'video 3' },]const index = ref(0)const onNext = () => { index.value = (index.value + 1) % videos.length;}</script><template> <VModal hideXButton modalClass="!w-full !max-w-[400px] !p-0 shadow-xl !rounded-lg" headerClass="!items-start !px-4 !pt-4 md:!px-6 md:!pt-6" footerClass="!p-4 !pt-0 md:!p-6 md:!pt-0 !mt-6 md:!mt-8" bodyClass="!px-4 !py-0 md:!px-6 !mt-5 md:!mt-6" > <template #header> <div class="relative overflow-hidden"> <div class="flex transition transform ease delay-50" :style="{ transform: `translateX(${-index * 100}%)` }"> <div v-for="(item, i) in videos" :key="i" class="flex flex-col shrink-0 w-full items-center justify-center"> <video :src="item.src" controls></video> </div> </div> </div> </template> <div class="flex flex-col justify-center font-semibold space-y-5"> <div class="flex flex-col gap-1"> <p class="text-lg font-semibold text-gray-900 text-center">Welcome to your dashboard</p> <p class="text-sm font-normal text-gray-600 text-center">We’re glad to have you onboard. Here are some quick tips to get you up and running.</p> </div> <div class="flex justify-center gap-x-4"> <div v-for="(item, i) in videos" :class="index == i ? 'h-2.5 w-2.5 bg-primary-700 rounded-lg' : 'h-2.5 w-2.5 bg-gray-100 rounded-lg'"></div> </div> </div> <template #footer> <div class="flex flex-1 gap-3 flex-col-reverse md:flex-row"> <VBtn block>Skip</VBtn> <VBtn color="primary" block @click="onNext">Next</VBtn> </div> </template> </VModal></template>