mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-01-19 06:21:46 +01:00
feat(module): devtools integration (#2196)
Co-authored-by: Benjamin Canac <canacb1@gmail.com>
This commit is contained in:
71
src/devtools/runtime/DevtoolsRenderer.vue
Normal file
71
src/devtools/runtime/DevtoolsRenderer.vue
Normal file
@@ -0,0 +1,71 @@
|
||||
<script setup lang="ts">
|
||||
import { onUnmounted, onMounted, reactive } from 'vue'
|
||||
import { pascalCase } from 'scule'
|
||||
import { defineAsyncComponent, useColorMode, useRoute } from '#imports'
|
||||
|
||||
const route = useRoute()
|
||||
const component = route.query?.example
|
||||
? defineAsyncComponent(() => import(`./examples/${route.query.example}.vue`))
|
||||
: route.params?.slug && defineAsyncComponent(() => import(`../../runtime/components/${pascalCase(route.params.slug as string)}.vue`))
|
||||
|
||||
const state = reactive<{ slots?: any, props?: any }>({})
|
||||
|
||||
function onUpdateRenderer(event: Event & { data?: any }) {
|
||||
state.props = { ...event.data.props }
|
||||
state.slots = { ...event.data.slots }
|
||||
}
|
||||
|
||||
const colorMode = useColorMode()
|
||||
function setColorMode(event: Event & { isDark?: boolean }) {
|
||||
colorMode.preference = event.isDark ? 'dark' : 'light'
|
||||
}
|
||||
|
||||
onMounted(() => {
|
||||
window.parent.addEventListener('nuxt-ui-devtools:update-renderer', onUpdateRenderer)
|
||||
window.parent.addEventListener('nuxt-ui-devtools:set-color-mode', setColorMode)
|
||||
})
|
||||
|
||||
onUnmounted(() => {
|
||||
window.parent.removeEventListener('nuxt-ui-devtools:update-renderer', onUpdateRenderer)
|
||||
window.parent.removeEventListener('nuxt-ui-devtools:set-color-mode', setColorMode)
|
||||
})
|
||||
|
||||
onMounted(async () => {
|
||||
const event: Event = new Event('nuxt-ui-devtools:component-loaded')
|
||||
window.parent.dispatchEvent(event)
|
||||
})
|
||||
|
||||
onMounted(() => {
|
||||
if (!route.query?.example) return
|
||||
})
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<div id="ui-devtools-renderer" class="nuxt-ui-component-renderer">
|
||||
<UApp :toaster="null">
|
||||
<component :is="component" v-if="component" v-bind="state.props" :class="state?.slots?.base" :ui="state.slots" />
|
||||
</UApp>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<style>
|
||||
.nuxt-ui-component-renderer {
|
||||
position: 'relative';
|
||||
height: 100vh;
|
||||
width: 100vw;
|
||||
|
||||
padding: 32px;
|
||||
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' transform='scale(3)'%3E%3Crect width='100%25' height='100%25' fill='%23fff'/%3E%3Cpath fill='none' stroke='hsla(0, 0%25, 98%25, 1)' stroke-width='.2' d='M10 0v20ZM0 10h20Z'/%3E%3C/svg%3E");
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
|
||||
.dark .nuxt-ui-component-renderer {
|
||||
background-image: url("data:image/svg+xml;charset=utf-8,%3Csvg xmlns='http://www.w3.org/2000/svg' width='20' height='20' transform='scale(3)'%3E%3Crect width='100%25' height='100%25' fill='hsl(0, 0%25, 8.5%25)'/%3E%3Cpath fill='none' stroke='hsl(0, 0%25, 11.0%25)' stroke-width='.2' d='M10 0v20ZM0 10h20Z'/%3E%3C/svg%3E");
|
||||
background-size: 40px 40px;
|
||||
}
|
||||
</style>
|
||||
7
src/devtools/runtime/examples/AvatarGroupExample.vue
Normal file
7
src/devtools/runtime/examples/AvatarGroupExample.vue
Normal file
@@ -0,0 +1,7 @@
|
||||
<template>
|
||||
<UAvatarGroup>
|
||||
<UAvatar src="https://github.com/benjamincanac.png" alt="Benjamin Canac" />
|
||||
<UAvatar src="https://github.com/romhml.png" alt="Romain Hamel" />
|
||||
<UAvatar src="https://github.com/noook.png" alt="Neil Richter" />
|
||||
</UAvatarGroup>
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/ButtonGroupExample.vue
Normal file
8
src/devtools/runtime/examples/ButtonGroupExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<UButtonGroup>
|
||||
<UInput placeholder="Search..." />
|
||||
<UButton color="neutral" variant="outline">
|
||||
Button
|
||||
</UButton>
|
||||
</UButtonGroup>
|
||||
</template>
|
||||
13
src/devtools/runtime/examples/CardExample.vue
Normal file
13
src/devtools/runtime/examples/CardExample.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<div class="flex flex-col gap-4">
|
||||
<UCard class="w-96">
|
||||
<template #header>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-8" />
|
||||
</template>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-32" />
|
||||
<template #footer>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-8" />
|
||||
</template>
|
||||
</UCard>
|
||||
</div>
|
||||
</template>
|
||||
13
src/devtools/runtime/examples/CarouselExample.vue
Normal file
13
src/devtools/runtime/examples/CarouselExample.vue
Normal file
@@ -0,0 +1,13 @@
|
||||
<template>
|
||||
<UCarousel
|
||||
v-slot="{ item }"
|
||||
class="basis-1/3"
|
||||
:items="[
|
||||
'https://picsum.photos/320/320?v=1',
|
||||
'https://picsum.photos/320/320?v=2',
|
||||
'https://picsum.photos/320/320?v=3'
|
||||
]"
|
||||
>
|
||||
<img :src="item" class="rounded-lg basis-1/3">
|
||||
</UCarousel>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/ChipExample.vue
Normal file
5
src/devtools/runtime/examples/ChipExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UChip>
|
||||
<UAvatar src="https://avatars.githubusercontent.com/u/739984?v=4" />
|
||||
</UChip>
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/CollapsibleExample.vue
Normal file
8
src/devtools/runtime/examples/CollapsibleExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<UCollapsible class="w-48">
|
||||
<UButton label="Open Collapse" block />
|
||||
<template #content>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-60" />
|
||||
</template>
|
||||
</UCollapsible>
|
||||
</template>
|
||||
29
src/devtools/runtime/examples/CommandPaletteExample.vue
Normal file
29
src/devtools/runtime/examples/CommandPaletteExample.vue
Normal file
@@ -0,0 +1,29 @@
|
||||
<script setup lang="ts">
|
||||
const groups = [{
|
||||
id: 'actions',
|
||||
items: [{
|
||||
label: 'Add new file',
|
||||
suffix: 'Create a new file in the current directory or workspace.',
|
||||
icon: 'i-heroicons-document-plus'
|
||||
}, {
|
||||
label: 'Add new folder',
|
||||
suffix: 'Create a new folder in the current directory or workspace.',
|
||||
icon: 'i-heroicons-folder-plus',
|
||||
kbds: ['meta', 'F']
|
||||
}, {
|
||||
label: 'Add hashtag',
|
||||
suffix: 'Add a hashtag to the current item.',
|
||||
icon: 'i-heroicons-hashtag',
|
||||
kbds: ['meta', 'H']
|
||||
}, {
|
||||
label: 'Add label',
|
||||
suffix: 'Add a label to the current item.',
|
||||
icon: 'i-heroicons-tag',
|
||||
kbds: ['meta', 'L']
|
||||
}]
|
||||
}]
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UCommandPalette :groups="groups" />
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/ContainerExample.vue
Normal file
5
src/devtools/runtime/examples/ContainerExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UContainer>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-60 aspect-video w-72" />
|
||||
</UContainer>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/ContextMenuExample.vue
Normal file
5
src/devtools/runtime/examples/ContextMenuExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UContextMenu>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-60 w-72" />
|
||||
</UContextMenu>
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/DrawerExample.vue
Normal file
8
src/devtools/runtime/examples/DrawerExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<UDrawer>
|
||||
<UButton label="Open Drawer" />
|
||||
<template #body>
|
||||
<div class="size-96" />
|
||||
</template>
|
||||
</UDrawer>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/DropdownMenuExample.vue
Normal file
5
src/devtools/runtime/examples/DropdownMenuExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UDropdownMenu>
|
||||
<UButton label="Open Dropdown" />
|
||||
</UDropdownMenu>
|
||||
</template>
|
||||
30
src/devtools/runtime/examples/FormExample.vue
Normal file
30
src/devtools/runtime/examples/FormExample.vue
Normal file
@@ -0,0 +1,30 @@
|
||||
<script setup lang="ts">
|
||||
import { reactive } from 'vue'
|
||||
|
||||
const state = reactive({ email: undefined, password: undefined })
|
||||
|
||||
function validate(data: Partial<typeof state>) {
|
||||
const errors: Array<{ name: string, message: string }> = []
|
||||
if (!data.email) errors.push({ name: 'email', message: 'Required' })
|
||||
if (!data.password) errors.push({ name: 'password', message: 'Required' })
|
||||
return errors
|
||||
}
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UForm
|
||||
:validate="validate"
|
||||
:state="state"
|
||||
class="space-y-4"
|
||||
>
|
||||
<UFormField name="email" label="Email">
|
||||
<UInput v-model="state.email" />
|
||||
</UFormField>
|
||||
<UFormField name="password" label="Password">
|
||||
<UInput v-model="state.password" />
|
||||
</UFormField>
|
||||
<UButton type="submit">
|
||||
Submit
|
||||
</UButton>
|
||||
</UForm>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/FormFieldExample.vue
Normal file
5
src/devtools/runtime/examples/FormFieldExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UFormField>
|
||||
<UInput />
|
||||
</UFormField>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/LinkExample.vue
Normal file
5
src/devtools/runtime/examples/LinkExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<ULink>
|
||||
Link
|
||||
</ULink>
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/ModalExample.vue
Normal file
8
src/devtools/runtime/examples/ModalExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<UModal>
|
||||
<UButton label="Open Modal" />
|
||||
<template #content>
|
||||
<div class="h-72" />
|
||||
</template>
|
||||
</UModal>
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/PopoverExample.vue
Normal file
8
src/devtools/runtime/examples/PopoverExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<UPopover>
|
||||
<UButton label="Open Collapse" />
|
||||
<template #content>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 h-24 w-60" />
|
||||
</template>
|
||||
</UPopover>
|
||||
</template>
|
||||
3
src/devtools/runtime/examples/SkeletonExample.vue
Normal file
3
src/devtools/runtime/examples/SkeletonExample.vue
Normal file
@@ -0,0 +1,3 @@
|
||||
<template>
|
||||
<USkeleton class="h-32 w-96" />
|
||||
</template>
|
||||
8
src/devtools/runtime/examples/SlideoverExample.vue
Normal file
8
src/devtools/runtime/examples/SlideoverExample.vue
Normal file
@@ -0,0 +1,8 @@
|
||||
<template>
|
||||
<USlideover>
|
||||
<UButton label="Open Slideover" />
|
||||
<template #body>
|
||||
<div class="size-96" />
|
||||
</template>
|
||||
</USlideover>
|
||||
</template>
|
||||
11
src/devtools/runtime/examples/ToasterExample.vue
Normal file
11
src/devtools/runtime/examples/ToasterExample.vue
Normal file
@@ -0,0 +1,11 @@
|
||||
<script setup>
|
||||
import { useToast } from '#imports'
|
||||
|
||||
const toast = useToast()
|
||||
</script>
|
||||
|
||||
<template>
|
||||
<UToaster>
|
||||
<UButton label="Open toast" @click="toast.add({ title: 'Heads up!' })" />
|
||||
</UToaster>
|
||||
</template>
|
||||
5
src/devtools/runtime/examples/TooltipExample.vue
Normal file
5
src/devtools/runtime/examples/TooltipExample.vue
Normal file
@@ -0,0 +1,5 @@
|
||||
<template>
|
||||
<UTooltip>
|
||||
<div class="bg-[var(--ui-bg-accented)]/40 size-20" />
|
||||
</UTooltip>
|
||||
</template>
|
||||
Reference in New Issue
Block a user