Skip to content

Commit

Permalink
feat: add directives page (#740)
Browse files Browse the repository at this point in the history
Co-authored-by: Anthony Fu <[email protected]>
  • Loading branch information
userquin and antfu authored Feb 6, 2025
1 parent dd9a91a commit c20c724
Show file tree
Hide file tree
Showing 9 changed files with 121 additions and 30 deletions.
29 changes: 23 additions & 6 deletions packages/devtools/client/components/ComposableItem.vue
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
<script setup lang="ts">
import type { Import, UnimportMeta } from 'unimport'
import { kebabCase } from 'scule'
import { computed } from 'vue'
import { ComposablesDocs } from '~/composables/constants'
import { useCopy, useOpenInEditor } from '~/composables/editor'
const props = withDefaults(
defineProps<{
item: Import
isDirective?: boolean
metadata?: UnimportMeta
filepath?: string
counter?: boolean
classes?: string
}>(),
{
isDirective: false,
counter: true,
classes: 'px2 py1 text-sm bg-gray:5 ',
},
Expand All @@ -22,6 +25,16 @@ const copy = useCopy()
const openInEditor = useOpenInEditor()
const name = computed(() => props.item.as || props.item.name)
const copyName = computed(() => {
let n = name.value
if (props.isDirective) {
if (n[0] !== 'v') {
n = `v${n}`
}
n = kebabCase(n)
}
return n
})
const usageCount = computed(() => props.metadata?.injectionUsage?.[name.value]?.count || 0)
const modules = computed(() =>
(props.metadata?.injectionUsage?.[name.value]?.moduleIds || [])
Expand All @@ -40,14 +53,18 @@ const docsUrl = computed(() => {

<template>
<VDropdown :disabled="!props.metadata">
<button hover:text-primary>
<code
rounded font-mono
:class="[metadata && !usageCount ? 'op30 hover:op100' : '', classes]"
>
<button hover:text-primary :class="[metadata && !usageCount ? 'op30 hover:op100' : '', classes]">
<code rounded font-mono>
{{ name }}
<sup v-if="usageCount && counter" text-primary>x{{ usageCount }}</sup>
</code>
<sup v-if="isDirective">
<abbr title="Vue Directive">
<NIcon
icon="tabler:hexagon-letter-d"
/>
</abbr>
</sup>
</button>
<template #popper>
<div max-w-100>
Expand All @@ -59,7 +76,7 @@ const docsUrl = computed(() => {
:markdown="item.meta.description"
/>
<div flex="~ gap2" n="primary xs">
<NButton icon="carbon-copy" @click="copy(name, 'imports-name')">
<NButton icon="carbon-copy" @click="copy(copyName, 'imports-name')">
Copy
</NButton>
<NButton v-if="filepath" icon="carbon-code" @click="filepath && openInEditor(filepath)">
Expand Down
1 change: 1 addition & 0 deletions packages/devtools/client/components/ComposableTree.vue
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ defineProps<{
v-for="i of value" :key="i.as"
:item="i"
:metadata="metadata"
:is-directive="i.meta?.vueDirective === true"
:filepath="key.match(/^[\w@]/) ? undefined : key"
/>
</div>
Expand Down
6 changes: 6 additions & 0 deletions packages/devtools/client/components/docs/imports.md
Original file line number Diff line number Diff line change
Expand Up @@ -15,3 +15,9 @@ Meanwhile, modules could also provide auto-imports for their own components. You
<hr>

[Learn more in the documentation](https://nuxt.com/docs/guide/concepts/auto-imports)

## Directives

Directives placed in the directives/ directory are automatically registered by Nuxt. They can be used in your templates without importing them.

[Learn more in the documentation](https://nuxt.com/docs/guide/directory-structure/directives)
51 changes: 43 additions & 8 deletions packages/devtools/client/pages/modules/imports.vue
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ definePageMeta({
const config = useServerConfig()
const filterMode = ref<'all' | 'using' | 'not-used'>('all')
const filterEntries = ref<'all' | 'composables' | 'directives'>('all')
const search = ref('')
const autoImports = useAutoImports()
Expand All @@ -39,6 +40,15 @@ const filtered = computed(() => {
? fuse.value.search(search.value).map(i => i.item)
: functions.value
const filter = filterEntries.value
if (filter === 'composables') {
result = result.filter(i => !(i.meta?.vueDirective === true))
}
else if (filter === 'directives') {
result = result.filter(i => i.meta?.vueDirective === true)
}
if (filterMode.value === 'using' && importsMetadata.value) {
result = result
.filter(i => (i.as || i.name) in importsMetadata.value!.injectionUsage)
Expand Down Expand Up @@ -74,12 +84,28 @@ const filtered = computed(() => {
count,
}
})
const filteredUserCountTitle = computed(() => {
return filterEntries.value === 'directives'
? `${filtered.value.count.user} directives from ${filtered.value.user.size} modules`
: `${filtered.value.count.user} composables from ${filtered.value.user.size} modules`
})
const filteredBuiltinTitle = computed(() => {
return filterEntries.value === 'directives'
? `${filtered.value.count.builtin} directives`
: `${filtered.value.count.builtin} composables`
})
const filteredLibTitle = computed(() => {
return filterEntries.value === 'directives'
? `${filtered.value.count.lib} directives from ${filtered.value.lib.size} packages`
: `${filtered.value.count.lib} composables from ${filtered.value.lib.size} packages`
})
</script>

<template>
<div v-if="config" relative h-full of-auto>
<NNavbar v-model:search="search" pb3>
<div v-if="importsMetadata" flex="~ gap-2 items-center">
<div v-if="importsMetadata" flex="~ gap-2 items-center lt-sm:col lt-sm:items-start">
<NIcon icon="carbon-filter" op50 />
<NSelectTabs
v-model="filterMode"
Expand All @@ -90,32 +116,41 @@ const filtered = computed(() => {
{ label: 'Not used', value: 'not-used' },
]"
/>
<NSelectTabs
v-model="filterEntries"
n="primary sm"
:options="[
{ label: 'All', value: 'all' },
{ label: 'Composables', value: 'composables' },
{ label: 'Directives', value: 'directives' },
]"
/>
</div>
</NNavbar>
<NSectionBlock
v-if="filtered.user.size"
:open="filtered.count.user <= DETAILS_MAX_ITEMS"
icon="carbon-function"
text="User composables"
:description="`${filtered.count.user} composables from ${filtered.user.size} modules`"
:icon="filterEntries === 'directives' ? 'tabler:hexagon-letter-d' : 'carbon-function'"
:text="`User ${filterEntries === 'directives' ? 'directives' : 'composables'}`"
:description="filteredUserCountTitle"
>
<ComposableTree :map="filtered.user" :root="config.rootDir" :metadata="importsMetadata" />
</NSectionBlock>
<NSectionBlock
v-if="filtered.builtin.size"
:open="filtered.count.builtin <= DETAILS_MAX_ITEMS"
icon="simple-icons-nuxtdotjs"
text="Built-in composables"
:description="`${filtered.count.builtin} composables`"
:text="`Built-in ${filterEntries === 'directives' ? 'directives' : 'composables'}`"
:description="filteredBuiltinTitle"
>
<ComposableTree :map="filtered.builtin" :root="config.rootDir" :metadata="importsMetadata" />
</NSectionBlock>
<NSectionBlock
v-if="filtered.lib.size"
:open="filtered.count.lib <= DETAILS_MAX_ITEMS"
icon="carbon-3d-mpr-toggle"
text="Composables from libraries"
:description="`${filtered.count.lib} composables from ${filtered.lib.size} packages`"
:text="`${filterEntries === 'directives' ? 'Directives' : 'Composables'} from libraries`"
:description="filteredLibTitle"
>
<ComposableTree :map="filtered.lib" :root="config.rootDir" :metadata="importsMetadata" />
</NSectionBlock>
Expand Down
6 changes: 3 additions & 3 deletions packages/devtools/src/integrations/vue-devtools.ts
Original file line number Diff line number Diff line change
@@ -1,15 +1,15 @@
import type { NuxtDevtoolsServerContext } from '../types'
import { addPluginTemplate } from '@nuxt/kit'
import { addPluginTemplate, resolvePath } from '@nuxt/kit'
import { join } from 'pathe'
import { runtimeDir } from '../dirs'

export function setup({ nuxt }: NuxtDevtoolsServerContext) {
export async function setup({ nuxt }: NuxtDevtoolsServerContext) {
if (!nuxt.options.dev || nuxt.options.test)
return

addPluginTemplate({
name: 'vue-devtools-client',
mode: 'client',
src: join(runtimeDir, 'vue-devtools-client.js'),
src: await resolvePath(join(runtimeDir, 'vue-devtools-client')),
})
}
23 changes: 23 additions & 0 deletions playgrounds/tab-pinia/directives/focus.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
// todo: remove this once nuxt with directives folder here
import type { DirectiveBinding } from 'vue'

function mounted(el: HTMLElement, binding: DirectiveBinding) {
// eslint-disable-next-line no-console
console.log('mounted', el, binding)
}

function unmounted(el: HTMLElement, binding: DirectiveBinding) {
// eslint-disable-next-line no-console
console.log('unmounted', el, binding)
}

function updated(el: HTMLElement, binding: DirectiveBinding) {
// eslint-disable-next-line no-console
console.log('updated', el, binding)
}

export const Focus = {
mounted,
unmounted,
updated,
}
18 changes: 18 additions & 0 deletions playgrounds/tab-pinia/nuxt.config.ts
Original file line number Diff line number Diff line change
@@ -1,3 +1,7 @@
import { createResolver } from '@nuxt/kit'

const resolver = createResolver(import.meta.url)

export default defineNuxtConfig({
css: ['~/assets/main.css'],

Expand All @@ -9,6 +13,20 @@ export default defineNuxtConfig({

imports: {
dirs: ['./stores'],
presets: [{
from: resolver.resolve('directives/focus.ts'),
imports: [{
name: 'Focus',
meta: {
vueDirective: true,
docsUrl: 'https://vuetifyjs.com/en/directives/click-outside/#usage',
description: 'The v-focus directive focus the element once mounted.',
},
}],
}],
addons: {
vueDirectives: true,
},
},

pinia: {
Expand Down
2 changes: 1 addition & 1 deletion playgrounds/tab-pinia/pages/index.vue
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ const counter = useCounter()

<template>
<div>
<div style="margin: 1rem 0">
<div v-focus style="margin: 1rem 0">
<PiniaLogo />
</div>

Expand Down
15 changes: 3 additions & 12 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

0 comments on commit c20c724

Please sign in to comment.