Skip to content

Commit 88bf14c

Browse files
authored
Merge pull request #2 from RandomCodeSpace/fix/frontend-dead-button-url-encoding-tailwind-cdn
fix: remove dead Run Analysis button, URL-encode node IDs, replace Tailwind CDN
2 parents 16fb4b1 + 14bdeb3 commit 88bf14c

12 files changed

Lines changed: 106 additions & 62 deletions

File tree

.claude/settings.local.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
{
2+
"prefersReducedMotion": true,
3+
"spinnerTipsEnabled": false
4+
}

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -43,6 +43,8 @@ src/main/frontend/node_modules/
4343
src/main/frontend/node/
4444
src/main/frontend/dist/
4545
src/main/frontend/tsconfig.tsbuildinfo
46+
# Generated explorer CSS (rebuild via: cd src/main/frontend && npm run build:explorer-css)
47+
src/main/resources/static/css/explorer.css
4648

4749
# Distribution
4850
*.tar.gz
Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
import type { Config } from 'tailwindcss';
2+
3+
/**
4+
* Tailwind config for the Thymeleaf explorer UI templates.
5+
* Separate from the React app config to preserve the original blue brand colors.
6+
*/
7+
export default {
8+
darkMode: 'class',
9+
content: [
10+
'../resources/templates/**/*.html',
11+
],
12+
theme: {
13+
extend: {
14+
colors: {
15+
brand: {
16+
50: '#eff6ff',
17+
100: '#dbeafe',
18+
200: '#bfdbfe',
19+
300: '#93c5fd',
20+
400: '#60a5fa',
21+
500: '#3b82f6',
22+
600: '#2563eb',
23+
700: '#1d4ed8',
24+
800: '#1e40af',
25+
900: '#1e3a5f',
26+
},
27+
surface: {
28+
DEFAULT: '#f8fafc',
29+
dark: '#0f172a',
30+
},
31+
card: {
32+
DEFAULT: '#ffffff',
33+
dark: '#1e293b',
34+
},
35+
muted: {
36+
DEFAULT: '#64748b',
37+
dark: '#94a3b8',
38+
},
39+
},
40+
animation: {
41+
'fade-in': 'fadeIn 0.3s ease-out',
42+
'slide-up': 'slideUp 0.3s ease-out',
43+
},
44+
keyframes: {
45+
fadeIn: {
46+
'0%': { opacity: '0' },
47+
'100%': { opacity: '1' },
48+
},
49+
slideUp: {
50+
'0%': { opacity: '0', transform: 'translateY(8px)' },
51+
'100%': { opacity: '1', transform: 'translateY(0)' },
52+
},
53+
},
54+
},
55+
},
56+
plugins: [],
57+
} satisfies Config;

