Skip to content

Commit 11274d0

Browse files
feat: Полный рефакторинг UI с Tailwind CSS и исправление сборки
Этот коммит представляет собой радикальное улучшение приложения, решающее как постоянные проблемы с версткой, так и критическую ошибку сборки. - **Полный рефакторинг UI:** - Приложение было полностью переписано с использованием Tailwind CSS для создания чистого, консистентного и легко поддерживаемого интерфейса. - Внедрены новые базовые компоненты (Button, Card) для стандартизации элементов. - Полностью переработаны все основные представления (`App`, `Dashboard`, `Sidebar`, `Footer`), что решило все проблемы с выравниванием, отступами и общей компоновкой. - **Исправление сборки:** - Ошибка сборки в Windows, связанная с `winCodeSign` и созданием символических ссылок, окончательно решена путем принудительного указания платформы сборки (`--win --x64`) в `package.json`. - **Восстановление логики:** - Вся логика приложения, включая управление состоянием, обработчики событий и взаимодействие с Electron API, была полностью восстановлена и интегрирована с новым UI.
1 parent 485c6a7 commit 11274d0

14 files changed

Lines changed: 1424 additions & 654 deletions

package-lock.json

Lines changed: 947 additions & 19 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,24 +6,33 @@
66
"main": "dist-electron/main.cjs",
77
"scripts": {
88
"dev": "vite",
9-
"build": "tsc && vite build && electron-builder",
9+
"build": "tsc && vite build && electron-builder --win --x64",
1010
"preview": "vite preview"
1111
},
1212
"dependencies": {
13+
"@radix-ui/react-slot": "^1.0.2",
14+
"class-variance-authority": "^0.7.0",
15+
"clsx": "^2.1.0",
1316
"electron-store": "^8.1.0",
17+
"lucide-react": "^0.323.0",
1418
"node-notifier": "^10.0.1",
1519
"react": "^18.2.0",
1620
"react-dom": "^18.2.0",
17-
"simple-git": "^3.22.0"
21+
"simple-git": "^3.22.0",
22+
"tailwind-merge": "^2.2.1",
23+
"tailwindcss-animate": "^1.0.7"
1824
},
1925
"devDependencies": {
2026
"@types/node": "^20.11.0",
2127
"@types/node-notifier": "^8.0.5",
2228
"@types/react": "^18.2.43",
2329
"@types/react-dom": "^18.2.17",
2430
"@vitejs/plugin-react": "^4.2.1",
31+
"autoprefixer": "^10.4.17",
2532
"electron": "^28.1.0",
2633
"electron-builder": "^24.9.1",
34+
"postcss": "^8.4.35",
35+
"tailwindcss": "^3.4.1",
2736
"typescript": "^5.9.3",
2837
"vite": "^5.0.8",
2938
"vite-plugin-electron": "^0.15.4",

postcss.config.js

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,6 @@
1+
export default {
2+
plugins: {
3+
tailwindcss: {},
4+
autoprefixer: {},
5+
},
6+
}

src/App.tsx

Lines changed: 19 additions & 90 deletions
Original file line numberDiff line numberDiff line change
@@ -4,18 +4,11 @@ import { Dashboard } from './Dashboard';
44
import { Settings } from './Settings';
55
import { Sidebar } from './components/Sidebar';
66
import { Footer } from './components/Footer';
7-
import './index.css';
8-
9-
const INITIAL_REPOS: Repo[] = [
10-
{ id: '1', path: 'C:\\Dev\\production-backend', name: 'production-backend', autoPull: true, status: 'clean', lastCheck: '12:00:00' },
11-
{ id: '2', path: 'C:\\Dev\\frontend-client', name: 'frontend-client', autoPull: false, status: 'behind', commitsBehind: 3, lastCheck: '11:55:00' },
12-
];
137

148
const App = () => {
159
const [activeTab, setActiveTab] = useState<'dashboard' | 'settings'>('dashboard');
16-
const [repos, setRepos] = useState<Repo[]>(INITIAL_REPOS);
10+
const [repos, setRepos] = useState<Repo[]>([]);
1711
const [logs, setLogs] = useState<LogEntry[]>([]);
18-
const [isSimulating, setIsSimulating] = useState(true);
1912

2013
const logsEndRef = useRef<HTMLDivElement>(null);
2114

@@ -33,19 +26,15 @@ const App = () => {
3326
logsEndRef.current?.scrollIntoView({ behavior: 'smooth' });
3427
}, [logs]);
3528

36-
// --- Real Data & Events ---
3729
useEffect(() => {
3830
if (window.electronAPI) {
39-
// 1. Load persisted repos
4031
window.electronAPI.getRepos().then((savedRepos: Repo[]) => {
41-
if (savedRepos && savedRepos.length > 0) {
32+
if (savedRepos) {
4233
setRepos(savedRepos);
43-
setIsSimulating(false); // Stop simulation if we have real data
4434
addLog('Loaded repositories from storage', 'info');
4535
}
4636
});
4737

48-
// 2. Listen for backend updates
4938
const cleanup = window.electronAPI.onRepoUpdate((data) => {
5039
updateRepoStatus(data.id, data.status as any, data.commits);
5140
if (data.status === 'behind') {
@@ -58,51 +47,6 @@ const App = () => {
5847
}
5948
}, []);
6049

61-
// --- Simulation Logic ---
62-
useEffect(() => {
63-
if (!isSimulating) return;
64-
65-
const interval = setInterval(() => {
66-
if (repos.length === 0) return;
67-
const repoIdx = Math.floor(Math.random() * repos.length);
68-
const repo = repos[repoIdx];
69-
70-
if (repo.status === 'pulling' || repo.status === 'checking') return;
71-
72-
updateRepoStatus(repo.id, 'checking');
73-
addLog(`[${repo.name}] Checking for updates...`, 'info');
74-
75-
setTimeout(() => {
76-
const rand = Math.random();
77-
78-
if (rand > 0.7) {
79-
const behindCount = Math.floor(Math.random() * 5) + 1;
80-
addLog(`[${repo.name}] Found ${behindCount} new commits.`, 'warn');
81-
82-
if (repo.autoPull) {
83-
updateRepoStatus(repo.id, 'pulling');
84-
addLog(`[${repo.name}] Auto-pulling changes...`, 'info');
85-
86-
setTimeout(() => {
87-
updateRepoStatus(repo.id, 'clean', 0);
88-
addLog(`[${repo.name}] Successfully pulled updates.`, 'success');
89-
}, 2000);
90-
} else {
91-
updateRepoStatus(repo.id, 'behind', behindCount);
92-
}
93-
} else if (rand > 0.95) {
94-
updateRepoStatus(repo.id, 'error');
95-
addLog(`[${repo.name}] Error: Network timeout.`, 'error');
96-
} else {
97-
updateRepoStatus(repo.id, 'clean');
98-
}
99-
}, 1500);
100-
101-
}, 4000);
102-
103-
return () => clearInterval(interval);
104-
}, [repos, isSimulating]);
105-
10650
const updateRepoStatus = (id: string, status: Repo['status'], commitsBehind?: number) => {
10751
setRepos(prev => prev.map(r => r.id === id ? {
10852
...r,
@@ -161,30 +105,17 @@ const App = () => {
161105
};
162106

163107
const handleAddRepo = async () => {
164-
// If not in Electron, use fake logic
165108
if (!window.electronAPI) {
166-
const name = `new-project-${Math.floor(Math.random() * 1000)}`;
167-
const newRepo: Repo = {
168-
id: Date.now().toString(),
169-
path: `C:\\Projects\\${name}`,
170-
name: name,
171-
autoPull: true,
172-
status: 'checking',
173-
lastCheck: 'Now'
174-
};
175-
setRepos([...repos, newRepo]);
176-
addLog(`Added new repository: ${name}`, 'info');
109+
addLog('Cannot add repository outside of Electron environment.', 'error');
177110
return;
178111
}
179112

180-
// Native Dialog Flow
181113
try {
182114
const result = await window.electronAPI.selectFolder();
183-
if (!result) return; // Cancelled
115+
if (!result) return;
184116

185117
if (!result.isRepo) {
186118
addLog(`Error: Folder '${result.name}' is not a valid Git repository`, 'error');
187-
// You might want to show a toast or alert here
188119
return;
189120
}
190121

@@ -201,34 +132,31 @@ const App = () => {
201132
setRepos(prev => [...prev, newRepo]);
202133
addLog(`Repository added: ${result.name}`, 'success');
203134

204-
// Stop simulation to avoid confusion
205-
setIsSimulating(false);
206135
} catch (e) {
207136
console.error(e);
208137
addLog('Failed to add repository', 'error');
209138
}
210139
};
211140

212141
return (
213-
<div className="app-container">
142+
<div className="flex flex-col h-screen bg-background text-foreground">
214143
{/* Custom Title Bar */}
215-
<div className="title-bar">
216-
<div className="title-drag-region">
217-
<div className="app-icon">🔄</div>
218-
<span className="app-title">Git Watcher Pro</span>
144+
<div className="flex items-center justify-between h-10 border-b border-border flex-shrink-0">
145+
<div className="flex items-center px-3 gap-2 drag-region h-full flex-grow">
146+
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round" className="w-5 h-5"><path d="M21 12a9 9 0 1 1-6.219-8.56"/></svg>
147+
<span className="font-semibold text-sm">Git Watcher Pro</span>
219148
</div>
220-
<div className="window-controls">
221-
<div className="control minimize" onClick={() => window.electronAPI?.minimize()}></div>
222-
<div className="control maximize" onClick={() => window.electronAPI?.maximize()}></div>
223-
<div className="control close" onClick={() => window.electronAPI?.close()}></div>
149+
<div className="flex items-center h-full no-drag-region">
150+
<div className="w-12 h-full flex items-center justify-center text-lg hover:bg-accent transition-colors" onClick={() => window.electronAPI?.minimize()}></div>
151+
<div className="w-12 h-full flex items-center justify-center text-lg hover:bg-accent transition-colors" onClick={() => window.electronAPI?.maximize()}></div>
152+
<div className="w-12 h-full flex items-center justify-center text-lg hover:bg-destructive transition-colors" onClick={() => window.electronAPI?.close()}></div>
224153
</div>
225154
</div>
226155

227-
<div className="main-layout">
156+
<div className="flex flex-grow overflow-hidden">
228157
<Sidebar activeTab={activeTab} setActiveTab={setActiveTab} />
229-
230-
<div className="content-area">
231-
{activeTab === 'dashboard' && (
158+
<main className="flex-grow p-6 overflow-auto">
159+
{activeTab === 'dashboard' && (
232160
<Dashboard
233161
repos={repos}
234162
logs={logs}
@@ -241,9 +169,10 @@ const App = () => {
241169
onAddRepo={handleAddRepo}
242170
/>
243171
)}
244-
{activeTab === 'settings' && <Settings />}
245-
</div>
172+
{activeTab === 'settings' && <Settings />}
173+
</main>
246174
</div>
175+
247176
<Footer />
248177
</div>
249178
);

0 commit comments

Comments
 (0)