2727 overflow : hidden;
2828 }
2929
30-
3130 # desktop {
3231 position : absolute; inset : 0 ;
3332 background-image : url ('https://cdn.jsdelivr.net/gh/tharun9772/game-assets@main/bloxy-os/background.png' );
3433 background-size : cover; background-position : center;
3534 filter : saturate (1.05 ) contrast (1.02 );
3635 }
3736
38-
3937 # topbar {
4038 position : fixed; top : 0 ; left : 0 ; right : 0 ; height : 38px ;
4139 display : flex; align-items : center; justify-content : space-between; padding : 0 12px ;
4442 }
4543 .chip { background : rgba (255 , 255 , 255 , 0.03 ); padding : 6px 8px ; border-radius : 10px ; font-size : 13px ; display : flex; gap : 8px ; align-items : center; }
4644
47-
4845 .desktop-icons { position : absolute; top : 80px ; left : 40px ; display : flex; flex-wrap : wrap; gap : 18px ; max-width : calc (100% - 80px ); z-index : 100 ; }
4946 .desktop-icon { width : 80px ; text-align : center; color : var (--text ); cursor : pointer; user-select : none; }
5047 .desktop-icon img { width : 64px ; height : 64px ; border-radius : 12px ; display : block; margin : 0 auto 6px ; box-shadow : 0 8px 20px rgba (0 , 0 , 0 , 0.35 ); }
5148 .desktop-icon span { display : block; font-size : 12px ; color : var (--muted ); white-space : nowrap; overflow : hidden; text-overflow : ellipsis; }
5249
53-
5450 # dock {
5551 position : fixed; bottom : 20px ; left : 50% ; transform : translateX (-50% ); padding : 12px 18px ; background : var (--dock-bg );
5652 border-radius : 18px ; display : flex; gap : 14px ; align-items : flex-end; z-index : 1500 ; box-shadow : var (--shadow ); backdrop-filter : blur (12px );
6359 .dock-underline { position : absolute; left : 8px ; right : 8px ; bottom : -8px ; height : 3px ; border-radius : 4px ; background : linear-gradient (90deg , # 7c3aed, # 4f46e5 ); transform-origin : center; opacity : 0 ; transition : opacity .18s ; }
6460 .dock-item .minimized .dock-underline { opacity : 1 ; }
6561
66-
6762 .launch-icon-grid {
6863 width : 44px ; height : 44px ; display : grid; grid-template-columns : repeat (2 , 1fr ); grid-template-rows : repeat (2 , 1fr ); gap : 4px ; padding : 6px ; border-radius : 8px ; background : rgba (255 , 255 , 255 , 0.03 );
6964 }
7065 .launch-icon-grid div { background : rgba (255 , 255 , 255 , 0.04 ); border-radius : 3px ; }
7166
72-
7367 # launcherModal {
7468 position : fixed; left : 50% ; top : 50% ; transform : translate (-50% , -50% ) scale (0.95 ); width : 760px ; max-width : calc (100% - 40px ); max-height : 72vh ;
7569 background : var (--launcher-bg ); border-radius : 14px ; padding : 18px ; box-shadow : 0 22px 80px rgba (0 , 0 , 0 , 0.7 ); display : none; z-index : 2500 ; backdrop-filter : blur (10px ); border : 1px solid rgba (255 , 255 , 255 , 0.05 );
8175 # launcherHeader h3 { margin : 0 ; font-weight : 600 ; color : var (--text ); }
8276 # launcherHeader .small-muted { color : var (--muted ); font-size : 13px ; }
8377
84-
8578 .launcher-grid-wrap { overflow : auto; max-height : 60vh ; padding-right : 6px ; }
8679 .launcher-grid {
8780 display : grid; grid-template-columns : repeat (5 , 1fr ); gap : 12px ; align-items : start;
9689 .app-card .app-actions { display : flex; gap : 8px ; margin-top : auto; }
9790 .btn { padding : 6px 8px ; border-radius : 8px ; background : rgba (255 , 255 , 255 , 0.03 ); border : 1px solid rgba (255 , 255 , 255 , 0.04 ); cursor : pointer; font-size : 13px ; color : var (--text ); }
9891
99-
10092 # addAppForm { display : flex; gap : 8px ; align-items : center; margin-left : 8px ; }
10193 # addAppForm input { padding : 8px 10px ; border-radius : 8px ; border : 1px solid rgba (255 , 255 , 255 , 0.06 ); background : transparent; color : var (--text ); outline : none; font-size : 13px ; width : 160px ; }
10294 # addAppForm input ::placeholder { color : rgba (234 , 240 , 255 , 0.35 ); }
10395
104-
10596 .small-muted { font-size : 12px ; color : var (--muted ); }
10697 .hint { font-size : 12px ; color : var (--muted ); position : fixed; right : 18px ; bottom : 18px ; background : rgba (0 , 0 , 0 , 0.35 ); padding : 8px 10px ; border-radius : 10px ; z-index : 2000 ; }
10798
108-
10999 .app-window { position : absolute; width : 720px ; height : 480px ; background : rgba (255 , 255 , 255 , 0.06 ); border-radius : 12px ; box-shadow : 0 18px 60px rgba (2 , 6 , 23 , 0.7 ); overflow : hidden; display : flex; flex-direction : column; backdrop-filter : blur (10px ); border : 1px solid rgba (255 , 255 , 255 , 0.06 ); z-index : 500 ; min-width : 300px ; min-height : 160px ; }
110100 .title-bar { height : 38px ; display : flex; align-items : center; gap : 10px ; padding : 6px 10px ; cursor : grab; background : linear-gradient (180deg , rgba (255 , 255 , 255 , 0.02 ), rgba (0 , 0 , 0 , 0.02 )); }
111101 .title-left { display : flex; gap : 8px ; align-items : center; width : 70% ; }
133123
134124< div id ="desktop " onclick ="focusClearAll() "> </ div >
135125
136-
137126< div id ="topbar ">
138127 < div style ="display:flex;gap:8px;align-items:center; ">
139128 < div class ="chip " style ="font-weight:600; font-size:13px; "> BloxyOS</ div >
149138 </ div >
150139</ div >
151140
152-
153141< div class ="desktop-icons " id ="desktopIcons "> </ div >
154142
155-
156143< div id ="dock "> </ div >
157144
158-
159145< div id ="launcherModal " role ="dialog " aria-modal ="true ">
160146 < div id ="launcherHeader ">
161147 < div >
@@ -173,14 +159,11 @@ <h3>Apps</h3>
173159 </ div >
174160
175161 < div class ="launcher-grid-wrap ">
176- < div class ="launcher-grid " id ="launcherGrid ">
177-
178- </ div >
162+ < div class ="launcher-grid " id ="launcherGrid "> </ div >
179163 </ div >
180-
181164</ div >
182165
183- < div class ="hint "> Click The 4-Square App To See All Apps</ div >
166+ < div class ="hint "> Click The App Menu Icon To See All Apps</ div >
184167
185168< script >
186169
@@ -208,40 +191,47 @@ <h3>Apps</h3>
208191
209192 { id : 'elite-gamez' , name : 'Elite Gamez' , icon : 'https://cdn.jsdelivr.net/gh/elite-gamez/fac@main/logoo.png' , url : '/apps/elite-gamez/' } ,
210193 { id : 'test-iframe' , name : 'Test Iframe' , icon : '/assets_handcurser.png' , url : '/iframe-sites/iframe-test-list/' } ,
211- { id : 'annoucements' , name : 'Annoucements' , icon : '/bloxraft .png' , url : 'https://padlet.com/embed/nhocearj1z6ibdyy' } ,
194+ { id : 'annoucements' , name : 'Annoucements' , icon : '/bloxcraft .png' , url : 'https://padlet.com/embed/nhocearj1z6ibdyy' } ,
212195 { id : 'tos' , name : 'Terms Of Service' , icon : '/bloxcraft_transparent.png' , url : '/terms' } ,
213196 { id : 'privacy-policy' , name : 'Privcy Policy' , icon : '/bloxcraft_transparent.png' , url : '/privacy-policy' }
214197] ;
215198
199+
216200let STORAGE = getCookieJson ( 'bloxy_state' ) || { pinned : [ ] , windows : { } , customApps : [ ] } ;
217201function saveState ( ) { setCookieJson ( 'bloxy_state' , STORAGE ) ; }
218202
219-
220203const dock = document . getElementById ( 'dock' ) ;
221204const desktopIcons = document . getElementById ( 'desktopIcons' ) ;
222205const launcherModal = document . getElementById ( 'launcherModal' ) ;
223206const launcherGrid = document . getElementById ( 'launcherGrid' ) ;
224207
225208function getAllApps ( ) {
226-
227209 return [ ...DEFAULT_APPS , ... ( STORAGE . customApps || [ ] ) ] ;
228210}
229211
212+
213+ const DEFAULT_FIRST_4 = DEFAULT_APPS . slice ( 0 , 4 ) ;
214+
215+
230216function renderDock ( ) {
231217 dock . innerHTML = '' ;
232- const apps = DEFAULT_APPS . slice ( 0 , 4 ) ;
233- const all = getAllApps ( ) ;
234218
235219
236- const launchItem = document . createElement ( 'div' ) ; launchItem . className = 'dock-item' ;
220+ const launchItem = document . createElement ( 'div' ) ; launchItem . className = 'dock-item launch-item ' ;
237221 launchItem . title = 'Launcher' ;
238- const gridIcon = document . createElement ( 'div' ) ; gridIcon . className = 'launch-icon-grid' ;
239- gridIcon . innerHTML = '<div></div><div></div><div></div><div></div>' ;
240- launchItem . appendChild ( gridIcon ) ;
222+ const launchImg = document . createElement ( 'img' ) ;
223+ launchImg . src = 'https://cdn.jsdelivr.net/gh/tharun9772/game-assets@main/bloxy-os/app-menu.png' ;
224+ launchImg . alt = 'App Menu' ;
225+ launchImg . style . width = '44px' ;
226+ launchImg . style . height = '44px' ;
227+ launchImg . style . borderRadius = '8px' ;
228+ launchItem . appendChild ( launchImg ) ;
241229 launchItem . onclick = ( e ) => { e . stopPropagation ( ) ; toggleLauncher ( true ) ; } ;
242230 dock . appendChild ( launchItem ) ;
243231
244-
232+ const all = getAllApps ( ) ;
233+
234+
245235 for ( const appId of STORAGE . pinned ) {
246236 const app = all . find ( a => a . id === appId ) ;
247237 if ( ! app ) continue ;
@@ -250,22 +240,14 @@ <h3>Apps</h3>
250240 }
251241
252242
253- for ( const app of DEFAULT_APPS ) {
254-
243+ for ( const app of DEFAULT_FIRST_4 ) {
255244 if ( STORAGE . pinned . includes ( app . id ) ) continue ;
256245 const item = createDockItemForApp ( app ) ;
257246 dock . appendChild ( item ) ;
258247 }
259-
260-
261- for ( const c of ( STORAGE . customApps || [ ] ) ) {
262- if ( STORAGE . pinned . includes ( c . id ) ) continue ;
263- if ( DEFAULT_APPS . find ( a => a . id === c . id ) ) continue ;
264- const item = createDockItemForApp ( c ) ;
265- dock . appendChild ( item ) ;
266- }
267248}
268249
250+
269251function createDockItemForApp ( app ) {
270252 const item = document . createElement ( 'div' ) ; item . className = 'dock-item' ; item . dataset . app = app . id ;
271253 const img = document . createElement ( 'img' ) ; img . src = app . icon || defaultIconFor ( app . name ) ; img . alt = app . name ;
@@ -274,30 +256,32 @@ <h3>Apps</h3>
274256 const pin = document . createElement ( 'div' ) ; pin . className = 'pin-btn' ; pin . innerHTML = '📌' ; pin . title = 'Pin/Unpin to desktop' ;
275257 pin . onclick = ( e ) => { e . stopPropagation ( ) ; togglePin ( app . id ) ; } ;
276258 item . appendChild ( pin ) ;
277-
259+
278260 const underline = document . createElement ( 'div' ) ; underline . className = 'dock-underline' ; item . appendChild ( underline ) ;
279-
261+
280262 item . onclick = ( ) => {
281263 const ws = STORAGE . windows [ app . id ] ;
282264 if ( ws && ws . minimized ) { createOrRestoreWindow ( app , ws ) ; ws . minimized = false ; saveState ( ) ; refreshDockUnderlineStatus ( ) ; return ; }
283265 if ( document . getElementById ( 'win-' + app . id ) ) { focusWindowById ( app . id ) ; return ; }
284266 openApp ( app ) ;
285267 } ;
268+
286269 item . oncontextmenu = ( e ) => {
287270 e . preventDefault ( ) ;
288-
289271 const menu = document . createElement ( 'div' ) ;
290272 menu . style . position = 'fixed' ; menu . style . left = e . clientX + 'px' ; menu . style . top = e . clientY + 'px' ;
291273 menu . style . background = 'rgba(0,0,0,0.8)' ; menu . style . padding = '8px' ; menu . style . borderRadius = '8px' ; menu . style . zIndex = 9999 ;
292- menu . innerHTML = `<div style="padding:6px 12px;cursor:pointer">Open</div><div style="padding:6px 12px;cursor:pointer">${ STORAGE . pinned . includes ( app . id ) ?'Unpin' :'Pin' } </div><div style="padding:6px 12px;cursor:pointer">Open in new tab</div>` ;
274+ menu . innerHTML = `<div style="padding:6px 12px;cursor:pointer">Open</div>
275+ <div style="padding:6px 12px;cursor:pointer">${ STORAGE . pinned . includes ( app . id ) ?'Unpin' :'Pin' } </div>
276+ <div style="padding:6px 12px;cursor:pointer">Open in new tab</div>` ;
293277 document . body . appendChild ( menu ) ;
294278 const rm = ( ) => menu . remove ( ) ;
295279 menu . children [ 0 ] . onclick = ( ) => { openApp ( app ) ; rm ( ) ; } ;
296280 menu . children [ 1 ] . onclick = ( ) => { togglePin ( app . id ) ; rm ( ) ; } ;
297281 menu . children [ 2 ] . onclick = ( ) => { window . open ( app . url , '_blank' ) ; rm ( ) ; } ;
298282 document . addEventListener ( 'click' , rm , { once :true } ) ;
299283 } ;
300- // minimized status
284+
301285 if ( STORAGE . windows [ app . id ] && STORAGE . windows [ app . id ] . minimized ) item . classList . add ( 'minimized' ) ;
302286 return item ;
303287}
@@ -306,6 +290,7 @@ <h3>Apps</h3>
306290 return 'https://cdn.jsdelivr.net/gh/tharun9772/game-assets@main/bloxy-os/565547.png' ;
307291}
308292
293+
309294function renderDesktopIcons ( ) {
310295 desktopIcons . innerHTML = '' ;
311296 for ( const id of STORAGE . pinned ) {
@@ -340,24 +325,26 @@ <h3>Apps</h3>
340325 if ( show ) openLauncher ( ) ; else closeLauncher ( ) ;
341326}
342327
328+
343329document . addEventListener ( 'click' , ( e ) => {
344- const inside = e . target . closest ( '#launcherModal' ) || e . target . closest ( '.launch-icon-grid' ) ;
330+ const inside = e . target . closest ( '#launcherModal' ) || e . target . closest ( '.launch-item' ) || e . target . closest ( '.launch- icon-grid' ) || e . target . closest ( '.launch-item img ') ;
345331 if ( ! inside ) closeLauncher ( ) ;
346332} ) ;
347333
348334
349335function buildLauncherGrid ( ) {
350336 launcherGrid . innerHTML = '' ;
351337 const apps = getAllApps ( ) ;
352-
338+
353339 apps . sort ( ( a , b ) => ( a . name || '' ) . localeCompare ( b . name || '' ) ) ;
354340 for ( const app of apps ) {
355341 const card = document . createElement ( 'div' ) ; card . className = 'app-card' ;
356342 const img = document . createElement ( 'img' ) ; img . src = app . icon || defaultIconFor ( app . name ) ;
357343 const name = document . createElement ( 'div' ) ; name . className = 'app-name' ; name . textContent = app . name ;
358344 const actions = document . createElement ( 'div' ) ; actions . className = 'app-actions' ;
359345 const launchBtn = document . createElement ( 'button' ) ; launchBtn . className = 'btn' ; launchBtn . textContent = 'Open' ;
360- launchBtn . onclick = ( ) => { openApp ( app ) ; } ;
346+
347+ launchBtn . onclick = ( ) => { openApp ( app ) ; closeLauncher ( ) ; } ;
361348 const pinBtn = document . createElement ( 'button' ) ; pinBtn . className = 'btn' ; pinBtn . textContent = STORAGE . pinned . includes ( app . id ) ?'Unpin' :'Pin' ;
362349 pinBtn . onclick = ( ) => { togglePin ( app . id ) ; pinBtn . textContent = STORAGE . pinned . includes ( app . id ) ?'Unpin' :'Pin' ; renderDesktopIcons ( ) ; renderDock ( ) ; } ;
363350 actions . appendChild ( launchBtn ) ; actions . appendChild ( pinBtn ) ;
@@ -392,7 +379,7 @@ <h3>Apps</h3>
392379
393380let zCounter = 1000 ;
394381function openApp ( app ) {
395-
382+
396383 const defaultState = {
397384 id : app . id ,
398385 name : app . name ,
@@ -402,9 +389,9 @@ <h3>Apps</h3>
402389 width : 720 , height : 480 ,
403390 minimized : false , fullscreen : false
404391 } ;
405- STORAGE . windows [ app . id ] = defaultState ;
392+ STORAGE . windows [ app . id ] = STORAGE . windows [ app . id ] || defaultState ;
406393 saveState ( ) ;
407- createWindowFromState ( app , defaultState ) ;
394+ createWindowFromState ( app , STORAGE . windows [ app . id ] ) ;
408395 renderDock ( ) ;
409396}
410397
@@ -421,22 +408,20 @@ <h3>Apps</h3>
421408}
422409
423410function createWindowFromState ( app , wstate ) {
424-
425411 if ( document . getElementById ( 'win-' + app . id ) ) return ;
426412 const w = document . createElement ( 'div' ) ; w . className = 'app-window' ; w . id = 'win-' + app . id ;
427413 w . style . left = ( wstate . left || 100 ) + 'px' ; w . style . top = ( wstate . top || 80 ) + 'px' ; w . style . width = ( wstate . width || 720 ) + 'px' ; w . style . height = ( wstate . height || 480 ) + 'px' ; w . style . zIndex = ++ zCounter ;
428414
429-
430415 const titleBar = document . createElement ( 'div' ) ; titleBar . className = 'title-bar' ;
431- const left = document . createElement ( 'div' ) ; left . className = 'title-left' ; left . innerHTML = `<div style="width:14px;height:14px;border-radius:50%;background:url(${ app . icon || defaultIconFor ( app . name ) } ) center/cover"></div><div class="win-title">${ app . name } </div>` ;
416+ const left = document . createElement ( 'div' ) ; left . className = 'title-left' ;
417+ left . innerHTML = `<div style="width:14px;height:14px;border-radius:50%;background:url(${ app . icon || defaultIconFor ( app . name ) } ) center/cover"></div><div class="win-title">${ app . name } </div>` ;
432418 const right = document . createElement ( 'div' ) ; right . className = 'title-right' ;
433419 const btnMin = document . createElement ( 'div' ) ; btnMin . className = 'control-btn btn-min' ;
434420 const btnMax = document . createElement ( 'div' ) ; btnMax . className = 'control-btn btn-max' ;
435421 const btnClose = document . createElement ( 'div' ) ; btnClose . className = 'control-btn btn-close' ;
436422 right . appendChild ( btnMin ) ; right . appendChild ( btnMax ) ; right . appendChild ( btnClose ) ;
437423 titleBar . appendChild ( left ) ; titleBar . appendChild ( right ) ;
438424
439-
440425 const frame = document . createElement ( 'div' ) ; frame . className = 'app-frame' ;
441426 const iframe = document . createElement ( 'iframe' ) ; iframe . src = app . url ;
442427 frame . appendChild ( iframe ) ;
@@ -455,14 +440,13 @@ <h3>Apps</h3>
455440 makeResizable ( w , resizer ) ;
456441
457442 btnMin . onclick = ( e ) => { e . stopPropagation ( ) ; minimizeWindow ( app . id ) ; } ;
458- btnClose . onclick = ( e ) => { e . stopPropagation ( ) ; minimizeWindow ( app . id ) ; } ;
443+ btnClose . onclick = ( e ) => { e . stopPropagation ( ) ; minimizeWindow ( app . id ) ; } ;
459444 btnMax . onclick = ( e ) => { e . stopPropagation ( ) ; toggleFullscreen ( w , app . id ) ; } ;
460445
461446 w . addEventListener ( 'mouseup' , ( ) => saveWindowStateFromDOM ( app . id , w ) ) ;
462447 w . addEventListener ( 'mouseleave' , ( ) => saveWindowStateFromDOM ( app . id , w ) ) ;
463448}
464449
465-
466450function makeDraggable ( winEl , handle ) {
467451 let isDown = false , startX = 0 , startY = 0 , origLeft = 0 , origTop = 0 ;
468452 handle . addEventListener ( 'mousedown' , ( e ) => {
@@ -493,7 +477,6 @@ <h3>Apps</h3>
493477 window . addEventListener ( 'mouseup' , ( ) => { if ( ! isRes ) return ; isRes = false ; document . body . style . userSelect = '' ; const appId = winEl . id . replace ( 'win-' , '' ) ; saveWindowStateFromDOM ( appId , winEl ) ; } ) ;
494478}
495479
496-
497480function saveWindowStateFromDOM ( appId , winEl ) {
498481 STORAGE . windows [ appId ] = STORAGE . windows [ appId ] || { } ;
499482 STORAGE . windows [ appId ] . left = parseInt ( winEl . style . left || winEl . offsetLeft ) ;
@@ -503,7 +486,6 @@ <h3>Apps</h3>
503486 saveState ( ) ; refreshDockUnderlineStatus ( ) ;
504487}
505488
506-
507489function minimizeWindow ( appId ) {
508490 const winEl = document . getElementById ( 'win-' + appId ) ;
509491 if ( winEl ) winEl . style . display = 'none' ;
@@ -512,7 +494,6 @@ <h3>Apps</h3>
512494 saveState ( ) ; refreshDockUnderlineStatus ( ) ;
513495}
514496
515-
516497function toggleFullscreen ( winEl , appId ) {
517498 const state = STORAGE . windows [ appId ] || { } ;
518499 if ( state . fullscreen ) requestFullscreenMode ( winEl , appId , false ) ;
@@ -524,15 +505,12 @@ <h3>Apps</h3>
524505 saveState ( ) ;
525506}
526507
527-
528508function focusWindow ( el ) { document . querySelectorAll ( '.app-window' ) . forEach ( e => e . style . boxShadow = '0 18px 60px rgba(2,6,23,0.7)' ) ; el . style . boxShadow = '0 28px 90px rgba(2,6,23,0.85)' ; el . style . zIndex = ++ zCounter ; }
529509function focusWindowById ( appId ) { const el = document . getElementById ( 'win-' + appId ) ; if ( el ) { el . style . display = 'flex' ; focusWindow ( el ) ; STORAGE . windows [ appId ] . minimized = false ; saveState ( ) ; refreshDockUnderlineStatus ( ) ; } }
530510function focusClearAll ( ) { document . querySelectorAll ( '.app-window' ) . forEach ( e => e . style . boxShadow = '0 18px 60px rgba(2,6,23,0.7)' ) ; }
531511
532-
533512function refreshDockUnderlineStatus ( ) { for ( const el of dock . querySelectorAll ( '.dock-item' ) ) { const id = el . dataset . app ; if ( id && STORAGE . windows [ id ] && STORAGE . windows [ id ] . minimized ) el . classList . add ( 'minimized' ) ; else el . classList . remove ( 'minimized' ) ; } }
534513
535-
536514function renderSavedWindows ( ) {
537515 for ( const [ appId , wstate ] of Object . entries ( STORAGE . windows || { } ) ) {
538516 const app = getAllApps ( ) . find ( a => a . id === appId ) ;
@@ -599,3 +577,4 @@ <h3>Apps</h3>
599577
600578</ body >
601579</ html >
580+
0 commit comments