Skip to content

Commit 7351b65

Browse files
committed
chore: wip
1 parent b5da7e7 commit 7351b65

File tree

18 files changed

+523
-22
lines changed

18 files changed

+523
-22
lines changed

package.json

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@
5353
"vite": "catalog:build",
5454
"vite-plugin-inspect": "catalog:devtools",
5555
"vitest": "catalog:testing",
56+
"vue": "catalog:",
5657
"vue-tsc": "catalog:devtools"
5758
},
5859
"resolutions": {
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
<script setup lang="ts">
2+
import type { RolldownEvent } from '../../../node/rolldown/events-manager'
3+
import { Dropdown as VDropdown } from 'floating-vue'
4+
import { defineProps, withDefaults } from 'vue'
5+
6+
type FIELDS = 'module_id' | 'kind' | 'source' | 'timestamp' | 'plugin_name'
7+
8+
const props = withDefaults(
9+
defineProps<{
10+
events: RolldownEvent[]
11+
fields?: FIELDS[]
12+
}>(),
13+
{
14+
fields: () => [
15+
'kind',
16+
'module_id',
17+
'plugin_name',
18+
'timestamp',
19+
'source',
20+
],
21+
},
22+
)
23+
24+
function getSource(event: RolldownEvent) {
25+
if (event.kind === 'HookLoadCallEnd') {
26+
return event.source
27+
}
28+
if (event.kind === 'HookTransformCallStart') {
29+
return event.source
30+
}
31+
if (event.kind === 'HookTransformCallEnd') {
32+
return event.transformed_source
33+
}
34+
return null
35+
}
36+
</script>
37+
38+
<template>
39+
<table>
40+
<tbody>
41+
<tr v-for="event of props.events" :key="event.event_id">
42+
<template v-for="field of props.fields" :key="field">
43+
<td px2>
44+
<DisplayModuleId v-if="field === 'module_id'" :id="event.module_id" />
45+
<DisplayBadge v-else-if="field === 'kind'" :text="event.kind" />
46+
<DisplayPluginName v-else-if="field === 'plugin_name'" font-mono :name="event.plugin_name" />
47+
<VDropdown v-else-if="field === 'source' && getSource(event)">
48+
<div i-ph-code />
49+
<template #popper>
50+
<pre p1 text-sm v-text="getSource(event)" />
51+
</template>
52+
</VDropdown>
53+
<DisplayTimestamp v-else-if="field === 'timestamp'" text-sm :timestamp="event.timestamp" />
54+
</td>
55+
</template>
56+
</tr>
57+
</tbody>
58+
</table>
59+
</template>
Lines changed: 48 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import {
4+
getHashColorFromString,
5+
getHsla,
6+
} from '../../utils/color'
7+
8+
const props = withDefaults(
9+
defineProps<{
10+
text?: string
11+
color?: boolean | number
12+
as?: string
13+
size?: string
14+
}>(),
15+
{
16+
color: true,
17+
},
18+
)
19+
20+
const style = computed(() => {
21+
if (!props.text || props.color === false)
22+
return {}
23+
return {
24+
color: typeof props.color === 'number'
25+
? getHsla(props.color)
26+
: getHashColorFromString(props.text),
27+
background: typeof props.color === 'number'
28+
? getHsla(props.color, 0.1)
29+
: getHashColorFromString(props.text, 0.1),
30+
}
31+
})
32+
33+
const sizeClasses = computed(() => {
34+
switch (props.size || 'sm') {
35+
case 'sm':
36+
return 'px-1.5 text-11px leading-1.6em'
37+
}
38+
return ''
39+
})
40+
</script>
41+
42+
<template>
43+
<component :is="as || 'span'" ws-nowrap rounded :class="sizeClasses" :style>
44+
<slot>
45+
<span v-text="props.text" />
46+
</slot>
47+
</component>
48+
</template>
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
<script setup lang="ts">
2+
import { computed } from 'vue'
3+
import { isDark } from '../../composables/dark'
4+
5+
const props = defineProps<{
6+
filename: string
7+
}>()
8+
9+
const map = {
10+
angular: 'i-catppuccin-angular',
11+
vue: 'i-catppuccin-vue',
12+
js: 'i-catppuccin-javascript',
13+
mjs: 'i-catppuccin-javascript',
14+
cjs: 'i-catppuccin-javascript',
15+
ts: 'i-catppuccin-typescript',
16+
mts: 'i-catppuccin-typescript',
17+
cts: 'i-catppuccin-typescript',
18+
md: 'i-catppuccin-markdown',
19+
markdown: 'i-catppuccin-markdown',
20+
mdx: 'i-catppuccin-mdx',
21+
jsx: 'i-catppuccin-javascript-react',
22+
tsx: 'i-catppuccin-typescript-react',
23+
svelte: 'i-catppuccin-svelte',
24+
html: 'i-catppuccin-html',
25+
css: 'i-catppuccin-css',
26+
scss: 'i-catppuccin-css',
27+
less: 'i-catppuccin-less',
28+
json: 'i-catppuccin-json',
29+
yaml: 'i-catppuccin-yaml',
30+
toml: 'i-catppuccin-toml',
31+
svg: 'i-catppuccin-svg',
32+
} as Record<string, string>
33+
34+
const icon = computed(() => {
35+
let file = props.filename
36+
file = file
37+
.replace(/(\?|&)v=[^&]*/, '$1')
38+
.replace(/\?$/, '')
39+
40+
if (file.match(/[\\/]node_modules[\\/]/))
41+
return 'i-catppuccin-folder-node-open'
42+
43+
let ext = (file.split('.').pop() || '').toLowerCase()
44+
let icon = map[ext]
45+
if (icon)
46+
return icon
47+
48+
ext = ext.split('?')[0]
49+
icon = map[ext]
50+
if (icon)
51+
return icon
52+
53+
return 'i-catppuccin-file'
54+
})
55+
</script>
56+
57+
<template>
58+
<div
59+
flex-none
60+
:class="[icon, isDark ? '' : 'brightness-60 hue-rotate-180 invert-100 saturate-200']"
61+
/>
62+
</template>
Lines changed: 170 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,170 @@
1+
<script setup lang="ts">
2+
import { vTooltip } from 'floating-vue'
3+
import { relative } from 'pathe'
4+
import { computed, defineComponent, h } from 'vue'
5+
import { getPluginColor } from '../../utils/color'
6+
7+
const props = withDefaults(
8+
defineProps<{
9+
id?: string
10+
badges?: boolean
11+
icon?: boolean
12+
module?: boolean
13+
}>(),
14+
{
15+
icon: true,
16+
},
17+
)
18+
19+
// const mod = computed(() => payload.modules.find(i => i.id === props.id))
20+
const root = '/Users/antfu/i/vite-devtools/' // TODO: get from cwd
21+
// const isVirtual = computed(() => mod.value?.virtual)
22+
const relativePath = computed(() => {
23+
if (!props.id)
24+
return ''
25+
const id = props.id.replace(/%2F/g, '/')
26+
let relate = relative(root, id)
27+
if (!relate.startsWith('.'))
28+
relate = `./${relate}`
29+
if (relate.startsWith('./'))
30+
return relate
31+
if (relate.match(/^(?:\.\.\/){1,3}[^.]/))
32+
return relate
33+
return id
34+
})
35+
36+
const HighlightedPath = defineComponent({
37+
render() {
38+
const parts = relativePath.value.split(/([/?&:])/g)
39+
let type: 'start' | 'path' | 'query' = 'start'
40+
41+
const classes: string[][] = parts.map(() => [])
42+
const nodes = parts.map((part) => {
43+
return h('span', { class: '' }, part)
44+
})
45+
46+
const removeIndexes = new Set<number>()
47+
48+
parts.forEach((part, index) => {
49+
const _class = classes[index]
50+
if (part === '?')
51+
type = 'query'
52+
53+
if (type === 'start') {
54+
if (part.match(/^\.+$/)) {
55+
_class.push('op50')
56+
}
57+
else if (part === '/') {
58+
_class.push('op50')
59+
}
60+
else if (part !== '/') {
61+
type = 'path'
62+
}
63+
}
64+
65+
if (type === 'path') {
66+
if (part === '/' || part === 'node_modules' || part.match(/^\.\w/)) {
67+
_class.push('op75')
68+
}
69+
if (part === '.pnpm') {
70+
classes[index]?.push('op50')
71+
if (nodes[index])
72+
nodes[index].children = ''
73+
removeIndexes.add(index + 1)
74+
removeIndexes.add(index + 2)
75+
if (nodes[index + 4]?.children === 'node_modules') {
76+
removeIndexes.add(index + 3)
77+
removeIndexes.add(index + 4)
78+
}
79+
}
80+
if (part === ':') {
81+
if (nodes[index - 1]) {
82+
nodes[index - 1].props ||= {}
83+
nodes[index - 1].props!.style ||= {}
84+
nodes[index - 1].props!.style.color = getPluginColor(parts[index - 1])
85+
}
86+
_class.push('op50')
87+
}
88+
if (parts[index - 2] === 'node_modules' && !part.startsWith('.')) {
89+
_class.push('text-purple-5 dark:text-purple-4')
90+
}
91+
}
92+
93+
if (type === 'query') {
94+
if (part === '?' || part === '&') {
95+
_class.push('text-orange-5 dark:text-orange-4')
96+
}
97+
else {
98+
_class.push('text-orange-9 dark:text-orange-2')
99+
}
100+
}
101+
})
102+
103+
nodes.forEach((node, index) => {
104+
if (node.props)
105+
node.props.class = classes[index].join(' ')
106+
})
107+
108+
Array.from(removeIndexes)
109+
.sort((a, b) => b - a)
110+
.forEach((index) => {
111+
nodes.splice(index, 1)
112+
classes.splice(index, 1)
113+
})
114+
115+
return nodes
116+
},
117+
})
118+
119+
const gridStyles = computed(() => {
120+
if (!props.module)
121+
return ''
122+
123+
const gridColumns: string[] = []
124+
if (props.icon)
125+
gridColumns.push('min-content')
126+
127+
if (props.module)
128+
gridColumns.push('minmax(0,1fr)')
129+
else
130+
gridColumns.push('100%')
131+
132+
// todo: handle slot, not being used
133+
134+
if (isVirtual.value)
135+
gridColumns.push('min-content')
136+
137+
return `grid-template-columns: ${gridColumns.join(' ')};`
138+
})
139+
const containerClass = computed(() => {
140+
return props.module
141+
? 'grid grid-rows-1 items-center gap-1'
142+
: 'flex items-center'
143+
})
144+
</script>
145+
146+
<template>
147+
<div
148+
v-if="id"
149+
v-tooltip.bottom-start="{
150+
content: props.id,
151+
triggers: ['hover', 'focus'],
152+
disabled: !module,
153+
}"
154+
my-auto text-sm font-mono
155+
:class="containerClass"
156+
:style="gridStyles"
157+
>
158+
<DisplayFileIcon v-if="icon" :filename="id" mr1.5 />
159+
<span :class="{ 'overflow-hidden': module, 'text-truncate': module }">
160+
<HighlightedPath />
161+
</span>
162+
<slot />
163+
164+
<!-- <DisplayBadge
165+
v-if="isVirtual"
166+
class="ml1"
167+
text="virtual"
168+
/> -->
169+
</div>
170+
</template>

0 commit comments

Comments
 (0)