Skip to content

Commit 880e223

Browse files
Lum1104claude
andcommitted
feat(dashboard): add mobile layout and responsive fixes
Bumps to 2.6.0. - MobileLayout activates via useIsMobile at <768px with bottom-tab navigation (Graph/Info/Files); panes stay mounted (visibility toggle) to preserve ReactFlow dimensions and FileExplorer state. - MobileDrawer holds persona, view mode, diff, node-type filters, layers, and tool buttons (Filter/Export/Path/Theme/Help). - Selecting a node auto-pivots to Info; CodeViewer is always fullscreen on mobile; SearchBar collapses to a 🔍 toggle. - Homepage Hero/Footer/Install responsive: drop nowrap on title and tagline, stack title spans for editorial wrap, full-width CTAs at <480px, narrow-width spacing refinements. - Desktop dashboard: sidebar telescopes 260/300/360px, header gaps tighten, Path button label collapses to icon at narrow widths. Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
1 parent 6e0d1c1 commit 880e223

14 files changed

Lines changed: 692 additions & 21 deletions

File tree

.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "understand-anything",
33
"description": "AI-powered codebase understanding — analyze, visualize, and explain any project",
4-
"version": "2.5.1",
4+
"version": "2.6.0",
55
"author": {
66
"name": "Lum1104"
77
},

.copilot-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "understand-anything",
33
"description": "AI-powered codebase understanding — analyze, visualize, and explain any project",
4-
"version": "2.5.1",
4+
"version": "2.6.0",
55
"author": {
66
"name": "Lum1104"
77
},

.cursor-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
"name": "understand-anything",
33
"displayName": "Understand Anything",
44
"description": "AI-powered codebase understanding — analyze, visualize, and explain any project",
5-
"version": "2.5.1",
5+
"version": "2.6.0",
66
"author": {
77
"name": "Lum1104"
88
},

homepage/src/components/Footer.astro

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,14 @@ const githubUrl = 'https://github.com/Lum1104/Understand-Anything';
2828
margin: 0 auto;
2929
}
3030

31+
.footer-links {
32+
display: flex;
33+
align-items: center;
34+
justify-content: center;
35+
flex-wrap: wrap;
36+
gap: 0.5rem 0.25rem;
37+
}
38+
3139
.footer-logo {
3240
font-family: var(--font-heading);
3341
font-size: 1.15rem;
@@ -60,4 +68,10 @@ const githubUrl = 'https://github.com/Lum1104/Understand-Anything';
6068
font-size: 0.8rem;
6169
color: var(--text-muted);
6270
}
71+
72+
@media (max-width: 480px) {
73+
.footer { padding: 3rem 1.25rem; }
74+
.footer-sep { display: none; }
75+
.footer-links { gap: 0.25rem 1rem; }
76+
}
6377
</style>

homepage/src/components/Hero.astro

Lines changed: 46 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -122,12 +122,13 @@ const githubUrl = 'https://github.com/Lum1104/Understand-Anything';
122122
/* Headline */
123123
.hero-title {
124124
font-family: var(--font-heading);
125-
font-size: clamp(3.5rem, 9vw, 7rem);
125+
font-size: clamp(2.75rem, 9vw, 7rem);
126126
color: #e8e2d8;
127127
line-height: 1.05;
128128
letter-spacing: -0.025em;
129129
margin-bottom: 2rem;
130130
white-space: nowrap;
131+
max-width: 100%;
131132
}
132133

