From f29ecb0be52b47ad2e1edc6f0526dcaf9558df5a Mon Sep 17 00:00:00 2001 From: Mikei386 <44135113+Mikei386@users.noreply.github.com> Date: Mon, 22 Jun 2026 22:40:50 +0200 Subject: [PATCH] Improve navigator UI and context actions --- build-plugin.sh | 6 +- packages/u-navigator-0.2.2.tgz | Bin 9976 -> 0 bytes packages/u-navigator-0.2.3.tgz | Bin 0 -> 10880 bytes .../plugins/u-navigator/U-NavigatorNav.page | 27 +++-- {public => server/public}/app.js | 112 ++++++++++++++++++ {public => server/public}/index.html | 0 {public => server/public}/styles.css | 40 ++++++- server/server.js | 2 +- u-navigator.plg | 4 +- 9 files changed, 176 insertions(+), 15 deletions(-) delete mode 100644 packages/u-navigator-0.2.2.tgz create mode 100644 packages/u-navigator-0.2.3.tgz rename {public => server/public}/app.js (80%) rename {public => server/public}/index.html (100%) rename {public => server/public}/styles.css (86%) diff --git a/build-plugin.sh b/build-plugin.sh index 0a9953c..2b77740 100755 --- a/build-plugin.sh +++ b/build-plugin.sh @@ -2,7 +2,7 @@ set -eu PLUGIN="u-navigator" -VERSION="0.2.2" +VERSION="0.2.3" PKG_DIR="packages" WORK_DIR=".plugin-build" PKG_NAME="${PLUGIN}-${VERSION}.tgz" @@ -11,8 +11,8 @@ rm -rf "$WORK_DIR" mkdir -p "$WORK_DIR/usr/local/emhttp/plugins/${PLUGIN}/assets" "$PKG_DIR" cp -R plugin-root/usr "$WORK_DIR/" -cp public/app.js "$WORK_DIR/usr/local/emhttp/plugins/${PLUGIN}/assets/app.js" -cp public/styles.css "$WORK_DIR/usr/local/emhttp/plugins/${PLUGIN}/assets/styles.css" +cp server/public/app.js "$WORK_DIR/usr/local/emhttp/plugins/${PLUGIN}/assets/app.js" +cp server/public/styles.css "$WORK_DIR/usr/local/emhttp/plugins/${PLUGIN}/assets/styles.css" tar -czf "$PKG_DIR/$PKG_NAME" -C "$WORK_DIR" usr rm -rf "$WORK_DIR" diff --git a/packages/u-navigator-0.2.2.tgz b/packages/u-navigator-0.2.2.tgz deleted file mode 100644 index e213fd0e379fee172c2c0934cdd972ae69cf67da..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 9976 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�#?$xMlb7oYe$D` z`(%3twtKK1Mz^jV4sAPHXTnh;$!!1VKs0i6xCyp_9fg~`c(oUX>(ET!dB@0XIN*IS zkRugn%yr={WBWr|nPid3A75Gly@7X7_fVK0`@{O7Hn9Coc$Tlm%;_VPRx}CGAYDIv z>^YHRxlZVSsZp&~_czC)$xYSfJ_4h<^Bj6umkRfTW1lU2bs-$dob_-^M^8Lf0H*brM(vcOjHm#c9?9@xw5^m zH$)T4)0)+@=d}IDi9N9s&7K987Y=|v=w;ll%n!{r_csA^G!u9&${w6jBl*6Y=xh1b1ukT-1Up+hip?mz|arc|!(-WlJDYQ6t)^&?b zG{eH6H-~(IKC3^42*+QXwUM*0EyVx8^}i+tbRPfL((#||MlFy3Tt!+`|0C7* zo_#E@|24Mi`TdWpNxA;_S*K<7zx&96<@LW-qm|$PxRR8u|LyE_YRy{i|Nr#UV)`F< zY~8ny<@G-_0CW9s6=|9IuXbb4{4#yimXH5v=jVS`lyd#=vrfzKf2;;BCkN*8e>(o7 znVSt7l^_B_p@efPC8?GzMEdALIKWtG?Z6H2OSiG>Pm!^DL`}5#HF`c6%V}@=WTbvE8xSqL*-J_5JHz25ZLl_=at5!T*A*ORLyu zm01)1wYJKvR&6vW^!n23y}b(ji3d=;vw|WHvc!)Yxqcw?=nN6&_MLF-TDQCGDsTvl zfsb(2TjQI}dbP#E+c2_6m5Ebk6_RHao>OMuV7LotQK$6$EmSMB^;7%Gx7n-5>tz;N zURVk3z#$}J^U&)EI*aT|;9rNk%$h_#s}BNvKXSav&~~nd&^a(?uUN0u-VIrW)jPHE z4S;&Lw)US!cHgmBaU9qfV^N_IRl?rT9sz#)Rv-?;=gF%)l4 z85#u|RW9x5+O|DoG<6t(sFxnburAI-W>E%`0g^263bF)d5xynjNK%fh02XJYf*NaO zcQRHCQ6+v%cS+eLqq#&w6w5{xQ;5O86+ED`OUHB+uC^1~pZJ_5rEY?H_kVo5YgPuc6jG6KA@Er=d76{(B7*_f~{ zVFWN=8JMUJ{N5xK6KwK4UkOIeP0{gK2y(S-iUHPc{JyMXrIgkF$hvVxK#)cc5@`vN z!8pMCa%!cq6t7AVif7ZZr$*6Za+&}ylaU8d!6eaaC1KY9EffS`>wW1vZv!E^i-WW|k@W+*(fmbyO;gI&N za0ntU!cb*?x_kN(p~Fz$PGU^;0l%!PO017*c$+Jk>ot(f8ZbKI=4o`*fdd9fWL>&; zVo`9dacEQT^lQH2lszfau&ebO4a=F?{W%La`_dVW{UEXo{LfzuQg9|3QY3;>yu+uF zL@zPeE_3Yxm3xQr@?dGn{1FIh*PcGgxg3#zV~Pf*Ykh*KDeGELS-VzC!w@W_2F*4= z`u4z@xKU=~+?FV(@~iUrcg8Cud5|Yp3rLEoJpz@?=rsGS>USQ6C8tD#0#DUfdawd7 zBzcV$b~~lm)whyz;nM0~rRB~d5^`r}CqqWY)HBUC%b=<`=9vI~YdaxW8(jY}#zRd2 z2aRlR@|U8H>l3h(RN~sRR_328pcL6RB-LsOZZk%zI}8kYoLD+im?o16y^PT`;WJIH zX7sPy`HLyk2JHx>Ykm9~kL*Bx7@3NspvkiA7LMJfLK_l02Lh2r!gs3&yM0gtdPGI*q z)AHftJG$&6+tH9^!kER$1S+R;64tJwEo4zK_$(V(&(&;}m?li;Eystc889aLNabrn zO|+WjBH>rRjI$chvX^PpXKDh^6@`gt!5toy^@q2{|(cGSMcZYKc9SBhX3!k z`p@J4R-;~TCD;E}C%^x9B}rV1s*I=uHtmkv->E`)T_dj-UzswiVq7Y&sa?R4c`pav zv5DtS3wl=w9=Bq>fpY~W#>92YWN>2(V3D0)l*#=?Hq7IGTtYe#PrN9&jkAS=1uwyg zGk@|gp()S4W>2kgv4mM36#9`m!A9$t_48xyHfq$??)KIMkQhu63Lv@Z>SK3>Z|VA+ z0s-f^Hs-(|dJb<#7&!!4cy%Xb`Oy%4Dh0flv_P#-MQ!Txm_jMzLd%}(^q^_R?`6hI zd}O5}ZvD<`J$aSPg6+rE=JudnD6?SWRD;@Gb37-)n>E+0@Yd_;7dc}-%>zuhFinYs zs+@RWlB{dXi5SpW5&pdjT)xuLC^z)9r=6}{gPbzpflp8#oDhk!~5^uoKn6eZ}y zM*|Us6FApzwnD_m4$dU%Ta5(jn~fOtbvX@y-yIW&azIG{1s_a@P2G-#aFH861yU;s zQcI(Ttr(_NlCl0-|3_50mN6NaM72*ufOI(L#K5PxYOrw zP{Z6cNj*uRMOW1u1-i_+E$btfx%6n_K)&M7{GD>%8pJ1;=&!%#L*UOkqGVh6genI| z91hLopYbFdB8isbS4zpi>(%?5TA}%%IFoW^8A6v*sH%y z#TpdHyqml6jaeu1$Fr;4rm7GzXIF|*59$u!J5?jK99;f+<0$?J!@<~ibigc4~#Cq(xaI|^8WsijT3hkM z3`FdYQ6;dh=xYg5AvMu@z`isx#71L+GNo!4OY^%WhQSg4A;(|{ex>Znr3vgwn3Q6X zK81iS(svd>E`F&*q|uJPZka7vQL$1l9bsKq3Z+h)#)M*9iX&ZsWwD&eu38`}aV#!N z2rH@${BsRTK`x2@m8OW5IB{jy)HFOq%%ks+fsaVw%wQ*zc|xyg9_@OUyv2}vHh`p$AEAOfYt$Ir_Yu{xQC;`2~<=EbsT z?#=G<$_GLE4|L7#G}&yF59|S;a=3o@%$_jU>L;t|*9vRHkHc0s-V@9i?)Dr5fMA7C zQKmwtQ4ou=WO+fsH~VAR9z}eto2y@37T3M;;TztX*_N>Fu-jB?PhdFWie!X@69f9U z&M;O|w9gGmMEChc=`OYK#D)jW*#W1GgrKE&nn;-`hhc{12w~!hEF%T)*@=@|mK%L{^bua9x|E4UmI>O=bg0nWwRU;iJxwAy@Q?vAqQm#6MzY&Xw7)&VkFdJx%s5Lk+Wd z??cJzMagNF#7m9o%jB5!4?@lx*G%D-qMzAt&k=6(K$#*1)ax1YPcL~l)nON_X+ofB zdnHoDnLAy=1W2oa51}lqDbIsGjGSRSxoZPKFknL4u|4+omwy3O-(y1uUR#$}Ftn?P zU4x-wdt7E52}Xt3 z;#0aMtv39kFLt~sReu6gvse({)D)B2pIl8k+IjABQl3@NamCmM%0rq=&QH zvHJa8@XNpa@{jSm@9bax87Vj7IS32>!nRb)xU$3Wkbn?wdX%6e5W?t4vqRERpgXa} z>d$>9Mm)iu&M~)=QBu}znq_c<(dG=otVwufU;pyYLpO@KLI091aYpP)iPs(7;W5*! zb`^&Dkw7^7*zfmek!QcJ*P@x3UI{5OT?x(US+zI=CTppQR~4sFce-XwBC76kq~2Gg z&XJZ$ESiT%qZ5oC5g%&iq=FgToD7Sliz-U`Kz@CisD=udLUv)=QG1BCw?VDhZd8INbx%9CK;+1O58A@3`^)*<^GH3pX|>3({w-Yj?lLFZy7cy02za z;3XjsMem$!5}_$+6`Oy|H;ze=J~HKXi7i<5iaU1>l$%z);Kqm6W^!vXj)zgcNzgg6 z;$hw(RbVvC5v`rL?DYJ;{p#i82mWXb)|?j=HQ4XoNb@8K4DW)T5(T7RNR<&8M7){N zBPk4|qed7QWtQvSCTqm#)XZMPyPYvzQ}n>(oEaOddK8X?8w5-c72|*$1|rBNHHpG- zsdlM*|6lct@^KQe9fSq-64fPS-3k{b@+_`YjfUP){l z>}d`3?J$BFAoS7xWQ;683s_=3ySVvxn;V;D;?zx$&d{ZdL*it}{o{Y*UlwN@5oH6; zvfj7ht4MR5L8RHpC#xcjYt&|v5}S`4S14pkSZuz9pEM&Sxyz*d4_F@^5Yw8DO)zXv zZaa{Yhp{5~m;awH(n81A20O5UZypTo-dnq`n0Ycr94y7oWd+E{j)s08kpANN=~+R> z_Tb90OF$Z?&@_x|jZfpYc-nFCD6`O?1U=iFR&%k<6kH^}VW7fenmtrno#H`e4UvDI zF5G4BSwRGbRX_!@3s6jFw4XxXE3murT8x#yIeq>N7A#aLoWX7Jeb!I_W6DFODGQ+; ziDj~kBc#`3-*pi!V)-m!c-grrIlAfQ0d|#{AtaM5=_P}q@Cvu-;GZdOC>$4z4*Ns(88Q)8pf>r8k!8&j4TM=9XzaD56?{q6jzQX}b*|4DH1j=!taYFtKkQf9@ z(QH#eG@UT?Ae;G~O>1S)<=n4{kgMP!ufO!hLbeB42bQ>KMf(vYVU`;4I956K5V zic<&bC_%EoBYBb_J{_)WX`&klVVr|Bi zcM`anN4f$#gf*A+kqj@PQEM;O0%WZ!y124^P1D<%+k3iOa#W~J{kL+hc5SqI`3?_R zoT?08)bZ3$A`6dnN~f}}@W#y)IVg!Smc-TqEMeNNLaY$K=Q?ikz^|?e-=z^~%8lfa z6Sb^Pje^%bHtdZwb@)!0x!*z?V0_>j99V`T*G)jQkWe1-s?8a^i_r2F8>94IY_HAO z5RkJ-wdKjv{R38)Dgckj)@ba_=Ei$oIs{eL#ucYhmz!zO!(C$gRl4w21~An672xXI z)|dEy9b^vU0TcU<^q%$`6!U0OjAYZ{B1TWPeDN7w)Zgt z)=PKn`A9 ztmrM~bTPh>Uz~?!@HQ^306yYNw2^-6(dTIi{a;1{FWtvI?*HCu)N=k`Ny_#A&pO>h z|6f`T+(Z9wwA#7;zltFq&R;^ZM1&W?>Lgx7qvzQiAOPd)R@zF7i%*9W^V+?#T>{(uRN9+jiv1L}sHuRGU z2;GJ!Pcjs$1>AnqGpfd&2pD+ic=A3Oz7@PNfPn%asXhsZ1^7R;$E$3Juuwn-9-M;Vw!R9aMU_kr=gJ0-H3Me|U1aD=|E~{zv;xo8ZyN{=HA0D5bbdS%TKjjCU zXlYXI?J{~S3Cr?==wK51K~$8(EXQF9#SN>>HZF~6w$Ax5E|Ou|?5nS!ta>};{s>m7 z?`1Xi<;=!X5#ge-x(ryMr!WdUE9zOH-5ZUmahjrwGBw42BjuN}?C^Nfk`yS6aDg6P zM&c?r!Sl3){U0A7T(Xb*?Ef|M?|-Z&<@Wz)o$g`(FD(b|v;Vi%$?gADq-^`Y+1$Yx zjNJbJ6TZQZ0sRWE0B>Nv zPv8|%p*T6uMiV@nX=ix{IJuIi!f+34biaN4o|=@@Pf2k7k7bg8E?!S7tK1Jb?C|& z56gVTi;tfy3_U&S!3=dlWrIPU(U*5KE zE~wtlQ{Y@k(?Ea~?|h$&SFugWTS40qf0-TFmP@yrS}wQ9sKlNsKxQQsLer7%CB^N- zc(>eg4FksjCSj;3o5bOk1clzBxmWD@6EBLl#7pdJRxg#)73m%#v5|rO|WK)&jHhPn34XOoa_4o`kN8PGlP5=OGvI#o@ZryP^<$h+*)_g(WKb%H!k zz;1v3?8$2&QQEbw7c!b8qiths-J+RB_m6^MNGHx=HX5}Wbo9=5`l2Hgs$F>qyo>kW z6h&z<6n@8K(YRj{I4W_w) zaR6r71;1oaJ`tlBb4I+P?r}@;nwZk~V?PFwK(k%CC?f1$JIIKpRuO}Pqa;!slpD#4%&$xQKpBT68H^A#_e>EbX59}1kf%yICZ*v;1`<;)xtVz6l9IofxZ5QrNP|^+ zL1VvajDoB=OnJNw8K`(zTWY2v0XZ>s1vmpJE)5TG#xh1%nsHg1Vm|8{?=(mMEv#qV z9$!epVgXdU-OWwyvw7$?=HFqYHKT9yH3J&}o-Dk-1N{l*r>-@DXrkVVRCW5$kS-s4 zps)dEaP6Uckh9lo{sG9;An{5`7-?@3gwDHoS&$be%V+&A=+sQ8s5)M2Hn|8I5zt_FH?ZomX-te*#D`uw(|X-Riy0w zpH{QIv$MUE@Be)AX<`1q_v%0Y{9mJ)y8okIYv=3#D$)mu|6AMO9}hrZ6OZ=e&pfQI zP~gFS8{N~Bmp`1mJTJUF`QxjT)3ff=le0(9AIc+AP_a--JC@^6E3vI1x_~F%e65gm zO06*Q-g$S4UEC@UNZd#F_27m^(z{t0pP` z=qpaM^fd*+LZxK1;F``0!uBumgOTE}Uwl%Nw;{4;QU4UmpH20d6u$_y&!cpTd~D>0 W6Z4d(Jmu*lrvC?Lao3apG64X`EbdqU literal 0 HcmV?d00001 diff --git a/plugin-root/usr/local/emhttp/plugins/u-navigator/U-NavigatorNav.page b/plugin-root/usr/local/emhttp/plugins/u-navigator/U-NavigatorNav.page index 7a3256b..f181124 100644 --- a/plugin-root/usr/local/emhttp/plugins/u-navigator/U-NavigatorNav.page +++ b/plugin-root/usr/local/emhttp/plugins/u-navigator/U-NavigatorNav.page @@ -29,17 +29,28 @@ Code="f07b" } const wrapper = toolsLink.parentElement?.tagName === 'LI' ? toolsLink.parentElement : toolsLink; - const item = wrapper.cloneNode(true); - const link = item.tagName === 'A' ? item : item.querySelector('a'); - if (!link) { - return; - } - + const isListItem = wrapper.tagName === 'LI'; + const item = isListItem ? document.createElement('li') : document.createElement('a'); + const link = isListItem ? document.createElement('a') : item; + link.className = toolsLink.className || ''; link.href = targetHref; link.textContent = targetText; link.setAttribute('data-u-navigator-nav', 'true'); - link.classList.remove('active', 'selected'); - item.classList?.remove('active', 'selected'); + link.classList.remove('active', 'selected', 'on'); + + if (isListItem) { + item.className = wrapper.className || ''; + item.classList.remove('active', 'selected', 'on'); + item.appendChild(link); + } + + if (location.pathname === targetHref) { + toolsLink.classList.remove('active', 'selected', 'on'); + wrapper.classList?.remove('active', 'selected', 'on'); + link.classList.add('active'); + item.classList?.add('active'); + } + wrapper.insertAdjacentElement('afterend', item); } diff --git a/public/app.js b/server/public/app.js similarity index 80% rename from public/app.js rename to server/public/app.js index f84fecb..8e9f49a 100644 --- a/public/app.js +++ b/server/public/app.js @@ -6,6 +6,7 @@ const state = { windows: [], focusedId: null, selectedEntry: null, + contextMenu: null, jobs: new Map(), nextWindowId: 1, zIndex: 20 @@ -106,6 +107,9 @@ function render() { for (const win of state.windows) { workspace.appendChild(renderWindow(win)); } + if (state.contextMenu) { + workspace.appendChild(renderContextMenu()); + } } function renderWindow(win) { @@ -181,6 +185,7 @@ function renderExplorer(body, win) { const dropZone = body.querySelector('.drop-zone'); dropZone.addEventListener('dragover', (event) => { event.preventDefault(); + event.dataTransfer.dropEffect = event.altKey ? 'copy' : 'move'; data.dragOver = true; dropZone.classList.add('drag-over'); }); @@ -194,6 +199,10 @@ function renderExplorer(body, win) { dropZone.classList.remove('drag-over'); await handleDrop(event, win, data.path); }); + dropZone.addEventListener('contextmenu', (event) => { + event.preventDefault(); + showContextMenu(event, win, null); + }); for (const row of body.querySelectorAll('.file-row')) { const entry = data.entries.find((item) => item.path === row.dataset.path); @@ -205,7 +214,12 @@ function renderExplorer(body, win) { }); row.addEventListener('dragstart', (event) => { event.dataTransfer.setData('application/x-u-navigator-path', entry.path); + event.dataTransfer.setData('text/plain', entry.path); event.dataTransfer.effectAllowed = 'copyMove'; + row.classList.add('dragging'); + }); + row.addEventListener('dragend', () => { + row.classList.remove('dragging'); }); row.addEventListener('dragover', (event) => { if (entry.type === 'directory') { @@ -218,6 +232,11 @@ function renderExplorer(body, win) { event.preventDefault(); await handleDrop(event, win, entry.path); }); + row.addEventListener('contextmenu', (event) => { + event.preventDefault(); + selectEntry(win, entry); + showContextMenu(event, win, entry); + }); } } @@ -334,6 +353,93 @@ async function createJob(type, source, destination) { render(); } +async function renameEntry(win, entry) { + const nextName = prompt('Neuer Name', entry.name); + if (!nextName || nextName === entry.name) { + return; + } + if (nextName.includes('/')) { + alert('Der Name darf keinen Slash enthalten.'); + return; + } + await createJob('move', entry.path, `${dirname(entry.path)}/${nextName}`); + await loadExplorer(win, win.data.path); +} + +async function promptTransfer(win, entry, type) { + const targetDir = prompt(type === 'copy' ? 'Kopieren nach Ordner' : 'Verschieben nach Ordner', win.data.path); + if (!targetDir) { + return; + } + await createJob(type, entry.path, `${targetDir.replace(/\/$/, '')}/${entry.name}`); + await loadExplorer(win, win.data.path); +} + +function showContextMenu(event, win, entry) { + const rect = workspace.getBoundingClientRect(); + state.contextMenu = { + x: event.clientX - rect.left, + y: event.clientY - rect.top, + winId: win.id, + entryPath: entry?.path || null + }; + render(); +} + +function renderContextMenu() { + const menu = document.createElement('div'); + menu.className = 'context-menu'; + menu.style.left = `${state.contextMenu.x}px`; + menu.style.top = `${state.contextMenu.y}px`; + + const win = state.windows.find((item) => item.id === state.contextMenu.winId); + const entry = win?.data.entries?.find((item) => item.path === state.contextMenu.entryPath) || null; + const actions = []; + + if (entry) { + if (entry.type === 'directory') { + actions.push(['Öffnen', () => loadExplorer(win, entry.path)]); + } + actions.push(['Umbenennen', () => renameEntry(win, entry)]); + actions.push(['Kopieren nach...', () => promptTransfer(win, entry, 'copy')]); + actions.push(['Verschieben nach...', () => promptTransfer(win, entry, 'move')]); + } else { + actions.push(['Neu laden', () => loadExplorer(win, win.data.path)]); + } + + for (const [label, action] of actions) { + const button = document.createElement('button'); + button.type = 'button'; + button.textContent = label; + button.addEventListener('click', async () => { + state.contextMenu = null; + render(); + try { + await action(); + } catch (error) { + alert(error.message); + } + }); + menu.appendChild(button); + } + + setTimeout(() => { + const close = () => { + state.contextMenu = null; + render(); + document.removeEventListener('click', close); + document.removeEventListener('keydown', keyClose); + }; + const keyClose = (event) => { + if (event.key === 'Escape') close(); + }; + document.addEventListener('click', close); + document.addEventListener('keydown', keyClose); + }, 0); + + return menu; +} + async function pollJob(id) { const job = await api(apiUrl(`job.php?id=${encodeURIComponent(id)}`)); state.jobs.set(id, job); @@ -429,6 +535,12 @@ function parentPath(value) { return `/${parts.slice(0, -1).join('/')}`; } +function dirname(value) { + const parts = String(value || '').split('/').filter(Boolean); + if (parts.length <= 1) return '/'; + return `/${parts.slice(0, -1).join('/')}`; +} + function formatBytes(bytes) { const value = Number(bytes || 0); if (value < 1024) return `${value} B`; diff --git a/public/index.html b/server/public/index.html similarity index 100% rename from public/index.html rename to server/public/index.html diff --git a/public/styles.css b/server/public/styles.css similarity index 86% rename from public/styles.css rename to server/public/styles.css index 758e203..d2c50e2 100644 --- a/public/styles.css +++ b/server/public/styles.css @@ -197,32 +197,46 @@ .u-nav .file-table { border-collapse: collapse; + background: var(--surface); + color: var(--text); width: 100%; } .u-nav .file-table th, .u-nav .file-table td { + background: var(--surface) !important; border-bottom: 1px solid var(--line); + color: var(--text) !important; padding: 8px 7px; text-align: left; vertical-align: middle; } .u-nav .file-table th { + background: var(--surface-2) !important; color: var(--muted); font-size: 12px; font-weight: 600; } .u-nav .file-row { + background: var(--surface); + color: var(--text); cursor: default; } .u-nav .file-row:hover, -.u-nav .file-row.selected { +.u-nav .file-row.selected, +.u-nav .file-row.dragging { background: var(--surface-2); } +.u-nav .file-row:hover td, +.u-nav .file-row.selected td, +.u-nav .file-row.dragging td { + background: var(--surface-2) !important; +} + .u-nav .name-cell { align-items: center; display: flex; @@ -241,6 +255,30 @@ padding: 2px 8px; } +.u-nav .context-menu { + background: var(--surface); + border: 1px solid var(--line); + border-radius: 8px; + box-shadow: var(--shadow); + display: grid; + min-width: 190px; + padding: 6px; + position: absolute; + z-index: 100000; +} + +.u-nav .context-menu button { + border-color: transparent; + justify-content: flex-start; + text-align: left; + width: 100%; +} + +.u-nav .context-menu button:hover { + background: var(--surface-2); + border-color: var(--line); +} + .u-nav .queue-list { display: grid; gap: 10px; diff --git a/server/server.js b/server/server.js index 6956997..10e45ce 100644 --- a/server/server.js +++ b/server/server.js @@ -9,7 +9,7 @@ import { Sandbox, rootsFromEnv } from './sandbox.js'; const __dirname = path.dirname(fileURLToPath(import.meta.url)); const projectRoot = path.resolve(__dirname, '..'); -const publicDir = path.join(projectRoot, 'public'); +const publicDir = path.join(projectRoot, 'server', 'public'); const MIME = { '.html': 'text/html; charset=utf-8', diff --git a/u-navigator.plg b/u-navigator.plg index e38d937..747d188 100644 --- a/u-navigator.plg +++ b/u-navigator.plg @@ -1,7 +1,7 @@ - + ]> @@ -14,7 +14,7 @@ https://git.casaderoll.de/michael/Unraid-Navigator/raw/branch/main/packages/&package; -0cb8fe513addbd7435a8c79107ae7973 +8d05b440bd2ad3e20b8d900238642c3f