diff --git a/apps/api/app/admin/files.rb b/apps/api/app/admin/files.rb index d9e8720..41dc6b4 100644 --- a/apps/api/app/admin/files.rb +++ b/apps/api/app/admin/files.rb @@ -13,11 +13,16 @@ ActiveAdmin.register_page "Files" do entries = [] end + # Picker mode: hide admin header/menu/footer + if picker_mode + text_node ''.html_safe + end + div class: "file-manager" do h2 do text_node "File Manager" if picker_mode - span " (Select a file)", style: "font-size:14px; color:#888; font-weight:normal;" + span " — select a file or folder", style: "font-size:14px; color:#888; font-weight:normal;" end end @@ -117,7 +122,7 @@ ActiveAdmin.register_page "Files" do text_node " " abs_path = "/softwares/#{entry[:path]}" a "Select", href: "#", class: "fm-btn fm-btn-select", - onclick: "window.opener.postMessage({type:'file-picked',field:'#{j picker_field}',path:'#{j abs_path}'},'*');window.close();return false;" + onclick: "window.parent.postMessage({type:'file-picked',field:'#{j picker_field}',path:'#{j abs_path}'},'*');return false;" end # Hidden rename form diff --git a/apps/api/app/assets/javascripts/active_admin.js b/apps/api/app/assets/javascripts/active_admin.js index 320ebc5..bbe762d 100644 --- a/apps/api/app/assets/javascripts/active_admin.js +++ b/apps/api/app/assets/javascripts/active_admin.js @@ -14,17 +14,54 @@ btn.className = 'fm-browse-btn'; btn.addEventListener('click', function(e) { e.preventDefault(); - window.open( - '/admin/files?picker=1&field=' + encodeURIComponent(input.id), - 'file_picker', - 'width=960,height=640,scrollbars=yes,resizable=yes' - ); + openFilePicker(input.id); }); input.parentNode.insertBefore(btn, input.nextSibling); }); }); } + function openFilePicker(fieldId) { + // Backdrop + var overlay = document.createElement('div'); + overlay.className = 'fm-modal-overlay'; + overlay.addEventListener('click', function(e) { + if (e.target === overlay) closeFilePicker(); + }); + + // Modal container + var modal = document.createElement('div'); + modal.className = 'fm-modal'; + + // Close button + var closeBtn = document.createElement('button'); + closeBtn.className = 'fm-modal-close'; + closeBtn.innerHTML = '×'; + closeBtn.addEventListener('click', closeFilePicker); + modal.appendChild(closeBtn); + + // Iframe + var iframe = document.createElement('iframe'); + iframe.src = '/admin/files?picker=1&field=' + encodeURIComponent(fieldId); + iframe.className = 'fm-modal-iframe'; + modal.appendChild(iframe); + + overlay.appendChild(modal); + document.body.appendChild(overlay); + document.body.style.overflow = 'hidden'; + + window._fmOverlay = overlay; + } + + function closeFilePicker() { + if (window._fmOverlay) { + window._fmOverlay.remove(); + window._fmOverlay = null; + document.body.style.overflow = ''; + } + } + + // Listen for file selection from iframe window.addEventListener('message', function(event) { if (event.data && event.data.type === 'file-picked') { var input = document.getElementById(event.data.field); @@ -32,6 +69,7 @@ input.value = event.data.path; input.dispatchEvent(new Event('change', { bubbles: true })); } + closeFilePicker(); } }); diff --git a/apps/api/app/assets/stylesheets/active_admin.scss b/apps/api/app/assets/stylesheets/active_admin.scss index 711e0f7..e16c841 100644 --- a/apps/api/app/assets/stylesheets/active_admin.scss +++ b/apps/api/app/assets/stylesheets/active_admin.scss @@ -29,6 +29,22 @@ // Browse button in release forms .fm-browse-btn { - display: inline-block; margin-left: 8px; padding: 4px 10px; background: #6c757d; color: #fff; border-radius: 3px; font-size: 11px; text-decoration: none; vertical-align: middle; - &:hover { background: #5a6268; color: #fff; } + display: inline-block; margin-left: 8px; padding: 4px 10px; background: #6c757d; color: #fff !important; border-radius: 3px; font-size: 11px; text-decoration: none !important; vertical-align: middle; + &:hover { background: #5a6268; color: #fff !important; } + &:visited { color: #fff !important; } +} + +// Inline file picker modal +.fm-modal-overlay { + position: fixed; inset: 0; z-index: 9999; background: rgba(0,0,0,0.6); display: flex; align-items: center; justify-content: center; +} +.fm-modal { + position: relative; width: 90vw; max-width: 1000px; height: 80vh; background: #fff; border-radius: 8px; box-shadow: 0 20px 60px rgba(0,0,0,0.3); overflow: hidden; +} +.fm-modal-close { + position: absolute; top: 8px; right: 12px; z-index: 10; background: none; border: none; font-size: 28px; color: #666; cursor: pointer; line-height: 1; + &:hover { color: #000; } +} +.fm-modal-iframe { + width: 100%; height: 100%; border: none; }