Skip to content

Commit f84d418

Browse files
committed
feat: align exports with repomix and remove AI chat
1 parent 6a5a0f6 commit f84d418

44 files changed

Lines changed: 4985 additions & 575 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

README.md

Lines changed: 3 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
55
[![GitHub stars](https://img.shields.io/github/stars/yeahhe365/Structure-Insight?style=social)](https://github.com/yeahhe365/Structure-Insight)
66

7-
**一个强大的浏览器端工具,用于快速分析和可视化任何代码项目的文件结构和内容。旨在帮助开发人员生成格式化的输出,非常适合与 Gemini 等 AI 语言模型共享和讨论代码。**
7+
**一个强大的浏览器端工具,用于快速分析和可视化任何代码项目的文件结构和内容。旨在帮助开发人员生成格式化的输出,便于与 AI 语言模型共享和讨论代码。**
88

99
---
1010

@@ -16,13 +16,12 @@
1616

1717
## 📖 简介 (Introduction)
1818

19-
在与 AI 语言模型(如 Google Gemini)协作进行代码审查、调试或功能开发时,提供清晰、完整的项目上下文至关重要。手动整理文件结构和复制代码是一项繁琐且容易出错的任务。
19+
在进行代码审查、调试或功能开发时,提供清晰、完整的项目上下文至关重要。手动整理文件结构和复制代码是一项繁琐且容易出错的任务。
2020

2121
**Structure Insight** 解决了这个问题。它允许您简单地将整个项目文件夹拖放到浏览器中。应用会立即:
2222
1. 分析您的文件和目录结构。
2323
2. 读取并高亮显示代码内容。
2424
3. 生成一个干净、格式化的文本输出,您可以轻松地复制并粘贴到 AI 的提示中。
25-
4. 内置 AI 聊天功能,可以直接在应用内就您的代码库进行对话。
2625

2726
所有处理都在您的浏览器本地进行,确保您的代码永远不会离开您的计算机,保障了隐私和安全。
2827

@@ -40,9 +39,6 @@
4039
* **🏷️ 文件类型过滤**: 通过可点击的扩展名标签快速筛选文件树中的文件类型。
4140
* **⌨️ 快捷键支持**: 按 Ctrl+/ 查看所有快捷键,支持快速打开、搜索和保存。
4241
* **🕐 最近项目**: 自动记录最近打开的项目,方便快速回顾。
43-
* **🤖 AI 聊天集成**:
44-
***Google Gemini** 模型无缝集成。
45-
* 自动将您的项目作为上下文,让您可以就代码提问、寻求建议或进行调试。
4642
* **🔍 全局搜索**: 在所有已加载的文件中进行高效搜索,支持正则表达式、大小写匹配和全词匹配。
4743
* **📱 响应式与 PWA**:
4844
* 完全响应式设计,在桌面和移动设备上均可良好运行。
@@ -58,17 +54,13 @@
5854
*主界面 (深色模式)*
5955
<img width="1920" height="887" alt="image" src="https://github.com/user-attachments/assets/ae0a19ad-c253-4aac-9982-8181c7ec2575" />
6056

61-
*AI 聊天面板*
62-
<img width="1920" height="838" alt="image" src="https://github.com/user-attachments/assets/45bfe3fd-e329-4b4b-8d3e-2db9d9a25ddc" />
63-
6457
*文件搜索功能*
6558
<img width="631" height="383" alt="image" src="https://github.com/user-attachments/assets/62a05635-6bd2-49dd-8e6c-df6abcde4453" />
6659

6760
## 🛠️ 技术栈 (Technology Stack)
6861

6962
* **前端框架**: [React](https://reactjs.org/)
7063
* **语言**: [TypeScript](https://www.typescriptlang.org/)
71-
* **AI 模型**: [Google Gemini API](https://ai.google.dev/)
7264
* **样式**: [Tailwind CSS](https://tailwindcss.com/)
7365
* **动画**: [Framer Motion](https://www.framer.com/motion/)
7466
* **语法高亮**: [Highlight.js](https://highlightjs.org/)
@@ -90,31 +82,12 @@ cd Structure-Insight
9082
npm install
9183
```
9284

93-
**3. 设置环境变量**
94-
为了使用 AI 聊天功能,您需要一个 Google Gemini API 密钥。
95-
96-
* 前往 [Google AI for Developers](https://makersuite.google.com/app/apikey) 获取您的 API 密钥。
97-
* 在项目根目录创建一个 `.env` 文件。
98-
* 将您的密钥添加到 `.env` 文件中:
99-
100-
```
101-
# .env
102-
VITE_GEMINI_API_KEY="YOUR_API_KEY_HERE"
103-
```
104-
*注意:即使没有 API 密钥,应用的核心功能(文件分析和格式化)仍然可用。*
105-
106-
**4. 运行开发服务器**
85+
**3. 运行开发服务器**
10786
```bash
10887
npm run dev
10988
```
11089
应用将在 `http://localhost:5173` (或其他可用端口) 上启动。
11190

112-
## 🔑 配置 Gemini API 密钥
113-
114-
您有两种方式配置 Gemini API 密钥:
115-
1. **环境变量 (推荐)**: 如上所述,通过在 `.env` 文件中设置 `VITE_GEMINI_API_KEY`
116-
2. **应用内设置**: 在应用的设置菜单中,您可以直接输入您的 API 密钥。此密钥将安全地存储在您浏览器的 `localStorage` 中,不会上传到任何服务器。
117-
11891
## 🤝 贡献 (Contributing)
11992

12093
欢迎各种形式的贡献!如果您有功能建议、发现错误或希望改进代码,请随时:

structure-insight/App.tsx

Lines changed: 48 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -3,15 +3,27 @@ import React from 'react';
33
import { AnimatePresence } from 'framer-motion';
44
import { useAppLogic } from './hooks/useAppLogic';
55
import Toast from './components/Toast';
6-
import SettingsDialog from './components/SettingsDialog';
76
import Header from './components/Header';
87
import MainContent from './components/MainContent';
98
import StatusBar from './components/StatusBar';
10-
import SearchDialog from './components/SearchDialog';
119
import ConfirmationDialog from './components/ConfirmationDialog';
12-
import AIChat from './components/AIChat';
13-
import FileRankDialog from './components/FileRankDialog';
14-
import KeyboardShortcutsDialog from './components/KeyboardShortcutsDialog';
10+
11+
// Lazy-load heavy components
12+
const SettingsDialog = React.lazy(() => import('./components/SettingsDialog'));
13+
const SearchDialog = React.lazy(() => import('./components/SearchDialog'));
14+
const FileRankDialog = React.lazy(() => import('./components/FileRankDialog'));
15+
const KeyboardShortcutsDialog = React.lazy(() => import('./components/KeyboardShortcutsDialog'));
16+
17+
const SuspenseFallback = () => null;
18+
19+
function getProgressWidth(message: string | null): string {
20+
if (!message) return '90%';
21+
const match = message.match(/(\d+)\/(\d+)/);
22+
if (!match) return '90%';
23+
const current = parseInt(match[1]);
24+
const total = Math.max(1, parseInt(match[2]));
25+
return `${Math.min(95, (current / total) * 100)}%`;
26+
}
1527

1628
const App: React.FC = () => {
1729
const codeViewRef = React.useRef<HTMLDivElement>(null);
@@ -21,17 +33,19 @@ const App: React.FC = () => {
2133
const { state, handlers, settings } = logic;
2234

2335
return (
24-
<div
36+
<div
2537
className="flex flex-col h-full bg-light-bg dark:bg-dark-bg"
26-
onDragEnter={(e) => {e.preventDefault(); e.stopPropagation(); handlers.setIsDragging(true);}}
27-
onDragOver={(e) => {e.preventDefault(); e.stopPropagation();}}
28-
onDragLeave={(e) => {e.preventDefault(); e.stopPropagation(); handlers.setIsDragging(false);}}
38+
onDragEnter={(e) => {e.preventDefault(); e.stopPropagation(); handlers.setIsDragging(true);}}
39+
onDragOver={(e) => {e.preventDefault(); e.stopPropagation();}}
40+
onDragLeave={(e) => {e.preventDefault(); e.stopPropagation(); handlers.setIsDragging(false);}}
2941
onDrop={handlers.handleDrop}
42+
role="application"
43+
aria-label="Structure Insight 代码分析工具"
3044
>
3145
{/* Loading progress bar */}
3246
{state.isLoading && (
33-
<div className="fixed top-0 left-0 right-0 z-50 h-0.5 bg-light-border dark:bg-dark-border overflow-hidden">
34-
<div className="h-full bg-gradient-to-r from-primary to-indigo-500 animate-pulse" style={{ width: '90%' }} />
47+
<div className="fixed top-0 left-0 right-0 z-50 h-1 bg-light-border dark:bg-dark-border overflow-hidden">
48+
<div className="h-full bg-gradient-to-r from-primary to-indigo-500 transition-all duration-300 ease-out" style={{ width: getProgressWidth(state.progressMessage) }} />
3549
</div>
3650
)}
3751
<Header
@@ -42,7 +56,6 @@ const App: React.FC = () => {
4256
onCancel={handlers.handleCancel}
4357
onSettings={() => handlers.setIsSettingsOpen(true)}
4458
onToggleSearch={() => handlers.setIsSearchOpen(true)}
45-
onToggleAiChat={() => handlers.setIsAiChatOpen(true)}
4659
onToggleFileRank={() => handlers.setIsFileRankOpen(true)}
4760
onShowStructure={() => handlers.setActiveView('structure')}
4861
hasContent={!!state.processedData}
@@ -57,8 +70,9 @@ const App: React.FC = () => {
5770
fileCount={state.stats.fileCount}
5871
totalLines={state.stats.totalLines}
5972
totalChars={state.stats.totalChars}
60-
selectedFileName={state.selectedFile?.name}
73+
selectedFileName={state.selectedFile?.path.split('/').pop()}
6174
isDark={state.isDark}
75+
processedData={state.processedData}
6276
/>
6377
)}
6478

@@ -72,18 +86,21 @@ const App: React.FC = () => {
7286

7387
<AnimatePresence>
7488
{state.isSearchOpen && (
75-
<SearchDialog
89+
<React.Suspense fallback={<SuspenseFallback />}>
90+
<SearchDialog
7691
onClose={() => handlers.setIsSearchOpen(false)}
7792
onSearch={handlers.handleSearch}
7893
onNavigate={handlers.handleNavigate}
7994
resultsCount={state.searchResults.length}
8095
currentIndex={state.activeResultIndex}
8196
/>
97+
</React.Suspense>
8298
)}
8399
</AnimatePresence>
84-
100+
85101
<AnimatePresence>
86102
{state.isFileRankOpen && (
103+
<React.Suspense fallback={<SuspenseFallback />}>
87104
<FileRankDialog
88105
isOpen={state.isFileRankOpen}
89106
onClose={() => handlers.setIsFileRankOpen(false)}
@@ -93,17 +110,13 @@ const App: React.FC = () => {
93110
onDeleteFile={handlers.handleDeleteFile}
94111
onToggleExclude={handlers.handleToggleExclude}
95112
/>
113+
</React.Suspense>
96114
)}
97115
</AnimatePresence>
98116

99-
<AIChat
100-
isOpen={state.isAiChatOpen}
101-
onClose={() => handlers.setIsAiChatOpen(false)}
102-
projectData={state.processedData}
103-
/>
104-
105117
<AnimatePresence>
106118
{state.isSettingsOpen && (
119+
<React.Suspense fallback={<SuspenseFallback />}>
107120
<SettingsDialog
108121
isOpen={state.isSettingsOpen}
109122
onClose={() => handlers.setIsSettingsOpen(false)}
@@ -120,19 +133,32 @@ const App: React.FC = () => {
120133
onSetMaxCharsThreshold={settings.setMaxCharsThreshold}
121134
wordWrap={state.wordWrap}
122135
onToggleWordWrap={() => settings.setWordWrap(!state.wordWrap)}
136+
includeFileSummary={state.includeFileSummary}
137+
onToggleIncludeFileSummary={() => settings.setIncludeFileSummary(!state.includeFileSummary)}
138+
includeDirectoryStructure={state.includeDirectoryStructure}
139+
onToggleIncludeDirectoryStructure={() => settings.setIncludeDirectoryStructure(!state.includeDirectoryStructure)}
140+
includeGitDiffs={state.includeGitDiffs}
141+
onToggleIncludeGitDiffs={() => settings.setIncludeGitDiffs(!state.includeGitDiffs)}
142+
exportHeaderText={state.exportHeaderText}
143+
onSetExportHeaderText={settings.setExportHeaderText}
144+
exportInstructionText={state.exportInstructionText}
145+
onSetExportInstructionText={settings.setExportInstructionText}
123146
/>
147+
</React.Suspense>
124148
)}
125149
</AnimatePresence>
126150
<AnimatePresence>
127151
{state.isShortcutsOpen && (
152+
<React.Suspense fallback={<SuspenseFallback />}>
128153
<KeyboardShortcutsDialog
129154
isOpen={state.isShortcutsOpen}
130155
onClose={() => handlers.setIsShortcutsOpen(false)}
131156
/>
157+
</React.Suspense>
132158
)}
133159
</AnimatePresence>
134160
<AnimatePresence>
135-
{state.toastMessage && <Toast message={state.toastMessage} onDone={() => handlers.setToastMessage(null)} />}
161+
{state.toastMessage && <Toast message={state.toastMessage} onDone={() => handlers.setToastMessage(null)} type={state.toastType} />}
136162
</AnimatePresence>
137163
</div>
138164
);

structure-insight/CHANGELOG.md

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
# Changelog
2+
3+
## [5.3.0] - 2025-03-30
4+
5+
### Bug Fixes
6+
- 修复搜索结果计数重复显示
7+
- 移除 FileTree 组件中未使用的 wordWrap prop
8+
- 修复 FileTree 展开状态在重新渲染时丢失的问题(提升至中央 Set 管理)
9+
- 修复拖放操作中双重 AbortController 创建
10+
- 修复 ScrollToTopButton 中不稳定的 ref 依赖
11+
12+
### Performance
13+
- 为大对象 localStorage 写入添加防抖机制(>200KB 延迟 500ms)
14+
- 文件排序优化:移除逐插入排序,改为单次递归排序
15+
- 文件处理批量让出主线程(每 50 个文件 yield 一次)
16+
- CodeView 高亮 DOM 操作添加缓存 key 避免重复执行
17+
- React.lazy 代码拆分:SettingsDialog、SearchDialog、FileRankDialog、KeyboardShortcutsDialog
18+
- 窗口 resize 事件添加 100ms 防抖
19+
- 移除 18 个冗余的 hljs 语言加载脚本(核心包已包含)
20+
21+
### UX
22+
- FileTree 添加键盘导航(方向键、Enter、Escape)
23+
- FileTree 添加全部展开/折叠按钮
24+
- CodeView 面包屑导航优化(文件夹图标 + 箭头分隔符)
25+
- 状态栏添加文件类型摘要(前 3 种扩展名)
26+
- Toast 添加彩色边框区分成功/错误/信息
27+
- 键盘快捷键对话框全面中文化
28+
- 搜索结果计数显示在输入框内
29+
30+
### Architecture
31+
- 提取 CSS 自定义属性到 index.css
32+
- 启用 TypeScript strict 模式
33+
- 提取常量到 services/constants.ts
34+
- 添加 ErrorBoundary 错误边界组件
35+
- 添加 ARIA 无障碍标签
36+
- HTML lang 属性设置为 zh-CN

structure-insight/README.md

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2,21 +2,18 @@
22
<img width="1200" height="475" alt="GHBanner" src="https://github.com/user-attachments/assets/0aa67016-6eaf-458a-adb2-6e31a0763ed6" />
33
</div>
44

5-
# Run and deploy your AI Studio app
5+
# Run and deploy Structure Insight
66

77
This contains everything you need to run your app locally.
88

9-
View your app in AI Studio: https://ai.studio/apps/drive/1-Kc1AEio_RcW0U7LusWKtyBhD4D0lRQw
10-
119
## Run Locally
1210

1311
**Prerequisites:** Node.js
1412

1513

1614
1. Install dependencies:
1715
`npm install`
18-
2. Set the `GEMINI_API_KEY` (or `API_KEY`) in [.env.local](.env.local) to your Gemini API key.
19-
3. Run the app:
16+
2. Run the app:
2017
`npm run dev`
2118

2219
## Deployment Troubleshooting

0 commit comments

Comments
 (0)