mirror of
https://github.com/ArthurDanjou/ui.git
synced 2026-02-01 04:37:57 +01:00
chore(example): dynamic editor
This commit is contained in:
@@ -1,36 +1,53 @@
|
|||||||
<template>
|
<template>
|
||||||
<div class="mx-auto max-w-7xl flex flex-col">
|
<div class="h-full bg-tw-gray-50 min-h-screen">
|
||||||
Welcome
|
<UContainer class="py-8">
|
||||||
<UButton class="ml-3" variant="primary" icon="mdi:bed-single">
|
<div class="lg:grid lg:grid-cols-12 lg:gap-10 lg:relative">
|
||||||
toto
|
<aside class="pb-8 lg:pb-0 lg:sticky lg:top-0 px-4 sm:px-6 lg:px-0 lg:pt-8 lg:-mt-8 lg:self-start lg:col-span-3" style="position: sticky;">
|
||||||
</UButton>
|
<nav class="space-y-3">
|
||||||
|
<div class="font-bold text-lg pb-6">
|
||||||
|
@nuxthq/ui
|
||||||
|
</div>
|
||||||
|
|
||||||
<UIcon name="mdi:bullhorn" class="w-4 h-4 text-black" />
|
<ULink
|
||||||
|
v-for="component in components"
|
||||||
|
:key="component.name"
|
||||||
|
:to="component.to"
|
||||||
|
class="text-sm font-medium block w-full"
|
||||||
|
active-class="text-primary-600"
|
||||||
|
inactive-class="text-tw-gray-900"
|
||||||
|
>
|
||||||
|
{{ component.name }}
|
||||||
|
</ULink>
|
||||||
|
</nav>
|
||||||
|
</aside>
|
||||||
|
|
||||||
<UAvatar class="ml-3" src="https://picsum.photos/200/300" />
|
<div class="space-y-6 sm:px-6 lg:px-0 lg:col-span-9">
|
||||||
|
<NuxtPage />
|
||||||
<UButton @click="toggleModalIsOpen()">
|
</div>
|
||||||
Toggle modal!
|
</div>
|
||||||
</UButton>
|
</UContainer>
|
||||||
|
|
||||||
{{ isModalOpen }}
|
|
||||||
|
|
||||||
<UModal v-model="isModalOpen" title="Modal">
|
|
||||||
Body
|
|
||||||
</UModal>
|
|
||||||
|
|
||||||
<!-- <UPopover v-slot="{ open }">
|
|
||||||
<UButton trailing variant="white" :icon="open ? 'heroicons-outline:chevron-up' : 'heroicons-outline:chevron-down'">
|
|
||||||
toto
|
|
||||||
</UButton>
|
|
||||||
</UPopover> -->
|
|
||||||
</div>
|
</div>
|
||||||
</template>
|
</template>
|
||||||
|
|
||||||
<script setup>
|
<script setup>
|
||||||
const isModalOpen = ref(false)
|
useMeta({
|
||||||
|
meta: [
|
||||||
|
{ name: 'viewport', content: 'width=device-width, initial-scale=1, maximum-scale=1' }
|
||||||
|
],
|
||||||
|
htmlAttrs: {
|
||||||
|
class: 'bg-tw-gray-50'
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
function toggleModalIsOpen () {
|
const components = [
|
||||||
isModalOpen.value = !isModalOpen.value
|
{ name: 'Avatar', to: '/Avatar' },
|
||||||
}
|
{ name: 'Button', to: '/Button' },
|
||||||
|
{ name: 'Badge', to: '/Badge' },
|
||||||
|
{ name: 'Dropdown', to: '/Dropdown' },
|
||||||
|
{ name: 'Icon', to: '/Icon' },
|
||||||
|
{ name: 'Toggle', to: '/Toggle' },
|
||||||
|
{ name: 'Card', to: '/Card' },
|
||||||
|
{ name: 'Modal', to: '/Modal' },
|
||||||
|
{ name: 'Select', to: '/Select' }
|
||||||
|
]
|
||||||
</script>
|
</script>
|
||||||
|
|||||||
102
example/pages/[component].vue
Normal file
102
example/pages/[component].vue
Normal file
@@ -0,0 +1,102 @@
|
|||||||
|
<template>
|
||||||
|
<UCard background-class="bg-tw-gray-100">
|
||||||
|
<div class="flex justify-center">
|
||||||
|
<component :is="is" v-bind="boundProps" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<template v-if="props.length" #footer>
|
||||||
|
<div class="space-y-3">
|
||||||
|
<UInputGroup
|
||||||
|
v-for="prop of props"
|
||||||
|
:key="prop.key"
|
||||||
|
:name="prop.key"
|
||||||
|
:label="prop.key"
|
||||||
|
>
|
||||||
|
<UToggle
|
||||||
|
v-if="prop.type === 'Boolean'"
|
||||||
|
v-model="prop.value"
|
||||||
|
:name="prop.key"
|
||||||
|
:label="prop.key"
|
||||||
|
/>
|
||||||
|
<USelect
|
||||||
|
v-else-if="prop.values"
|
||||||
|
v-model="prop.value"
|
||||||
|
:name="prop.key"
|
||||||
|
:options="prop.values"
|
||||||
|
size="sm"
|
||||||
|
/>
|
||||||
|
<UInput
|
||||||
|
v-else-if="prop.type === 'String'"
|
||||||
|
v-model="prop.value"
|
||||||
|
:name="prop.key"
|
||||||
|
size="sm"
|
||||||
|
autocomplete="off"
|
||||||
|
/>
|
||||||
|
<UInput
|
||||||
|
v-else-if="prop.type === 'Number'"
|
||||||
|
type="number"
|
||||||
|
:value="prop.value"
|
||||||
|
:name="prop.key"
|
||||||
|
size="sm"
|
||||||
|
autocomplete="off"
|
||||||
|
@input="(value) => inputProp(prop.key, value)"
|
||||||
|
/>
|
||||||
|
<p v-else class="text-sm text-tw-gray-400">
|
||||||
|
This prop of type <span class="p-0.5 rounded bg-gray-100 dark:bg-gray-900">{{ prop.type }}</span> is not yet supported.
|
||||||
|
</p>
|
||||||
|
</UInputGroup>
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
</UCard>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const nuxtApp = useNuxtApp()
|
||||||
|
const { params } = useRoute()
|
||||||
|
|
||||||
|
const is = `U${params.component}`
|
||||||
|
|
||||||
|
const component = nuxtApp.vueApp.component(is)
|
||||||
|
|
||||||
|
const { props: componentProps } = await component.__asyncLoader()
|
||||||
|
|
||||||
|
const refProps = Object.entries(componentProps).map(([key, prop]) => {
|
||||||
|
let value = prop.default
|
||||||
|
let type = prop.type
|
||||||
|
if (Array.isArray(type)) {
|
||||||
|
type = type[0].name
|
||||||
|
} else {
|
||||||
|
type = type.name
|
||||||
|
}
|
||||||
|
|
||||||
|
let values
|
||||||
|
if (prop.validator) {
|
||||||
|
const result = prop.validator.toString().match(/\[.*\]/g, '')[0]
|
||||||
|
values = JSON.parse(result.replace(/'/g, '"'))
|
||||||
|
}
|
||||||
|
|
||||||
|
if (type === 'Boolean') {
|
||||||
|
value = value === 'true'
|
||||||
|
} else if (type === 'String') {
|
||||||
|
value = value === 'undefined' ? '' : value
|
||||||
|
value = value === 'null' ? '' : value
|
||||||
|
value = (value || '').replace(/^'(.*)'$/, '$1')
|
||||||
|
}
|
||||||
|
|
||||||
|
return {
|
||||||
|
key,
|
||||||
|
type,
|
||||||
|
value,
|
||||||
|
values
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
|
const props = ref(refProps)
|
||||||
|
const boundProps = computed(() => {
|
||||||
|
const bound = {}
|
||||||
|
for (const prop of props.value) {
|
||||||
|
bound[prop.key] = prop.value
|
||||||
|
}
|
||||||
|
return bound
|
||||||
|
})
|
||||||
|
</script>
|
||||||
106
example/pages/index.vue
Normal file
106
example/pages/index.vue
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<template>
|
||||||
|
<div class="mx-auto max-w-5xl py-12 space-y-4">
|
||||||
|
<div>
|
||||||
|
<UButton variant="primary" icon="heroicons-outline:bell">
|
||||||
|
toto
|
||||||
|
</UButton>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UAvatar src="https://picsum.photos/200/300" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UButton @click="toggleModalIsOpen()">
|
||||||
|
Toggle modal!
|
||||||
|
</UButton>
|
||||||
|
|
||||||
|
<UModal v-model="isModalOpen" title="Modal">
|
||||||
|
Body
|
||||||
|
</UModal>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UDropdown v-slot="{ open }" :items="dropdownItems" placement="bottom-start">
|
||||||
|
<UButton variant="white" :icon="open ? 'heroicons-solid:chevron-up' : 'heroicons-solid:chevron-down'" trailing icon-class="transition">
|
||||||
|
Open menu!
|
||||||
|
</UButton>
|
||||||
|
</UDropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UDropdown :items="customDropdownItems" placement="bottom-end">
|
||||||
|
<button>
|
||||||
|
<UAvatar src="https://picsum.photos/200/300" />
|
||||||
|
</button>
|
||||||
|
|
||||||
|
<template #item-with-avatar="{ item }">
|
||||||
|
<UAvatar v-if="item.avatar" :src="item.avatar" size="xs" class="mr-3" />
|
||||||
|
|
||||||
|
{{ item.label }}
|
||||||
|
</template>
|
||||||
|
</UDropdown>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div>
|
||||||
|
<UToggle v-model="isSwitchEnabled" />
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<!-- <UPopover v-slot="{ open }">
|
||||||
|
<UButton trailing variant="white" :icon="open ? 'heroicons-outline:chevron-up' : 'heroicons-outline:chevron-down'">
|
||||||
|
toto
|
||||||
|
</UButton>
|
||||||
|
</UPopover> -->
|
||||||
|
</div>
|
||||||
|
</template>
|
||||||
|
|
||||||
|
<script setup>
|
||||||
|
const isModalOpen = ref(false)
|
||||||
|
const isSwitchEnabled = ref(false)
|
||||||
|
|
||||||
|
function toggleModalIsOpen () {
|
||||||
|
isModalOpen.value = !isModalOpen.value
|
||||||
|
}
|
||||||
|
|
||||||
|
function clickItem () {
|
||||||
|
// eslint-disable-next-line no-console
|
||||||
|
console.warn('clicked')
|
||||||
|
}
|
||||||
|
|
||||||
|
const dropdownItems = [
|
||||||
|
[{
|
||||||
|
label: 'Edit',
|
||||||
|
icon: 'heroicons-solid:pencil',
|
||||||
|
click: () => clickItem()
|
||||||
|
}, {
|
||||||
|
label: 'Duplicate',
|
||||||
|
icon: 'heroicons-solid:duplicate'
|
||||||
|
}],
|
||||||
|
[{
|
||||||
|
label: 'Archive',
|
||||||
|
icon: 'heroicons-solid:archive'
|
||||||
|
}, {
|
||||||
|
label: 'Move',
|
||||||
|
icon: 'heroicons-solid:external-link'
|
||||||
|
}],
|
||||||
|
[{
|
||||||
|
label: 'Delete',
|
||||||
|
icon: 'heroicons-solid:trash'
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
|
||||||
|
const customDropdownItems = [
|
||||||
|
[{
|
||||||
|
label: 'benjamincanac',
|
||||||
|
avatar: 'https://picsum.photos/200/300',
|
||||||
|
href: 'https://google.fr',
|
||||||
|
target: '_blank',
|
||||||
|
slot: 'item-with-avatar'
|
||||||
|
}],
|
||||||
|
[{
|
||||||
|
label: 'About',
|
||||||
|
icon: 'heroicons-solid:plus',
|
||||||
|
to: '/about'
|
||||||
|
}]
|
||||||
|
]
|
||||||
|
</script>
|
||||||
Reference in New Issue
Block a user