@geminilight/mindos 0.6.8 → 0.6.12
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.
- package/README.md +2 -0
- package/README_zh.md +2 -0
- package/app/app/api/mcp/install/route.ts +4 -1
- package/app/app/api/setup/check-path/route.ts +2 -7
- package/app/app/api/setup/ls/route.ts +3 -9
- package/app/app/api/setup/path-utils.ts +8 -0
- package/app/app/api/setup/route.ts +2 -7
- package/app/app/api/uninstall/route.ts +47 -0
- package/app/app/globals.css +11 -0
- package/app/components/ActivityBar.tsx +10 -3
- package/app/components/AskFab.tsx +7 -3
- package/app/components/CreateSpaceModal.tsx +1 -1
- package/app/components/DirView.tsx +1 -1
- package/app/components/FileTree.tsx +30 -23
- package/app/components/GuideCard.tsx +1 -1
- package/app/components/HomeContent.tsx +137 -109
- package/app/components/ImportModal.tsx +16 -477
- package/app/components/MarkdownView.tsx +3 -0
- package/app/components/OnboardingView.tsx +1 -1
- package/app/components/OrganizeToast.tsx +386 -0
- package/app/components/Panel.tsx +23 -2
- package/app/components/Sidebar.tsx +1 -1
- package/app/components/SidebarLayout.tsx +44 -1
- package/app/components/agents/AgentDetailContent.tsx +33 -12
- package/app/components/agents/AgentsMcpSection.tsx +1 -1
- package/app/components/agents/AgentsOverviewSection.tsx +3 -4
- package/app/components/agents/AgentsPrimitives.tsx +2 -2
- package/app/components/agents/AgentsSkillsSection.tsx +2 -2
- package/app/components/agents/SkillDetailPopover.tsx +24 -8
- package/app/components/ask/AskContent.tsx +124 -75
- package/app/components/ask/HighlightMatch.tsx +14 -0
- package/app/components/ask/MentionPopover.tsx +5 -3
- package/app/components/ask/MessageList.tsx +39 -11
- package/app/components/ask/SlashCommandPopover.tsx +4 -2
- package/app/components/changes/ChangesBanner.tsx +20 -2
- package/app/components/changes/ChangesContentPage.tsx +10 -2
- package/app/components/echo/EchoHero.tsx +1 -1
- package/app/components/echo/EchoInsightCollapsible.tsx +1 -1
- package/app/components/echo/EchoPageSections.tsx +1 -1
- package/app/components/explore/UseCaseCard.tsx +1 -1
- package/app/components/panels/DiscoverPanel.tsx +29 -25
- package/app/components/panels/ImportHistoryPanel.tsx +195 -0
- package/app/components/panels/PluginsPanel.tsx +2 -2
- package/app/components/settings/AiTab.tsx +24 -0
- package/app/components/settings/KnowledgeTab.tsx +1 -1
- package/app/components/settings/McpSkillCreateForm.tsx +1 -1
- package/app/components/settings/McpSkillRow.tsx +1 -1
- package/app/components/settings/McpSkillsSection.tsx +2 -2
- package/app/components/settings/McpTab.tsx +2 -2
- package/app/components/settings/PluginsTab.tsx +1 -1
- package/app/components/settings/Primitives.tsx +118 -6
- package/app/components/settings/SettingsContent.tsx +5 -2
- package/app/components/settings/UninstallTab.tsx +179 -0
- package/app/components/settings/UpdateTab.tsx +17 -5
- package/app/components/settings/types.ts +2 -1
- package/app/components/ui/dialog.tsx +1 -1
- package/app/hooks/useAiOrganize.ts +122 -10
- package/app/hooks/useMention.ts +21 -3
- package/app/hooks/useSlashCommand.ts +18 -4
- package/app/lib/agent/reconnect.ts +40 -0
- package/app/lib/core/backlinks.ts +2 -2
- package/app/lib/core/git.ts +14 -10
- package/app/lib/fs.ts +2 -1
- package/app/lib/i18n-en.ts +46 -2
- package/app/lib/i18n-zh.ts +46 -2
- package/app/lib/organize-history.ts +74 -0
- package/app/lib/settings.ts +2 -0
- package/app/lib/types.ts +2 -0
- package/app/next.config.ts +23 -5
- package/bin/cli.js +6 -9
- package/bin/lib/mcp-build.js +74 -0
- package/bin/lib/mcp-spawn.js +8 -5
- package/bin/lib/port.js +17 -2
- package/bin/lib/stop.js +12 -2
- package/mcp/dist/index.cjs +43 -43
- package/mcp/src/index.ts +58 -12
- package/package.json +1 -1
- package/scripts/setup.js +2 -2
|
@@ -65,13 +65,12 @@ function groupBySpace(recent: RecentFile[], spaces: SpaceInfo[]): { groups: Spac
|
|
|
65
65
|
return { groups, rootFiles };
|
|
66
66
|
}
|
|
67
67
|
|
|
68
|
-
/* ──
|
|
68
|
+
/* ── Shared small components ── */
|
|
69
|
+
|
|
69
70
|
interface SectionTitleProps {
|
|
70
71
|
icon: React.ReactNode;
|
|
71
72
|
children: React.ReactNode;
|
|
72
|
-
/** Item count badge — only rendered when > 0 */
|
|
73
73
|
count?: number;
|
|
74
|
-
/** Right-aligned action slot (e.g. "View all" button) */
|
|
75
74
|
action?: React.ReactNode;
|
|
76
75
|
}
|
|
77
76
|
|
|
@@ -90,8 +89,83 @@ function SectionTitle({ icon, children, count, action }: SectionTitleProps) {
|
|
|
90
89
|
);
|
|
91
90
|
}
|
|
92
91
|
|
|
92
|
+
/** Reusable "Show more / Show less" toggle */
|
|
93
|
+
function ToggleButton({ expanded, onToggle, showLabel, hideLabel, className = '' }: {
|
|
94
|
+
expanded: boolean;
|
|
95
|
+
onToggle: () => void;
|
|
96
|
+
showLabel: string;
|
|
97
|
+
hideLabel: string;
|
|
98
|
+
className?: string;
|
|
99
|
+
}) {
|
|
100
|
+
return (
|
|
101
|
+
<button
|
|
102
|
+
onClick={onToggle}
|
|
103
|
+
aria-expanded={expanded}
|
|
104
|
+
className={`flex items-center gap-1.5 text-xs font-medium text-[var(--amber)] transition-colors hover:opacity-80 cursor-pointer font-display ${className}`}
|
|
105
|
+
>
|
|
106
|
+
<ChevronDown size={12} className={`transition-transform duration-200 ${expanded ? 'rotate-180' : ''}`} />
|
|
107
|
+
<span>{expanded ? hideLabel : showLabel}</span>
|
|
108
|
+
</button>
|
|
109
|
+
);
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
/** Reusable file row for recent-file lists */
|
|
113
|
+
function FileRow({ filePath, mtime, formatTime, subPath }: {
|
|
114
|
+
filePath: string;
|
|
115
|
+
mtime: number;
|
|
116
|
+
formatTime: (t: number) => string;
|
|
117
|
+
subPath?: string;
|
|
118
|
+
}) {
|
|
119
|
+
const isCSV = filePath.endsWith('.csv');
|
|
120
|
+
const name = filePath.split('/').pop() || filePath;
|
|
121
|
+
return (
|
|
122
|
+
<Link
|
|
123
|
+
href={`/view/${encodePath(filePath)}`}
|
|
124
|
+
className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted group"
|
|
125
|
+
>
|
|
126
|
+
{isCSV
|
|
127
|
+
? <Table size={12} className="shrink-0 text-success" />
|
|
128
|
+
: <FileText size={12} className="shrink-0 text-muted-foreground" />
|
|
129
|
+
}
|
|
130
|
+
<div className="flex-1 min-w-0">
|
|
131
|
+
<span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
|
|
132
|
+
{subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
|
|
133
|
+
</div>
|
|
134
|
+
<span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
|
|
135
|
+
{formatTime(mtime)}
|
|
136
|
+
</span>
|
|
137
|
+
</Link>
|
|
138
|
+
);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
/** Reusable chip for builtin features / plugins */
|
|
142
|
+
function FeatureChip({ id, icon, name, entryPath, active, inactiveTitle }: {
|
|
143
|
+
id: string;
|
|
144
|
+
icon: string;
|
|
145
|
+
name: string;
|
|
146
|
+
entryPath?: string;
|
|
147
|
+
active: boolean;
|
|
148
|
+
inactiveTitle?: string;
|
|
149
|
+
}) {
|
|
150
|
+
const cls = active
|
|
151
|
+
? 'inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60'
|
|
152
|
+
: 'inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-dashed border-border text-xs text-muted-foreground opacity-70';
|
|
153
|
+
|
|
154
|
+
const inner = (
|
|
155
|
+
<>
|
|
156
|
+
<span className="text-sm leading-none" suppressHydrationWarning>{icon}</span>
|
|
157
|
+
<span className={`font-medium ${active ? 'text-foreground' : ''}`}>{name}</span>
|
|
158
|
+
</>
|
|
159
|
+
);
|
|
160
|
+
|
|
161
|
+
if (active && entryPath) {
|
|
162
|
+
return <Link key={id} href={`/view/${encodePath(entryPath)}`}><span className={cls}>{inner}</span></Link>;
|
|
163
|
+
}
|
|
164
|
+
return <span key={id} className={cls} title={inactiveTitle}>{inner}</span>;
|
|
165
|
+
}
|
|
166
|
+
|
|
93
167
|
const FILES_PER_GROUP = 3;
|
|
94
|
-
const SPACES_PER_ROW = 6;
|
|
168
|
+
const SPACES_PER_ROW = 6;
|
|
95
169
|
const PLUGINS_INITIAL = 4;
|
|
96
170
|
|
|
97
171
|
export default function HomeContent({ recent, existingFiles, spaces, dirPaths }: { recent: RecentFile[]; existingFiles?: string[]; spaces?: SpaceInfo[]; dirPaths?: string[] }) {
|
|
@@ -148,18 +222,18 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
148
222
|
</p>
|
|
149
223
|
|
|
150
224
|
{/* AI-first command bar */}
|
|
151
|
-
<div className="w-full max-w-
|
|
225
|
+
<div className="w-full max-w-xl flex flex-col sm:flex-row items-stretch sm:items-center gap-2 ml-4">
|
|
152
226
|
<button
|
|
153
227
|
onClick={triggerAsk}
|
|
154
228
|
title="⌘/"
|
|
155
229
|
data-walkthrough="ask-button"
|
|
156
|
-
className="flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card transition-all duration-150 hover:border-[var(--amber)]/50 hover:bg-[var(--amber)]
|
|
230
|
+
className="flex-1 flex items-center gap-3 px-4 py-3 rounded-xl border border-border bg-card transition-all duration-150 hover:border-[var(--amber)]/50 hover:bg-[var(--amber-dim)]"
|
|
157
231
|
>
|
|
158
232
|
<Sparkles size={15} className="shrink-0 text-[var(--amber)]" />
|
|
159
233
|
<span className="text-sm flex-1 text-left text-foreground">
|
|
160
234
|
{suggestions[suggestionIdx]}
|
|
161
235
|
</span>
|
|
162
|
-
<kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber)]">
|
|
236
|
+
<kbd className="hidden sm:inline-flex items-center gap-0.5 px-2 py-0.5 rounded text-xs font-mono font-medium bg-[var(--amber-dim)] text-[var(--amber-text)]">
|
|
163
237
|
⌘/
|
|
164
238
|
</kbd>
|
|
165
239
|
</button>
|
|
@@ -180,14 +254,15 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
180
254
|
<div className="flex flex-wrap gap-2.5 mt-4 pl-4">
|
|
181
255
|
<button
|
|
182
256
|
onClick={() => window.dispatchEvent(new CustomEvent('mindos:open-import'))}
|
|
183
|
-
className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-[var(--amber-dim)] text-[var(--amber)]"
|
|
257
|
+
className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-[var(--amber-dim)] text-[var(--amber-text)]"
|
|
184
258
|
>
|
|
185
259
|
<FolderInput size={14} />
|
|
186
260
|
<span>{t.fileTree.importFile}</span>
|
|
261
|
+
<ArrowRight size={13} className="opacity-50" />
|
|
187
262
|
</button>
|
|
188
263
|
<Link
|
|
189
264
|
href="/view/Untitled.md"
|
|
190
|
-
className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-
|
|
265
|
+
className="inline-flex items-center gap-2 px-3.5 py-2 rounded-lg text-sm font-medium transition-all duration-150 hover:translate-x-0.5 bg-muted text-muted-foreground hover:text-foreground"
|
|
191
266
|
>
|
|
192
267
|
<FilePlus size={14} />
|
|
193
268
|
<span>{t.home.newNote}</span>
|
|
@@ -199,7 +274,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
199
274
|
>
|
|
200
275
|
<ArrowRight size={14} />
|
|
201
276
|
<span>{t.home.continueEditing}</span>
|
|
202
|
-
<span className="text-xs opacity-50 truncate max-w-
|
|
277
|
+
<span className="text-xs opacity-50 truncate max-w-36" suppressHydrationWarning>
|
|
203
278
|
{lastFile.path.split('/').pop()}
|
|
204
279
|
</span>
|
|
205
280
|
</Link>
|
|
@@ -259,13 +334,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
259
334
|
})}
|
|
260
335
|
</div>
|
|
261
336
|
{spaceList.length > SPACES_PER_ROW && (
|
|
262
|
-
<
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
337
|
+
<ToggleButton
|
|
338
|
+
expanded={showAllSpaces}
|
|
339
|
+
onToggle={() => setShowAllSpaces(v => !v)}
|
|
340
|
+
showLabel={t.home.showMore}
|
|
341
|
+
hideLabel={t.home.showLess}
|
|
342
|
+
className="mt-2"
|
|
343
|
+
/>
|
|
269
344
|
)}
|
|
270
345
|
</>
|
|
271
346
|
) : (
|
|
@@ -285,25 +360,16 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
285
360
|
<div className="flex flex-wrap gap-2">
|
|
286
361
|
{builtinFeatures.map((r) => {
|
|
287
362
|
const active = !!r.entryPath && existingSet.has(r.entryPath);
|
|
288
|
-
if (active && r.entryPath) {
|
|
289
|
-
return (
|
|
290
|
-
<Link key={r.id} href={`/view/${encodePath(r.entryPath)}`}>
|
|
291
|
-
<span className="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60">
|
|
292
|
-
<span className="text-sm leading-none" suppressHydrationWarning>{r.icon}</span>
|
|
293
|
-
<span className="font-medium text-foreground">{r.name}</span>
|
|
294
|
-
</span>
|
|
295
|
-
</Link>
|
|
296
|
-
);
|
|
297
|
-
}
|
|
298
363
|
return (
|
|
299
|
-
<
|
|
364
|
+
<FeatureChip
|
|
300
365
|
key={r.id}
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
|
|
366
|
+
id={r.id}
|
|
367
|
+
icon={r.icon}
|
|
368
|
+
name={r.name}
|
|
369
|
+
entryPath={r.entryPath}
|
|
370
|
+
active={active}
|
|
371
|
+
inactiveTitle={r.entryPath ? t.home.createToActivate.replace('{file}', r.entryPath) : t.home.builtinInactive}
|
|
372
|
+
/>
|
|
307
373
|
);
|
|
308
374
|
})}
|
|
309
375
|
</div>
|
|
@@ -318,13 +384,12 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
318
384
|
count={availablePlugins.length}
|
|
319
385
|
action={
|
|
320
386
|
availablePlugins.length > PLUGINS_INITIAL ? (
|
|
321
|
-
<
|
|
322
|
-
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
|
|
326
|
-
|
|
327
|
-
</button>
|
|
387
|
+
<ToggleButton
|
|
388
|
+
expanded={showAllPlugins}
|
|
389
|
+
onToggle={() => setShowAllPlugins(v => !v)}
|
|
390
|
+
showLabel={t.home.viewAll}
|
|
391
|
+
hideLabel={t.home.showLess}
|
|
392
|
+
/>
|
|
328
393
|
) : undefined
|
|
329
394
|
}
|
|
330
395
|
>
|
|
@@ -332,14 +397,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
332
397
|
</SectionTitle>
|
|
333
398
|
<div className="flex flex-wrap gap-2">
|
|
334
399
|
{(showAllPlugins ? availablePlugins : availablePlugins.slice(0, PLUGINS_INITIAL)).map(r => (
|
|
335
|
-
<
|
|
336
|
-
key={r.id}
|
|
337
|
-
href={`/view/${encodePath(r.entryPath!)}`}
|
|
338
|
-
className="inline-flex items-center gap-2 px-3 py-2 rounded-lg border border-border text-xs transition-all duration-150 hover:border-[var(--amber)]/30 hover:bg-muted/60"
|
|
339
|
-
>
|
|
340
|
-
<span className="text-sm leading-none" suppressHydrationWarning>{r.icon}</span>
|
|
341
|
-
<span className="font-medium text-foreground">{r.name}</span>
|
|
342
|
-
</Link>
|
|
400
|
+
<FeatureChip key={r.id} id={r.id} icon={r.icon} name={r.name} entryPath={r.entryPath} active />
|
|
343
401
|
))}
|
|
344
402
|
</div>
|
|
345
403
|
</section>
|
|
@@ -376,30 +434,15 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
376
434
|
)}
|
|
377
435
|
</Link>
|
|
378
436
|
<div className="flex flex-col gap-0.5 ml-2 border-l border-border pl-3">
|
|
379
|
-
{visibleFiles.map(({ path: filePath, mtime }) =>
|
|
380
|
-
|
|
381
|
-
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
>
|
|
389
|
-
{isCSV
|
|
390
|
-
? <Table size={12} className="shrink-0 text-success" />
|
|
391
|
-
: <FileText size={12} className="shrink-0 text-muted-foreground" />
|
|
392
|
-
}
|
|
393
|
-
<div className="flex-1 min-w-0">
|
|
394
|
-
<span className="text-sm truncate block text-foreground" suppressHydrationWarning>{name}</span>
|
|
395
|
-
{subPath && <span className="text-xs truncate block text-muted-foreground opacity-50" suppressHydrationWarning>{subPath}</span>}
|
|
396
|
-
</div>
|
|
397
|
-
<span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
|
|
398
|
-
{formatTime(mtime)}
|
|
399
|
-
</span>
|
|
400
|
-
</Link>
|
|
401
|
-
);
|
|
402
|
-
})}
|
|
437
|
+
{visibleFiles.map(({ path: filePath, mtime }) => (
|
|
438
|
+
<FileRow
|
|
439
|
+
key={filePath}
|
|
440
|
+
filePath={filePath}
|
|
441
|
+
mtime={mtime}
|
|
442
|
+
formatTime={formatTime}
|
|
443
|
+
subPath={filePath.split('/').slice(1, -1).join('/')}
|
|
444
|
+
/>
|
|
445
|
+
))}
|
|
403
446
|
</div>
|
|
404
447
|
</div>
|
|
405
448
|
);
|
|
@@ -416,19 +459,7 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
416
459
|
</div>
|
|
417
460
|
<div className="flex flex-col gap-0.5 ml-2 border-l border-border pl-3">
|
|
418
461
|
{rootFiles.map(({ path: filePath, mtime }) => (
|
|
419
|
-
<
|
|
420
|
-
key={filePath}
|
|
421
|
-
href={`/view/${encodePath(filePath)}`}
|
|
422
|
-
className="flex items-center gap-3 px-3 py-2 rounded-lg transition-all duration-100 hover:translate-x-0.5 hover:bg-muted"
|
|
423
|
-
>
|
|
424
|
-
<FileText size={12} className="shrink-0 text-muted-foreground" />
|
|
425
|
-
<span className="text-sm flex-1 min-w-0 truncate text-foreground" suppressHydrationWarning>
|
|
426
|
-
{filePath.split('/').pop() || filePath}
|
|
427
|
-
</span>
|
|
428
|
-
<span className="text-xs shrink-0 tabular-nums font-display text-muted-foreground opacity-40" suppressHydrationWarning>
|
|
429
|
-
{formatTime(mtime)}
|
|
430
|
-
</span>
|
|
431
|
-
</Link>
|
|
462
|
+
<FileRow key={filePath} filePath={filePath} mtime={mtime} formatTime={formatTime} />
|
|
432
463
|
))}
|
|
433
464
|
</div>
|
|
434
465
|
</div>
|
|
@@ -436,14 +467,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
436
467
|
|
|
437
468
|
{/* Show more / less */}
|
|
438
469
|
{groups.some(g => g.files.length > FILES_PER_GROUP) && (
|
|
439
|
-
<
|
|
440
|
-
|
|
441
|
-
|
|
442
|
-
|
|
443
|
-
|
|
444
|
-
|
|
445
|
-
|
|
446
|
-
</button>
|
|
470
|
+
<ToggleButton
|
|
471
|
+
expanded={showAll}
|
|
472
|
+
onToggle={() => setShowAll(v => !v)}
|
|
473
|
+
showLabel={t.home.showMore}
|
|
474
|
+
hideLabel={t.home.showLess}
|
|
475
|
+
className="mt-1 ml-1"
|
|
476
|
+
/>
|
|
447
477
|
)}
|
|
448
478
|
</div>
|
|
449
479
|
) : (
|
|
@@ -459,11 +489,11 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
459
489
|
<div key={filePath} className="relative group">
|
|
460
490
|
<div
|
|
461
491
|
aria-hidden="true"
|
|
462
|
-
className={`absolute -left-4 top-1/2 -translate-y-1/2 rounded-full transition-all duration-150 group-hover:scale-150 ${
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
}}
|
|
492
|
+
className={`absolute -left-4 top-1/2 -translate-y-1/2 rounded-full transition-all duration-150 group-hover:scale-150 ${
|
|
493
|
+
idx === 0
|
|
494
|
+
? 'w-2 h-2 bg-[var(--amber)] outline-2 outline-[var(--amber-dim)]'
|
|
495
|
+
: 'w-1.5 h-1.5 bg-border'
|
|
496
|
+
}`}
|
|
467
497
|
/>
|
|
468
498
|
<Link
|
|
469
499
|
href={`/view/${encodePath(filePath)}`}
|
|
@@ -486,14 +516,13 @@ export default function HomeContent({ recent, existingFiles, spaces, dirPaths }:
|
|
|
486
516
|
})}
|
|
487
517
|
</div>
|
|
488
518
|
{recent.length > 5 && (
|
|
489
|
-
<
|
|
490
|
-
|
|
491
|
-
|
|
492
|
-
|
|
493
|
-
|
|
494
|
-
|
|
495
|
-
|
|
496
|
-
</button>
|
|
519
|
+
<ToggleButton
|
|
520
|
+
expanded={showAll}
|
|
521
|
+
onToggle={() => setShowAll(v => !v)}
|
|
522
|
+
showLabel={t.home.showMore}
|
|
523
|
+
hideLabel={t.home.showLess}
|
|
524
|
+
className="mt-2 ml-3"
|
|
525
|
+
/>
|
|
497
526
|
)}
|
|
498
527
|
</div>
|
|
499
528
|
)}
|
|
@@ -569,7 +598,7 @@ function ExampleCleanupBanner() {
|
|
|
569
598
|
<button
|
|
570
599
|
onClick={handleCleanup}
|
|
571
600
|
disabled={cleaning}
|
|
572
|
-
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber)] hover:opacity-80"
|
|
601
|
+
className="flex items-center gap-1.5 px-3 py-1.5 text-xs font-medium rounded-lg transition-colors shrink-0 disabled:opacity-50 bg-[var(--amber-dim)] text-[var(--amber-text)] hover:opacity-80"
|
|
573
602
|
>
|
|
574
603
|
{cleaning ? <Loader2 size={11} className="animate-spin" /> : <Trash2 size={11} />}
|
|
575
604
|
{t.home.cleanupExamplesButton}
|
|
@@ -583,4 +612,3 @@ function ExampleCleanupBanner() {
|
|
|
583
612
|
</div>
|
|
584
613
|
);
|
|
585
614
|
}
|
|
586
|
-
|