src/main/frontend/package.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,8 @@
55
"type": "module",
66
"scripts": {
77
"dev": "vite",
8-
"build": "tsc -b && vite build",
8+
"build": "tsc -b && vite build && npm run build:explorer-css",
9+
"build:explorer-css": "npx tailwindcss -c ./explorer-tailwind.config.ts -i ./src/explorer.css -o ../resources/static/css/explorer.css --minify",
910
"preview": "vite preview"
1011
},
1112
"dependencies": {

src/main/frontend/src/explorer.css

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
@tailwind base;
2+
@tailwind components;
3+
@tailwind utilities;
4+
5+
[x-cloak] { display: none !important; }
6+
.htmx-indicator { display: none; }
7+
.htmx-request .htmx-indicator { display: inline-block; }
8+
.htmx-request.htmx-indicator { display: inline-block; }
9+
.card-stagger:nth-child(1) { animation-delay: 0ms; }
10+
.card-stagger:nth-child(2) { animation-delay: 30ms; }
11+
.card-stagger:nth-child(3) { animation-delay: 60ms; }
12+
.card-stagger:nth-child(4) { animation-delay: 90ms; }
13+
.card-stagger:nth-child(5) { animation-delay: 120ms; }
14+
.card-stagger:nth-child(6) { animation-delay: 150ms; }
15+
.card-stagger:nth-child(7) { animation-delay: 180ms; }
16+
.card-stagger:nth-child(8) { animation-delay: 210ms; }
17+
::-webkit-scrollbar { width: 6px; height: 6px; }
18+
::-webkit-scrollbar-track { background: transparent; }
19+
::-webkit-scrollbar-thumb { background: #475569; border-radius: 3px; }

src/main/java/io/github/randomcodespace/iq/web/ExplorerController.java

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -50,8 +50,8 @@ public String nodesByKind(
5050
return "explorer/nodes";
5151
}
5252

53-
@GetMapping("/node/{nodeId}")
54-
public String nodeDetail(@PathVariable String nodeId, Model model) {
53+
@GetMapping("/node")
54+
public String nodeDetail(@RequestParam String nodeId, Model model) {
5555
Map<String, Object> detail = queryService.nodeDetailWithEdges(nodeId);
5656
model.addAttribute("detail", detail);
5757
return "explorer/detail";
@@ -76,8 +76,8 @@ public String nodesFragment(
7676
return "explorer/fragments/nodes-grid";
7777
}
7878

79-
@GetMapping("/fragments/detail/{nodeId}")
80-
public String detailFragment(@PathVariable String nodeId, Model model) {
79+
@GetMapping("/fragments/detail")
80+
public String detailFragment(@RequestParam String nodeId, Model model) {
8181
Map<String, Object> detail = queryService.nodeDetailWithEdges(nodeId);
8282
model.addAttribute("detail", detail);
8383
return "explorer/fragments/detail-panel";

src/main/resources/static/css/explorer.css

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/main/resources/templates/explorer/fragments/detail-panel.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -107,7 +107,7 @@ <h2 class="font-semibold mb-4">
107107
<span th:if="${edge['target_kind'] != null}"
108108
class="text-[10px] px-1.5 py-0.5 rounded bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 capitalize whitespace-nowrap"
109109
th:text="${edge['target_kind']}">class</span>
110-
<a th:href="@{/ui/node/{id}(id=${edge['target']})}"
110+
<a th:href="@{/ui/node(nodeId=${edge['target']})}"
111111
class="text-brand-600 dark:text-brand-400 hover:underline text-sm truncate"
112112
th:text="${edge['target_label'] != null ? edge['target_label'] : edge['target']}">target</a>
113113
</div>
@@ -137,7 +137,7 @@ <h2 class="font-semibold mb-4">
137137
th:text="${node['kind']}">class</span>
138138
<svg class="w-4 h-4 text-muted dark:text-muted-dark shrink-0" fill="none" stroke="currentColor" stroke-width="2" viewBox="0 0 24 24"><path d="M19 12H5M12 19l-7-7 7-7"/></svg>
139139
<div class="flex items-center gap-2 min-w-0">
140-
<a th:href="@{/ui/node/{id}(id=${node['id']})}"
140+
<a th:href="@{/ui/node(nodeId=${node['id']})}"
141141
class="text-brand-600 dark:text-brand-400 hover:underline text-sm truncate"
142142
th:text="${node['label']}">label</a>
143143
<span th:if="${node['layer'] != null}"

src/main/resources/templates/explorer/fragments/nodes-grid.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,7 @@ <h2 class="text-lg font-semibold capitalize" th:text="${kind}">kind</h2>
2525
<div class="flex items-start justify-between gap-4">
2626
<div class="flex-1 min-w-0">
2727
<div class="flex items-center gap-2 mb-1">
28-
<a th:href="@{/ui/node/{id}(id=${node['id']})}"
28+
<a th:href="@{/ui/node(nodeId=${node['id']})}"
2929
class="font-medium text-brand-600 dark:text-brand-400 hover:underline truncate"
3030
th:text="${node['label']}">label</a>
3131
<span th:if="${node['layer'] != null}"
@@ -49,7 +49,7 @@ <h2 class="text-lg font-semibold capitalize" th:text="${kind}">kind</h2>
4949
class="text-[10px] px-1.5 py-0.5 rounded bg-violet-100 dark:bg-violet-900/30 text-violet-700 dark:text-violet-300 font-mono"
5050
th:text="${ann}">@ann</span>
5151
</div>
52-
<button th:attr="hx-get='/ui/fragments/detail/' + ${node['id']}"
52+
<button th:attr="hx-get='/ui/fragments/detail?nodeId=' + ${#uris.escapeQueryStringParam(node['id'])}"
5353
hx-target="#content" hx-swap="innerHTML"
5454
class="text-xs font-medium px-3 py-1.5 rounded-md text-muted dark:text-muted-dark hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors whitespace-nowrap">
5555
Details

src/main/resources/templates/explorer/fragments/search-results.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ <h2 class="text-lg font-semibold">
2626
<div class="flex items-start justify-between gap-4">
2727
<div class="flex-1 min-w-0">
2828
<div class="flex items-center gap-2 mb-1">
29-
<a th:href="@{/ui/node/{id}(id=${node['id']})}"
29+
<a th:href="@{/ui/node(nodeId=${node['id']})}"
3030
class="font-medium text-brand-600 dark:text-brand-400 hover:underline truncate"
3131
th:text="${node['label']}">label</a>
3232
<span class="text-[10px] px-1.5 py-0.5 rounded bg-slate-100 dark:bg-slate-800 text-slate-600 dark:text-slate-400 capitalize"
@@ -38,7 +38,7 @@ <h2 class="text-lg font-semibold">
3838
<div th:if="${node['file_path'] != null}" class="text-xs text-muted dark:text-muted-dark font-mono truncate"
3939
th:text="${node['file_path']}">file</div>
4040
</div>
41-
<button th:attr="hx-get='/ui/fragments/detail/' + ${node['id']}"
41+
<button th:attr="hx-get='/ui/fragments/detail?nodeId=' + ${#uris.escapeQueryStringParam(node['id'])}"
4242
hx-target="#content" hx-swap="innerHTML"
4343
class="text-xs font-medium px-3 py-1.5 rounded-md text-muted dark:text-muted-dark hover:bg-slate-100 dark:hover:bg-slate-800 transition-colors whitespace-nowrap">
4444
Details

0 commit comments

Comments
 (0)