Skip to content

Commit 5af7e9a

Browse files
authored
refactor(ui): migrate devtools panel to shadcn-vue (#12)
* refactor(ui): migrate devtools panel to shadcn-vue * fix(ui): restore locale toggle and diff styling * fix(ui): scroll diff table container to top * fix(ui): pin locale and theme controls top right * fix(ui): use locale selector for language control * fix(ui): prevent page scrollbar flicker * docs: update screenshot * fix(ui): strengthen diff row contrast * fix(ui): highlight second diff value * fix(ui): open header info on click * refactor(ui): redesign diff workspace * fix(ui): remove filter highlight spacing * fix(ui): mark missing diff values on both sides * fix(ui): center empty table state * feat(ui): remove individual selections * fix(ui): align header control sizes * refactor(ui): compact selected element headers * fix(ui): clear diffs after removing synced selection * fix(ui): unify compact control sizing * refactor(ui): remove back to top control * feat(ui): show logo in panel header * fix(ui): use neutral language switch icon * fix(lint): add node import resolver * fix(ui): default theme to system preference * fix(ui): keep detail labels on one line * docs: update screenshot * fix(i18n): localize missing css values * fix(review): address remaining codex feedback
1 parent 08578f9 commit 5af7e9a

45 files changed

Lines changed: 5053 additions & 2561 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

‎.gitignore‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ stats.html
1313
stats-*.json
1414
.wxt
1515
web-ext.config.ts
16+
.superpowers/
1617
coverage
1718
playwright-report
1819
test-results

‎AGENTS.md‎

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@ Guidance for coding agents working in this repository.
1010

1111
- Package manager: `pnpm` (`packageManager` is `pnpm@9.14.1`).
1212
- Extension framework: WXT.
13-
- UI: Vue 3 single-file components with Element Plus and Tailwind CSS.
13+
- UI: Vue 3 single-file components with shadcn-vue style components, Reka UI primitives, and Tailwind CSS v4.
1414
- Localization: WXT/browser `i18n` messages under `public/_locales`.
1515
- Language: TypeScript with Vue type checking through `vue-tsc`.
1616
- Formatting and linting: ESLint 9 with `@antfu/eslint-config`; Prettier is intentionally disabled in VS Code.
@@ -27,7 +27,7 @@ Guidance for coding agents working in this repository.
2727
-`entrypoints/devtools-panel/lang.ts`: typed wrapper around `browser.i18n.getMessage`.
2828
-`public/_locales/en/messages.json`: English extension and panel messages.
2929
-`public/_locales/zh_CN/messages.json`: Simplified Chinese extension and panel messages.
30-
-`assets/main.css`: Tailwind CSS v4 import and small global Element Plus table overrides.
30+
-`assets/main.css`: Tailwind CSS v4 import, shadcn design tokens, theme variables, and global panel styles.
3131
-`public/icon/`: extension icons.
3232
-`.github/renovate.json5`: dependency update policy.
3333

@@ -69,7 +69,7 @@ There is no dedicated `lint` or `format` script in `package.json`; use ESLint di
6969
- Keep Vue component state and browser interaction logic in composables such as `useDevToolsPanel`.
7070
- Keep pure data helpers in `entrypoints/devtools-panel/utils/`.
7171
- Preserve the existing i18n structure by updating both `public/_locales/en/messages.json` and `public/_locales/zh_CN/messages.json` when adding user-visible strings.
72-
- Use Element Plus components consistently with the existing DevTools panel UI.
72+
- Use local `components/ui/*` shadcn-vue style components for controls.
7373
- Use Tailwind utility classes for layout and small style adjustments.
7474
- The existing code relies on WXT/browser extension globals such as `browser`; do not replace them with unrelated APIs without a compatibility reason.
7575

@@ -84,7 +84,7 @@ There is no dedicated `lint` or `format` script in `package.json`; use ESLint di
8484
- Computed styles are normalized by `formatStyle` before comparison.
8585
- Selected elements are compared as `left` and `right`; a third selection is ignored until the current selection is cleared.
8686
- Cross-window/tab synchronization is handled by broadcasting through `browser.tabs.sendMessage`.
87-
- Table rows use color classes to distinguish changed and unchanged CSS properties, and clicking a value cell copies `property: value;`.
87+
- Table rows use monochrome emphasis to distinguish changed and unchanged CSS properties, and clicking a value cell copies `property: value;`.
8888

8989
## Pull Request Expectations
9090

‎assets/main.css‎

Lines changed: 95 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,100 @@
11
@import"tailwindcss";
22

3-
body {
4-
padding:16px;
5-
overflow-x: hidden;
6-
overflow-y: scroll;
3+
@source"../entrypoints";
4+
@source"../components";
5+
@source"../lib";
6+
7+
@custom-variant dark (&:where(.dark, .dark*));
8+
9+
@theme inline {
10+
--color-background:hsl(var(--background));
11+
--color-foreground:hsl(var(--foreground));
12+
--color-popover:hsl(var(--popover));
13+
--color-popover-foreground:hsl(var(--popover-foreground));
14+
--color-primary:hsl(var(--primary));
15+
--color-primary-foreground:hsl(var(--primary-foreground));
16+
--color-secondary:hsl(var(--secondary));
17+
--color-secondary-foreground:hsl(var(--secondary-foreground));
18+
--color-muted:hsl(var(--muted));
19+
--color-muted-foreground:hsl(var(--muted-foreground));
20+
--color-accent:hsl(var(--accent));
21+
--color-accent-foreground:hsl(var(--accent-foreground));
22+
--color-destructive:hsl(var(--destructive));
23+
--color-destructive-foreground:hsl(var(--destructive-foreground));
24+
--color-border:hsl(var(--border));
25+
--color-input:hsl(var(--input));
26+
--color-ring:hsl(var(--ring));
27+
--radius-lg:var(--radius);
28+
--radius-md:calc(var(--radius) -2px);
29+
--radius-sm:calc(var(--radius) -4px);
30+
}
31+
32+
@layer base {
33+
:root {
34+
--background:00%100%;
35+
--foreground:00%3.9%;
36+
--popover:00%100%;
37+
--popover-foreground:00%3.9%;
38+
--primary:00%9%;
39+
--primary-foreground:00%98%;
40+
--secondary:00%96.1%;
41+
--secondary-foreground:00%9%;
42+
--muted:00%96.1%;
43+
--muted-foreground:00%45.1%;
44+
--accent:00%96.1%;
45+
--accent-foreground:00%9%;
46+
--destructive:00%9%;
47+
--destructive-foreground:00%98%;
48+
--border:00%89.8%;
49+
--input:00%89.8%;
50+
--ring:00%3.9%;
51+
--radius:0.5rem;
52+
}
53+
54+
.dark {
55+
--background:00%3.9%;
56+
--foreground:00%98%;
57+
--popover:00%3.9%;
58+
--popover-foreground:00%98%;
59+
--primary:00%98%;
60+
--primary-foreground:00%9%;
61+
--secondary:00%14.9%;
62+
--secondary-foreground:00%98%;
63+
--muted:00%14.9%;
64+
--muted-foreground:00%63.9%;
65+
--accent:00%14.9%;
66+
--accent-foreground:00%98%;
67+
--destructive:00%98%;
68+
--destructive-foreground:00%9%;
69+
--border:00%14.9%;
70+
--input:00%14.9%;
71+
--ring:00%83.1%;
72+
}
73+
74+
* {
75+
@apply border-border;
76+
}
77+
78+
html {
79+
color-scheme: light;
80+
}
81+
82+
html.dark {
83+
color-scheme: dark;
84+
}
85+
86+
body {
87+
@apply bg-background text-foreground antialiased;
88+
min-width:0;
89+
margin:0;
90+
padding:16px;
91+
overflow-y: hidden;
92+
}
793
}
894

9-
.el-table--enable-row-hover .el-table__bodytr:hover>td.el-table__cell{
10-
background-color: inherit !important;
95+
@layer utilities {
96+
.css-diff-scrollbar {
97+
scrollbar-color:hsl(var(--muted-foreground) /0.35) transparent;
98+
scrollbar-width: thin;
99+
}
11100
}

‎components.json‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
{
2+
"$schema": "https://shadcn-vue.com/schema.json",
3+
"style": "new-york",
4+
"typescript": true,
5+
"tailwind": {
6+
"config": "",
7+
"css": "assets/main.css",
8+
"baseColor": "neutral",
9+
"cssVariables": true,
10+
"prefix": ""
11+
},
12+
"aliases": {
13+
"components": "@/components",
14+
"composables": "@/composables",
15+
"utils": "@/lib/utils",
16+
"ui": "@/components/ui",
17+
"lib": "@/lib"
18+
},
19+
"iconLibrary": "lucide"
20+
}

‎components/ui/button/Button.vue‎

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
<script setup lang="ts">
2+
importtype { HTMLAttributes } from'vue'
3+
import { Primitive, typePrimitiveProps } from'reka-ui'
4+
import { cn } from'@/lib/utils'
5+
import { buttonVariants, typeButtonVariants } from'.'
6+
7+
interfacePropsextendsPrimitiveProps {
8+
variant?:ButtonVariants['variant']
9+
size?:ButtonVariants['size']
10+
class?:HTMLAttributes['class']
11+
}
12+
13+
const props =withDefaults(defineProps<Props>(), {
14+
as: 'button',
15+
})
16+
</script>
17+
18+
<template>
19+
<Primitive
20+
:as="props.as"
21+
:as-child="props.asChild"
22+
:class="cn(buttonVariants({ variant: props.variant, size: props.size }), props.class)"
23+
>
24+
<slot />
25+
</Primitive>
26+
</template>

‎components/ui/button/index.ts‎

Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
import{cva,typeVariantProps}from'class-variance-authority'
2+
3+
export{defaultasButton}from'./Button.vue'
4+
5+
exportconstbuttonVariants=cva(
6+
'inline-flex items-center justify-center gap-2 whitespace-nowrap rounded-md text-sm font-medium transition-colors focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:pointer-events-none disabled:opacity-50 [&_svg]:pointer-events-none [&_svg]:size-4 [&_svg]:shrink-0',
7+
{
8+
variants: {
9+
variant: {
10+
default: 'bg-primary text-primary-foreground shadow hover:bg-primary/90',
11+
destructive: 'bg-destructive text-destructive-foreground shadow-sm hover:bg-destructive/90',
12+
outline: 'border border-input bg-background shadow-sm hover:bg-accent hover:text-accent-foreground',
13+
secondary: 'bg-secondary text-secondary-foreground shadow-sm hover:bg-secondary/80',
14+
ghost: 'hover:bg-accent hover:text-accent-foreground',
15+
},
16+
size: {
17+
default: 'h-9 px-4 py-2',
18+
sm: 'h-8 rounded-md px-3 text-xs',
19+
icon: 'h-8 w-8',
20+
},
21+
},
22+
defaultVariants: {
23+
variant: 'default',
24+
size: 'default',
25+
},
26+
},
27+
)
28+
29+
exporttypeButtonVariants=VariantProps<typeofbuttonVariants>
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
<script setup lang="ts">
2+
importtype { HTMLAttributes } from'vue'
3+
import { Check } from'lucide-vue-next'
4+
import { CheckboxIndicator, CheckboxRoot } from'reka-ui'
5+
import { cn } from'@/lib/utils'
6+
7+
const props =defineProps<{
8+
class?:HTMLAttributes['class']
9+
}>()
10+
11+
const checked =defineModel<boolean|'indeterminate'>('checked')
12+
</script>
13+
14+
<template>
15+
<CheckboxRoot
16+
v-model:checked="checked"
17+
:class="cn('peer h-4 w-4 shrink-0 rounded border border-primary shadow focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50 data-[state=checked]:bg-primary data-[state=checked]:text-primary-foreground', props.class)"
18+
>
19+
<CheckboxIndicator class="flex items-center justify-center text-current">
20+
<Check class="h-3.5 w-3.5" />
21+
</CheckboxIndicator>
22+
</CheckboxRoot>
23+
</template>

‎components/ui/checkbox/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export{defaultasCheckbox}from'./Checkbox.vue'

‎components/ui/input/Input.vue‎

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
<script setup lang="ts">
2+
importtype { HTMLAttributes } from'vue'
3+
import { cn } from'@/lib/utils'
4+
5+
const props =defineProps<{
6+
class?:HTMLAttributes['class']
7+
}>()
8+
9+
const modelValue =defineModel<string|number>()
10+
</script>
11+
12+
<template>
13+
<input
14+
v-model="modelValue"
15+
:class="cn('flex h-9 w-full rounded-md border border-input bg-transparent px-3 py-1 text-sm shadow-sm transition-colors placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-1 focus-visible:ring-ring disabled:cursor-not-allowed disabled:opacity-50', props.class)"
16+
>
17+
</template>

‎components/ui/input/index.ts‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export{defaultasInput}from'./Input.vue'

0 commit comments

Comments
 (0)