sonance-brand-mcp 1.3.72 → 1.3.74
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.
|
@@ -569,7 +569,7 @@ function searchFilesSmart(
|
|
|
569
569
|
results.set(foundPath, {
|
|
570
570
|
path: foundPath,
|
|
571
571
|
content,
|
|
572
|
-
score:
|
|
572
|
+
score: 1500, // HIGHEST priority - component name matched visible text
|
|
573
573
|
filenameMatch: true
|
|
574
574
|
});
|
|
575
575
|
debugLog("Phase 2a: Found file by component name", { componentName, foundPath });
|
|
@@ -565,7 +565,7 @@ function searchFilesSmart(
|
|
|
565
565
|
results.set(foundPath, {
|
|
566
566
|
path: foundPath,
|
|
567
567
|
content,
|
|
568
|
-
score:
|
|
568
|
+
score: 1500, // HIGHEST priority - component name matched visible text
|
|
569
569
|
filenameMatch: true
|
|
570
570
|
});
|
|
571
571
|
debugLog("Phase 2a: Found file by component name", { componentName, foundPath });
|
|
@@ -271,6 +271,12 @@ export function SonanceDevTools() {
|
|
|
271
271
|
// Check if session is recent (< 1 hour old)
|
|
272
272
|
const MAX_SESSION_AGE = 60 * 60 * 1000; // 1 hour
|
|
273
273
|
if (session.timestamp && Date.now() - session.timestamp < MAX_SESSION_AGE) {
|
|
274
|
+
// Validate session has actual modifications
|
|
275
|
+
if (!session.modifications || session.modifications.length === 0) {
|
|
276
|
+
console.log("[Apply-First] Session has no modifications, auto-clearing:", session.sessionId);
|
|
277
|
+
localStorage.removeItem("sonance-apply-first-session");
|
|
278
|
+
return;
|
|
279
|
+
}
|
|
274
280
|
console.log("[Apply-First] Restoring session from localStorage:", session.sessionId);
|
|
275
281
|
setApplyFirstSession(session);
|
|
276
282
|
setApplyFirstStatus("reviewing");
|
|
@@ -2408,6 +2414,11 @@ export function SonanceDevTools() {
|
|
|
2408
2414
|
colorScheme: "light",
|
|
2409
2415
|
transform: `translate(${dragPosition.x}px, ${dragPosition.y}px)`,
|
|
2410
2416
|
}}
|
|
2417
|
+
// Event isolation - prevent clicks from closing popups in the main app
|
|
2418
|
+
onMouseDown={(e) => e.stopPropagation()}
|
|
2419
|
+
onClick={(e) => e.stopPropagation()}
|
|
2420
|
+
onFocus={(e) => e.stopPropagation()}
|
|
2421
|
+
onBlur={(e) => e.stopPropagation()}
|
|
2411
2422
|
>
|
|
2412
2423
|
{/* Header - Draggable */}
|
|
2413
2424
|
<div
|
|
@@ -1,176 +1,10 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
|
|
3
|
-
import React, { useState, useEffect
|
|
4
|
-
import { X, Zap, Loader2, Check, ChevronDown, ChevronRight, FileCode, AlertTriangle, Info
|
|
3
|
+
import React, { useState, useEffect } from "react";
|
|
4
|
+
import { X, Zap, Loader2, Check, ChevronDown, ChevronRight, FileCode, AlertTriangle, Info } from "lucide-react";
|
|
5
5
|
import { cn } from "../../../lib/utils";
|
|
6
6
|
import { ApplyFirstSession, ApplyFirstStatus, VisionFileModification } from "../types";
|
|
7
7
|
|
|
8
|
-
// CSS Injection Preview ID
|
|
9
|
-
const PREVIEW_STYLE_ID = "sonance-preview-css";
|
|
10
|
-
|
|
11
|
-
/**
|
|
12
|
-
* Extract className changes from a diff
|
|
13
|
-
* Returns: { removed: string[], added: string[] }
|
|
14
|
-
*/
|
|
15
|
-
function extractClassNameChanges(diff: string): { removed: string[]; added: string[] } {
|
|
16
|
-
const removed: string[] = [];
|
|
17
|
-
const added: string[] = [];
|
|
18
|
-
|
|
19
|
-
// Regex to find className="..." patterns
|
|
20
|
-
const classNameRegex = /className=["']([^"']+)["']/g;
|
|
21
|
-
|
|
22
|
-
const lines = diff.split("\n");
|
|
23
|
-
for (const line of lines) {
|
|
24
|
-
if (line.startsWith("-") && !line.startsWith("---")) {
|
|
25
|
-
// Removed line - extract className
|
|
26
|
-
let match;
|
|
27
|
-
while ((match = classNameRegex.exec(line)) !== null) {
|
|
28
|
-
removed.push(...match[1].split(/\s+/));
|
|
29
|
-
}
|
|
30
|
-
} else if (line.startsWith("+") && !line.startsWith("+++")) {
|
|
31
|
-
// Added line - extract className
|
|
32
|
-
let match;
|
|
33
|
-
while ((match = classNameRegex.exec(line)) !== null) {
|
|
34
|
-
added.push(...match[1].split(/\s+/));
|
|
35
|
-
}
|
|
36
|
-
}
|
|
37
|
-
}
|
|
38
|
-
|
|
39
|
-
return { removed, added };
|
|
40
|
-
}
|
|
41
|
-
|
|
42
|
-
/**
|
|
43
|
-
* Common Tailwind class to CSS mapping for preview
|
|
44
|
-
* Covers styling classes for instant visual feedback
|
|
45
|
-
*/
|
|
46
|
-
const TAILWIND_TO_CSS: Record<string, string> = {
|
|
47
|
-
// Text colors - basic
|
|
48
|
-
"text-white": "color: white !important;",
|
|
49
|
-
"text-black": "color: black !important;",
|
|
50
|
-
"text-gray-900": "color: rgb(17, 24, 39) !important;",
|
|
51
|
-
"text-gray-800": "color: rgb(31, 41, 55) !important;",
|
|
52
|
-
"text-gray-700": "color: rgb(55, 65, 81) !important;",
|
|
53
|
-
"text-gray-600": "color: rgb(75, 85, 99) !important;",
|
|
54
|
-
"text-gray-500": "color: rgb(107, 114, 128) !important;",
|
|
55
|
-
"text-gray-400": "color: rgb(156, 163, 175) !important;",
|
|
56
|
-
|
|
57
|
-
// Sonance brand colors
|
|
58
|
-
"text-sonance-charcoal": "color: #333F48 !important;",
|
|
59
|
-
"text-sonance-blue": "color: #00D3C8 !important;",
|
|
60
|
-
"border-sonance-charcoal": "border-color: #333F48 !important;",
|
|
61
|
-
"border-sonance-blue": "border-color: #00D3C8 !important;",
|
|
62
|
-
"bg-sonance-charcoal": "background-color: #333F48 !important;",
|
|
63
|
-
"bg-sonance-blue": "background-color: #00D3C8 !important;",
|
|
64
|
-
|
|
65
|
-
// Semantic text colors
|
|
66
|
-
"text-primary": "color: var(--primary) !important;",
|
|
67
|
-
"text-primary-foreground": "color: var(--primary-foreground) !important;",
|
|
68
|
-
"text-secondary": "color: var(--secondary) !important;",
|
|
69
|
-
"text-secondary-foreground": "color: var(--secondary-foreground) !important;",
|
|
70
|
-
"text-accent": "color: var(--accent) !important;",
|
|
71
|
-
"text-accent-foreground": "color: var(--accent-foreground) !important;",
|
|
72
|
-
"text-foreground": "color: var(--foreground) !important;",
|
|
73
|
-
"text-muted": "color: var(--muted) !important;",
|
|
74
|
-
"text-muted-foreground": "color: var(--muted-foreground) !important;",
|
|
75
|
-
"text-destructive": "color: var(--destructive) !important;",
|
|
76
|
-
"text-destructive-foreground": "color: var(--destructive-foreground) !important;",
|
|
77
|
-
|
|
78
|
-
// Semantic backgrounds
|
|
79
|
-
"bg-primary": "background-color: hsl(var(--primary)) !important;",
|
|
80
|
-
"bg-secondary": "background-color: hsl(var(--secondary)) !important;",
|
|
81
|
-
"bg-accent": "background-color: hsl(var(--accent)) !important;",
|
|
82
|
-
"bg-muted": "background-color: hsl(var(--muted)) !important;",
|
|
83
|
-
"bg-destructive": "background-color: hsl(var(--destructive)) !important;",
|
|
84
|
-
"bg-success": "background-color: var(--success) !important;",
|
|
85
|
-
"bg-card": "background-color: hsl(var(--card)) !important;",
|
|
86
|
-
"bg-background": "background-color: hsl(var(--background)) !important;",
|
|
87
|
-
|
|
88
|
-
// Common backgrounds
|
|
89
|
-
"bg-white": "background-color: white !important;",
|
|
90
|
-
"bg-black": "background-color: black !important;",
|
|
91
|
-
"bg-gray-50": "background-color: rgb(249, 250, 251) !important;",
|
|
92
|
-
"bg-gray-100": "background-color: rgb(243, 244, 246) !important;",
|
|
93
|
-
"bg-gray-200": "background-color: rgb(229, 231, 235) !important;",
|
|
94
|
-
"bg-gray-300": "background-color: rgb(209, 213, 219) !important;",
|
|
95
|
-
"bg-gray-800": "background-color: rgb(31, 41, 55) !important;",
|
|
96
|
-
"bg-gray-900": "background-color: rgb(17, 24, 39) !important;",
|
|
97
|
-
|
|
98
|
-
// Status colors
|
|
99
|
-
"bg-green-500": "background-color: rgb(34, 197, 94) !important;",
|
|
100
|
-
"bg-green-600": "background-color: rgb(22, 163, 74) !important;",
|
|
101
|
-
"bg-blue-500": "background-color: rgb(59, 130, 246) !important;",
|
|
102
|
-
"bg-blue-600": "background-color: rgb(37, 99, 235) !important;",
|
|
103
|
-
"bg-red-500": "background-color: rgb(239, 68, 68) !important;",
|
|
104
|
-
"bg-red-600": "background-color: rgb(220, 38, 38) !important;",
|
|
105
|
-
"bg-yellow-500": "background-color: rgb(234, 179, 8) !important;",
|
|
106
|
-
"bg-orange-500": "background-color: rgb(249, 115, 22) !important;",
|
|
107
|
-
|
|
108
|
-
// Borders
|
|
109
|
-
"border-gray-200": "border-color: rgb(229, 231, 235) !important;",
|
|
110
|
-
"border-gray-300": "border-color: rgb(209, 213, 219) !important;",
|
|
111
|
-
"border-primary": "border-color: hsl(var(--primary)) !important;",
|
|
112
|
-
"border-accent": "border-color: hsl(var(--accent)) !important;",
|
|
113
|
-
"border-destructive": "border-color: hsl(var(--destructive)) !important;",
|
|
114
|
-
};
|
|
115
|
-
|
|
116
|
-
/**
|
|
117
|
-
* Generate CSS for preview based on class changes
|
|
118
|
-
*/
|
|
119
|
-
function generatePreviewCSS(modifications: VisionFileModification[]): string {
|
|
120
|
-
const cssRules: string[] = [];
|
|
121
|
-
|
|
122
|
-
for (const mod of modifications) {
|
|
123
|
-
const { added } = extractClassNameChanges(mod.diff);
|
|
124
|
-
|
|
125
|
-
// Generate CSS for added classes
|
|
126
|
-
for (const cls of added) {
|
|
127
|
-
if (TAILWIND_TO_CSS[cls]) {
|
|
128
|
-
// We can't know the exact selector, so we apply to elements with data-sonance-preview
|
|
129
|
-
cssRules.push(TAILWIND_TO_CSS[cls]);
|
|
130
|
-
}
|
|
131
|
-
}
|
|
132
|
-
}
|
|
133
|
-
|
|
134
|
-
if (cssRules.length === 0) return "";
|
|
135
|
-
|
|
136
|
-
// Apply to changed elements (marked by InspectorOverlay)
|
|
137
|
-
return `
|
|
138
|
-
[data-sonance-changed="true"] {
|
|
139
|
-
${cssRules.join("\n ")}
|
|
140
|
-
outline: 2px dashed #00D3C8 !important;
|
|
141
|
-
outline-offset: 2px !important;
|
|
142
|
-
}
|
|
143
|
-
`;
|
|
144
|
-
}
|
|
145
|
-
|
|
146
|
-
/**
|
|
147
|
-
* Inject preview CSS into the document
|
|
148
|
-
*/
|
|
149
|
-
function injectPreviewCSS(css: string): void {
|
|
150
|
-
// Remove existing preview styles first
|
|
151
|
-
removePreviewCSS();
|
|
152
|
-
|
|
153
|
-
if (!css.trim()) return;
|
|
154
|
-
|
|
155
|
-
const style = document.createElement("style");
|
|
156
|
-
style.id = PREVIEW_STYLE_ID;
|
|
157
|
-
style.textContent = css;
|
|
158
|
-
document.head.appendChild(style);
|
|
159
|
-
|
|
160
|
-
console.log("[Preview CSS] Injected:", css.substring(0, 200));
|
|
161
|
-
}
|
|
162
|
-
|
|
163
|
-
/**
|
|
164
|
-
* Remove preview CSS from the document
|
|
165
|
-
*/
|
|
166
|
-
function removePreviewCSS(): void {
|
|
167
|
-
const existing = document.getElementById(PREVIEW_STYLE_ID);
|
|
168
|
-
if (existing) {
|
|
169
|
-
existing.remove();
|
|
170
|
-
console.log("[Preview CSS] Removed");
|
|
171
|
-
}
|
|
172
|
-
}
|
|
173
|
-
|
|
174
8
|
export interface ApplyFirstPreviewProps {
|
|
175
9
|
session: ApplyFirstSession;
|
|
176
10
|
status: ApplyFirstStatus;
|
|
@@ -260,15 +94,6 @@ function HMRStatusBadge({ status }: { status: ApplyFirstStatus }) {
|
|
|
260
94
|
);
|
|
261
95
|
}
|
|
262
96
|
|
|
263
|
-
if (status === "previewing") {
|
|
264
|
-
return (
|
|
265
|
-
<span className="flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded bg-blue-100 text-blue-700">
|
|
266
|
-
<Eye className="h-3 w-3" />
|
|
267
|
-
Preview Mode
|
|
268
|
-
</span>
|
|
269
|
-
);
|
|
270
|
-
}
|
|
271
|
-
|
|
272
97
|
return null;
|
|
273
98
|
}
|
|
274
99
|
|
|
@@ -281,7 +106,6 @@ export function ApplyFirstPreview({
|
|
|
281
106
|
onApplyPreview,
|
|
282
107
|
}: ApplyFirstPreviewProps) {
|
|
283
108
|
const [expandedFiles, setExpandedFiles] = useState<Set<string>>(new Set());
|
|
284
|
-
const [cssPreviewEnabled, setCssPreviewEnabled] = useState(true);
|
|
285
109
|
|
|
286
110
|
// Expand first file by default
|
|
287
111
|
useEffect(() => {
|
|
@@ -289,31 +113,6 @@ export function ApplyFirstPreview({
|
|
|
289
113
|
setExpandedFiles(new Set([session.modifications[0].filePath]));
|
|
290
114
|
}
|
|
291
115
|
}, [session]);
|
|
292
|
-
|
|
293
|
-
// CSS Preview injection for ALL modes (preview AND applied)
|
|
294
|
-
// This ensures the user can always see visual changes immediately
|
|
295
|
-
useEffect(() => {
|
|
296
|
-
if (cssPreviewEnabled && session.modifications.length > 0) {
|
|
297
|
-
// Generate and inject preview CSS to show visual changes immediately
|
|
298
|
-
const previewCSS = generatePreviewCSS(session.modifications);
|
|
299
|
-
if (previewCSS) {
|
|
300
|
-
injectPreviewCSS(previewCSS);
|
|
301
|
-
}
|
|
302
|
-
} else {
|
|
303
|
-
// Remove preview CSS when disabled
|
|
304
|
-
removePreviewCSS();
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
// Cleanup on unmount
|
|
308
|
-
return () => {
|
|
309
|
-
removePreviewCSS();
|
|
310
|
-
};
|
|
311
|
-
}, [session, cssPreviewEnabled]);
|
|
312
|
-
|
|
313
|
-
// Toggle CSS preview
|
|
314
|
-
const toggleCssPreview = useCallback(() => {
|
|
315
|
-
setCssPreviewEnabled(prev => !prev);
|
|
316
|
-
}, []);
|
|
317
116
|
|
|
318
117
|
const toggleFile = (filePath: string) => {
|
|
319
118
|
setExpandedFiles((prev) => {
|
|
@@ -356,20 +155,6 @@ export function ApplyFirstPreview({
|
|
|
356
155
|
</span>
|
|
357
156
|
</div>
|
|
358
157
|
<div className="flex items-center gap-2">
|
|
359
|
-
{/* CSS Preview Toggle - show for all modes to ensure visual changes are visible */}
|
|
360
|
-
<button
|
|
361
|
-
onClick={toggleCssPreview}
|
|
362
|
-
className={cn(
|
|
363
|
-
"flex items-center gap-1 text-[10px] px-1.5 py-0.5 rounded transition-colors",
|
|
364
|
-
cssPreviewEnabled
|
|
365
|
-
? isPreviewMode ? "bg-blue-200 text-blue-700" : "bg-green-200 text-green-700"
|
|
366
|
-
: "bg-gray-200 text-gray-500"
|
|
367
|
-
)}
|
|
368
|
-
title={cssPreviewEnabled ? "Hide visual preview" : "Show visual preview"}
|
|
369
|
-
>
|
|
370
|
-
{cssPreviewEnabled ? <Eye className="h-3 w-3" /> : <EyeOff className="h-3 w-3" />}
|
|
371
|
-
Preview
|
|
372
|
-
</button>
|
|
373
158
|
<HMRStatusBadge status={status} />
|
|
374
159
|
</div>
|
|
375
160
|
</div>
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "sonance-brand-mcp",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.74",
|
|
4
4
|
"description": "MCP Server for Sonance Brand Guidelines and Component Library - gives Claude instant access to brand colors, typography, and UI components.",
|
|
5
5
|
"main": "dist/index.js",
|
|
6
6
|
"type": "module",
|