133134
.hero-grad {
@@ -141,7 +142,7 @@ const githubUrl = 'https://github.com/Lum1104/Understand-Anything';
141142

142143
/* Tagline */
143144
.hero-tagline {
144-
font-size: clamp(1.1rem, 2vw, 1.4rem);
145+
font-size: clamp(1rem, 2vw, 1.4rem);
145146
color: #8a8578;
146147
line-height: 1.7;
147148
max-width: 900px;
@@ -329,15 +330,56 @@ const githubUrl = 'https://github.com/Lum1104/Understand-Anything';
329330
.anim-6 { animation-delay: 1.15s; }
330331

331332
/* Responsive */
333+
@media (max-width: 900px) {
334+
.hero-tagline {
335+
white-space: normal;
336+
max-width: 36ch;
337+
margin-left: auto;
338+
margin-right: auto;
339+
}
340+
}
341+
332342
@media (max-width: 768px) {
333-
.hero-pillars { gap: 0.5rem; }
343+
.hero { padding: 5rem 1.5rem 3rem; min-height: auto; }
344+
.hero-content { gap: 0; }
345+
.hero-pillars { gap: 0.5rem; margin-bottom: 2.25rem; }
334346
.pillar { font-size: 0.8rem; }
347+
.hero-badge {
348+
font-size: 0.72rem;
349+
padding: 0.35rem 1rem;
350+
margin-bottom: 1.75rem;
351+
}
352+
.hero-title { margin-bottom: 1.5rem; }
353+
}
354+
355+
@media (max-width: 640px) {
356+
.hero-title {
357+
white-space: normal;
358+
line-height: 1.02;
359+
letter-spacing: -0.03em;
360+
}
361+
/* Stack the two words on dedicated lines for editorial drama */
362+
.hero-title > span { display: block; }
335363
}
336364

337365
@media (max-width: 480px) {
338-
.hero-actions { flex-direction: column; gap: 1rem; }
366+
.hero { padding: 4rem 1.25rem 2.25rem; }
367+
.hero-actions {
368+
flex-direction: column;
369+
gap: 0.75rem;
370+
width: 100%;
371+
max-width: 320px;
372+
}
373+
.hero-cta,
374+
.hero-demo {
375+
width: 100%;
376+
text-align: center;
377+
padding: 0.85rem 1.5rem;
378+
}
339379
.hero-pillars { flex-direction: column; gap: 0.4rem; }
340380
.pillar-dot { display: none; }
381+
.hero-subscribe { margin-top: 1.5rem; }
341382
.hero-subscribe-toggle { font-size: 0.85rem; }
383+
.hero-subscribe-frame iframe { height: 130px; }
342384
}
343385
</style>

homepage/src/components/Install.astro

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -131,4 +131,14 @@
131131
.install-note strong {
132132
color: var(--text);
133133
}
134+
135+
@media (max-width: 480px) {
136+
.install { padding: 4.5rem 1.25rem; }
137+
.install-title { margin-bottom: 1.75rem; }
138+
pre { padding: 1rem 1.1rem; }
139+
code { font-size: 0.82rem; line-height: 1.7; }
140+
.install-code-header { padding: 0.65rem 0.85rem; }
141+
.install-code-label { font-size: 0.72rem; }
142+
.install-note { font-size: 0.82rem; line-height: 1.55; }
143+
}
134144
</style>

understand-anything-plugin/.claude-plugin/plugin.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
{
22
"name": "understand-anything",
33
"description": "AI-powered codebase understanding — analyze, visualize, and explain any project",
4-
"version": "2.5.1",
4+
"version": "2.6.0",
55
"author": {
66
"name": "Lum1104"
77
},

understand-anything-plugin/package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "@understand-anything/skill",
3-
"version": "2.5.1",
3+
"version": "2.6.0",
44
"type": "module",
55
"main": "dist/index.js",
66
"types": "dist/index.d.ts",

understand-anything-plugin/packages/dashboard/src/App.tsx

Lines changed: 27 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,8 @@ import ProjectOverview from "./components/ProjectOverview";
1616
import FileExplorer from "./components/FileExplorer";
1717
import WarningBanner from "./components/WarningBanner";
1818
import TokenGate from "./components/TokenGate";
19+
import MobileLayout from "./components/MobileLayout";
20+
import { useIsMobile } from "./hooks/useIsMobile";
1921
import { useKeyboardShortcuts } from "./hooks/useKeyboardShortcuts";
2022
import type { KeyboardShortcut } from "./hooks/useKeyboardShortcuts";
2123
import { ThemeProvider } from "./themes/index.ts";
@@ -118,6 +120,7 @@ function Dashboard({ accessToken }: { accessToken: string }) {
118120
const domainGraph = useDashboardStore((s) => s.domainGraph);
119121
const setDomainGraph = useDashboardStore((s) => s.setDomainGraph);
120122
const layoutIssues = useDashboardStore((s) => s.layoutIssues);
123+
const isMobile = useIsMobile();
121124
// Schema issues + ELK layout issues share the WarningBanner — graph-load
122125
// problems and dashboard rendering problems are equally surfaced.
123126
const allIssues = useMemo(
@@ -376,17 +379,32 @@ function Dashboard({ accessToken }: { accessToken: string }) {
376379
</div>
377380
);
378381

382+
if (isMobile) {
383+
return (
384+
<ThemeProvider metaTheme={metaTheme}>
385+
<MobileLayout
386+
accessToken={accessToken}
387+
showKeyboardHelp={showKeyboardHelp}
388+
setShowKeyboardHelp={setShowKeyboardHelp}
389+
loadError={loadError}
390+
allIssues={allIssues}
391+
shortcuts={shortcuts}
392+
/>
393+
</ThemeProvider>
394+
);
395+
}
396+
379397
return (
380398
<ThemeProvider metaTheme={metaTheme}>
381399
<div className="h-screen w-screen flex flex-col bg-root text-text-primary noise-overlay">
382400
{/* Header */}
383-
<header className="flex items-center px-5 py-3 bg-surface border-b border-border-subtle shrink-0 gap-4">
401+
<header className="flex items-center px-3 sm:px-5 py-3 bg-surface border-b border-border-subtle shrink-0 gap-2 sm:gap-4">
384402
{/* Left — fixed */}
385-
<div className="flex items-center gap-5 shrink-0">
386-
<h1 className="font-serif text-lg text-text-primary tracking-wide">
403+
<div className="flex items-center gap-3 sm:gap-5 shrink-0 min-w-0">
404+
<h1 className="font-serif text-base sm:text-lg text-text-primary tracking-wide truncate max-w-[160px] sm:max-w-[220px] lg:max-w-none">
387405
{graph?.project.name ?? "Understand Anything"}
388406
</h1>
389-
<div className="w-px h-5 bg-border-subtle" />
407+
<div className="w-px h-5 bg-border-subtle hidden sm:block" />
390408
<PersonaSelector />
391409
{graph && !isKnowledgeGraph && domainGraph && (
392410
<>
@@ -463,12 +481,12 @@ function Dashboard({ accessToken }: { accessToken: string }) {
463481
</div>
464482

465483
{/* Right — fixed actions */}
466-
<div className="flex items-center gap-4 shrink-0">
484+
<div className="flex items-center gap-2 sm:gap-4 shrink-0">
467485
<FilterPanel />
468486
<ExportMenu />
469487
<button
470488
onClick={togglePathFinder}
471-
className="flex items-center gap-1.5 px-3 py-1.5 rounded-lg text-sm bg-elevated text-text-secondary hover:text-text-primary transition-colors"
489+
className="flex items-center gap-1.5 px-2 sm:px-3 py-1.5 rounded-lg text-sm bg-elevated text-text-secondary hover:text-text-primary transition-colors"
472490
title="Find path between nodes (P)"
473491
>
474492
<svg
@@ -484,7 +502,7 @@ function Dashboard({ accessToken }: { accessToken: string }) {
484502
d="M13 7h8m0 0v8m0-8l-8 8-4-4-6 6"
485503
/>
486504
</svg>
487-
Path
505+
<span className="hidden md:inline">Path</span>
488506
</button>
489507
<ThemePicker />
490508
<button
@@ -540,8 +558,8 @@ function Dashboard({ accessToken }: { accessToken: string }) {
540558
</div>
541559
</div>
542560

543-
{/* Right sidebar */}
544-
<aside className="w-[360px] shrink-0 bg-surface border-l border-border-subtle overflow-auto">
561+
{/* Right sidebar — telescopes at narrower widths */}
562+
<aside className="w-[260px] md:w-[300px] lg:w-[360px] shrink-0 bg-surface border-l border-border-subtle overflow-auto">
545563
{sidebarContent}
546564
</aside>
547565

Lines changed: 73 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,73 @@
1+
import type { ReactNode } from "react";
2+
3+
export type MobileTab = "graph" | "info" | "files";
4+
5+
interface Props {
6+
activeTab: MobileTab;
7+
onTabChange: (tab: MobileTab) => void;
8+
}
9+
10+
const tabs: { id: MobileTab; label: string; icon: ReactNode }[] = [
11+
{
12+
id: "graph",
13+
label: "Graph",
14+
icon: (
15+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6}>
16+
<circle cx="6" cy="7" r="2" />
17+
<circle cx="18" cy="7" r="2" />
18+
<circle cx="12" cy="17" r="2" />
19+
<path strokeLinecap="round" d="M7.6 8.5L11 15.5M16.4 8.5L13 15.5M8 7h8" />
20+
</svg>
21+
),
22+
},
23+
{
24+
id: "info",
25+
label: "Info",
26+
icon: (
27+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6}>
28+
<circle cx="12" cy="12" r="9" />
29+
<path strokeLinecap="round" strokeLinejoin="round" d="M12 11v5M12 8h.01" />
30+
</svg>
31+
),
32+
},
33+
{
34+
id: "files",
35+
label: "Files",
36+
icon: (
37+
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth={1.6}>
38+
<path
39+
strokeLinecap="round"
40+
strokeLinejoin="round"
41+
d="M4 6.5A1.5 1.5 0 0 1 5.5 5h3.382a1.5 1.5 0 0 1 1.342.83l.671 1.34A1.5 1.5 0 0 0 12.236 8H18.5A1.5 1.5 0 0 1 20 9.5v8a1.5 1.5 0 0 1-1.5 1.5h-13A1.5 1.5 0 0 1 4 17.5z"
42+
/>
43+
</svg>
44+
),
45+
},
46+
];
47+
48+
export default function MobileBottomNav({ activeTab, onTabChange }: Props) {
49+
return (
50+
<nav className="flex shrink-0 bg-surface border-t border-border-subtle">
51+
{tabs.map((tab) => {
52+
const active = activeTab === tab.id;
53+
return (
54+
<button
55+
key={tab.id}
56+
type="button"
57+
onClick={() => onTabChange(tab.id)}
58+
className={`relative flex-1 flex flex-col items-center justify-center gap-1 py-2.5 text-[10px] font-semibold uppercase tracking-[0.14em] transition-colors ${
59+
active ? "text-accent" : "text-text-muted hover:text-text-secondary"
60+
}`}
61+
aria-current={active ? "page" : undefined}
62+
>
63+
<span className="w-5 h-5">{tab.icon}</span>
64+
{tab.label}
65+
{active && (
66+
<span className="absolute top-0 left-1/2 -translate-x-1/2 w-8 h-px bg-accent" />
67+
)}
68+
</button>
69+
);
70+
})}
71+
</nav>
72+
);
73+
}

0 commit comments

Comments
 (0)