Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat(module): devtools integration #2196

Merged
merged 110 commits into from
Nov 5, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
110 commits
Select commit Hold shift + click to select a range
c11a3ce
feat: devtools poc
romhml Sep 13, 2024
70f324b
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Sep 13, 2024
f55a11c
feat(devtools): add data-slot selector on all components
romhml Sep 13, 2024
72a6ca2
refactor(devtools): override nuxt-root
romhml Sep 18, 2024
fe54379
feat(devtools): init devtools app
romhml Sep 20, 2024
8853690
feat(devtools): setup local development configuration
romhml Sep 22, 2024
3f8e790
fix(devtools): disable devtools in component view
romhml Sep 22, 2024
dd6693c
feat(devtools): add slots and props customization
romhml Sep 23, 2024
6133fe8
feat(devtools): add code preview
romhml Sep 24, 2024
d592aff
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Sep 24, 2024
6a48789
feat(devtools): ui rework
romhml Sep 25, 2024
7a58132
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Sep 28, 2024
9994083
feat(devtools): code block improvements
romhml Sep 28, 2024
5a84bf8
chore: update pnpm-lock
romhml Sep 28, 2024
78d791e
chore: tailwind playground notes
romhml Sep 28, 2024
bdf973e
refactor(devtools): component preview
romhml Sep 28, 2024
4887935
feat: ui improvements
romhml Sep 28, 2024
3554b63
feat(devtools): improve ComponentPropInput
romhml Oct 5, 2024
13e9b5d
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 5, 2024
b273ac7
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 7, 2024
3229956
chore(devtools): remove theme tab
romhml Oct 7, 2024
0beb089
chore: cleanup
romhml Oct 8, 2024
6d8205b
feat(devtools): ui improvements
romhml Oct 8, 2024
2d77a8f
fix(devtools): favicon color for dark mode
romhml Oct 8, 2024
0275b9d
feat(devtools): ui tweaks
romhml Oct 8, 2024
a023c28
chore(devtools): typechecks
romhml Oct 8, 2024
a09b1c2
revert(devtools): data-slot on components
romhml Oct 9, 2024
7923efe
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 9, 2024
7594c2c
feat(devtools): extend component meta and dynamically resolve compone…
romhml Oct 11, 2024
70ef00b
fix(devtools): typing errors
romhml Oct 11, 2024
eeb25f6
refactor(devtools): component meta fetching
romhml Oct 12, 2024
32a9c27
refactor(devtools): ui improvements
romhml Oct 12, 2024
fe4f6c6
refactor(devtools): use nuxt-component-meta cli to generate metas
romhml Oct 12, 2024
9de498e
chore(devtools): fix typechecks
romhml Oct 12, 2024
7e457c5
fix(devtools): add devtools:prepare in dev:prepare
romhml Oct 12, 2024
cc2b1da
fix(devtools): generate component meta on devtools to resolve build t…
romhml Oct 13, 2024
0cbdf14
feat(devtools): support for component examples
romhml Oct 13, 2024
02fd6f2
feat(devtools): support for enum array and sort props by name
romhml Oct 13, 2024
0131842
feat(devtools): add component examples
romhml Oct 13, 2024
4bfc7e8
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 13, 2024
8a1fe81
feat(devtools): add collapse on nested props
romhml Oct 13, 2024
4115a46
fix(devtools): default value types
romhml Oct 13, 2024
10824cb
fix(devtools): component template fetching
romhml Oct 13, 2024
f993791
chore(devtools): fix build
romhml Oct 14, 2024
b12b919
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 14, 2024
01c4c15
chore: update pnpm-lock
romhml Oct 14, 2024
4de6105
chore: lint
romhml Oct 14, 2024
2992756
chore(devtools): cleanup
romhml Oct 14, 2024
6381a5a
refactor(devtools): component props input
romhml Oct 15, 2024
7bf7e82
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 15, 2024
1697d79
fix(devtools): use on ui css variables
romhml Oct 15, 2024
0e1bfb3
fix: typechecks
romhml Oct 15, 2024
91ca729
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 15, 2024
b677b67
chore(devtools): fix build
romhml Oct 15, 2024
57e739e
refactor(devtools): remove duplicate markdown parser
romhml Oct 15, 2024
482bb04
fix(devtools): navigation menu items select hook
romhml Oct 15, 2024
14e24ab
fix(devtools): code preview for props if defaultSlot
romhml Oct 15, 2024
c4c070c
fix(devtools): small tweaks
romhml Oct 16, 2024
3012fa3
fix(devtools): duplicate toaster provider
romhml Oct 16, 2024
f7c3a49
fix(devtools): parse devtools meta in get-component-meta and reoganiz…
romhml Oct 17, 2024
d71691a
chore(devtools): move devtools runtime resources to src/devtools
romhml Oct 18, 2024
65d08fe
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 18, 2024
87cc977
chore: remove devtools from typechecks
romhml Oct 18, 2024
8f2ddc9
Merge branch 'v3' into wip/devtools
benjamincanac Oct 18, 2024
79d3868
chore(package): add `devtools:build` script
benjamincanac Oct 18, 2024
6d93fc7
clean nuxt.config spacing
benjamincanac Oct 18, 2024
60fb0f2
devtools(app): improve navigation
benjamincanac Oct 18, 2024
6fdbc5f
playground(nuxt.config): configure `nuxt-component-meta`
benjamincanac Oct 18, 2024
32aa158
refactor(devtools): use unbuild
romhml Oct 19, 2024
1ac3014
feat(devtools): display error if component preview is not visible
romhml Oct 19, 2024
39e4386
chore(devtools): remove await on useAsyncData
romhml Oct 19, 2024
9315f95
devtools: remove `toaster` in `app.config`
benjamincanac Oct 19, 2024
6504490
docs(prettier): apply changes from devtools
benjamincanac Oct 19, 2024
89b1fb2
chore(devtools): replace NUXT_UI_DEVTOOLS_LOCAL by false in build
romhml Oct 19, 2024
a59e218
fix(devtools): get-component-example file resolution
romhml Oct 19, 2024
548408a
fix(devtools): use shiki for syntax highlighting client side and impr…
romhml Oct 20, 2024
4d7c8cc
refactor(devtools): removed `@nuxt/mdc`
romhml Oct 20, 2024
c1d488b
fix(devtools): run sirv in dev mode
romhml Oct 20, 2024
93ec9cc
fix(devtools): disable SSR on devtools routes
romhml Oct 20, 2024
63284d7
fix(devtools): remove defineAsyncComponent from dynamic imports in De…
romhml Oct 20, 2024
e850158
fix(devtools): use material-theme-lighter for syntax highlighting in …
romhml Oct 20, 2024
b3fd29c
fix(devtools): remove unused imports
romhml Oct 20, 2024
99d4eb3
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 20, 2024
39df9ff
fix(devtools): ToasterExample
romhml Oct 20, 2024
832ba5e
fix: replace fast-deep-equals with fast-equals
romhml Oct 20, 2024
cdf8842
fix(devtools): shiki colormode
romhml Oct 20, 2024
837e6c9
feat(devtools): remove hash imports from code preview
romhml Oct 20, 2024
dfba09f
fix(devtools): code preview indents
romhml Oct 20, 2024
6fd350e
fix(devtools): component preview error
romhml Oct 20, 2024
45e3f0e
feat(devtools): add template defaultVariants to component prop default
romhml Oct 20, 2024
1b8d699
chore(devtools): up
romhml Oct 20, 2024
6d0af61
chore: remove logs
benjamincanac Oct 21, 2024
34b9428
Update src/module.ts
romhml Oct 21, 2024
878ae73
chore: up
romhml Oct 21, 2024
72ddb1d
chore: up
romhml Oct 21, 2024
81828d5
Merge branch 'wip/devtools' of github.com:nuxt/ui into wip/devtools
romhml Oct 21, 2024
3deaeb3
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Oct 21, 2024
b50140f
chore(components): order `extendDevtoolsMeta` imports
benjamincanac Oct 21, 2024
739483b
chore(devtools): move script setup first
benjamincanac Oct 21, 2024
d8820b9
chore(devtools): clean nuxt.config
benjamincanac Oct 21, 2024
76ba184
chore(components): clean
benjamincanac Oct 21, 2024
b817343
Merge branch 'v3' into wip/devtools
benjamincanac Oct 21, 2024
9dcef0a
chore: remove devtools and docs specific typechecks
romhml Oct 21, 2024
820e672
refactor(devtools): replace devtools rpc client with vite API
romhml Nov 1, 2024
79a9224
Merge branch 'v3' of github.com:nuxt/ui into wip/devtools
romhml Nov 1, 2024
985864a
fix(devtools): component labels
romhml Nov 1, 2024
5663eb8
fix(devtools): downgrade @nuxt/fonts to 0.9.2
romhml Nov 1, 2024
48bb69e
fix(devtools): add explicit dependency to get-port-please
romhml Nov 1, 2024
3d69762
fix(devtools): upgrade nuxt/fonts to 10.0.2 and disable it from the p…
romhml Nov 1, 2024
0b5aa8c
Merge branch 'v3' into wip/devtools
benjamincanac Nov 5, 2024
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions .github/workflows/ci-v3.yml
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,9 @@ jobs:
- name: Prepare
run: pnpm run dev:prepare

