@wtdlee/repomap 0.3.1 → 0.3.3

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.
@@ -1,128 +1,4 @@
1
- // src/generators/page-map-generator.ts
2
- var PageMapGenerator = class {
3
- graphqlOps = [];
4
- apiCalls = [];
5
- components = [];
6
- generatePageMapHtml(report, options) {
7
- const allPages = [];
8
- const envResult = options?.envResult;
9
- const railsAnalysis = options?.railsAnalysis;
10
- const activeTab = options?.activeTab || "pages";
11
- const repoName = report.repositories[0]?.displayName || report.repositories[0]?.name || "Repository";
12
- for (const repoResult of report.repositories) {
13
- this.graphqlOps.push(...repoResult.analysis?.graphqlOperations || []);
14
- this.apiCalls.push(...repoResult.analysis?.apiCalls || []);
15
- const comps = repoResult.analysis?.components || [];
16
- for (const comp of comps) {
17
- this.components.push({
18
- name: comp.name,
19
- filePath: comp.filePath,
20
- type: comp.type,
21
- dependencies: comp.dependencies || []
22
- });
23
- }
24
- }
25
- for (const repoResult of report.repositories) {
26
- const pages = repoResult.analysis?.pages || [];
27
- for (const page of pages) {
28
- allPages.push({
29
- ...page,
30
- repo: repoResult.name,
31
- children: [],
32
- parent: null,
33
- depth: 0
34
- });
35
- }
36
- }
37
- const { rootPages, relations } = this.buildHierarchy(allPages);
38
- return this.renderPageMapHtml(allPages, rootPages, relations, repoName, {
39
- envResult,
40
- railsAnalysis,
41
- activeTab
42
- });
43
- }
44
- buildHierarchy(pages) {
45
- const pathMap = /* @__PURE__ */ new Map();
46
- const relations = [];
47
- for (const page of pages) {
48
- pathMap.set(page.path, page);
49
- }
50
- for (const page of pages) {
51
- const segments = page.path.split("/").filter(Boolean);
52
- for (let i = segments.length - 1; i >= 1; i--) {
53
- const parentPath = "/" + segments.slice(0, i).join("/");
54
- const parent = pathMap.get(parentPath);
55
- if (parent) {
56
- page.parent = parentPath;
57
- page.depth = parent.depth + 1;
58
- if (!parent.children.includes(page.path)) {
59
- parent.children.push(page.path);
60
- }
61
- relations.push({
62
- from: parentPath,
63
- to: page.path,
64
- type: "parent-child",
65
- description: `Sub-page of ${parentPath}`
66
- });
67
- break;
68
- }
69
- }
70
- if (!page.parent) {
71
- page.depth = Math.max(0, segments.length - 1);
72
- }
73
- if (page.layout) {
74
- for (const other of pages) {
75
- if (other.path !== page.path && other.layout === page.layout) {
76
- const existing = relations.find(
77
- (r) => r.type === "same-layout" && (r.from === page.path && r.to === other.path || r.from === other.path && r.to === page.path)
78
- );
79
- if (!existing) {
80
- relations.push({
81
- from: page.path,
82
- to: other.path,
83
- type: "same-layout",
84
- description: `Both use ${page.layout}`
85
- });
86
- }
87
- }
88
- }
89
- }
90
- }
91
- const rootPages = pages.filter((p) => !p.parent).sort((a, b) => a.path.localeCompare(b.path));
92
- return { rootPages, relations };
93
- }
94
- renderPageMapHtml(allPages, rootPages, relations, repoName, options) {
95
- const envResult = options?.envResult;
96
- const railsAnalysis = options?.railsAnalysis;
97
- const activeTab = options?.activeTab || "pages";
98
- const graphqlOpsJson = JSON.stringify(
99
- this.graphqlOps.map((op) => ({
100
- name: op.name,
101
- type: op.type,
102
- variables: op.variables,
103
- fields: op.fields,
104
- returnType: op.returnType,
105
- usedIn: op.usedIn
106
- }))
107
- );
108
- const componentsJson = JSON.stringify(this.components);
109
- const railsRoutesJson = railsAnalysis ? JSON.stringify(railsAnalysis.routes.routes) : "[]";
110
- const railsControllersJson = railsAnalysis ? JSON.stringify(railsAnalysis.controllers.controllers) : "[]";
111
- const railsModelsJson = railsAnalysis ? JSON.stringify(railsAnalysis.models.models) : "[]";
112
- const railsViewsJson = railsAnalysis ? JSON.stringify(railsAnalysis.views) : '{ "views": [], "pages": [], "summary": {} }';
113
- const railsReactJson = railsAnalysis ? JSON.stringify(railsAnalysis.react) : '{ "components": [], "entryPoints": [], "summary": {} }';
114
- const railsGrpcJson = railsAnalysis ? JSON.stringify(railsAnalysis.grpc) : '{ "services": [] }';
115
- const railsSummaryJson = railsAnalysis ? JSON.stringify(railsAnalysis.summary) : "null";
116
- const hasRails = envResult?.hasRails || false;
117
- const hasNextjs = envResult?.hasNextjs || false;
118
- const hasReact = envResult?.hasReact || false;
119
- const groups = /* @__PURE__ */ new Map();
120
- for (const page of allPages) {
121
- const seg = page.path.split("/").filter(Boolean)[0] || "root";
122
- if (!groups.has(seg)) groups.set(seg, []);
123
- groups.get(seg)?.push(page);
124
- }
125
- return `<!DOCTYPE html>
1
+ var S=class{graphqlOps=[];apiCalls=[];components=[];generatePageMapHtml(s,r){let c=[],v=r?.envResult,t=r?.railsAnalysis,l=r?.activeTab||"pages",e=s.repositories[0]?.displayName||s.repositories[0]?.name||"Repository";for(let p of s.repositories){this.graphqlOps.push(...p.analysis?.graphqlOperations||[]),this.apiCalls.push(...p.analysis?.apiCalls||[]);let f=p.analysis?.components||[];for(let a of f)this.components.push({name:a.name,filePath:a.filePath,type:a.type,dependencies:a.dependencies||[]});}for(let p of s.repositories){let f=p.analysis?.pages||[];for(let a of f)c.push({...a,repo:p.name,children:[],parent:null,depth:0});}let{rootPages:i,relations:o}=this.buildHierarchy(c);return this.renderPageMapHtml(c,i,o,e,{envResult:v,railsAnalysis:t,activeTab:l})}buildHierarchy(s){let r=new Map,c=[];for(let t of s)r.set(t.path,t);for(let t of s){let l=t.path.split("/").filter(Boolean);for(let e=l.length-1;e>=1;e--){let i="/"+l.slice(0,e).join("/"),o=r.get(i);if(o){t.parent=i,t.depth=o.depth+1,o.children.includes(t.path)||o.children.push(t.path),c.push({from:i,to:t.path,type:"parent-child",description:`Sub-page of ${i}`});break}}if(t.parent||(t.depth=Math.max(0,l.length-1)),t.layout)for(let e of s)e.path!==t.path&&e.layout===t.layout&&(c.find(o=>o.type==="same-layout"&&(o.from===t.path&&o.to===e.path||o.from===e.path&&o.to===t.path))||c.push({from:t.path,to:e.path,type:"same-layout",description:`Both use ${t.layout}`}));}return {rootPages:s.filter(t=>!t.parent).sort((t,l)=>t.path.localeCompare(l.path)),relations:c}}renderPageMapHtml(s,r,c,v,t){let l=t?.envResult,e=t?.railsAnalysis,i=t?.activeTab||"pages",o=JSON.stringify(this.graphqlOps.map(d=>({name:d.name,type:d.type,variables:d.variables,fields:d.fields,returnType:d.returnType,usedIn:d.usedIn}))),p=JSON.stringify(this.components),f=e?JSON.stringify(e.routes.routes):"[]",a=e?JSON.stringify(e.controllers.controllers):"[]",m=e?JSON.stringify(e.models.models):"[]",u=e?JSON.stringify(e.views):'{ "views": [], "pages": [], "summary": {} }',h=e?JSON.stringify(e.react):'{ "components": [], "entryPoints": [], "summary": {} }',y=e?JSON.stringify(e.grpc):'{ "services": [] }',P=e?JSON.stringify(e.summary):"null",n=l?.hasRails||false,w=l?.hasNextjs||false,C=l?.hasReact||false,x=new Map;for(let d of s){let b=d.path.split("/").filter(Boolean)[0]||"root";x.has(b)||x.set(b,[]),x.get(b)?.push(d);}return `<!DOCTYPE html>
126
2
  <html lang="en">
127
3
  <head>
128
4
  <meta charset="UTF-8">
@@ -133,21 +9,21 @@ var PageMapGenerator = class {
133
9
  <body>
134
10
  <header class="header">
135
11
  <div style="display:flex;align-items:center;gap:24px">
136
- <h1 style="cursor:pointer" onclick="location.href='/'">\u{1F4CA} ${repoName}</h1>
12
+ <h1 style="cursor:pointer" onclick="location.href='/'">\u{1F4CA} ${v}</h1>
137
13
  <nav style="display:flex;gap:4px">
138
- <a href="/page-map" class="nav-link ${activeTab === "pages" ? "active" : ""}">Page Map</a>
139
- ${hasRails ? `<a href="/rails-map" class="nav-link ${activeTab === "rails" ? "active" : ""}">Rails Map</a>` : ""}
14
+ <a href="/page-map" class="nav-link ${i==="pages"?"active":""}">Page Map</a>
15
+ ${n?`<a href="/rails-map" class="nav-link ${i==="rails"?"active":""}">Rails Map</a>`:""}
140
16
  <a href="/docs" class="nav-link">Docs</a>
141
17
  <a href="/api/report" class="nav-link" target="_blank">API</a>
142
18
  </nav>
143
19
  </div>
144
20
  <div style="display:flex;gap:12px;align-items:center">
145
21
  <!-- Environment filter badges -->
146
- ${hasRails && hasNextjs ? `<div class="env-filters" style="display:flex;gap:4px;margin-right:8px">
22
+ ${n&&w?`<div class="env-filters" style="display:flex;gap:4px;margin-right:8px">
147
23
  <button class="env-badge env-badge-active" data-env="all" onclick="filterByEnv('all')">All</button>
148
24
  <button class="env-badge" data-env="nextjs" onclick="filterByEnv('nextjs')">\u269B\uFE0F Next.js</button>
149
25
  <button class="env-badge" data-env="rails" onclick="filterByEnv('rails')">\u{1F6E4}\uFE0F Rails</button>
150
- </div>` : ""}
26
+ </div>`:""}
151
27
  <input class="search" type="text" placeholder="Search pages, queries..." oninput="filter(this.value)">
152
28
  <div class="tabs">
153
29
  <button class="tab active" onclick="setView('tree')">List</button>
@@ -182,40 +58,40 @@ var PageMapGenerator = class {
182
58
  <!-- Frontend Stats -->
183
59
  <h3 style="margin-top:16px;font-size:10px;text-transform:uppercase;color:var(--text2);letter-spacing:1px">Frontend</h3>
184
60
  <div class="stats" id="stats-container">
185
- <div class="stat" data-filter="pages"><div class="stat-val">${allPages.length}</div><div class="stat-label">Pages</div></div>
186
- <div class="stat" data-filter="hierarchies"><div class="stat-val">${relations.filter((r) => r.type === "parent-child").length}</div><div class="stat-label">Hierarchies</div></div>
61
+ <div class="stat" data-filter="pages"><div class="stat-val">${s.length}</div><div class="stat-label">Pages</div></div>
62
+ <div class="stat" data-filter="hierarchies"><div class="stat-val">${c.filter(d=>d.type==="parent-child").length}</div><div class="stat-label">Hierarchies</div></div>
187
63
  <div class="stat" data-filter="graphql"><div class="stat-val">${this.graphqlOps.length}</div><div class="stat-label">GraphQL</div></div>
188
64
  <div class="stat" data-filter="restapi"><div class="stat-val">${this.apiCalls.length}</div><div class="stat-label">REST API</div></div>
189
65
  </div>
190
66
 
191
- ${hasRails && railsAnalysis ? `
67
+ ${n&&e?`
192
68
  <!-- Rails Stats -->
193
69
  <h3 style="margin-top:16px;font-size:10px;text-transform:uppercase;color:var(--text2);letter-spacing:1px;cursor:pointer" onclick="switchToRailsTab()">Rails Backend</h3>
194
70
  <div class="stats" id="rails-stats">
195
- <div class="stat" data-filter="rails-routes" onclick="switchToRailsTab()"><div class="stat-val">${railsAnalysis.summary.totalRoutes}</div><div class="stat-label">Routes</div></div>
196
- <div class="stat" data-filter="rails-controllers" onclick="showRailsControllers(); this.blur();"><div class="stat-val">${railsAnalysis.summary.totalControllers}</div><div class="stat-label">Controllers</div></div>
197
- <div class="stat" data-filter="rails-models" onclick="showRailsModels(); this.blur();"><div class="stat-val">${railsAnalysis.summary.totalModels}</div><div class="stat-label">Models</div></div>
198
- <div class="stat" data-filter="rails-grpc" onclick="showRailsGrpc(); this.blur();"><div class="stat-val">${railsAnalysis.summary.totalGrpcServices}</div><div class="stat-label">gRPC</div></div>
199
- <div class="stat" data-filter="rails-react" onclick="showReactComponents(); this.blur();"><div class="stat-val">${railsAnalysis.summary.totalReactComponents}</div><div class="stat-label">\u269B React</div></div>
71
+ <div class="stat" data-filter="rails-routes" onclick="switchToRailsTab()"><div class="stat-val">${e.summary.totalRoutes}</div><div class="stat-label">Routes</div></div>
72
+ <div class="stat" data-filter="rails-controllers" onclick="showRailsControllers(); this.blur();"><div class="stat-val">${e.summary.totalControllers}</div><div class="stat-label">Controllers</div></div>
73
+ <div class="stat" data-filter="rails-models" onclick="showRailsModels(); this.blur();"><div class="stat-val">${e.summary.totalModels}</div><div class="stat-label">Models</div></div>
74
+ <div class="stat" data-filter="rails-grpc" onclick="showRailsGrpc(); this.blur();"><div class="stat-val">${e.summary.totalGrpcServices}</div><div class="stat-label">gRPC</div></div>
75
+ <div class="stat" data-filter="rails-react" onclick="showReactComponents(); this.blur();"><div class="stat-val">${e.summary.totalReactComponents}</div><div class="stat-label">\u269B React</div></div>
200
76
  </div>
201
- ` : ""}
77
+ `:""}
202
78
  </aside>
203
79
 
204
80
  <div class="content">
205
81
  <!-- Pages Tree View (for all screens - Next.js/React/Rails) -->
206
- <div class="tree-view ${activeTab === "pages" ? "active" : ""}" id="tree-view" data-tab="pages">
207
- ${allPages.length > 0 ? this.buildTreeHtml(groups, allPages) : ""}
208
- <div id="page-map-react-components-section" style="${hasRails ? "margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px" : ""}">
82
+ <div class="tree-view ${i==="pages"?"active":""}" id="tree-view" data-tab="pages">
83
+ ${s.length>0?this.buildTreeHtml(x,s):""}
84
+ <div id="page-map-react-components-section" style="${n?"margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px":""}">
209
85
  </div>
210
- <div id="page-map-rails-section" style="${allPages.length > 0 && hasRails ? "margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px" : ""}">
211
- ${hasRails && allPages.length === 0 ? '<div style="padding:20px;color:var(--text2)">Loading screens...</div>' : ""}
86
+ <div id="page-map-rails-section" style="${s.length>0&&n?"margin-top:20px;border-top:1px solid var(--bg3);padding-top:20px":""}">
87
+ ${n&&s.length===0?'<div class="empty-state-sm">Loading screens...</div>':""}
212
88
  </div>
213
89
  </div>
214
90
 
215
91
  <!-- Rails Routes View (dedicated) -->
216
- <div class="tree-view ${activeTab === "rails" ? "active" : ""}" id="rails-tree-view" data-tab="rails">
92
+ <div class="tree-view ${i==="rails"?"active":""}" id="rails-tree-view" data-tab="rails">
217
93
  <div id="rails-routes-container">
218
- ${hasRails ? '<div style="padding:20px;color:var(--text2)">Loading Rails routes...</div>' : '<div style="padding:40px;text-align:center;color:var(--text2)">No Rails environment detected</div>'}
94
+ ${n?'<div class="empty-state-sm">Loading Rails routes...</div>':'<div class="empty-state">No Rails environment detected</div>'}
219
95
  </div>
220
96
  </div>
221
97
 
@@ -257,16 +133,16 @@ var PageMapGenerator = class {
257
133
  <script>
258
134
  // Environment detection results
259
135
  const envInfo = {
260
- hasRails: ${hasRails},
261
- hasNextjs: ${hasNextjs},
262
- hasReact: ${hasReact}
136
+ hasRails: ${n},
137
+ hasNextjs: ${w},
138
+ hasReact: ${C}
263
139
  };
264
140
 
265
141
  // Frontend data
266
- const pages = ${JSON.stringify(allPages)};
267
- const relations = ${JSON.stringify(relations)};
268
- const graphqlOps = ${graphqlOpsJson};
269
- const components = ${componentsJson};
142
+ const pages = ${JSON.stringify(s)};
143
+ const relations = ${JSON.stringify(c)};
144
+ const graphqlOps = ${o};
145
+ const components = ${p};
270
146
  const apiCallsData = ${JSON.stringify(this.apiCalls)};
271
147
  window.apiCalls = apiCallsData;
272
148
  const pageMap = new Map(pages.map(p => [p.path, p]));
@@ -274,16 +150,16 @@ var PageMapGenerator = class {
274
150
  const compMap = new Map(components.map(c => [c.name, c]));
275
151
 
276
152
  // Rails data (if available)
277
- const railsRoutes = ${railsRoutesJson};
278
- const railsControllers = ${railsControllersJson};
279
- const railsModels = ${railsModelsJson};
280
- const railsViews = ${railsViewsJson};
281
- const railsReact = ${railsReactJson};
282
- const railsGrpc = ${railsGrpcJson};
283
- const railsSummary = ${railsSummaryJson};
153
+ const railsRoutes = ${f};
154
+ const railsControllers = ${a};
155
+ const railsModels = ${m};
156
+ const railsViews = ${u};
157
+ const railsReact = ${h};
158
+ const railsGrpc = ${y};
159
+ const railsSummary = ${P};
284
160
 
285
161
  // Current active tab state
286
- let currentMainTab = '${activeTab}';
162
+ let currentMainTab = '${i}';
287
163
 
288
164
  // Modal history stack for back navigation
289
165
  const modalHistory = [];
@@ -377,17 +253,17 @@ var PageMapGenerator = class {
377
253
  routesByNamespace.get(ns).push(r);
378
254
  });
379
255
 
380
- let html = '<div style="max-height:60vh;overflow-y:auto">';
256
+ let html = '<div class="max-h-60vh overflow-y-auto">';
381
257
  for (const [ns, routes] of routesByNamespace) {
382
258
  html += '<div style="margin-bottom:16px">';
383
259
  html += '<div style="font-weight:600;margin-bottom:8px;color:var(--accent)">\u{1F4C2} ' + ns + ' (' + routes.length + ')</div>';
384
260
  html += '<table style="width:100%;border-collapse:collapse;font-size:12px">';
385
- html += '<tr style="background:var(--bg3)"><th style="padding:6px;text-align:left">Method</th><th style="padding:6px;text-align:left">Path</th><th style="padding:6px;text-align:left">Controller#Action</th></tr>';
261
+ html += '<tr class="bg-surface"><th class="cell">Method</th><th class="cell">Path</th><th class="cell">Controller#Action</th></tr>';
386
262
  routes.slice(0, 20).forEach(r => {
387
263
  const methodColor = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',PATCH:'#f59e0b',DELETE:'#ef4444'}[r.method] || '#888';
388
264
  html += '<tr style="border-bottom:1px solid var(--border)">';
389
265
  html += '<td style="padding:6px"><span style="background:' + methodColor + ';color:white;padding:2px 6px;border-radius:3px;font-size:10px">' + r.method + '</span></td>';
390
- html += '<td style="padding:6px;font-family:monospace">' + r.path.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>') + '</td>';
266
+ html += '<td style="padding:6px;font-family:monospace">' + r.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</td>';
391
267
  html += '<td style="padding:6px;color:var(--text2)">' + r.controller + '#' + r.action + '</td>';
392
268
  html += '</tr>';
393
269
  });
@@ -407,13 +283,13 @@ var PageMapGenerator = class {
407
283
  return;
408
284
  }
409
285
 
410
- let html = '<div style="max-height:60vh;overflow-y:auto">';
286
+ let html = '<div class="max-h-60vh overflow-y-auto">';
411
287
  railsControllers.forEach(ctrl => {
412
- html += '<div style="background:var(--bg3);padding:12px;border-radius:6px;margin-bottom:8px">';
413
- html += '<div style="font-weight:600;margin-bottom:4px">' + ctrl.className + '</div>';
414
- html += '<div style="font-size:11px;color:var(--text2);margin-bottom:8px">extends ' + ctrl.parentClass + '</div>';
288
+ html += '<div class="info-box">';
289
+ html += '<div class="section-title">' + ctrl.className + '</div>';
290
+ html += '<div class="hint mb-3">extends ' + ctrl.parentClass + '</div>';
415
291
  if (ctrl.actions && ctrl.actions.length > 0) {
416
- html += '<div style="display:flex;flex-wrap:wrap;gap:4px">';
292
+ html += '<div class="flex flex-wrap gap-1">';
417
293
  ctrl.actions.slice(0, 10).forEach(action => {
418
294
  const color = action.visibility === 'public' ? '#22c55e' : action.visibility === 'private' ? '#ef4444' : '#f59e0b';
419
295
  html += '<span style="background:rgba(255,255,255,0.1);padding:2px 8px;border-radius:4px;font-size:11px;border-left:2px solid ' + color + '">' + action.name + '</span>';
@@ -434,16 +310,16 @@ var PageMapGenerator = class {
434
310
  return;
435
311
  }
436
312
 
437
- let html = '<div style="max-height:60vh;overflow-y:auto">';
313
+ let html = '<div class="max-h-60vh overflow-y-auto">';
438
314
  railsModels.forEach(model => {
439
- html += '<div style="background:var(--bg3);padding:12px;border-radius:6px;margin-bottom:8px">';
440
- html += '<div style="font-weight:600;margin-bottom:4px">\u{1F4E6} ' + model.className + '</div>';
441
- html += '<div style="display:flex;gap:16px;font-size:11px;color:var(--text2);margin-bottom:8px">';
315
+ html += '<div class="info-box">';
316
+ html += '<div class="section-title">\u{1F4E6} ' + model.className + '</div>';
317
+ html += '<div class="flex gap-3 hint mb-3">';
442
318
  html += '<span>\u{1F4CE} ' + (model.associations?.length || 0) + ' associations</span>';
443
319
  html += '<span>\u2713 ' + (model.validations?.length || 0) + ' validations</span>';
444
320
  html += '</div>';
445
321
  if (model.associations && model.associations.length > 0) {
446
- html += '<div style="display:flex;flex-wrap:wrap;gap:4px">';
322
+ html += '<div class="flex flex-wrap gap-1">';
447
323
  model.associations.slice(0, 8).forEach(assoc => {
448
324
  const typeColor = {belongs_to:'#3b82f6',has_many:'#22c55e',has_one:'#f59e0b'}[assoc.type] || '#888';
449
325
  html += '<span style="background:rgba(255,255,255,0.1);padding:2px 8px;border-radius:4px;font-size:10px"><span style="color:' + typeColor + '">' + assoc.type + '</span> :' + assoc.name + '</span>';
@@ -469,24 +345,24 @@ var PageMapGenerator = class {
469
345
  (b.usedIn?.length || 0) - (a.usedIn?.length || 0)
470
346
  );
471
347
 
472
- let html = '<div style="max-height:60vh;overflow-y:auto">';
348
+ let html = '<div class="max-h-60vh overflow-y-auto">';
473
349
 
474
350
  // Stats
475
351
  html += '<div style="display:flex;gap:16px;margin-bottom:16px;padding:12px;background:var(--bg3);border-radius:8px">';
476
- html += '<div style="text-align:center"><div style="font-size:20px;font-weight:bold;color:var(--accent)">' + railsReact.summary.totalComponents + '</div><div style="font-size:10px;color:var(--text2)">Components</div></div>';
477
- html += '<div style="text-align:center"><div style="font-size:20px;font-weight:bold;color:#22c55e">' + railsReact.summary.ssrComponents + '</div><div style="font-size:10px;color:var(--text2)">SSR</div></div>';
478
- html += '<div style="text-align:center"><div style="font-size:20px;font-weight:bold;color:#3b82f6">' + railsReact.summary.clientComponents + '</div><div style="font-size:10px;color:var(--text2)">Client</div></div>';
479
- html += '<div style="text-align:center"><div style="font-size:20px;font-weight:bold;color:#f59e0b">' + railsReact.summary.totalEntryPoints + '</div><div style="font-size:10px;color:var(--text2)">Entry Points</div></div>';
352
+ html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:var(--accent)">' + railsReact.summary.totalComponents + '</div><div style="font-size:10px;color:var(--text2)">Components</div></div>';
353
+ html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#22c55e">' + railsReact.summary.ssrComponents + '</div><div style="font-size:10px;color:var(--text2)">SSR</div></div>';
354
+ html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#3b82f6">' + railsReact.summary.clientComponents + '</div><div style="font-size:10px;color:var(--text2)">Client</div></div>';
355
+ html += '<div class="text-center"><div style="font-size:20px;font-weight:bold;color:#f59e0b">' + railsReact.summary.totalEntryPoints + '</div><div style="font-size:10px;color:var(--text2)">Entry Points</div></div>';
480
356
  html += '</div>';
481
357
 
482
358
  sortedComponents.forEach(comp => {
483
359
  const usageCount = comp.usedIn?.length || 0;
484
- const ssrBadge = comp.ssr ? '<span style="margin-left:6px;font-size:9px;background:#22c55e;color:white;padding:1px 4px;border-radius:2px">SSR</span>' : '';
360
+ const ssrBadge = comp.ssr ? '<span class="badge-success">SSR</span>' : '';
485
361
 
486
362
  html += '<div style="background:var(--bg3);padding:12px;border-radius:6px;margin-bottom:8px;cursor:pointer" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
487
363
  html += '<div style="display:flex;align-items:center;justify-content:space-between">';
488
- html += '<div style="font-weight:600;display:flex;align-items:center"><span style="color:#61dafb;margin-right:6px">\u269B</span>' + comp.name + ssrBadge + '</div>';
489
- html += '<span style="font-size:11px;color:var(--text2)">' + usageCount + ' usage' + (usageCount !== 1 ? 's' : '') + '</span>';
364
+ html += '<div style="font-weight:600;display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + ssrBadge + '</div>';
365
+ html += '<span class="hint">' + usageCount + ' usage' + (usageCount !== 1 ? 's' : '') + '</span>';
490
366
  html += '</div>';
491
367
 
492
368
  // Entry point info
@@ -507,7 +383,7 @@ var PageMapGenerator = class {
507
383
  html += '<span style="background:rgba(255,255,255,0.1);padding:2px 6px;border-radius:3px;font-size:10px;border-left:2px solid ' + patternColor + '">' + usage.controller + '/' + usage.action + '</span>';
508
384
  });
509
385
  if (comp.usedIn.length > 3) {
510
- html += '<span style="font-size:10px;color:var(--text2)">+' + (comp.usedIn.length - 3) + ' more</span>';
386
+ html += '<span class="hint-sm">+' + (comp.usedIn.length - 3) + ' more</span>';
511
387
  }
512
388
  html += '</div>';
513
389
  }
@@ -591,17 +467,17 @@ var PageMapGenerator = class {
591
467
  return;
592
468
  }
593
469
 
594
- let html = '<div style="max-height:60vh;overflow-y:auto">';
470
+ let html = '<div class="max-h-60vh overflow-y-auto">';
595
471
  railsGrpc.services.forEach(svc => {
596
- html += '<div style="background:var(--bg3);padding:12px;border-radius:6px;margin-bottom:8px">';
597
- html += '<div style="font-weight:600;margin-bottom:4px">\u{1F50C} ' + svc.className + '</div>';
472
+ html += '<div class="info-box">';
473
+ html += '<div class="section-title">\u{1F50C} ' + svc.className + '</div>';
598
474
  if (svc.namespace) {
599
- html += '<div style="font-size:11px;color:var(--text2);margin-bottom:8px">namespace: ' + svc.namespace + '</div>';
475
+ html += '<div class="hint mb-3">namespace: ' + svc.namespace + '</div>';
600
476
  }
601
477
  if (svc.rpcs && svc.rpcs.length > 0) {
602
- html += '<div style="display:flex;flex-wrap:wrap;gap:4px">';
478
+ html += '<div class="flex flex-wrap gap-1">';
603
479
  svc.rpcs.slice(0, 15).forEach(rpc => {
604
- html += '<span class="tag" style="background:var(--accent);font-size:10px">' + rpc.name + '</span>';
480
+ html += '<span class="tag tag-rpc tag-sm">' + rpc.name + '</span>';
605
481
  });
606
482
  if (svc.rpcs.length > 15) html += '<span style="color:var(--text2);font-size:11px">+' + (svc.rpcs.length - 15) + ' more</span>';
607
483
  html += '</div>';
@@ -623,7 +499,7 @@ var PageMapGenerator = class {
623
499
  const routes = railsRoutes || [];
624
500
 
625
501
  if (pages.length === 0 && routes.length === 0) {
626
- container.innerHTML = '<div style="padding:40px;text-align:center;color:var(--text2)">No Rails pages or routes found</div>';
502
+ container.innerHTML = '<div class="empty-state">No Rails pages or routes found</div>';
627
503
  return;
628
504
  }
629
505
 
@@ -790,7 +666,7 @@ var PageMapGenerator = class {
790
666
  if (displayPath.length > 80) {
791
667
  displayPath = displayPath.slice(0, 77) + '...';
792
668
  }
793
- const pathHighlighted = displayPath.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>');
669
+ const pathHighlighted = displayPath.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>');
794
670
 
795
671
  // Indicators for view, API, and response types
796
672
  let indicators = '';
@@ -820,7 +696,7 @@ var PageMapGenerator = class {
820
696
 
821
697
  html += '<div class="page-item rails-route-item" data-path="' + searchPath + '"' + hiddenAttr + ' ' + filterAttrs.join(' ') + ' onclick="showRailsRouteDetail(\\''+encodeURIComponent(JSON.stringify(route))+'\\', true)" style="cursor:pointer;' + hiddenStyle + '">';
822
698
  html += '<span class="page-type" style="background:' + methodColor + ';min-width:50px;text-align:center">' + route.method + '</span>';
823
- html += '<span class="page-path" style="font-family:monospace;font-size:12px;flex:1">' + pathHighlighted + '</span>';
699
+ html += '<span class="page-path">' + pathHighlighted + '</span>';
824
700
  html += indicators;
825
701
  html += '</div>';
826
702
  });
@@ -906,7 +782,7 @@ var PageMapGenerator = class {
906
782
 
907
783
  html += '<div class="detail-section">';
908
784
  html += '<div class="detail-label">Path</div>';
909
- html += '<div class="detail-value" style="font-family:monospace">' + route.path.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>') + '</div>';
785
+ html += '<div class="detail-value" style="font-family:monospace">' + route.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</div>';
910
786
  html += '</div>';
911
787
 
912
788
  html += '<div class="detail-section">';
@@ -928,14 +804,14 @@ var PageMapGenerator = class {
928
804
  responseTypes.push('<span style="background:#8b5cf6;color:white;padding:2px 8px;border-radius:4px;font-size:11px;margin-right:4px">' + f.toUpperCase() + '</span>');
929
805
  });
930
806
  }
931
- html += responseTypes.length > 0 ? responseTypes.join('') : '<span style="color:var(--text2)">Unknown</span>';
807
+ html += responseTypes.length > 0 ? responseTypes.join('') : '<span class="text-muted">Unknown</span>';
932
808
  html += '</div></div>';
933
809
 
934
810
  // Redirect destination if exists
935
811
  if (action.redirectsTo) {
936
812
  html += '<div class="detail-section">';
937
813
  html += '<div class="detail-label">\u21AA\uFE0F Redirects To</div>';
938
- html += '<div class="detail-value" style="font-family:monospace;font-size:12px;background:var(--bg3);padding:8px;border-radius:4px">' + action.redirectsTo + '</div>';
814
+ html += '<div class="detail-value-block">' + action.redirectsTo + '</div>';
939
815
  html += '</div>';
940
816
  }
941
817
  }
@@ -944,9 +820,9 @@ var PageMapGenerator = class {
944
820
  if (route.hasView && route.view) {
945
821
  html += '<div class="detail-section">';
946
822
  html += '<div class="detail-label">\u{1F4C4} View Template</div>';
947
- html += '<div class="detail-value" style="font-family:monospace;font-size:12px">app/views/' + route.view.path + '</div>';
823
+ html += '<div class="detail-value">app/views/' + route.view.path + '</div>';
948
824
  if (route.view.partials && route.view.partials.length > 0) {
949
- html += '<div style="margin-top:6px;font-size:11px;color:var(--text2)">Partials: ' + route.view.partials.slice(0, 5).join(', ') + (route.view.partials.length > 5 ? '...' : '') + '</div>';
825
+ html += '<div class="subtext">Partials: ' + route.view.partials.slice(0, 5).join(', ') + (route.view.partials.length > 5 ? '...' : '') + '</div>';
950
826
  }
951
827
  if (route.view.instanceVars && route.view.instanceVars.length > 0) {
952
828
  html += '<div style="margin-top:4px;font-size:11px;color:var(--text2)">Instance vars: @' + route.view.instanceVars.slice(0, 5).join(', @') + (route.view.instanceVars.length > 5 ? '...' : '') + '</div>';
@@ -958,7 +834,7 @@ var PageMapGenerator = class {
958
834
  if (ctrl && (ctrl.beforeActions.length > 0 || ctrl.afterActions.length > 0)) {
959
835
  html += '<div class="detail-section">';
960
836
  html += '<div class="detail-label">\u{1F512} Filters Applied to This Action</div>';
961
- html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px">';
837
+ html += '<div class="code-block">';
962
838
 
963
839
  // Filter before_actions that apply to this action
964
840
  const applicableBeforeFilters = ctrl.beforeActions.filter(f => {
@@ -971,7 +847,7 @@ var PageMapGenerator = class {
971
847
  html += '<div style="font-size:11px;margin-bottom:6px"><span style="color:#22c55e;font-weight:600">Before:</span></div>';
972
848
  html += '<div class="detail-items" style="margin-left:8px">';
973
849
  applicableBeforeFilters.forEach(f => {
974
- let filterInfo = '<span class="tag" style="background:#22c55e;font-size:10px">before</span><span class="name">' + f.name + '</span>';
850
+ let filterInfo = '<span class="tag tag-before tag-sm">before</span><span class="name">' + f.name + '</span>';
975
851
  if (f.if) filterInfo += '<span style="font-size:10px;color:var(--text2);margin-left:4px">if: ' + f.if + '</span>';
976
852
  if (f.unless) filterInfo += '<span style="font-size:10px;color:var(--text2);margin-left:4px">unless: ' + f.unless + '</span>';
977
853
  html += '<div class="detail-item">' + filterInfo + '</div>';
@@ -989,7 +865,7 @@ var PageMapGenerator = class {
989
865
  html += '<div style="font-size:11px;margin-top:8px;margin-bottom:6px"><span style="color:#f59e0b;font-weight:600">After:</span></div>';
990
866
  html += '<div class="detail-items" style="margin-left:8px">';
991
867
  applicableAfterFilters.forEach(f => {
992
- let filterInfo = '<span class="tag" style="background:#f59e0b;font-size:10px">after</span><span class="name">' + f.name + '</span>';
868
+ let filterInfo = '<span class="tag tag-after tag-sm">after</span><span class="name">' + f.name + '</span>';
993
869
  html += '<div class="detail-item">' + filterInfo + '</div>';
994
870
  });
995
871
  html += '</div>';
@@ -1008,7 +884,7 @@ var PageMapGenerator = class {
1008
884
  html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
1009
885
  html += '<div class="detail-items">';
1010
886
  services.forEach(s => {
1011
- html += '<div class="detail-item"><span class="tag" style="background:#8b5cf6">Service</span><span class="name" style="font-family:monospace">' + s + '</span></div>';
887
+ html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
1012
888
  });
1013
889
  html += '</div></div>';
1014
890
  }
@@ -1019,7 +895,7 @@ var PageMapGenerator = class {
1019
895
  html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
1020
896
  html += '<div class="detail-items">';
1021
897
  route.grpcCalls.forEach(g => {
1022
- html += '<div class="detail-item"><span class="tag" style="background:#06b6d4">gRPC</span><span class="name" style="font-family:monospace">' + g + '</span></div>';
898
+ html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
1023
899
  });
1024
900
  html += '</div></div>';
1025
901
  }
@@ -1031,7 +907,7 @@ var PageMapGenerator = class {
1031
907
  html += '<div class="detail-label">\u{1F4BE} Models Accessed</div>';
1032
908
  html += '<div class="detail-items">';
1033
909
  models.forEach(m => {
1034
- html += '<div class="detail-item"><span class="tag" style="background:#f59e0b">Model</span><span class="name" style="font-family:monospace">' + m + '</span></div>';
910
+ html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
1035
911
  });
1036
912
  html += '</div></div>';
1037
913
  }
@@ -1050,13 +926,13 @@ var PageMapGenerator = class {
1050
926
  html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;max-height:150px;overflow-y:auto">';
1051
927
  html += '<div style="font-family:monospace;font-size:11px;line-height:1.6">';
1052
928
  meaningfulCalls.forEach((call, i) => {
1053
- html += '<div style="padding:2px 0;border-bottom:1px solid var(--bg1)">';
929
+ html += '<div class="accordion-item">';
1054
930
  html += '<span style="color:var(--text2);margin-right:8px">' + (i+1) + '.</span>';
1055
- html += '<span style="color:var(--accent)">' + call + '</span>';
931
+ html += '<span class="text-accent">' + call + '</span>';
1056
932
  html += '</div>';
1057
933
  });
1058
934
  if (action.methodCalls.length > 15) {
1059
- html += '<div style="padding:4px 0;color:var(--text2);font-style:italic">...and ' + (action.methodCalls.length - 15) + ' more calls</div>';
935
+ html += '<div class="note">...and ' + (action.methodCalls.length - 15) + ' more calls</div>';
1060
936
  }
1061
937
  html += '</div></div></div>';
1062
938
  }
@@ -1068,23 +944,23 @@ var PageMapGenerator = class {
1068
944
  html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;font-family:monospace;font-size:11px">';
1069
945
 
1070
946
  if (route.line > 0) {
1071
- html += '<div style="padding:4px 0;display:flex;align-items:center">';
1072
- html += '<span style="color:var(--text2);width:80px">Route:</span>';
1073
- html += '<span>config/routes.rb:<span style="color:#22c55e">' + route.line + '</span></span>';
947
+ html += '<div class="detail-item flex items-center py-1">';
948
+ html += '<span class="text-muted w-20">Route:</span>';
949
+ html += '<span>config/routes.rb:<span class="text-success">' + route.line + '</span></span>';
1074
950
  html += '</div>';
1075
951
  }
1076
952
 
1077
953
  if (ctrl) {
1078
- html += '<div style="padding:4px 0;display:flex;align-items:center">';
1079
- html += '<span style="color:var(--text2);width:80px">Controller:</span>';
954
+ html += '<div class="detail-item flex items-center py-1">';
955
+ html += '<span class="text-muted w-20">Controller:</span>';
1080
956
  html += '<span>app/controllers/' + ctrl.filePath;
1081
- if (action && action.line) html += ':<span style="color:#22c55e">' + action.line + '</span>';
957
+ if (action && action.line) html += ':<span class="text-success">' + action.line + '</span>';
1082
958
  html += '</span></div>';
1083
959
  }
1084
960
 
1085
961
  if (route.hasView && route.view) {
1086
- html += '<div style="padding:4px 0;display:flex;align-items:center">';
1087
- html += '<span style="color:var(--text2);width:80px">View:</span>';
962
+ html += '<div class="detail-item flex items-center py-1">';
963
+ html += '<span class="text-muted w-20">View:</span>';
1088
964
  html += '<span>app/views/' + route.view.path + '</span>';
1089
965
  html += '</div>';
1090
966
  }
@@ -1094,12 +970,12 @@ var PageMapGenerator = class {
1094
970
  if (ctrl) {
1095
971
  html += '<div class="detail-section">';
1096
972
  html += '<div class="detail-label">\u{1F4CB} Controller Info</div>';
1097
- html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px">';
1098
- html += '<div style="font-weight:600;margin-bottom:4px">' + ctrl.className + '</div>';
973
+ html += '<div class="code-block">';
974
+ html += '<div class="section-title">' + ctrl.className + '</div>';
1099
975
  html += '<div style="font-size:11px;color:var(--text2)">extends ' + ctrl.parentClass + '</div>';
1100
976
  if (ctrl.concerns && ctrl.concerns.length > 0) {
1101
977
  html += '<div style="margin-top:6px;font-size:11px">';
1102
- html += '<span style="color:var(--text2)">Concerns:</span> ' + ctrl.concerns.join(', ');
978
+ html += '<span class="text-muted">Concerns:</span> ' + ctrl.concerns.join(', ');
1103
979
  html += '</div>';
1104
980
  }
1105
981
  html += '</div></div>';
@@ -1139,12 +1015,12 @@ var PageMapGenerator = class {
1139
1015
  const withUsageCount = components.filter(c => c.usedIn && c.usedIn.length > 0).length;
1140
1016
 
1141
1017
  let html = '';
1142
- html += '<div style="padding:12px;background:var(--bg3);border-radius:8px;margin-bottom:12px">';
1018
+ html += '<div class="info-box mb-3">';
1143
1019
  html += '<div style="font-weight:600;margin-bottom:8px;display:flex;align-items:center;gap:8px"><span style="color:#61dafb">\u269B</span> React Components (from Rails)</div>';
1144
1020
  html += '<div style="display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--text2)">';
1145
1021
  html += '<span>' + components.length + ' components</span>';
1146
1022
  html += '<span>\u2022</span>';
1147
- html += '<span style="color:#22c55e">' + ssrCount + ' SSR</span>';
1023
+ html += '<span class="text-success">' + ssrCount + ' SSR</span>';
1148
1024
  html += '<span>\u2022</span>';
1149
1025
  html += '<span style="color:#3b82f6">' + (components.length - ssrCount) + ' client</span>';
1150
1026
  html += '<span>\u2022</span>';
@@ -1169,9 +1045,9 @@ var PageMapGenerator = class {
1169
1045
  withEntry.forEach(comp => {
1170
1046
  const usageCount = comp.usedIn?.length || 0;
1171
1047
  const tags = [];
1172
- if (comp.ssr) tags.push('<span class="tag" style="background:#166534;color:#86efac" title="Server-Side Rendering">SSR</span>');
1173
- if (usageCount > 0) tags.push('<span class="tag" style="background:#5b21b6;color:#c4b5fd" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
1174
- if (comp.sourceFile) tags.push('<span class="tag" style="background:#1e3a5f;color:#93c5fd" title="Has source file">SRC</span>');
1048
+ if (comp.ssr) tags.push('<span class="tag tag-ssr" title="Server-Side Rendering">SSR</span>');
1049
+ if (usageCount > 0) tags.push('<span class="tag tag-view" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
1050
+ if (comp.sourceFile) tags.push('<span class="tag tag-src" title="Has source file">SRC</span>');
1175
1051
 
1176
1052
  // Find URL from routes based on controller/action OR infer from entry file
1177
1053
  let urlInfo = '';
@@ -1193,7 +1069,7 @@ var PageMapGenerator = class {
1193
1069
 
1194
1070
  html += '<div class="page-item" data-path="' + comp.name.toLowerCase() + '" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
1195
1071
  html += '<div class="page-info">';
1196
- html += '<span class="page-name" style="display:flex;align-items:center"><span style="color:#61dafb;margin-right:6px">\u269B</span>' + comp.name + '</span>';
1072
+ html += '<span class="page-name" style="display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + '</span>';
1197
1073
  html += '<span class="page-path" style="font-size:10px;color:var(--accent)">' + urlInfo + '</span>';
1198
1074
  html += '</div>';
1199
1075
  html += '<div class="page-tags">' + tags.join('') + '</div>';
@@ -1216,8 +1092,8 @@ var PageMapGenerator = class {
1216
1092
  withoutEntry.forEach(comp => {
1217
1093
  const usageCount = comp.usedIn?.length || 0;
1218
1094
  const tags = [];
1219
- if (comp.ssr) tags.push('<span class="tag" style="background:#166534;color:#86efac" title="Server-Side Rendering">SSR</span>');
1220
- if (usageCount > 0) tags.push('<span class="tag" style="background:#5b21b6;color:#c4b5fd" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
1095
+ if (comp.ssr) tags.push('<span class="tag tag-ssr" title="Server-Side Rendering">SSR</span>');
1096
+ if (usageCount > 0) tags.push('<span class="tag tag-view" title="Used in ' + usageCount + ' view(s)">View:' + usageCount + '</span>');
1221
1097
 
1222
1098
  // Find URL from routes based on controller/action
1223
1099
  let urlInfo = '';
@@ -1235,7 +1111,7 @@ var PageMapGenerator = class {
1235
1111
 
1236
1112
  html += '<div class="page-item" data-path="' + comp.name.toLowerCase() + '" onclick="showReactComponentDetail(\\'' + encodeURIComponent(JSON.stringify(comp)) + '\\')">';
1237
1113
  html += '<div class="page-info">';
1238
- html += '<span class="page-name" style="display:flex;align-items:center"><span style="color:#61dafb;margin-right:6px">\u269B</span>' + comp.name + '</span>';
1114
+ html += '<span class="page-name" style="display:flex;align-items:center"><span class="text-react mr-2">\u269B</span>' + comp.name + '</span>';
1239
1115
  html += '<span class="page-path" style="font-size:10px;color:var(--accent)">' + (urlInfo || 'View-only') + '</span>';
1240
1116
  html += '</div>';
1241
1117
  html += '<div class="page-tags">' + tags.join('') + '</div>';
@@ -1345,7 +1221,7 @@ var PageMapGenerator = class {
1345
1221
  const totalWithPartials = enrichedViews.filter(v => v.partials.length > 0).length;
1346
1222
 
1347
1223
  let html = '';
1348
- html += '<div style="padding:12px;background:var(--bg3);border-radius:8px;margin-bottom:12px">';
1224
+ html += '<div class="info-box mb-3">';
1349
1225
  html += '<div style="font-weight:600;margin-bottom:8px">\u{1F5BC}\uFE0F Rails Screens (View Templates)</div>';
1350
1226
  html += '<div style="display:flex;gap:16px;flex-wrap:wrap;font-size:12px;color:var(--text2)">';
1351
1227
  html += '<span>' + enrichedViews.length + ' screens</span>';
@@ -1392,7 +1268,7 @@ var PageMapGenerator = class {
1392
1268
  if (!view.hasRoute) indicators += '<span class="route-tag route-tag-warn" title="No matching route found">\u26A0\uFE0F</span>';
1393
1269
 
1394
1270
  // Display: URL path (if route exists) or controller/action
1395
- const displayName = view.hasRoute ? view.path.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>') : view.controller + '#' + view.action;
1271
+ const displayName = view.hasRoute ? view.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') : view.controller + '#' + view.action;
1396
1272
 
1397
1273
  // Search-friendly data-path includes path, controller, action
1398
1274
  const searchPath = [view.path || '', view.controller || '', view.action || '', view.viewPath || ''].join(' ').toLowerCase();
@@ -1430,7 +1306,7 @@ var PageMapGenerator = class {
1430
1306
  html += '<div class="detail-section">';
1431
1307
  html += '<div class="detail-label">\u{1F310} URL Path</div>';
1432
1308
  if (screen.hasRoute) {
1433
- html += '<div class="detail-value" style="font-family:monospace">' + screen.path.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>') + '</div>';
1309
+ html += '<div class="detail-value" style="font-family:monospace">' + screen.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</div>';
1434
1310
  } else {
1435
1311
  html += '<div class="detail-value" style="color:var(--text2)">No route defined (orphan view)</div>';
1436
1312
  }
@@ -1523,7 +1399,7 @@ var PageMapGenerator = class {
1523
1399
 
1524
1400
  const tooltip = assignment && assignment.assignedValue ? assignment.assignedValue.replace(/"/g, '&quot;') : '';
1525
1401
  html += '<div class="detail-item"' + hiddenClass + ' title="' + tooltip + '">';
1526
- html += '<span class="tag" style="background:#8b5cf6;font-size:10px">@</span>';
1402
+ html += '<span class="tag tag-var tag-sm">@</span>';
1527
1403
  html += '<span class="name" style="font-family:monospace;font-weight:500">' + v + '</span>';
1528
1404
 
1529
1405
  if (linkedModel) {
@@ -1567,10 +1443,10 @@ var PageMapGenerator = class {
1567
1443
  html += '<div class="detail-items">';
1568
1444
  screen.reactComponents.forEach(rc => {
1569
1445
  html += '<div class="detail-item">';
1570
- html += '<span class="tag" style="background:#61dafb;color:#222;font-size:10px;font-weight:600">React</span>';
1446
+ html += '<span class="tag tag-react tag-sm" style="font-weight:600">React</span>';
1571
1447
  html += '<span class="name" style="font-family:monospace;font-weight:500">' + rc.name + '</span>';
1572
1448
  if (rc.ssr) {
1573
- html += '<span style="margin-left:6px;font-size:9px;background:#22c55e;color:white;padding:1px 4px;border-radius:2px">SSR</span>';
1449
+ html += '<span class="badge-success">SSR</span>';
1574
1450
  }
1575
1451
  if (rc.propsVar) {
1576
1452
  html += '<span style="margin-left:auto;font-size:10px;color:var(--text2);font-family:monospace">props: ' + rc.propsVar + '</span>';
@@ -1591,7 +1467,7 @@ var PageMapGenerator = class {
1591
1467
  html += '<div class="detail-items" id="' + partialListId + '">';
1592
1468
  screen.partials.forEach((p, idx) => {
1593
1469
  const hiddenClass = idx >= partialLimit ? ' style="display:none" data-hidden="true"' : '';
1594
- html += '<div class="detail-item"' + hiddenClass + '><span class="tag" style="background:#06b6d4;font-size:10px">PARTIAL</span><span class="name" style="font-family:monospace;font-size:11px">' + p + '</span></div>';
1470
+ html += '<div class="detail-item"' + hiddenClass + '><span class="tag tag-partial tag-sm">PARTIAL</span><span class="name" style="font-family:monospace;font-size:11px">' + p + '</span></div>';
1595
1471
  });
1596
1472
  html += '</div>';
1597
1473
  if (hasMorePartials) {
@@ -1606,7 +1482,7 @@ var PageMapGenerator = class {
1606
1482
  html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
1607
1483
  html += '<div class="detail-items">';
1608
1484
  screen.services.forEach(s => {
1609
- html += '<div class="detail-item"><span class="tag" style="background:#8b5cf6">Service</span><span class="name" style="font-family:monospace">' + s + '</span></div>';
1485
+ html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
1610
1486
  });
1611
1487
  html += '</div></div>';
1612
1488
  }
@@ -1617,7 +1493,7 @@ var PageMapGenerator = class {
1617
1493
  html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
1618
1494
  html += '<div class="detail-items">';
1619
1495
  screen.grpcCalls.forEach(g => {
1620
- html += '<div class="detail-item"><span class="tag" style="background:#06b6d4">gRPC</span><span class="name" style="font-family:monospace">' + g + '</span></div>';
1496
+ html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
1621
1497
  });
1622
1498
  html += '</div></div>';
1623
1499
  }
@@ -1628,7 +1504,7 @@ var PageMapGenerator = class {
1628
1504
  html += '<div class="detail-label">\u{1F4BE} Models Used</div>';
1629
1505
  html += '<div class="detail-items">';
1630
1506
  screen.modelAccess.forEach(m => {
1631
- html += '<div class="detail-item"><span class="tag" style="background:#f59e0b">Model</span><span class="name" style="font-family:monospace">' + m + '</span></div>';
1507
+ html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
1632
1508
  });
1633
1509
  html += '</div></div>';
1634
1510
  }
@@ -1636,10 +1512,10 @@ var PageMapGenerator = class {
1636
1512
  // Controller Action info
1637
1513
  html += '<div class="detail-section">';
1638
1514
  html += '<div class="detail-label">\u{1F3AE} Controller Action</div>';
1639
- html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px">';
1515
+ html += '<div class="code-block">';
1640
1516
  html += '<div style="font-family:monospace;font-size:12px">' + screen.controller + '#' + screen.action + '</div>';
1641
1517
  if (screen.controllerInfo) {
1642
- html += '<div style="margin-top:6px;font-size:11px;color:var(--text2)">app/controllers/' + screen.controllerInfo.filePath;
1518
+ html += '<div class="subtext">app/controllers/' + screen.controllerInfo.filePath;
1643
1519
  if (screen.actionLine) html += ':' + screen.actionLine;
1644
1520
  html += '</div>';
1645
1521
 
@@ -1652,7 +1528,7 @@ var PageMapGenerator = class {
1652
1528
  });
1653
1529
  if (applicableFilters.length > 0) {
1654
1530
  html += '<div style="margin-top:8px;font-size:11px">';
1655
- html += '<span style="color:#22c55e">Before filters:</span> ' + applicableFilters.map(f => f.name).join(', ');
1531
+ html += '<span class="text-success">Before filters:</span> ' + applicableFilters.map(f => f.name).join(', ');
1656
1532
  html += '</div>';
1657
1533
  }
1658
1534
  }
@@ -1717,7 +1593,7 @@ var PageMapGenerator = class {
1717
1593
  html += '<div class="detail-label">Method & Path</div>';
1718
1594
  html += '<div class="detail-value">';
1719
1595
  html += '<span style="background:' + methodColor + ';color:white;padding:2px 8px;border-radius:4px;font-weight:600;margin-right:8px">' + (route.method || 'GET') + '</span>';
1720
- html += '<span style="font-family:monospace">' + route.path.replace(/:([a-z_]+)/g, '<span style="color:#f59e0b">:$1</span>') + '</span>';
1596
+ html += '<span class="mono">' + route.path.replace(/:([a-z_]+)/g, '<span class="text-warning">:$1</span>') + '</span>';
1721
1597
  html += '</div></div>';
1722
1598
 
1723
1599
  html += '<div class="detail-section">';
@@ -1739,7 +1615,7 @@ var PageMapGenerator = class {
1739
1615
  responseTypes.push('<span style="background:#8b5cf6;color:white;padding:2px 8px;border-radius:4px;font-size:11px;margin-right:4px">' + f.toUpperCase() + '</span>');
1740
1616
  });
1741
1617
  }
1742
- html += responseTypes.length > 0 ? responseTypes.join('') : '<span style="color:var(--text2)">Unknown</span>';
1618
+ html += responseTypes.length > 0 ? responseTypes.join('') : '<span class="text-muted">Unknown</span>';
1743
1619
  html += '</div></div>';
1744
1620
 
1745
1621
  if (actionDetails.redirectsTo) {
@@ -1757,7 +1633,7 @@ var PageMapGenerator = class {
1757
1633
  html += '<div class="detail-label">\u{1F4C4} View Template</div>';
1758
1634
  html += '<div class="detail-value" style="font-family:monospace;font-size:12px">app/views/' + view.path + '</div>';
1759
1635
  if (view.partials && view.partials.length > 0) {
1760
- html += '<div style="margin-top:6px;font-size:11px;color:var(--text2)">Partials: ' + view.partials.slice(0, 5).join(', ') + '</div>';
1636
+ html += '<div class="subtext">Partials: ' + view.partials.slice(0, 5).join(', ') + '</div>';
1761
1637
  }
1762
1638
  if (view.instanceVars && view.instanceVars.length > 0) {
1763
1639
  html += '<div style="margin-top:4px;font-size:11px;color:var(--text2)">Instance vars: @' + view.instanceVars.slice(0, 5).join(', @') + '</div>';
@@ -1769,7 +1645,7 @@ var PageMapGenerator = class {
1769
1645
  if (controllerInfo && (controllerInfo.beforeActions.length > 0 || controllerInfo.afterActions.length > 0)) {
1770
1646
  html += '<div class="detail-section">';
1771
1647
  html += '<div class="detail-label">\u{1F512} Filters Applied</div>';
1772
- html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px">';
1648
+ html += '<div class="code-block">';
1773
1649
 
1774
1650
  const applicableBeforeFilters = controllerInfo.beforeActions.filter(f => {
1775
1651
  if (f.only && f.only.length > 0) return f.only.includes(route.action);
@@ -1781,7 +1657,7 @@ var PageMapGenerator = class {
1781
1657
  html += '<div style="font-size:11px;margin-bottom:4px"><span style="color:#22c55e;font-weight:600">Before:</span> ';
1782
1658
  html += applicableBeforeFilters.map(f => {
1783
1659
  let info = f.name;
1784
- if (f.if) info += ' <span style="color:var(--text2)">(if: ' + f.if + ')</span>';
1660
+ if (f.if) info += ' <span class="text-muted">(if: ' + f.if + ')</span>';
1785
1661
  return info;
1786
1662
  }).join(', ');
1787
1663
  html += '</div>';
@@ -1812,7 +1688,7 @@ var PageMapGenerator = class {
1812
1688
  html += '<div class="detail-label">\u2699\uFE0F Services Called</div>';
1813
1689
  html += '<div class="detail-items">';
1814
1690
  services.forEach(s => {
1815
- html += '<div class="detail-item"><span class="tag" style="background:#8b5cf6">Service</span><span class="name" style="font-family:monospace">' + s + '</span></div>';
1691
+ html += '<div class="detail-item"><span class="tag tag-service">Service</span><span class="name">' + s + '</span></div>';
1816
1692
  });
1817
1693
  html += '</div></div>';
1818
1694
  }
@@ -1824,7 +1700,7 @@ var PageMapGenerator = class {
1824
1700
  html += '<div class="detail-label">\u{1F50C} gRPC Calls</div>';
1825
1701
  html += '<div class="detail-items">';
1826
1702
  grpcCalls.forEach(g => {
1827
- html += '<div class="detail-item"><span class="tag" style="background:#06b6d4">gRPC</span><span class="name" style="font-family:monospace">' + g + '</span></div>';
1703
+ html += '<div class="detail-item"><span class="tag tag-grpc">gRPC</span><span class="name">' + g + '</span></div>';
1828
1704
  });
1829
1705
  html += '</div></div>';
1830
1706
  }
@@ -1836,7 +1712,7 @@ var PageMapGenerator = class {
1836
1712
  html += '<div class="detail-label">\u{1F4BE} Models Accessed</div>';
1837
1713
  html += '<div class="detail-items">';
1838
1714
  models.forEach(m => {
1839
- html += '<div class="detail-item"><span class="tag" style="background:#f59e0b">Model</span><span class="name" style="font-family:monospace">' + m + '</span></div>';
1715
+ html += '<div class="detail-item"><span class="tag tag-model">Model</span><span class="name">' + m + '</span></div>';
1840
1716
  });
1841
1717
  html += '</div></div>';
1842
1718
  }
@@ -1854,13 +1730,13 @@ var PageMapGenerator = class {
1854
1730
  html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;max-height:150px;overflow-y:auto">';
1855
1731
  html += '<div style="font-family:monospace;font-size:11px;line-height:1.6">';
1856
1732
  meaningfulCalls.forEach((call, i) => {
1857
- html += '<div style="padding:2px 0;border-bottom:1px solid var(--bg1)">';
1733
+ html += '<div class="accordion-item">';
1858
1734
  html += '<span style="color:var(--text2);margin-right:8px">' + (i+1) + '.</span>';
1859
- html += '<span style="color:var(--accent)">' + call + '</span>';
1735
+ html += '<span class="text-accent">' + call + '</span>';
1860
1736
  html += '</div>';
1861
1737
  });
1862
1738
  if (actionDetails.methodCalls.length > 15) {
1863
- html += '<div style="padding:4px 0;color:var(--text2);font-style:italic">...and ' + (actionDetails.methodCalls.length - 15) + ' more</div>';
1739
+ html += '<div class="note">...and ' + (actionDetails.methodCalls.length - 15) + ' more</div>';
1864
1740
  }
1865
1741
  html += '</div></div></div>';
1866
1742
  }
@@ -1872,16 +1748,16 @@ var PageMapGenerator = class {
1872
1748
  html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px;font-family:monospace;font-size:11px">';
1873
1749
 
1874
1750
  if (controllerInfo) {
1875
- html += '<div style="padding:4px 0;display:flex;align-items:center">';
1876
- html += '<span style="color:var(--text2);width:80px">Controller:</span>';
1751
+ html += '<div class="detail-item flex items-center py-1">';
1752
+ html += '<span class="text-muted w-20">Controller:</span>';
1877
1753
  html += '<span>app/controllers/' + controllerInfo.filePath;
1878
- if (actionDetails && actionDetails.line) html += ':<span style="color:#22c55e">' + actionDetails.line + '</span>';
1754
+ if (actionDetails && actionDetails.line) html += ':<span class="text-success">' + actionDetails.line + '</span>';
1879
1755
  html += '</span></div>';
1880
1756
  }
1881
1757
 
1882
1758
  if (view) {
1883
- html += '<div style="padding:4px 0;display:flex;align-items:center">';
1884
- html += '<span style="color:var(--text2);width:80px">View:</span>';
1759
+ html += '<div class="detail-item flex items-center py-1">';
1760
+ html += '<span class="text-muted w-20">View:</span>';
1885
1761
  html += '<span>app/views/' + view.path + '</span>';
1886
1762
  html += '</div>';
1887
1763
  }
@@ -1891,12 +1767,12 @@ var PageMapGenerator = class {
1891
1767
  if (controllerInfo) {
1892
1768
  html += '<div class="detail-section">';
1893
1769
  html += '<div class="detail-label">\u{1F4CB} Controller Info</div>';
1894
- html += '<div style="background:var(--bg3);padding:10px;border-radius:6px;margin-top:6px">';
1895
- html += '<div style="font-weight:600;margin-bottom:4px">' + controllerInfo.className + '</div>';
1770
+ html += '<div class="code-block">';
1771
+ html += '<div class="section-title">' + controllerInfo.className + '</div>';
1896
1772
  html += '<div style="font-size:11px;color:var(--text2)">extends ' + controllerInfo.parentClass + '</div>';
1897
1773
  if (controllerInfo.concerns && controllerInfo.concerns.length > 0) {
1898
1774
  html += '<div style="margin-top:6px;font-size:11px">';
1899
- html += '<span style="color:var(--text2)">Concerns:</span> ' + controllerInfo.concerns.join(', ');
1775
+ html += '<span class="text-muted">Concerns:</span> ' + controllerInfo.concerns.join(', ');
1900
1776
  html += '</div>';
1901
1777
  }
1902
1778
  html += '</div></div>';
@@ -1935,7 +1811,7 @@ var PageMapGenerator = class {
1935
1811
  html += '<div class="detail-label">Partials Used</div>';
1936
1812
  html += '<div class="detail-items">';
1937
1813
  view.partials.forEach(p => {
1938
- html += '<div class="detail-item"><span class="tag" style="background:#6b7280">PARTIAL</span><span class="name">' + p + '</span></div>';
1814
+ html += '<div class="detail-item"><span class="tag tag-partial">PARTIAL</span><span class="name">' + p + '</span></div>';
1939
1815
  });
1940
1816
  html += '</div></div>';
1941
1817
  }
@@ -1945,7 +1821,7 @@ var PageMapGenerator = class {
1945
1821
  html += '<div class="detail-label">Instance Variables</div>';
1946
1822
  html += '<div class="detail-items">';
1947
1823
  view.instanceVars.slice(0, 10).forEach(v => {
1948
- html += '<div class="detail-item"><span class="tag" style="background:#f59e0b">@</span><span class="name">' + v + '</span></div>';
1824
+ html += '<div class="detail-item"><span class="tag tag-var">@</span><span class="name">' + v + '</span></div>';
1949
1825
  });
1950
1826
  if (view.instanceVars.length > 10) {
1951
1827
  html += '<div style="padding:4px 8px;color:var(--text2);font-size:11px">...and ' + (view.instanceVars.length - 10) + ' more</div>';
@@ -2150,7 +2026,7 @@ var PageMapGenerator = class {
2150
2026
  // Path header with depth visual
2151
2027
  dataHtml += '<div class="data-path-group" style="margin:8px 0">' +
2152
2028
  '<div class="data-path-header" style="font-size:11px;color:var(--text2);margin-bottom:4px;padding-left:'+(ops[0]?.depth * 8)+'px">' +
2153
- depthIndicator + '<span style="color:var(--accent)">' + pathLabel + '</span> (' + ops.length + ')' +
2029
+ depthIndicator + '<span class="text-accent">' + pathLabel + '</span> (' + ops.length + ')' +
2154
2030
  '</div>';
2155
2031
 
2156
2032
  ops.forEach(op => {
@@ -2171,7 +2047,7 @@ var PageMapGenerator = class {
2171
2047
  dataHtml += '<div class="detail-section"><h4>Used Components</h4>';
2172
2048
  uniqueComponentRefs.forEach(df => {
2173
2049
  const name = df.operationName || '';
2174
- dataHtml += '<div class="detail-item" style="cursor:default"><span class="tag" style="background:var(--text2);color:var(--bg)">COMPONENT</span> '+name+'</div>';
2050
+ dataHtml += '<div class="detail-item" style="cursor:default"><span class="tag tag-default">COMPONENT</span> '+name+'</div>';
2175
2051
  });
2176
2052
  dataHtml += '</div>';
2177
2053
  }
@@ -2196,7 +2072,7 @@ var PageMapGenerator = class {
2196
2072
  const methodColors = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',DELETE:'#ef4444',PATCH:'#8b5cf6'};
2197
2073
  const color = methodColors[api.method] || '#6b7280';
2198
2074
  restApiHtml += '<div class="detail-item api-item" onclick="event.stopPropagation(); showApiDetail(\\''+api.id.replace(/'/g, "\\\\'")+'\\')">' +
2199
- '<div class="api-row"><span class="tag" style="background:'+color+'">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
2075
+ '<div class="api-row"><span class="tag" style="background:'+color+';color:white">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
2200
2076
  (api.filePath ? '<div class="api-route">'+api.callType+' in '+api.filePath+'</div>' : '') +
2201
2077
  '</div>';
2202
2078
  });
@@ -2343,7 +2219,7 @@ var PageMapGenerator = class {
2343
2219
  html += '<div style="margin-bottom:12px">';
2344
2220
  html += '<div class="detail-item" style="cursor:pointer;background:var(--bg3);border-radius:4px" onclick="toggleGroupList(this)">';
2345
2221
  html += '<div class="detail-label" style="display:flex;align-items:center;gap:6px"><span class="group-toggle">\u25B8</span>/'+g+'</div>';
2346
- html += '<span style="color:var(--accent)">'+groupPages.length+' pages</span></div>';
2222
+ html += '<span class="text-accent">'+groupPages.length+' pages</span></div>';
2347
2223
  html += '<div class="group-page-list" style="display:none;margin-left:16px;margin-top:4px">';
2348
2224
  groupPages.sort((a,b) => a.path.localeCompare(b.path)).forEach(p => {
2349
2225
  const isAuth = p.authentication?.required;
@@ -2351,7 +2227,7 @@ var PageMapGenerator = class {
2351
2227
  html += '<div class="detail-item rel-item" style="cursor:pointer;padding:6px 8px" onclick="event.stopPropagation(); selectPage(\\''+p.path+'\\')">'+
2352
2228
  '<span style="font-family:monospace;font-size:11px;color:var(--text)">'+p.path+'</span>'+
2353
2229
  (isAuth ? '<span class="tag tag-auth" style="margin-left:6px;font-size:9px">AUTH</span>' : '')+
2354
- (isDynamic ? '<span class="tag" style="margin-left:6px;font-size:9px;background:#6366f1">DYNAMIC</span>' : '')+
2230
+ (isDynamic ? '<span class="tag tag-info" style="margin-left:6px" title="Dynamic Route">DYNAMIC</span>' : '')+
2355
2231
  '</div>';
2356
2232
  });
2357
2233
  html += '</div></div>';
@@ -2464,7 +2340,7 @@ var PageMapGenerator = class {
2464
2340
  const fragments = Array.from(gqlMap.values()).filter(o => o.type === 'fragment');
2465
2341
 
2466
2342
  if (queries.length > 0) {
2467
- html += '<div style="margin:8px 0;font-size:11px;color:var(--accent)">Queries ('+queries.length+')</div>';
2343
+ html += '<div class="subtext-accent">Queries ('+queries.length+')</div>';
2468
2344
  queries.slice(0, 20).forEach(op => {
2469
2345
  html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
2470
2346
  '<span class="tag tag-query">QUERY</span> '+op.name+'</div>';
@@ -2475,7 +2351,7 @@ var PageMapGenerator = class {
2475
2351
  }
2476
2352
 
2477
2353
  if (mutations.length > 0) {
2478
- html += '<div style="margin:8px 0;font-size:11px;color:var(--accent)">Mutations ('+mutations.length+')</div>';
2354
+ html += '<div class="subtext-accent">Mutations ('+mutations.length+')</div>';
2479
2355
  mutations.slice(0, 10).forEach(op => {
2480
2356
  html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
2481
2357
  '<span class="tag tag-mutation">MUTATION</span> '+op.name+'</div>';
@@ -2486,10 +2362,10 @@ var PageMapGenerator = class {
2486
2362
  }
2487
2363
 
2488
2364
  if (fragments.length > 0) {
2489
- html += '<div style="margin:8px 0;font-size:11px;color:var(--accent)">Fragments ('+fragments.length+')</div>';
2365
+ html += '<div class="subtext-accent">Fragments ('+fragments.length+')</div>';
2490
2366
  fragments.slice(0, 5).forEach(op => {
2491
2367
  html += '<div class="detail-item data-op" onclick="event.stopPropagation(); showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
2492
- '<span class="tag" style="background:#6b7280">FRAGMENT</span> '+op.name+'</div>';
2368
+ '<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
2493
2369
  });
2494
2370
  if (fragments.length > 5) {
2495
2371
  html += '<div style="color:var(--text2);font-size:10px;padding:4px">... and '+(fragments.length-5)+' more fragments</div>';
@@ -2514,7 +2390,7 @@ var PageMapGenerator = class {
2514
2390
  const methodColors = {GET:'#22c55e',POST:'#3b82f6',PUT:'#f59e0b',DELETE:'#ef4444',PATCH:'#8b5cf6'};
2515
2391
  const color = methodColors[api.method] || '#6b7280';
2516
2392
  html += '<div class="detail-item api-item" onclick="event.stopPropagation(); showApiDetail(\\''+api.id.replace(/'/g, "\\\\'")+'\\')">' +
2517
- '<div class="api-row"><span class="tag" style="background:'+color+'">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
2393
+ '<div class="api-row"><span class="tag" style="background:'+color+';color:white">'+api.method+'</span><span class="api-url">'+api.url+'</span></div>' +
2518
2394
  '<div class="api-route">'+api.callType+' in '+api.filePath+'</div>' +
2519
2395
  '</div>';
2520
2396
  });
@@ -2549,7 +2425,7 @@ var PageMapGenerator = class {
2549
2425
 
2550
2426
  if (api.category && api.category !== 'internal') {
2551
2427
  html += '<div class="detail-section"><h4>Category</h4>' +
2552
- '<span class="tag" style="background:var(--accent);color:white">'+api.category.toUpperCase()+'</span></div>';
2428
+ '<span class="tag tag-accent">'+api.category.toUpperCase()+'</span></div>';
2553
2429
  }
2554
2430
 
2555
2431
  // Show in modal
@@ -2656,7 +2532,7 @@ var PageMapGenerator = class {
2656
2532
  // Source info
2657
2533
  if (sourcePath) {
2658
2534
  const isHook = sourcePath.startsWith('use');
2659
- html += '<div class="detail-section"><h4>Source</h4><div class="detail-item" style="font-size:12px">via '+(isHook?'Hook':'Component')+': <span style="color:var(--accent)">'+sourcePath+'</span></div></div>';
2535
+ html += '<div class="detail-section"><h4>Source</h4><div class="detail-item" style="font-size:12px">via '+(isHook?'Hook':'Component')+': <span class="text-accent">'+sourcePath+'</span></div></div>';
2660
2536
  }
2661
2537
 
2662
2538
  // Operation Name with copy button
@@ -2734,7 +2610,7 @@ var PageMapGenerator = class {
2734
2610
  });
2735
2611
  if (queries.length > 5) {
2736
2612
  const remaining = queries.slice(5).map(o => ({name: o.name}));
2737
- html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (queries.length - 5) + ' more queries</div>';
2613
+ html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 5) + ' more queries</div>';
2738
2614
  }
2739
2615
  }
2740
2616
 
@@ -2746,7 +2622,7 @@ var PageMapGenerator = class {
2746
2622
  });
2747
2623
  if (mutations.length > 5) {
2748
2624
  const remaining = mutations.slice(5).map(o => ({name: o.name}));
2749
- html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (mutations.length - 5) + ' more mutations</div>';
2625
+ html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more mutations</div>';
2750
2626
  }
2751
2627
  }
2752
2628
 
@@ -2754,11 +2630,11 @@ var PageMapGenerator = class {
2754
2630
  html += '<div style="margin:8px 0;font-size:10px;color:var(--text2)">Fragments ('+fragments.length+')</div>';
2755
2631
  fragments.slice(0,3).forEach(op => {
2756
2632
  html += '<div class="detail-item data-op" onclick="showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
2757
- '<span class="tag" style="background:#6b7280">FRAGMENT</span> '+op.name+'</div>';
2633
+ '<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
2758
2634
  });
2759
2635
  if (fragments.length > 3) {
2760
2636
  const remaining = fragments.slice(3).map(o => ({name: o.name}));
2761
- html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (fragments.length - 3) + ' more fragments</div>';
2637
+ html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more fragments</div>';
2762
2638
  }
2763
2639
  }
2764
2640
 
@@ -2874,7 +2750,7 @@ var PageMapGenerator = class {
2874
2750
  });
2875
2751
  if (queries.length > 8) {
2876
2752
  const remaining = queries.slice(8).map(o => ({name: o.name}));
2877
- html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (queries.length - 8) + ' more</div>';
2753
+ html += '<div class="expand-more" onclick="expandMore(\\'query\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (queries.length - 8) + ' more</div>';
2878
2754
  }
2879
2755
  }
2880
2756
 
@@ -2886,7 +2762,7 @@ var PageMapGenerator = class {
2886
2762
  });
2887
2763
  if (mutations.length > 5) {
2888
2764
  const remaining = mutations.slice(5).map(o => ({name: o.name}));
2889
- html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (mutations.length - 5) + ' more</div>';
2765
+ html += '<div class="expand-more" onclick="expandMore(\\'mutation\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (mutations.length - 5) + ' more</div>';
2890
2766
  }
2891
2767
  }
2892
2768
 
@@ -2894,11 +2770,11 @@ var PageMapGenerator = class {
2894
2770
  html += '<div style="margin:8px 0 6px;font-size:10px;color:var(--text2)">Fragments ('+fragments.length+')</div>';
2895
2771
  fragments.slice(0, 3).forEach(op => {
2896
2772
  html += '<div class="detail-item data-op" onclick="showDataDetail(\\''+op.name.replace(/'/g, "\\\\'")+'\\')">' +
2897
- '<span class="tag" style="background:#6b7280">FRAGMENT</span> '+op.name+'</div>';
2773
+ '<span class="tag tag-default">FRAGMENT</span> '+op.name+'</div>';
2898
2774
  });
2899
2775
  if (fragments.length > 3) {
2900
2776
  const remaining = fragments.slice(3).map(o => ({name: o.name}));
2901
- html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" style="color:var(--accent);font-size:10px;cursor:pointer;padding:4px 0">\u25B8 Show ' + (fragments.length - 3) + ' more</div>';
2777
+ html += '<div class="expand-more" onclick="expandMore(\\'fragment\\', '+JSON.stringify(remaining).replace(/"/g, '&quot;')+', this)" class="expand-more">\u25B8 Show ' + (fragments.length - 3) + ' more</div>';
2902
2778
  }
2903
2779
  }
2904
2780
 
@@ -3441,86 +3317,21 @@ var PageMapGenerator = class {
3441
3317
  }
3442
3318
  </script>
3443
3319
  </body>
3444
- </html>`;
3445
- }
3446
- buildTreeHtml(groups, allPages) {
3447
- const colors = [
3448
- "#ef4444",
3449
- "#f97316",
3450
- "#eab308",
3451
- "#22c55e",
3452
- "#14b8a6",
3453
- "#3b82f6",
3454
- "#8b5cf6",
3455
- "#ec4899"
3456
- ];
3457
- let idx = 0;
3458
- return Array.from(groups.entries()).sort((a, b) => a[0].localeCompare(b[0])).map(([name, pages]) => {
3459
- const color = colors[idx++ % colors.length];
3460
- const sorted = pages.sort((a, b) => a.path.localeCompare(b.path));
3461
- const pathSet = new Set(sorted.map((p) => p.path));
3462
- const depthMap = /* @__PURE__ */ new Map();
3463
- for (const p of sorted) {
3464
- const segments = p.path.split("/").filter(Boolean);
3465
- let depth = 0;
3466
- for (let i = segments.length - 1; i >= 1; i--) {
3467
- const ancestorPath = "/" + segments.slice(0, i).join("/");
3468
- if (pathSet.has(ancestorPath)) {
3469
- depth = (depthMap.get(ancestorPath) ?? 0) + 1;
3470
- break;
3471
- }
3472
- }
3473
- depthMap.set(p.path, depth);
3474
- }
3475
- const pagesHtml = sorted.map((p) => {
3476
- const type = this.getPageType(p.path);
3477
- const queries = (p.dataFetching || []).filter(
3478
- (d) => !d.type?.includes("Mutation")
3479
- ).length;
3480
- const mutations = (p.dataFetching || []).filter(
3481
- (d) => d.type?.includes("Mutation")
3482
- ).length;
3483
- const depth = depthMap.get(p.path) ?? 0;
3484
- const pageNode = p;
3485
- const repoName = pageNode.repo || "";
3486
- const showRepoTag = allPages.some(
3487
- (pg) => pg.repo && pg.repo !== repoName
3488
- );
3489
- const shortRepoName = repoName.split("/").pop()?.split("-").map((s) => s.substring(0, 4)).join("-") || repoName.substring(0, 8);
3490
- const repoTag = showRepoTag && repoName ? `<span class="tag tag-repo" title="${repoName}">${shortRepoName}</span>` : "";
3491
- const isSpaComponent = /^\/[A-Z]/.test(p.path) || p.filePath && p.filePath.includes("components/pages");
3492
- const displayPath = isSpaComponent && p.filePath ? p.filePath.replace(/\.tsx?$/, "").replace(/^(frontend\/src\/|src\/)/, "") : p.path;
3493
- const spaTag = isSpaComponent ? '<span class="tag" style="background:#6366f1;color:white" title="SPA Component Page">SPA</span>' : "";
3494
- return `<div class="page-item" data-path="${p.path}" data-repo="${repoName}" onclick="selectPage('${p.path}')" style="--depth:${depth}">
3495
- <span class="page-type" style="--type-color:${type.color}">${type.label}</span>
3496
- <span class="page-path">${displayPath}</span>
3320
+ </html>`}buildTreeHtml(s,r){let c=["#ef4444","#f97316","#eab308","#22c55e","#14b8a6","#3b82f6","#8b5cf6","#ec4899"],v=0;return Array.from(s.entries()).sort((t,l)=>t[0].localeCompare(l[0])).map(([t,l])=>{let e=c[v++%c.length],i=l.sort((a,m)=>a.path.localeCompare(m.path)),o=new Set(i.map(a=>a.path)),p=new Map;for(let a of i){let m=a.path.split("/").filter(Boolean),u=0;for(let h=m.length-1;h>=1;h--){let y="/"+m.slice(0,h).join("/");if(o.has(y)){u=(p.get(y)??0)+1;break}}p.set(a.path,u);}let f=i.map(a=>{let m=this.getPageType(a.path),u=(a.dataFetching||[]).filter(g=>!g.type?.includes("Mutation")).length,h=(a.dataFetching||[]).filter(g=>g.type?.includes("Mutation")).length,y=p.get(a.path)??0,n=a.repo||"",w=r.some(g=>g.repo&&g.repo!==n),C=n.split("/").pop()?.split("-").map(g=>g.substring(0,4)).join("-")||n.substring(0,8),x=w&&n?`<span class="tag tag-repo" title="${n}">${C}</span>`:"",d=/^\/[A-Z]/.test(a.path)||a.filePath&&a.filePath.includes("components/pages"),b=d&&a.filePath?a.filePath.replace(/\.tsx?$/,"").replace(/^(frontend\/src\/|src\/)/,""):a.path,R=d?'<span class="tag tag-info" title="SPA Component Page">SPA</span>':"";return `<div class="page-item" data-path="${a.path}" data-repo="${n}" onclick="selectPage('${a.path}')" style="--depth:${y}">
3321
+ <span class="page-type" style="--type-color:${m.color}">${m.label}</span>
3322
+ <span class="page-path">${b}</span>
3497
3323
  <div class="page-tags">
3498
- ${repoTag}
3499
- ${spaTag}
3500
- ${p.authentication?.required ? '<span class="tag tag-auth">AUTH</span>' : ""}
3501
- ${queries > 0 ? `<span class="tag tag-query">Q:${queries}</span>` : ""}
3502
- ${mutations > 0 ? `<span class="tag tag-mutation">M:${mutations}</span>` : ""}
3324
+ ${x}
3325
+ ${R}
3326
+ ${a.authentication?.required?'<span class="tag tag-auth">AUTH</span>':""}
3327
+ ${u>0?`<span class="tag tag-query">Q:${u}</span>`:""}
3328
+ ${h>0?`<span class="tag tag-mutation">M:${h}</span>`:""}
3503
3329
  </div>
3504
- </div>`;
3505
- }).join("");
3506
- return `<div class="group">
3507
- <div class="group-header" onclick="toggleGroup(this)" style="--group-color:${color}">
3330
+ </div>`}).join("");return `<div class="group">
3331
+ <div class="group-header" onclick="toggleGroup(this)" style="--group-color:${e}">
3508
3332
  <span class="group-arrow">\u25BC</span>
3509
- <span class="group-name">/${name}</span>
3510
- <span class="group-count">${pages.length}</span>
3333
+ <span class="group-name">/${t}</span>
3334
+ <span class="group-count">${l.length}</span>
3511
3335
  </div>
3512
- <div class="group-content">${pagesHtml}</div>
3513
- </div>`;
3514
- }).join("");
3515
- }
3516
- getPageType(path) {
3517
- const last = path.split("/").filter(Boolean).pop() || "";
3518
- if (last === "new" || path.endsWith("/new")) return { label: "CREATE", color: "#22c55e" };
3519
- if (last === "edit" || path.includes("/edit")) return { label: "EDIT", color: "#f59e0b" };
3520
- if (last.startsWith("[") || last.startsWith(":")) return { label: "DETAIL", color: "#3b82f6" };
3521
- if (path.includes("setting")) return { label: "SETTINGS", color: "#6b7280" };
3522
- return { label: "LIST", color: "#06b6d4" };
3523
- }
3524
- };
3525
-
3526
- export { PageMapGenerator };
3336
+ <div class="group-content">${f}</div>
3337
+ </div>`}).join("")}getPageType(s){let r=s.split("/").filter(Boolean).pop()||"";return r==="new"||s.endsWith("/new")?{label:"CREATE",color:"#22c55e"}:r==="edit"||s.includes("/edit")?{label:"EDIT",color:"#f59e0b"}:r.startsWith("[")||r.startsWith(":")?{label:"DETAIL",color:"#3b82f6"}:s.includes("setting")?{label:"SETTINGS",color:"#6b7280"}:{label:"LIST",color:"#06b6d4"}}};export{S as a};