diff --git a/app/routers/board.py b/app/routers/board.py index 3a887aa..0234be0 100644 --- a/app/routers/board.py +++ b/app/routers/board.py @@ -946,7 +946,9 @@ async def delete_page(request: Request, page_id: int): @router.get("/pages/{page_id}", response_class=HTMLResponse) async def view_page(request: Request, page_id: int): - """Render a page as HTML, or a file viewer for uploaded files.""" + """Render a page as HTML, or a file viewer for uploaded files. + ?embed=1 — minimal mode for side peek (no sidebar/topbar).""" + embed = request.query_params.get("embed") == "1" from jinja2 import Environment, FileSystemLoader env = Environment(loader=FileSystemLoader("app/templates")) with get_conn() as conn: @@ -1003,7 +1005,8 @@ async def view_page(request: Request, page_id: int): "page_data": page_data, "breadcrumb_items": nav_crumbs, "nav_workspace_id": page.get("workspace_id") or 0, - "nav_page_id": page_id} + "nav_page_id": page_id, + "embed_mode": embed} template = env.get_template("page_editor.html") response = template.render(**ctx) return HTMLResponse(content=response, headers={"Cache-Control": "no-store, max-age=0"}) diff --git a/app/templates/base.html b/app/templates/base.html index d7dee33..704a6be 100644 --- a/app/templates/base.html +++ b/app/templates/base.html @@ -88,12 +88,18 @@ font-size: 13px; } } + /* Embed mode — hide sidebar + topbar for peek panels */ + body.embed-mode .sidebar, body.embed-mode .topbar, body.embed-mode .app-layout { display: block !important; } + body.embed-mode .sidebar { display: none !important; } + body.embed-mode .topbar { display: none !important; } + body.embed-mode .app-layout { margin-left: 0 !important; padding-top: 0 !important; } + body.embed-mode .sidebar-collapsed .app-layout { margin-left: 0 !important; } - +
diff --git a/app/templates/library.html b/app/templates/library.html index 1f74989..7529777 100644 --- a/app/templates/library.html +++ b/app/templates/library.html @@ -407,6 +407,7 @@
+
@@ -1202,40 +1198,17 @@ function libraryPage() { // ── Side peek ── async openPeek(item) { this.peekItem = item; - this.peekContent = ''; - this.peekLoading = true; this.peekFavorited = item.favorited || false; - try { - var r = await fetch('/board/api/pages/' + item.id); - var d = await r.json(); - var content = d.content || ''; - // Simple preview - if (d.content_format === 'blocks') { - try { - var blocks = typeof content === 'string' ? JSON.parse(content) : content; - var preview = ''; - var lines = Array.isArray(blocks) ? blocks.slice(0, 30) : ((blocks && blocks.blocks) ? blocks.blocks.slice(0, 30) : []); - for (var i = 0; i < lines.length; i++) { - var b = lines[i]; - var txt = b.content || b.text || (typeof b === 'string' ? b : ''); - if (txt && txt.trim()) preview += '
' + this._escHtml(String(txt)) + '
'; - } - this.peekContent = preview || '
(empty page)
'; - } catch(e) { - this.peekContent = '
' + this._escHtml(String(content).substring(0, 2000)) + '
'; - } - } else { - this.peekContent = content ? '
' + this._escHtml(String(content).substring(0, 2000)) + '
' : ''; - } - } catch(e) { - this.peekContent = ''; - } - this.peekLoading = false; + // Load editor in iframe + var iframe = document.getElementById('lib-peek-iframe'); + if (iframe) iframe.src = '/pages/' + item.id + '?embed=1'; }, closePeek() { this.peekItem = null; - this.peekContent = ''; + // Clear iframe + var iframe = document.getElementById('lib-peek-iframe'); + if (iframe) iframe.src = ''; }, async toggleFavoritePeek() { @@ -1303,5 +1276,41 @@ function libraryPage() { } }; } +// Init peek resize handle (vanilla JS) +(function() { + var panel = document.querySelector('.peek-overlay'); + var handle = document.getElementById('lib-peek-resize-handle'); + if (!panel || !handle) return; + var startX, startWidth, dragging = false; + handle.addEventListener('mousedown', function(e) { + e.preventDefault(); + startX = e.clientX; + startWidth = panel.offsetWidth; + dragging = true; + document.body.style.userSelect = 'none'; + }); + document.addEventListener('mousemove', function(e) { + if (!dragging) return; + var deltaX = startX - e.clientX; + var newWidth = Math.max(300, Math.min(window.innerWidth * 0.9, startWidth + deltaX)); + panel.style.width = newWidth + 'px'; + }); + document.addEventListener('mouseup', function(e) { + if (!dragging) return; + document.body.style.userSelect = ''; + var moved = Math.abs(e.clientX - startX); + if (moved < 3) { + // Click — close via Alpine data + var libData = document.querySelector('[x-data]')._x_dataStack[0]; + if (libData && libData.closePeek) libData.closePeek(); + } + dragging = false; + try { localStorage.setItem('fd_peek_width', panel.style.width); } catch(ex) {} + }); + try { + var saved = localStorage.getItem('fd_peek_width'); + if (saved) panel.style.width = saved; + } catch(ex) {} +})(); {% endblock %} diff --git a/app/templates/local_workspace.html b/app/templates/local_workspace.html index 1236bfb..b44001e 100644 --- a/app/templates/local_workspace.html +++ b/app/templates/local_workspace.html @@ -631,6 +631,44 @@ window._wsInitData = (function() { this.loadWorkspaceTags(); } catch(e) { console.error('Tree load error:', e); this.loaded = true; } this._recompute(); + this._initResizeHandle(); + }, + + _initResizeHandle() { + var panel = document.getElementById('ws-preview-panel'); + var handle = document.getElementById('ws-preview-resize-handle'); + if (!panel || !handle) return; + var startX, startWidth, dragging = false; + handle.addEventListener('mousedown', function(e) { + e.preventDefault(); + startX = e.clientX; + startWidth = panel.offsetWidth; + dragging = true; + document.body.style.userSelect = 'none'; + }); + document.addEventListener('mousemove', function(e) { + if (!dragging) return; + var deltaX = startX - e.clientX; + var newWidth = Math.max(300, Math.min(window.innerWidth * 0.9, startWidth + deltaX)); + panel.style.width = newWidth + 'px'; + }); + document.addEventListener('mouseup', function(e) { + if (!dragging) return; + document.body.style.userSelect = ''; + var moved = Math.abs(e.clientX - startX); + if (moved < 3) { + // Simple click — close panel + window._wsData.closePreviewPanel(); + } + dragging = false; + // Save width preference + try { localStorage.setItem('fd_peek_width', panel.style.width); } catch(ex) {} + }); + // Restore saved width + try { + var saved = localStorage.getItem('fd_peek_width'); + if (saved) panel.style.width = saved; + } catch(ex) {} }, _recompute() { @@ -796,7 +834,7 @@ window._wsInitData = (function() { return null; }, - // ── Preview panel (vanilla JS — matches Library peek-overlay) ── + // ── Preview panel (vanilla JS — loads /pages/{id}?embed=1 in iframe) ── selectForPreview(node) { var panel = document.getElementById('ws-preview-panel'); if (!panel) return; @@ -819,21 +857,9 @@ window._wsInitData = (function() { window.showToast('Failed to copy', 'error'); }); }; - // Body: meta info header + loading indicator - var meta = '
' - + '' + (node.is_folder ? 'Folder' : this._fileTypeLabel(node.name, node.content_format)) + '' - + '' + (node.size_display || '-') + '' - + '' + this._formatDate(node.updated_at) + '' - + '
'; - if (node.tags && node.tags.length > 0) { - meta += '
'; - for (var i = 0; i < node.tags.length; i++) { - var t = node.tags[i]; - meta += '' + this._escHtml(t.name) + ''; - } - meta += '
'; - } - document.getElementById('ws-preview-body').innerHTML = meta + '
Loading...
'; + // Load the full page editor in iframe (reuses /pages/{id} code) + var iframe = document.getElementById('ws-preview-iframe'); + if (iframe) iframe.src = '/pages/' + node.id + '?embed=1'; // Show panel with slide-in panel.style.display = 'flex'; requestAnimationFrame(function() { @@ -841,8 +867,6 @@ window._wsInitData = (function() { panel.style.transform = 'translateX(0)'; }); }); - // Load content async - this._loadPreviewContentVanilla(node); }, closePreviewPanel() { @@ -852,6 +876,9 @@ window._wsInitData = (function() { var self = this; setTimeout(function() { panel.style.display = 'none'; + // Clear iframe + var iframe = document.getElementById('ws-preview-iframe'); + if (iframe) iframe.src = ''; self.previewItem = null; }, 200); }, @@ -2883,6 +2910,7 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
-
-
{{ fd_icon("file",32) }}
Select a file to preview
-
+