Unify all New Page / New Folder buttons across the app
- Add global window.FlowDeck namespace with createPage() and showCreateFolderModal() - createPage() creates a Notion-style page via /board/api/pages (same as sidebar bottom-right button) - showCreateFolderModal() opens a global themed modal (dark/light) instead of browser prompt() - All New Page buttons now call window.FlowDeck.createPage() - All New Folder buttons now call window.FlowDeck.showCreateFolderModal() - Global New Folder modal uses existing .flowdeck-modal CSS classes for theme consistency - Updated Ctrl+N keyboard shortcut to use unified createPage()
This commit is contained in:
+89
-8
@@ -123,8 +123,8 @@
|
||||
<span>{% if gitea_workspace %}📁 {{ active_ws_name }}{% elif workspace_key and '/' in workspace_key %}🔗{% else %}📁{% endif %} {{ active_ws_name if not gitea_workspace else '' }}</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<button class="section-action-btn" title="New Page" @click.stop="newPageInWorkspace()">📄</button>
|
||||
<button class="section-action-btn" title="New Folder" @click.stop="newFolderInWorkspace()">📁</button>
|
||||
<button class="section-action-btn" title="New Page" @click.stop="window.FlowDeck.createPage()">📄</button>
|
||||
<button class="section-action-btn" title="New Folder" @click.stop="window.FlowDeck.showCreateFolderModal()">📁</button>
|
||||
</div>
|
||||
</div>
|
||||
{% from '_workspace_tree_macro.html' import render_workspace_tree %}
|
||||
@@ -170,7 +170,7 @@
|
||||
<span>Meetings</span>
|
||||
</div>
|
||||
<div class="sidebar-section-actions">
|
||||
<button class="section-action-btn" title="Add" @click.stop="newPage('Meetings')">+</button>
|
||||
<button class="section-action-btn" title="Add" @click.stop="window.FlowDeck.createPage()">+</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="sidebar-section-items" x-show="sectionsOpen.meetings" x-transition>
|
||||
@@ -332,7 +332,7 @@
|
||||
<span style="font-size:14px;">💬</span> New chat
|
||||
<span class="shortcut">Ctrl+O</span>
|
||||
</button>
|
||||
<button class="sidebar-footer-btn" style="width:36px; justify-content:center; background:var(--bg-hover); border-radius:8px;" @click="newPage('Private')" title="New page">
|
||||
<button class="sidebar-footer-btn" style="width:36px; justify-content:center; background:var(--bg-hover); border-radius:8px;" onclick="window.FlowDeck.createPage()" title="New page">
|
||||
<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><path d="M14 2H6a2 2 0 00-2 2v16a2 2 0 002 2h12a2 2 0 002-2V8z"/><polyline points="14 2 14 8 20 8"/><line x1="12" y1="18" x2="12" y2="12"/><line x1="9" y1="15" x2="15" y2="15"/></svg>
|
||||
</button>
|
||||
</div>
|
||||
@@ -425,10 +425,10 @@
|
||||
@click.outside="wsCtx.visible = false">
|
||||
<template x-if="wsCtx.isFolder">
|
||||
<div class="context-menu-section">
|
||||
<div class="context-menu-item" @click="wsCtxAction('new-file')">
|
||||
<div class="context-menu-item" onclick="window.FlowDeck.createPage()">
|
||||
<span class="menu-icon">📄</span> New File
|
||||
</div>
|
||||
<div class="context-menu-item" @click="wsCtxAction('new-folder')">
|
||||
<div class="context-menu-item" onclick="window.FlowDeck.showCreateFolderModal()">
|
||||
<span class="menu-icon">📁</span> New Folder
|
||||
</div>
|
||||
</div>
|
||||
@@ -488,6 +488,70 @@
|
||||
});
|
||||
})();
|
||||
|
||||
// ── Global FlowDeck namespace ────────────────────────────────
|
||||
// All "New Page" and "New Folder" buttons across the app call
|
||||
// these functions for consistent behaviour.
|
||||
window.FlowDeck = {
|
||||
getCsrfToken: function() {
|
||||
var m = document.cookie.match(/csrf_token=([^;]+)/);
|
||||
return m ? m[1] : '';
|
||||
},
|
||||
|
||||
/** Create a new Notion-style page (same as sidebar bottom-right button). */
|
||||
createPage: function() {
|
||||
var project = (window.appState && window.appState.workspaceKey) || '';
|
||||
var url = '/board/api/pages?section=Private&project=' + encodeURIComponent(project);
|
||||
fetch(url, {
|
||||
method: 'POST',
|
||||
headers: { 'X-CSRF-Token': this.getCsrfToken() }
|
||||
})
|
||||
.then(function(r) { if (!r.ok) throw new Error('CSRF or API error'); return r.json(); })
|
||||
.then(function(data) { window.location.href = '/pages/' + data.id; })
|
||||
.catch(function(err) {
|
||||
if (window.appState && window.appState.toast) window.appState.toast('Failed to create page: ' + err.message, 'error');
|
||||
else alert('Failed to create page: ' + err.message);
|
||||
});
|
||||
},
|
||||
|
||||
/** Show the global New Folder modal. */
|
||||
showCreateFolderModal: function() {
|
||||
var modal = document.getElementById('fd-global-folder-modal');
|
||||
if (!modal) return;
|
||||
modal.style.display = 'flex';
|
||||
var input = document.getElementById('fd-global-folder-input');
|
||||
if (input) { input.value = ''; setTimeout(function() { input.focus(); }, 100); }
|
||||
},
|
||||
|
||||
/** Called by the global New Folder modal's Create button. */
|
||||
_confirmCreateFolder: function() {
|
||||
var input = document.getElementById('fd-global-folder-input');
|
||||
var name = (input && input.value || '').trim();
|
||||
if (!name) return;
|
||||
var modal = document.getElementById('fd-global-folder-modal');
|
||||
if (modal) modal.style.display = 'none';
|
||||
var self = this;
|
||||
fetch('/api/local-workspace/items', {
|
||||
method: 'POST',
|
||||
headers: { 'Content-Type': 'application/json', 'X-CSRF-Token': this.getCsrfToken() },
|
||||
body: JSON.stringify({ name: name, type: 'folder' })
|
||||
})
|
||||
.then(function(r) { if (!r.ok) throw new Error('Failed'); return r.json(); })
|
||||
.then(function() {
|
||||
// Refresh sidebar tree
|
||||
if (window.appState && window.appState.refreshSidebarTree) window.appState.refreshSidebarTree();
|
||||
// Notify workspace page
|
||||
document.dispatchEvent(new CustomEvent('flowdeck:workspace-changed'));
|
||||
if (window._wsData && window._wsData._reloadAfterAction) window._wsData._reloadAfterAction();
|
||||
// Show toast
|
||||
if (window.appState && window.appState.toast) window.appState.toast('Folder created', 'success');
|
||||
})
|
||||
.catch(function(err) {
|
||||
if (window.appState && window.appState.toast) window.appState.toast('Failed: ' + err.message, 'error');
|
||||
else alert('Failed to create folder: ' + err.message);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
function appState() {
|
||||
return {
|
||||
init() {
|
||||
@@ -1164,8 +1228,7 @@
|
||||
|
||||
if (e.ctrlKey && e.key === 'n') {
|
||||
e.preventDefault();
|
||||
if (data && data.newPageInWorkspace) data.newPageInWorkspace();
|
||||
else if (data && data.newPage) data.newPage('Private');
|
||||
window.FlowDeck.createPage();
|
||||
}
|
||||
else if (e.key === 'Enter' && !editable) {
|
||||
var activeSidebar = document.querySelector('.sidebar-item.active');
|
||||
@@ -1237,5 +1300,23 @@
|
||||
.flowdeck-modal-btn.confirm:hover{background:#2C8CEB;}
|
||||
</style>
|
||||
|
||||
<!-- Global New Folder Modal -->
|
||||
<div id="fd-global-folder-modal" class="flowdeck-modal-overlay" style="display:none" onclick="if(event.target===this)this.style.display='none'">
|
||||
<div class="flowdeck-modal">
|
||||
<div class="flowdeck-modal-header">
|
||||
<h3>📁 New Folder</h3>
|
||||
<button class="flowdeck-modal-close" onclick="document.getElementById('fd-global-folder-modal').style.display='none'">×</button>
|
||||
</div>
|
||||
<div class="flowdeck-modal-body">
|
||||
<p>Enter a name for the new folder.</p>
|
||||
<input class="flowdeck-modal-input" id="fd-global-folder-input" type="text" placeholder="Folder name" onkeydown="if(event.key==='Enter')window.FlowDeck._confirmCreateFolder()">
|
||||
</div>
|
||||
<div class="flowdeck-modal-footer">
|
||||
<button class="flowdeck-modal-btn cancel" onclick="document.getElementById('fd-global-folder-modal').style.display='none'">Cancel</button>
|
||||
<button class="flowdeck-modal-btn confirm" onclick="window.FlowDeck._confirmCreateFolder()">Create</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</body>
|
||||
</html>
|
||||
|
||||
@@ -779,7 +779,7 @@ document.addEventListener('alpine:init', () => {
|
||||
<div class="gw-content">
|
||||
<div style="display:flex;align-items:center;justify-content:space-between;margin-bottom:16px;">
|
||||
<h3>🔒 Private Pages</h3>
|
||||
<button class="btn btn-primary" @click="newPrivate()">+ New Page</button>
|
||||
<button class="btn btn-primary" onclick="window.FlowDeck.createPage()">+ New Page</button>
|
||||
</div>
|
||||
<template x-if="privatePages.length === 0">
|
||||
<div class="empty-state" style="padding:40px 20px;">
|
||||
|
||||
@@ -186,7 +186,7 @@
|
||||
<div class="lib-header">
|
||||
<h1>Library</h1>
|
||||
<div class="lib-header-actions">
|
||||
<button class="lib-btn-primary" @click="newPage()">
|
||||
<button class="lib-btn-primary" onclick="window.FlowDeck.createPage()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
New page
|
||||
</button>
|
||||
@@ -326,7 +326,7 @@
|
||||
|
||||
<!-- "+ Add new" (root level) -->
|
||||
<div class="add-new-row" x-show="!loading && tab !== 'favorites' && tab !== 'shared' && tab !== 'published' && tab !== 'repository'"
|
||||
@click="addNewPage(0)">
|
||||
onclick="window.FlowDeck.createPage()">
|
||||
<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg>
|
||||
Add new
|
||||
</div>
|
||||
@@ -541,7 +541,7 @@ function libraryPage() {
|
||||
// ── Synthetic "+ Add new" placeholder row for an expanded parent ──
|
||||
if (item._isAddNew) {
|
||||
var pad = 30 + (item.depth || 0) * 20;
|
||||
html += '<div class="add-new-under" style="padding-left:' + pad + 'px" onclick="window._libData.addNewPage(' + item._parentId + ')">';
|
||||
html += '<div class="add-new-under" style="padding-left:' + pad + 'px" onclick="window.FlowDeck.createPage()">';
|
||||
html += '<svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2"><line x1="12" y1="5" x2="12" y2="19"/><line x1="5" y1="12" x2="19" y2="12"/></svg> Add new</div>';
|
||||
continue;
|
||||
}
|
||||
|
||||
@@ -1072,10 +1072,10 @@ window._wsInitData = (function() {
|
||||
|
||||
switch(action) {
|
||||
case 'new-file':
|
||||
this.openModal('file', {db_id: id, name: name});
|
||||
window.FlowDeck.createPage();
|
||||
break;
|
||||
case 'new-folder':
|
||||
this.openModal('folder', {db_id: id, name: name});
|
||||
window.FlowDeck.showCreateFolderModal();
|
||||
break;
|
||||
case 'rename':
|
||||
this.startRename({db_id: id, name: name});
|
||||
@@ -2183,8 +2183,8 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
</select>
|
||||
<button class="btn-icon" @click="expandAll()" title="Expand" x-show="viewMode==='tree'">⊞</button>
|
||||
<button class="btn-icon" @click="collapseAll()" title="Collapse" x-show="viewMode==='tree'">⊟</button>
|
||||
<button class="btn-icon btn-create" @click="openModal('file')" title="New file">📄</button>
|
||||
<button class="btn-icon btn-create" @click="openModal('folder')" title="New folder">📁</button>
|
||||
<button class="btn-icon btn-create" onclick="window.FlowDeck.createPage()" title="New file">📄</button>
|
||||
<button class="btn-icon btn-create" onclick="window.FlowDeck.showCreateFolderModal()" title="New folder">📁</button>
|
||||
</div>
|
||||
|
||||
<!-- Bulk actions bar -->
|
||||
@@ -2274,8 +2274,8 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<div class="actions">
|
||||
<template x-if="node.is_folder">
|
||||
<span style="display:flex;gap:2px">
|
||||
<button class="ws-act" @click.stop="openModal('file',node)" title="New file">📄</button>
|
||||
<button class="ws-act" @click.stop="openModal('folder',node)" title="New folder">📁</button>
|
||||
<button class="ws-act" @click.stop="window.FlowDeck.createPage()" title="New file">📄</button>
|
||||
<button class="ws-act" @click.stop="window.FlowDeck.showCreateFolderModal()" title="New folder">📁</button>
|
||||
</span>
|
||||
</template>
|
||||
<button class="ws-act" @click.stop="startRename(node)" title="Rename">✏️</button>
|
||||
@@ -2480,8 +2480,8 @@ console.log('FLOWDECK v2.4.6 — IIFE done, _wsInitData keys:', Object.keys(wind
|
||||
<h2 x-text="currentFolder > 0 ? 'Empty folder' : 'Welcome to your Workspace'"></h2>
|
||||
<p x-text="currentFolder > 0 ? 'Create a new file or folder to get started' : 'Drag & drop files from your computer, or create new ones.'"></p>
|
||||
<div class="empty-actions">
|
||||
<button class="btn-icon" @click="openModal('file')" title="New file">📄</button>
|
||||
<button class="btn-icon" @click="openModal('folder')" title="New folder">📁</button>
|
||||
<button class="btn-icon" onclick="window.FlowDeck.createPage()" title="New file">📄</button>
|
||||
<button class="btn-icon" onclick="window.FlowDeck.showCreateFolderModal()" title="New folder">📁</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Reference in New Issue
Block a user