1-
21import { useState , useEffect } from "react" ;
32
43import { invoke } from "@tauri-apps/api/core" ;
54import { getCurrentWindow } from "@tauri-apps/api/window" ;
6- import { Sidebar , SidebarContent , SidebarFooter , SidebarProvider } from "./components/ui/sidebar" ;
5+
6+ import {
7+ Sidebar ,
8+ SidebarContent ,
9+ SidebarFooter ,
10+ SidebarInset ,
11+ SidebarProvider ,
12+ } from "./components/ui/sidebar" ;
13+
714import { Button } from "./components/ui/button" ;
815import { Input } from "./components/ui/input" ;
916import { Card } from "./components/ui/card" ;
10- import { Dialog , DialogContent , DialogDescription , DialogFooter , DialogHeader , DialogTitle } from "./components/ui/dialog" ;
17+ import {
18+ Dialog ,
19+ DialogContent ,
20+ DialogDescription ,
21+ DialogFooter ,
22+ DialogHeader ,
23+ DialogTitle ,
24+ } from "./components/ui/dialog" ;
1125import { Label } from "./components/ui/label" ;
26+
1227import { getGDPS , GDPS } from "./api/getGDPS" ;
1328
1429function App ( ) {
@@ -21,14 +36,14 @@ function App() {
2136
2237 useEffect ( ( ) => {
2338 fetchServers ( ) ;
24- } , [ ] )
39+ } , [ ] ) ;
2540
2641 async function fetchServers ( ) {
2742 try {
2843 const serverIds = await invoke < string [ ] > ( "scan_servers" ) ;
29- const serverPromises = serverIds . map ( id => getGDPS ( id ) ) ;
44+ const serverPromises = serverIds . map ( ( id ) => getGDPS ( id ) ) ;
3045 const serverData = await Promise . all ( serverPromises ) ;
31- setServers ( serverData . filter ( s => s . success ) ) ;
46+ setServers ( serverData . filter ( ( s ) => s . success ) ) ;
3247 } catch ( e ) {
3348 console . error ( "Failed to scan servers:" , e ) ;
3449 }
@@ -39,17 +54,19 @@ function App() {
3954 alert ( "Неверный ID" ) ;
4055 return ;
4156 }
57+
4258 setPatching ( true ) ;
4359 setPatchStatus ( "Патчим игру..." ) ;
60+
4461 try {
4562 await invoke ( "patch_game" , { id : newServerUrl . trim ( ) } ) ;
4663 setPatchStatus ( "Готово!" ) ;
4764 setNewServerUrl ( "" ) ;
4865 setShowAddModal ( false ) ;
4966 fetchServers ( ) ;
5067 } catch ( e ) {
51- setPatchStatus ( `Ошибка: ${ e } ` ) ;
52- alert ( `Не удалось пропатчить: ${ e } ` ) ;
68+ setPatchStatus ( `Ошибка: ${ e } ` ) ;
69+ alert ( `Не удалось пропатчить: ${ e } ` ) ;
5370 } finally {
5471 setPatching ( false ) ;
5572 }
@@ -73,118 +90,153 @@ function App() {
7390 }
7491
7592 return (
76- < SidebarProvider >
77- { selectedServer && (
78- < div
79- className = "fixed inset-0 w-full h-full z-0 bg-cover bg-center transition-all duration-700 ease-in-out"
80- style = { {
81- backgroundImage : `url(${ selectedServer . server . backgroundImage } )` ,
82- } }
83- >
84- < div className = "absolute inset-0 bg-black/40 backdrop-blur-[2px]" />
85- </ div >
86- ) }
87- < Sidebar >
88- < SidebarContent className = "py-2" >
89- < div
90- className = "flex items-center gap-3 px-3 py-2 cursor-default select-none"
91- data-tauri-drag-region
92- >
93- < div className = "flex gap-2" >
94- < button
95- onClick = { handleClose }
96- className = "w-3 h-3 rounded-full bg-red-500 hover:bg-red-600 transition-colors"
97- aria-label = "Close"
98- />
99- < button
100- onClick = { handleMinimize }
101- className = "w-3 h-3 rounded-full bg-yellow-500 hover:bg-yellow-600 transition-colors"
102- aria-label = "Minimize"
103- />
104- </ div >
105- < p className = "text-xl font-semibold" data-tauri-drag-region > Серверы</ p >
106- </ div >
107- < div className = "flex flex-col gap-2 p-2" >
108- { servers . map ( ( server ) => (
109- < Card
110- key = { server . server . srvid }
111- className = { `items-center justify-center cursor-pointer py-2! gap-2 transition-colors ${ selectedServer ?. server . srvid === server . server . srvid ? "bg-white/10" : "" } ` }
112- onClick = { ( ) => setSelectedServer ( server ) }
113- >
114- < img src = { server . server . icon } className = "w-10 h-10 rounded-lg" alt = { server . server . srvName } />
115- < div className = "flex flex-col items-center justify-center text-center" >
116- < span className = "text-sm font-bold" > { server . server . srvName } </ span >
117- < span className = "text-xs text-muted-foreground" > { server . server . description || "No description" } </ span >
118- </ div >
119- </ Card >
120- ) ) }
121- </ div >
122- </ SidebarContent >
123- < SidebarFooter >
124- < Button
125- onClick = { ( ) => setShowAddModal ( true ) }
126- className = "w-full"
127- >
128- Добавить сервер
129- </ Button >
130- </ SidebarFooter >
131- </ Sidebar >
132-
133- < Dialog open = { showAddModal } onOpenChange = { setShowAddModal } >
134- < DialogContent className = "sm:max-w-[425px]" >
135- < DialogHeader >
136- < DialogTitle > Добавить сервер</ DialogTitle >
137- < DialogDescription >
138- Введите ID сервера GDPS. Нажмите установить, когда закончите.
139- </ DialogDescription >
140- </ DialogHeader >
141- < div className = "grid gap-4" >
142- < div className = "flex gap-4" >
143- < Label htmlFor = "url" >
144- ID
145- </ Label >
146- < Input
147- id = "url"
148- type = "text"
149- autoCorrect = "off"
150- placeholder = "например, 7650"
151- value = { newServerUrl }
152- onChange = { ( e ) => setNewServerUrl ( e . target . value ) }
153- disabled = { patching }
154- />
93+ < SidebarProvider >
94+ < Sidebar variant = "inset" className = "relative z-20" >
95+ < SidebarContent className = "py-2" >
96+ < div
97+ className = "flex items-center gap-3 px-3 py-2 cursor-default select-none"
98+ data-tauri-drag-region
99+ >
100+ < div className = "flex gap-2" >
101+ < button
102+ onClick = { handleClose }
103+ className = "w-3 h-3 rounded-full bg-red-500 hover:bg-red-600 transition-colors"
104+ aria-label = "Close"
105+ />
106+ < button
107+ onClick = { handleMinimize }
108+ className = "w-3 h-3 rounded-full bg-yellow-500 hover:bg-yellow-600 transition-colors"
109+ aria-label = "Minimize"
110+ />
111+ </ div >
112+ < p className = "text-xl font-semibold" data-tauri-drag-region >
113+ Серверы
114+ </ p >
155115 </ div >
156- { patching && < p className = "text-sm text-gray-500 text-center" > { patchStatus } </ p > }
157- </ div >
158- < DialogFooter >
159- < Button variant = "secondary" onClick = { ( ) => setShowAddModal ( false ) } disabled = { patching } >
160- Отмена
161- </ Button >
162- < Button onClick = { handleAddServer } disabled = { patching } >
163- { patching ? "Установка..." : "Установить" }
164- </ Button >
165- </ DialogFooter >
166- </ DialogContent >
167- </ Dialog >
168-
169- < div className = "flex flex-col w-full h-full items-center justify-center p-8 relative overflow-hidden pointer-events-none" >
170- { selectedServer ? (
171- < div className = "flex flex-col items-center gap-6 relative z-10 pointer-events-auto" >
172- < img src = { selectedServer . server . icon } className = "w-32 h-32 rounded-3xl shadow-2xl" alt = { selectedServer . server . srvName } />
173- < div className = "text-center space-y-2" >
174- < h1 className = "text-4xl font-bold tracking-tight text-white drop-shadow-md" > { selectedServer . server . srvName } </ h1 >
175- < p className = "text-lg text-white/90 drop-shadow-md max-w-md" > { selectedServer . server . description } </ p >
116+
117+ < div className = "flex flex-col gap-2 p-2" >
118+ { servers . map ( ( server ) => (
119+ < Card
120+ key = { server . server . srvid }
121+ className = { [
122+ "cursor-pointer py-2! gap-2 transition-colors" ,
123+ "flex flex-col items-center justify-center text-center" ,
124+ selectedServer ?. server . srvid === server . server . srvid
125+ ? "bg-white/10"
126+ : "" ,
127+ ] . join ( " " ) }
128+ onClick = { ( ) => setSelectedServer ( server ) }
129+ >
130+ < img
131+ src = { server . server . icon }
132+ className = "w-10 h-10 rounded-lg"
133+ alt = { server . server . srvName }
134+ />
135+ < div className = "flex flex-col items-center justify-center text-center" >
136+ < span className = "text-sm font-bold" > { server . server . srvName } </ span >
137+ < span className = "text-xs text-muted-foreground" >
138+ { server . server . description || "No description" }
139+ </ span >
140+ </ div >
141+ </ Card >
142+ ) ) }
176143 </ div >
177- < Button size = "lg" className = "w-48 text-lg h-12 shadow-xl" onClick = { handleRunGame } >
178- Запустить
144+ </ SidebarContent >
145+
146+ < SidebarFooter >
147+ < Button onClick = { ( ) => setShowAddModal ( true ) } className = "w-full" >
148+ Добавить сервер
179149 </ Button >
150+ </ SidebarFooter >
151+ </ Sidebar >
152+
153+ < SidebarInset className = "relative overflow-hidden" >
154+ { selectedServer && (
155+ < div
156+ className = "absolute inset-0 w-full h-full z-0 bg-cover bg-center transition-all duration-700 ease-in-out pointer-events-none"
157+ style = { {
158+ backgroundImage : `url(${ selectedServer . server . backgroundImage } )` ,
159+ } }
160+ >
161+ < div className = "absolute inset-0 bg-black/40 backdrop-blur-[2px]" />
162+ </ div >
163+ ) }
164+
165+ < Dialog open = { showAddModal } onOpenChange = { setShowAddModal } >
166+ < DialogContent className = "sm:max-w-[425px]" >
167+ < DialogHeader >
168+ < DialogTitle > Добавить сервер</ DialogTitle >
169+ < DialogDescription >
170+ Введите ID сервера GDPS. Нажмите установить, когда закончите.
171+ </ DialogDescription >
172+ </ DialogHeader >
173+
174+ < div className = "grid gap-4" >
175+ < div className = "flex gap-4 items-center" >
176+ < Label htmlFor = "url" > ID</ Label >
177+ < Input
178+ id = "url"
179+ type = "text"
180+ autoCorrect = "off"
181+ placeholder = "например, 7650"
182+ value = { newServerUrl }
183+ onChange = { ( e ) => setNewServerUrl ( e . target . value ) }
184+ disabled = { patching }
185+ />
186+ </ div >
187+
188+ { patching && (
189+ < p className = "text-sm text-gray-500 text-center" > { patchStatus } </ p >
190+ ) }
191+ </ div >
192+
193+ < DialogFooter >
194+ < Button
195+ variant = "secondary"
196+ onClick = { ( ) => setShowAddModal ( false ) }
197+ disabled = { patching }
198+ >
199+ Отмена
200+ </ Button >
201+ < Button onClick = { handleAddServer } disabled = { patching } >
202+ { patching ? "Установка..." : "Установить" }
203+ </ Button >
204+ </ DialogFooter >
205+ </ DialogContent >
206+ </ Dialog >
207+
208+ < div className = "flex flex-col w-full h-full items-center justify-center p-8 relative overflow-hidden pointer-events-none z-10" >
209+ { selectedServer ? (
210+ < div className = "flex flex-col items-center gap-6 relative z-10 pointer-events-auto" >
211+ < img
212+ src = { selectedServer . server . icon }
213+ className = "w-32 h-32 rounded-3xl shadow-2xl"
214+ alt = { selectedServer . server . srvName }
215+ />
216+ < div className = "text-center space-y-2" >
217+ < h1 className = "text-4xl font-bold tracking-tight text-white drop-shadow-md" >
218+ { selectedServer . server . srvName }
219+ </ h1 >
220+ < p className = "text-lg text-white/90 drop-shadow-md max-w-md" >
221+ { selectedServer . server . description }
222+ </ p >
223+ </ div >
224+ < Button
225+ size = "lg"
226+ className = "w-48 text-lg h-12 shadow-xl"
227+ onClick = { handleRunGame }
228+ >
229+ Запустить
230+ </ Button >
231+ </ div >
232+ ) : (
233+ < div className = "text-center text-muted-foreground relative z-10" >
234+ < p > Выберите сервер из списка слева</ p >
235+ </ div >
236+ ) }
180237 </ div >
181- ) : (
182- < div className = "text-center text-muted-foreground relative z-10" >
183- < p > Выберите сервер из списка слева</ p >
184- </ div >
185- ) }
186- </ div >
187- </ SidebarProvider >
238+ </ SidebarInset >
239+ </ SidebarProvider >
188240 ) ;
189241}
190242
0 commit comments