vite-plugin-specter 0.6.0 → 0.6.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +64 -41
- package/dist/client.js +6 -2
- package/dist/extension-chrome/content.js +6 -2
- package/dist/extension-chrome/manifest.json +1 -1
- package/dist/extension-firefox/content.js +6 -2
- package/dist/extension-firefox/manifest.json +1 -1
- package/dist/index.cjs +6 -2
- package/dist/index.js +6 -2
- package/extension/content.js +6 -2
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
# Specter
|
|
2
2
|
|
|
3
|
-
**
|
|
3
|
+
**Point at any element on your dev site. Mark what to change — with exact values and a source anchor — and hand it to your AI.**
|
|
4
4
|
|
|
5
|
-
Specter is a Vite plugin that
|
|
5
|
+
Specter is a Vite plugin that overlays an element inspector on your dev server. Hover any element to see its styles, component name, and spacing; measure gaps Figma-style; mark elements as **Specs** with a plain-language note; then copy them all to your AI assistant — each one carries the exact current values and a greppable source anchor, so there's no "which element?" and no "what's the current value?". Optionally, push your Specs straight into Claude Code with `/spectify`. Specter is automatically stripped from production builds.
|
|
6
6
|
|
|
7
7
|
## Requirements
|
|
8
8
|
|
|
@@ -46,51 +46,71 @@ If you ever need Specter gone entirely, remove `specter()` from the Vite config
|
|
|
46
46
|
|
|
47
47
|
### Toggle on/off
|
|
48
48
|
|
|
49
|
-
Press **Ctrl+Option+Z** to
|
|
49
|
+
Press **Ctrl+Option+Z** to activate Specter. A small zap icon appears at the bottom-left. Press again (or **Esc**) to hide it — your Specs are kept and reappear when you reactivate.
|
|
50
50
|
|
|
51
|
-
###
|
|
51
|
+
### Three modes
|
|
52
52
|
|
|
53
|
-
|
|
53
|
+
Specter has three modes; switching mode only changes *what's shown on screen* — you can mark a Spec in any of them.
|
|
54
|
+
|
|
55
|
+
| Mode | Enter | Shows |
|
|
56
|
+
|------|-------|-------|
|
|
57
|
+
| **Properties** (default) | — | Styles tooltip on hover |
|
|
58
|
+
| **Measure** | tap **Option** | Figma-style spacing to neighbors |
|
|
59
|
+
| **Comment** | **C** | Just an outline — for clean design review |
|
|
60
|
+
|
|
61
|
+
### Inspect an element (Properties mode)
|
|
62
|
+
|
|
63
|
+
**Hover** any element. A tooltip shows:
|
|
54
64
|
|
|
55
65
|
- HTML tag + React/Vue component name + dimensions
|
|
56
66
|
- Text content (truncated)
|
|
57
67
|
- Font: family, weight, size, line-height
|
|
58
|
-
- Color (with hex) and background
|
|
68
|
+
- Color (with hex) and background — flagged `(hover)` if the value comes from a `:hover` rule
|
|
59
69
|
- Padding, margin, border-radius (if non-zero)
|
|
60
70
|
- Display + gap + flex direction
|
|
61
71
|
|
|
62
|
-
###
|
|
72
|
+
### Measure spacing (Measure mode)
|
|
73
|
+
|
|
74
|
+
Tap **Option** to switch to Measure mode. Hover any element to see distances to its surrounding neighbors. Press **M** while hovering to **pin** that element, then hover another to measure the gap or inset between the two; **M** again unpins. Tap **Option** again to return to Properties.
|
|
63
75
|
|
|
64
|
-
|
|
76
|
+
### Mark a Spec (and optionally annotate)
|
|
65
77
|
|
|
66
|
-
|
|
78
|
+
Press **P** while hovering an element to mark it as a **Spec**. A note box opens on the element — type the change you want ("reduce width to 320", "tighten padding to 8px") and press **Enter**, or just leave it empty for a plain mark. Numbered badges appear on each marked element. Mark as many as you like across the page.
|
|
67
79
|
|
|
68
|
-
|
|
80
|
+
### Comment mode
|
|
69
81
|
|
|
70
|
-
|
|
82
|
+
Press **C** for Comment mode: the props/measure overlays hide and you get just a hover outline — good for talking through a design without visual noise. Specs still capture full properties underneath, so a Comment-mode Spec copies exactly like any other.
|
|
71
83
|
|
|
72
|
-
|
|
84
|
+
### Specs side panel
|
|
73
85
|
|
|
74
|
-
|
|
86
|
+
Press **L** to open the Specs review panel. It lists every Spec; hover a row to scroll to and highlight its element; edit or delete notes inline. Specs survive a reload (saved to `localStorage` per URL).
|
|
75
87
|
|
|
76
|
-
|
|
88
|
+
### Copy to your AI
|
|
77
89
|
|
|
78
|
-
|
|
90
|
+
Press **Cmd+C**:
|
|
79
91
|
|
|
80
|
-
|
|
92
|
+
- **With Specs marked** → copies **all** of them at once. Each block leads with your `✏️ CHANGE:` note (if any).
|
|
93
|
+
- **With nothing marked** → copies the hovered element's properties (or, in Measure mode, the measurement).
|
|
81
94
|
|
|
82
|
-
|
|
95
|
+
The copied format is lean and AI-ready — the current values plus a `find:` line that anchors the element in your source (test-id → id → aria-label → unique text → class → CSS path), so the assistant greps straight to the code:
|
|
83
96
|
|
|
84
97
|
```
|
|
85
|
-
[Specter 1/
|
|
86
|
-
✏️ CHANGE:
|
|
87
|
-
<button
|
|
88
|
-
|
|
89
|
-
padding: 12px 20px
|
|
90
|
-
|
|
98
|
+
[Specter 1/2]
|
|
99
|
+
✏️ CHANGE: tighten the vertical padding to 8px
|
|
100
|
+
<button> .btn-primary "Book a demo" 200×48
|
|
101
|
+
find: .btn-primary
|
|
102
|
+
font: Inter 600 14/20 · color: #fff · bg: #4f46e5 · padding: 12px 20px · radius: 10px · display: inline-flex
|
|
103
|
+
|
|
104
|
+
---
|
|
105
|
+
|
|
106
|
+
[Specter 2/2]
|
|
107
|
+
✏️ CHANGE: make this text darker — it fails contrast
|
|
108
|
+
<p> .hero-sub "Analytics that…" 560×57
|
|
109
|
+
find: .hero-sub
|
|
110
|
+
font: Inter 400 19/28.5 · color: #c7cbd1
|
|
91
111
|
```
|
|
92
112
|
|
|
93
|
-
|
|
113
|
+
Paste into Claude, Cursor, or any AI assistant — the instructions travel with the elements, so there's nothing left to explain.
|
|
94
114
|
|
|
95
115
|
## Shortcut reference
|
|
96
116
|
|
|
@@ -98,36 +118,39 @@ So when you paste into your AI assistant, it already knows both *what* to change
|
|
|
98
118
|
|--------|----------|
|
|
99
119
|
| Toggle Specter | **Ctrl+Option+Z** |
|
|
100
120
|
| Inspect element | Hover (while active) |
|
|
101
|
-
|
|
|
102
|
-
|
|
|
103
|
-
|
|
|
104
|
-
|
|
|
105
|
-
|
|
|
106
|
-
|
|
|
107
|
-
|
|
|
121
|
+
| Mark a Spec (+ optional note) | **P** |
|
|
122
|
+
| Copy (all Specs, or hovered element) | **Cmd+C** |
|
|
123
|
+
| Measure mode (toggle) | **Option** (tap) |
|
|
124
|
+
| Pin / unpin for measuring | **M** (in Measure mode) |
|
|
125
|
+
| Comment mode (toggle) | **C** |
|
|
126
|
+
| Specs panel (toggle) | **L** |
|
|
127
|
+
| Close panel / hide Specter | **Esc** |
|
|
108
128
|
|
|
109
|
-
##
|
|
129
|
+
## Optional: push Specs straight to Claude Code (`/spectify`)
|
|
130
|
+
|
|
131
|
+
Instead of copy-paste, Specter can auto-sync your Specs to a local bridge that Claude Code reads on demand. Enable it in your Vite config:
|
|
132
|
+
|
|
133
|
+
```ts
|
|
134
|
+
specter({ claudeBridge: true })
|
|
135
|
+
```
|
|
110
136
|
|
|
111
|
-
1.
|
|
112
|
-
2. Hover the element you want to change
|
|
113
|
-
3. Either press **Cmd+C** to copy its properties, or press **N** to annotate the exact change you want first
|
|
114
|
-
4. Repeat **N** on every element you want to change, then **Cmd+C** once to copy them all
|
|
115
|
-
5. Paste into your AI assistant's chat — the instructions travel with the elements, so there's nothing left to explain
|
|
137
|
+
With it on, every Spec you mark auto-syncs (watch for the sync dot in the panel) to a local bridge at `http://127.0.0.1:8787`. Run the bridge (`node node_modules/vite-plugin-specter/mcp-bridge/server.mjs`, or register it in your project's `.mcp.json` so your IDE launches it), then in Claude Code run **`/spectify`** — it pulls whatever's currently synced and implements it. See [`mcp-bridge/`](https://github.com/setugk/vite-plugin-specter/tree/main/mcp-bridge) for setup. One bridge can serve several projects; `/spectify <port>` scopes to one.
|
|
116
138
|
|
|
117
|
-
|
|
139
|
+
`claudeBridge` is **off by default** — the shipped plugin never opens a connection unless you enable it.
|
|
118
140
|
|
|
119
141
|
## Configuration
|
|
120
142
|
|
|
121
143
|
```ts
|
|
122
|
-
specter()
|
|
123
|
-
specter({ shortcuts: { activate: 'ctrl+shift+i' } })
|
|
144
|
+
specter() // defaults
|
|
145
|
+
specter({ shortcuts: { activate: 'ctrl+shift+i' } }) // custom activate shortcut
|
|
146
|
+
specter({ claudeBridge: true }) // enable the Claude Code bridge
|
|
124
147
|
```
|
|
125
148
|
|
|
126
149
|
The `activate` shortcut accepts any combination of `ctrl`, `alt`, `shift`, `meta`/`cmd`, and a key. Default is `ctrl+alt+z`.
|
|
127
150
|
|
|
128
151
|
## Optional: `data-style` attribute
|
|
129
152
|
|
|
130
|
-
Tag elements with `data-style="keyName"` to
|
|
153
|
+
Tag elements with `data-style="keyName"` to surface the style-object key in the inspector and the copied output:
|
|
131
154
|
|
|
132
155
|
```jsx
|
|
133
156
|
<h1 data-style="pageTitle">Welcome</h1>
|
package/dist/client.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
var TIP_BG = '#292B32';
|
|
15
15
|
var GREEN = '#22C55E';
|
|
16
16
|
var LABEL = '#8B8D94';
|
|
17
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
17
18
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
18
19
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
19
20
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1326,9 +1327,10 @@
|
|
|
1326
1327
|
badge.textContent = String(i + 1);
|
|
1327
1328
|
Object.assign(badge.style, {
|
|
1328
1329
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1329
|
-
background:
|
|
1330
|
-
border: '
|
|
1330
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1331
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1331
1332
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1333
|
+
transition: 'background 0.12s ease',
|
|
1332
1334
|
});
|
|
1333
1335
|
var content = document.createElement('div');
|
|
1334
1336
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1450,12 +1452,14 @@
|
|
|
1450
1452
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1451
1453
|
row.addEventListener('mouseenter', function () {
|
|
1452
1454
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1455
|
+
badge.style.background = PURPLE;
|
|
1453
1456
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1454
1457
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1455
1458
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1456
1459
|
});
|
|
1457
1460
|
row.addEventListener('mouseleave', function () {
|
|
1458
1461
|
row.style.background = 'transparent';
|
|
1462
|
+
badge.style.background = BADGE_IDLE;
|
|
1459
1463
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1460
1464
|
actions.style.background = 'transparent';
|
|
1461
1465
|
if (highlightSpec === spec) highlightSpec = null;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
var TIP_BG = '#292B32';
|
|
15
15
|
var GREEN = '#22C55E';
|
|
16
16
|
var LABEL = '#8B8D94';
|
|
17
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
17
18
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
18
19
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
19
20
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1326,9 +1327,10 @@
|
|
|
1326
1327
|
badge.textContent = String(i + 1);
|
|
1327
1328
|
Object.assign(badge.style, {
|
|
1328
1329
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1329
|
-
background:
|
|
1330
|
-
border: '
|
|
1330
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1331
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1331
1332
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1333
|
+
transition: 'background 0.12s ease',
|
|
1332
1334
|
});
|
|
1333
1335
|
var content = document.createElement('div');
|
|
1334
1336
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1450,12 +1452,14 @@
|
|
|
1450
1452
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1451
1453
|
row.addEventListener('mouseenter', function () {
|
|
1452
1454
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1455
|
+
badge.style.background = PURPLE;
|
|
1453
1456
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1454
1457
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1455
1458
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1456
1459
|
});
|
|
1457
1460
|
row.addEventListener('mouseleave', function () {
|
|
1458
1461
|
row.style.background = 'transparent';
|
|
1462
|
+
badge.style.background = BADGE_IDLE;
|
|
1459
1463
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1460
1464
|
actions.style.background = 'transparent';
|
|
1461
1465
|
if (highlightSpec === spec) highlightSpec = null;
|
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
var TIP_BG = '#292B32';
|
|
15
15
|
var GREEN = '#22C55E';
|
|
16
16
|
var LABEL = '#8B8D94';
|
|
17
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
17
18
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
18
19
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
19
20
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1326,9 +1327,10 @@
|
|
|
1326
1327
|
badge.textContent = String(i + 1);
|
|
1327
1328
|
Object.assign(badge.style, {
|
|
1328
1329
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1329
|
-
background:
|
|
1330
|
-
border: '
|
|
1330
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1331
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1331
1332
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1333
|
+
transition: 'background 0.12s ease',
|
|
1332
1334
|
});
|
|
1333
1335
|
var content = document.createElement('div');
|
|
1334
1336
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1450,12 +1452,14 @@
|
|
|
1450
1452
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1451
1453
|
row.addEventListener('mouseenter', function () {
|
|
1452
1454
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1455
|
+
badge.style.background = PURPLE;
|
|
1453
1456
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1454
1457
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1455
1458
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1456
1459
|
});
|
|
1457
1460
|
row.addEventListener('mouseleave', function () {
|
|
1458
1461
|
row.style.background = 'transparent';
|
|
1462
|
+
badge.style.background = BADGE_IDLE;
|
|
1459
1463
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1460
1464
|
actions.style.background = 'transparent';
|
|
1461
1465
|
if (highlightSpec === spec) highlightSpec = null;
|
package/dist/index.cjs
CHANGED
|
@@ -46,6 +46,7 @@ function getClientScript(options) {
|
|
|
46
46
|
var TIP_BG = '#292B32';
|
|
47
47
|
var GREEN = '#22C55E';
|
|
48
48
|
var LABEL = '#8B8D94';
|
|
49
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
49
50
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
50
51
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
51
52
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1358,9 +1359,10 @@ function getClientScript(options) {
|
|
|
1358
1359
|
badge.textContent = String(i + 1);
|
|
1359
1360
|
Object.assign(badge.style, {
|
|
1360
1361
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1361
|
-
background:
|
|
1362
|
-
border: '
|
|
1362
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1363
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1363
1364
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1365
|
+
transition: 'background 0.12s ease',
|
|
1364
1366
|
});
|
|
1365
1367
|
var content = document.createElement('div');
|
|
1366
1368
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1482,12 +1484,14 @@ function getClientScript(options) {
|
|
|
1482
1484
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1483
1485
|
row.addEventListener('mouseenter', function () {
|
|
1484
1486
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1487
|
+
badge.style.background = PURPLE;
|
|
1485
1488
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1486
1489
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1487
1490
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1488
1491
|
});
|
|
1489
1492
|
row.addEventListener('mouseleave', function () {
|
|
1490
1493
|
row.style.background = 'transparent';
|
|
1494
|
+
badge.style.background = BADGE_IDLE;
|
|
1491
1495
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1492
1496
|
actions.style.background = 'transparent';
|
|
1493
1497
|
if (highlightSpec === spec) highlightSpec = null;
|
package/dist/index.js
CHANGED
|
@@ -19,6 +19,7 @@ function getClientScript(options) {
|
|
|
19
19
|
var TIP_BG = '#292B32';
|
|
20
20
|
var GREEN = '#22C55E';
|
|
21
21
|
var LABEL = '#8B8D94';
|
|
22
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
22
23
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
23
24
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
24
25
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1331,9 +1332,10 @@ function getClientScript(options) {
|
|
|
1331
1332
|
badge.textContent = String(i + 1);
|
|
1332
1333
|
Object.assign(badge.style, {
|
|
1333
1334
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1334
|
-
background:
|
|
1335
|
-
border: '
|
|
1335
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1336
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1336
1337
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1338
|
+
transition: 'background 0.12s ease',
|
|
1337
1339
|
});
|
|
1338
1340
|
var content = document.createElement('div');
|
|
1339
1341
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1455,12 +1457,14 @@ function getClientScript(options) {
|
|
|
1455
1457
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1456
1458
|
row.addEventListener('mouseenter', function () {
|
|
1457
1459
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1460
|
+
badge.style.background = PURPLE;
|
|
1458
1461
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1459
1462
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1460
1463
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1461
1464
|
});
|
|
1462
1465
|
row.addEventListener('mouseleave', function () {
|
|
1463
1466
|
row.style.background = 'transparent';
|
|
1467
|
+
badge.style.background = BADGE_IDLE;
|
|
1464
1468
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1465
1469
|
actions.style.background = 'transparent';
|
|
1466
1470
|
if (highlightSpec === spec) highlightSpec = null;
|
package/extension/content.js
CHANGED
|
@@ -14,6 +14,7 @@
|
|
|
14
14
|
var TIP_BG = '#292B32';
|
|
15
15
|
var GREEN = '#22C55E';
|
|
16
16
|
var LABEL = '#8B8D94';
|
|
17
|
+
var BADGE_IDLE = '#6B6D75'; // panel row-number badges sit greyscale; the hovered row's badge colors to PURPLE
|
|
17
18
|
var MONO = "'JetBrains Mono', 'SF Mono', 'Fira Code', monospace";
|
|
18
19
|
var ZAP = '<svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2.5" stroke-linecap="round" stroke-linejoin="round"><polygon points="13 2 3 14 12 14 11 22 21 10 12 10 13 2"></polygon></svg>';
|
|
19
20
|
var PENCIL = '<svg width="13" height="13" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M21.174 6.812a1 1 0 0 0-3.986-3.987L3.842 16.174a2 2 0 0 0-.5.83l-1.321 4.352a.5.5 0 0 0 .623.622l4.353-1.32a2 2 0 0 0 .83-.497z"></path><path d="m15 5 4 4"></path></svg>';
|
|
@@ -1326,9 +1327,10 @@
|
|
|
1326
1327
|
badge.textContent = String(i + 1);
|
|
1327
1328
|
Object.assign(badge.style, {
|
|
1328
1329
|
flexShrink: '0', width: '20px', height: '20px', borderRadius: '999px',
|
|
1329
|
-
background:
|
|
1330
|
-
border: '
|
|
1330
|
+
background: BADGE_IDLE, color: '#fff', fontSize: '11px', fontWeight: '700',
|
|
1331
|
+
border: '1px solid #fff', boxSizing: 'border-box',
|
|
1331
1332
|
display: 'flex', alignItems: 'center', justifyContent: 'center',
|
|
1333
|
+
transition: 'background 0.12s ease',
|
|
1332
1334
|
});
|
|
1333
1335
|
var content = document.createElement('div');
|
|
1334
1336
|
Object.assign(content.style, { flex: '1', minWidth: '0', display: 'flex', flexDirection: 'column', gap: '6px', paddingRight: '30px' });
|
|
@@ -1450,12 +1452,14 @@
|
|
|
1450
1452
|
note.addEventListener('click', function (e) { if (spec.note) { e.stopPropagation(); spec._expanded = !spec._expanded; renderPanel(); } });
|
|
1451
1453
|
row.addEventListener('mouseenter', function () {
|
|
1452
1454
|
row.style.background = 'rgba(255,255,255,0.05)';
|
|
1455
|
+
badge.style.background = PURPLE;
|
|
1453
1456
|
editBtn.style.display = delBtn.style.display = 'flex';
|
|
1454
1457
|
actions.style.background = 'linear-gradient(to right, rgba(52,54,60,0) 0, rgba(52,54,60,1) 22px)';
|
|
1455
1458
|
if (visible) { highlightSpec = spec; revealSpec(spec); }
|
|
1456
1459
|
});
|
|
1457
1460
|
row.addEventListener('mouseleave', function () {
|
|
1458
1461
|
row.style.background = 'transparent';
|
|
1462
|
+
badge.style.background = BADGE_IDLE;
|
|
1459
1463
|
editBtn.style.display = delBtn.style.display = 'none';
|
|
1460
1464
|
actions.style.background = 'transparent';
|
|
1461
1465
|
if (highlightSpec === spec) highlightSpec = null;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "vite-plugin-specter",
|
|
3
|
-
"version": "0.6.
|
|
3
|
+
"version": "0.6.1",
|
|
4
4
|
"description": "Inspect elements and Figma-style measure spacing in your vibe-coded Vite projects. Give your AI exactly what it needs to make the right change.",
|
|
5
5
|
"author": "Setu Kathawate <dev@setugk.com>",
|
|
6
6
|
"homepage": "https://github.com/setugk/vite-plugin-specter#readme",
|