- name: Devtools prepare
run: pnpm run devtools:prepare

- name: Lint
run: pnpm run lint

Expand Down
3 changes: 3 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
.component-meta/
component-meta.*

# Nuxt dev/build outputs
.output
.data
Expand Down
6 changes: 5 additions & 1 deletion build.config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,14 +2,18 @@ import { defineBuildConfig } from 'unbuild'

export default defineBuildConfig({
entries: [
// Include devtools runtime files
{ input: './src/devtools/runtime', builder: 'mkdist', outDir: 'dist/devtools/runtime' },
// Vue support
'./src/unplugin',
'./src/vite'
],
rollup: {
emitCJS: true
},
replace: {
'process.env.DEV': 'false'
'process.env.DEV': 'false',
'process.env.NUXT_UI_DEVTOOLS_LOCAL': 'false'
},
hooks: {
'mkdist:entry:options'(ctx, entry, options) {
Expand Down
8 changes: 8 additions & 0 deletions devtools/app/app.config.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
export default defineAppConfig({
ui: {
colors: {
primary: 'green',
neutral: 'zinc'
}
}
})
222 changes: 222 additions & 0 deletions devtools/app/app.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,222 @@
<script setup lang="ts">
import type { Component } from '../../src/devtools/meta'
import { watchDebounced } from '@vueuse/core'

// Disable devtools in component renderer iframe
// @ts-expect-error - Nuxt Devtools internal value
window.__NUXT_DEVTOOLS_DISABLE__ = true

const component = useState<Component | undefined>('__ui-devtools-component')
const state = useState<Record<string, any>>('__ui-devtools-state', () => ({}))

const { data: components, status, error } = useAsyncData<Array<Component>>('__ui-devtools-components', async () => {
const componentMeta = await $fetch<Record<string, Component>>('/api/component-meta')

if (!component.value || !componentMeta[component.value.slug]) {
component.value = componentMeta['button']
}

state.value.props = Object.values(componentMeta).reduce((acc, comp) => {
const componentDefaultProps = comp.meta?.props.reduce((acc, prop) => {
if (prop.default) acc[prop.name] = prop.default
return acc
}, {} as Record<string, any>)

acc[comp.slug] = {
...comp.defaultVariants, // Default values from the theme template
...componentDefaultProps, // Default values from vue props
...componentMeta[comp.slug]?.meta?.devtools?.defaultProps // Default values from devtools extended meta
}

return acc
}, {} as Record<string, any>)

return Object.values(componentMeta)
})

const componentProps = computed(() => {
if (!component.value) return
return state.value.props[component.value?.slug]
})

const componentPropsMeta = computed(() => {
return component.value?.meta?.props.filter(prop => prop.name !== 'ui').sort((a, b) => a.name.localeCompare(b.name))
})

function updateRenderer() {
if (!component.value) return
const event: Event & { data?: any } = new Event('nuxt-ui-devtools:update-renderer')
event.data = {
props: state.value.props?.[component.value.slug], slots: state.value.slots?.[component.value?.slug]
}
window.dispatchEvent(event)
}

watchDebounced(state, updateRenderer, { deep: true, debounce: 200, maxWait: 500 })
onMounted(() => window.addEventListener('nuxt-ui-devtools:component-loaded', onComponentLoaded))
onUnmounted(() => window.removeEventListener('nuxt-ui-devtools:component-loaded', onComponentLoaded))

function onComponentLoaded() {
if (!component.value) return
updateRenderer()
}

const tabs = computed(() => {
if (!component.value) return
return [
{ label: 'Props', slot: 'props', icon: 'i-heroicons-cog-6-tooth', disabled: !component.value.meta?.props?.length }
]
})

function openDocs() {
if (!component.value) return
window.parent.open(`https://ui3.nuxt.dev/components/${component.value.slug}`)
}

const colorMode = useColorMode()
const isDark = computed({
get() {
return colorMode.value === 'dark'
},
set(value) {
colorMode.preference = value ? 'dark' : 'light'

const event: Event & { isDark?: boolean } = new Event('nuxt-ui-devtools:set-color-mode')
event.isDark = value
window.dispatchEvent(event)
}
})
</script>

<template>
<UApp class="flex justify-center items-center h-screen w-full relative font-sans">
<div v-if="status === 'pending' || error || !component || !components?.length">
<div v-if="error" class="flex flex-col justify-center items-center h-screen w-screen text-center text-[var(--ui-color-error-500)]">
<UILogo class="h-8" />
<UIcon name="i-heroicons-exclamation-circle" size="20" class="mt-2" />
<p>
{{ (error.data as any)?.error ?? 'Unexpected error' }}
</p>
</div>
</div>
<template v-else>
<div
class="top-0 h-[49px] border-b border-[var(--ui-border)] flex justify-center"
>
<span />

<UInputMenu
v-model="component"
variant="none"
:items="components"
placeholder="Search component..."
class="top-0 translate-y-0 w-full mx-2"
icon="i-heroicons-magnifying-glass"
/>

<div class="absolute top-[49px] bottom-0 inset-x-0 grid xl:grid-cols-8 grid-cols-4 bg-[var(--ui-bg)]">
<div class="col-span-1 border-r border-[var(--ui-border)] hidden xl:block overflow-y-auto">
<UNavigationMenu
:items="components.map((c) => ({ ...c, active: c.slug === component?.slug, onSelect: () => component = c }))"
orientation="vertical"
:ui="{ link: 'before:rounded-none' }"
/>
</div>

<div class="xl:col-span-5 col-span-2 relative">
<ComponentPreview :component="component" :props="componentProps" class="h-full" />
<div class="flex gap-2 absolute top-1 right-2">
<UButton
:icon="isDark ? 'i-heroicons-moon-20-solid' : 'i-heroicons-sun-20-solid'"
variant="ghost"
color="neutral"
@click="isDark = !isDark"
/>
<UButton
v-if="component"
variant="ghost"
color="neutral"
icon="i-heroicons-arrow-top-right-on-square"
@click="openDocs()"
>
Open docs
</UButton>
</div>
</div>

<div class="border-l border-[var(--ui-border)] flex flex-col col-span-2 overflow-y-auto">
<UTabs color="neutral" variant="link" :items="tabs" class="relative" :ui="{ list: 'sticky top-0 bg-[var(--ui-bg)] z-50' }">
<template #props>
<div v-for="prop in componentPropsMeta" :key="'prop-' + prop.name" class="px-3 py-5 border-b border-[var(--ui-border)]">
<ComponentPropInput
v-model="componentProps[prop.name]"
:meta="prop"
:ignore="component.meta?.devtools?.ignoreProps?.includes(prop.name)"
/>
</div>
</template>
</UTabs>
</div>
</div>
</div>
</template>
</UApp>
</template>

<style>
@import 'tailwindcss';
@import '@nuxt/ui';

@theme {
--font-family-sans: 'DM Sans', sans-serif;

--color-primary-50: var(--ui-color-primary-50);
--color-primary-100: var(--ui-color-primary-100);
--color-primary-200: var(--ui-color-primary-200);
--color-primary-300: var(--ui-color-primary-300);
--color-primary-400: var(--ui-color-primary-400);
--color-primary-500: var(--ui-color-primary-500);
--color-primary-600: var(--ui-color-primary-600);
--color-primary-700: var(--ui-color-primary-700);
--color-primary-800: var(--ui-color-primary-800);
--color-primary-900: var(--ui-color-primary-900);
--color-primary-950: var(--ui-color-primary-950);

--color-neutral-50: var(--ui-color-neutral-50);
--color-neutral-100: var(--ui-color-neutral-100);
--color-neutral-200: var(--ui-color-neutral-200);
--color-neutral-300: var(--ui-color-neutral-300);
--color-neutral-400: var(--ui-color-neutral-400);
--color-neutral-500: var(--ui-color-neutral-500);
--color-neutral-600: var(--ui-color-neutral-600);
--color-neutral-700: var(--ui-color-neutral-700);
--color-neutral-800: var(--ui-color-neutral-800);
--color-neutral-900: var(--ui-color-neutral-900);
--color-neutral-950: var(--ui-color-neutral-950);
}

:root {
--ui-border: var(--ui-color-neutral-200);
--ui-bg: white;
}

.dark {
--ui-border: var(--ui-color-neutral-800);
--ui-bg: var(--ui-color-neutral-900);
}

.shiki
.shiki span {
background-color: transparent !important;
}

html.dark .shiki,
html.dark .shiki span {
color: var(--shiki-dark) !important;
background-color: transparent !important;
/* Optional, if you also want font styles */
font-style: var(--shiki-dark-font-style) !important;
font-weight: var(--shiki-dark-font-weight) !important;
text-decoration: var(--shiki-dark-text-decoration) !important;
}
</style>
43 changes: 43 additions & 0 deletions devtools/app/components/CollapseContainer.vue
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
<script setup lang="ts">
import { ref, computed, onMounted } from 'vue'

const collapsed = ref(true)
const wrapper = ref<HTMLElement | null>(null)
const content = ref<HTMLElement | null>(null)

const overflow = computed(() => {
if (!content.value || !wrapper.value) return false
return content.value.scrollHeight > 48 * 4
})

onMounted(() => {
if (wrapper.value) {
wrapper.value.style.transition = 'max-height 0.3s ease' // Set transition for max-height
}
})
</script>

<template>
<div class="border rounded border-[var(--ui-border)]">
<div
ref="wrapper"
:class="['overflow-hidden', collapsed && overflow ? 'max-h-48' : 'max-h-none']"
>
<div ref="content">
<slot />
</div>
</div>
<UButton
v-if="overflow"
class="bg-[var(--ui-bg)] group w-full flex justify-center my-1 border-t border-[var(--ui-border)] rounded-t-none"
variant="link"
color="neutral"
trailing-icon="i-heroicons-chevron-down"
:data-state="collapsed ? 'closed' : 'open'"
:ui="{ trailingIcon: 'transition group-data-[state=open]:rotate-180' }"
@click="collapsed = !collapsed"
>
{{ collapsed ? 'Expand' : 'Collapse' }}
</UButton>
</div>
</template>
Loading