sonance-brand-mcp 1.3.73 → 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.
@@ -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");
@@ -1,176 +1,10 @@
1
1
  "use client";
2
2
 
3
- import React, { useState, useEffect, useCallback } from "react";
4
- import { X, Zap, Loader2, Check, ChevronDown, ChevronRight, FileCode, AlertTriangle, Info, Eye, EyeOff } from "lucide-react";
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.73",
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",