Skip to content

Commit 287401b

Browse files
committed
feat: enhanced status bar and recent projects history
- Status bar now shows selected file name, UTF-8 encoding, and theme indicator - Recent projects tracked in localStorage (last 5 entries) - InitialPrompt shows recent projects with relative time labels - timeAgo helper for human-readable timestamps - Tailwind config: added light-hover and dark-hover color aliases
1 parent b60223b commit 287401b

6 files changed

Lines changed: 87 additions & 9 deletions

File tree

structure-insight/App.tsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,12 @@ const App: React.FC = () => {
4747
<MainContent logic={logic} codeViewRef={codeViewRef} leftPanelRef={leftPanelRef} />
4848

4949
{state.processedData && (
50-
<StatusBar
51-
fileCount={state.stats.fileCount}
52-
totalLines={state.stats.totalLines}
53-
totalChars={state.stats.totalChars}
50+
<StatusBar
51+
fileCount={state.stats.fileCount}
52+
totalLines={state.stats.totalLines}
53+
totalChars={state.stats.totalChars}
54+
selectedFileName={state.selectedFile?.name}
55+
isDark={state.isDark}
5456
/>
5557
)}
5658

structure-insight/components/InitialPrompt.tsx

Lines changed: 40 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,26 @@
11
import React from 'react';
22
import { motion } from 'framer-motion';
33

4+
interface RecentProject {
5+
name: string;
6+
openedAt: number;
7+
}
8+
9+
function timeAgo(timestamp: number): string {
10+
const seconds = Math.floor((Date.now() - timestamp) / 1000);
11+
if (seconds < 60) return "刚刚";
12+
if (seconds < 3600) return `${Math.floor(seconds / 60)}分钟前`;
13+
if (seconds < 86400) return `${Math.floor(seconds / 3600)}小时前`;
14+
if (seconds < 604800) return `${Math.floor(seconds / 86400)}天前`;
15+
return new Date(timestamp).toLocaleDateString();
16+
}
17+
418
interface InitialPromptProps {
519
onOpenFolder: () => void;
20+
recentProjects?: RecentProject[];
621
}
722

8-
const InitialPrompt: React.FC<InitialPromptProps> = ({ onOpenFolder }) => {
23+
const InitialPrompt: React.FC<InitialPromptProps> = ({ onOpenFolder, recentProjects = [] }) => {
924
return (
1025
<div className="relative flex flex-col items-center justify-center h-full w-full overflow-hidden p-6 select-none bg-light-bg dark:bg-dark-bg">
1126
{/* Background Pattern */}
@@ -60,6 +75,30 @@ const InitialPrompt: React.FC<InitialPromptProps> = ({ onOpenFolder }) => {
6075
</div>
6176
</button>
6277
</motion.div>
78+
79+
{/* Recent Projects */}
80+
{recentProjects.length > 0 && (
81+
<motion.div
82+
initial={{ opacity: 0, y: 10 }}
83+
animate={{ opacity: 1, y: 0 }}
84+
transition={{ duration: 0.5, delay: 0.4 }}
85+
className="w-full max-w-lg mb-16"
86+
>
87+
<p className="text-xs font-medium text-light-subtle-text dark:text-dark-subtle-text mb-3 uppercase tracking-wider">最近项目</p>
88+
<div className="grid grid-cols-1 gap-2">
89+
{recentProjects.map((project) => (
90+
<div
91+
key={project.name + project.openedAt}
92+
className="flex items-center gap-3 px-4 py-3 rounded-xl bg-light-panel dark:bg-dark-panel border border-light-border dark:border-dark-border cursor-default"
93+
>
94+
<i className="fa-solid fa-folder text-sm text-primary"></i>
95+
<span className="text-sm font-medium text-light-text dark:text-dark-text flex-1 truncate">{project.name}</span>
96+
<span className="text-xs text-light-subtle-text dark:text-dark-subtle-text whitespace-nowrap">{timeAgo(project.openedAt)}</span>
97+
</div>
98+
))}
99+
</div>
100+
</motion.div>
101+
)}
63102
</div>
64103

65104
{/* Footer Info */}

structure-insight/components/MainContent.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -169,7 +169,7 @@ const MainContent: React.FC<MainContentProps> = ({ logic, codeViewRef, leftPanel
169169
)}
170170
</div>
171171
) : (
172-
<div className="flex-1"><InitialPrompt onOpenFolder={handlers.handleFileSelect}/></div>
172+
<div className="flex-1"><InitialPrompt onOpenFolder={handlers.handleFileSelect} recentProjects={state.recentProjects}/></div>
173173
)}
174174
</motion.div>
175175
)}
@@ -251,7 +251,7 @@ const MainContent: React.FC<MainContentProps> = ({ logic, codeViewRef, leftPanel
251251
<ScrollToTopButton targetRef={codeViewRef} />
252252
</div>
253253
) : (
254-
<InitialPrompt onOpenFolder={handlers.handleFileSelect}/>
254+
<InitialPrompt onOpenFolder={handlers.handleFileSelect} recentProjects={state.recentProjects}/>
255255
)}
256256
</div>
257257
</div>

structure-insight/components/StatusBar.tsx

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@ interface StatusBarProps {
44
fileCount: number;
55
totalLines: number;
66
totalChars: number;
7+
selectedFileName?: string;
8+
isDark?: boolean;
79
}
810

911
const StatusBarItem: React.FC<{icon: string, value: number, label: string}> = ({icon, value, label}) => (
@@ -13,9 +15,24 @@ const StatusBarItem: React.FC<{icon: string, value: number, label: string}> = ({
1315
</span>
1416
);
1517

16-
const StatusBar: React.FC<StatusBarProps> = ({ fileCount, totalLines, totalChars }) => {
18+
const StatusBar: React.FC<StatusBarProps> = ({ fileCount, totalLines, totalChars, selectedFileName, isDark }) => {
1719
return (
18-
<footer className="h-8 flex items-center justify-end px-4 space-x-6 bg-light-header dark:bg-dark-header border-t border-light-border dark:border-dark-border text-xs text-light-subtle-text dark:text-dark-subtle-text shrink-0">
20+
<footer className="h-8 flex items-center px-4 space-x-6 bg-light-header dark:bg-dark-header border-t border-light-border dark:border-dark-border text-xs text-light-subtle-text dark:text-dark-subtle-text shrink-0">
21+
{selectedFileName && (
22+
<span className="flex items-center mr-auto" title="当前文件">
23+
<i className="fa-solid fa-file-code w-4 text-center mr-1.5"></i>
24+
{selectedFileName}
25+
</span>
26+
)}
27+
{!selectedFileName && <span className="mr-auto" />}
28+
<span className="flex items-center" title="编码">
29+
<i className="fa-solid fa-text-width w-4 text-center mr-1.5"></i>
30+
UTF-8
31+
</span>
32+
<span className="flex items-center" title={isDark ? '深色主题' : '浅色主题'}>
33+
<i className={`fa-solid ${isDark ? 'fa-moon' : 'fa-sun'} w-4 text-center mr-1.5`}></i>
34+
{isDark ? 'Dark' : 'Light'}
35+
</span>
1936
<StatusBarItem icon="fa-file-lines" value={fileCount} label="文件" />
2037
<StatusBarItem icon="fa-align-left" value={totalLines} label="行数" />
2138
<StatusBarItem icon="fa-quote-left" value={totalChars} label="字符数" />

structure-insight/hooks/useAppLogic.ts

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -41,6 +41,16 @@ export const useAppLogic = (
4141
const [mobileView, setMobileView] = React.useState<'tree' | 'editor'>('editor');
4242
const isMobile = React.useMemo(() => windowSize.width <= 768, [windowSize.width]);
4343

44+
// --- Recent Projects History ---
45+
const [recentProjects, setRecentProjects] = usePersistentState<{name: string, openedAt: number}[]>('recentProjects', []);
46+
47+
const addToHistory = React.useCallback((name: string) => {
48+
setRecentProjects(prev => {
49+
const filtered = prev.filter(p => p.name !== name);
50+
return [{ name, openedAt: Date.now() }, ...filtered].slice(0, 5);
51+
});
52+
}, [setRecentProjects]);
53+
4454
const handleShowToast = React.useCallback((message: string) => {
4555
setToastMessage(message);
4656
}, []);
@@ -81,6 +91,13 @@ export const useAppLogic = (
8191
}
8292
}, [showCharCount, processedData?.treeData, processedData?.rootName]);
8393

94+
// Track recent projects when processedData changes
95+
React.useEffect(() => {
96+
if (processedData?.rootName) {
97+
addToHistory(processedData.rootName);
98+
}
99+
}, [processedData?.rootName]);
100+
84101
// --- Derived State ---
85102
const selectedFile = React.useMemo<FileContent | null>(() => {
86103
if (!selectedFilePath || !processedData?.fileContents) return null;
@@ -225,6 +242,7 @@ export const useAppLogic = (
225242
isSearchOpen, isFileRankOpen, isShortcutsOpen, searchResults, activeResultIndex, isMobile, isAiChatOpen,
226243
selectedFilePath, selectedFile, activeView,
227244
searchQuery, searchOptions, activeMatchIndexInFile,
245+
recentProjects,
228246
},
229247
handlers: {
230248
setIsDragging, handleDrop: (e: React.DragEvent) => { setIsDragging(false); handleDrop(e, isLoading); },

structure-insight/index.html

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -71,6 +71,8 @@
7171
'primary': '#3B82F6', // blue-500
7272
'primary-hover': '#2563EB', // blue-600
7373
'primary-disabled': '#93C5FD', // blue-300
74+
'light-hover': '#F3F4F6', // gray-100
75+
'dark-hover': '#374151', // gray-700
7476
},
7577
keyframes: {
7678
'enter': {

0 commit comments

Comments
 (0)