fix: Gitea sidebar tree + header actions inline with title
Gitea workspace sidebar: - loadSidebarTree() now uses innerHTML replacement instead of DOM manipulation (avoids Alpine reactivity overwrites) - Ensures workspace section is visible when tree loads - Shows error message when Gitea API fails (no token/gateway) - Better error handling with console.error catch Header actions inline: - page_editor: moved Edited/Share/Copy/Favorite/More buttons into the unified header (right_actions), accessible via window.E (editorState global reference set in init) - Removed duplicate page-topbar div from content area - Share dialog, More menu, and Activity popover stay in content area (triggered by header buttons via window.E references) - Gitea workspace: header now uses page-action-btn for consistency
This commit is contained in:
@@ -6,7 +6,7 @@
|
|||||||
{% block topbar %}
|
{% block topbar %}
|
||||||
{% set breadcrumb_items = [{"label": "Home", "url": "/workspaces"}, {"label": owner ~ "/" ~ repo, "url": None}] %}
|
{% set breadcrumb_items = [{"label": "Home", "url": "/workspaces"}, {"label": owner ~ "/" ~ repo, "url": None}] %}
|
||||||
{% set page_icon = "🔗" %}
|
{% set page_icon = "🔗" %}
|
||||||
{% set right_actions = '<button class="topbar-btn" @click="showNewFile=!showNewFile" title="New file">📄+</button><button class="topbar-btn" @click="triggerUpload()" title="Upload file">📤</button><input type="file" id="gitea-upload-input" style="display:none" @change="doUpload($event)" multiple><button class="topbar-btn" @click="refreshTree()" title="Refresh">🔄</button><a href="/accounts/settings" class="topbar-btn" title="Settings">⚙</a>' %}
|
{% set right_actions = '<button class="page-action-btn" @click="showNewFile=!showNewFile" title="New file">📄+</button><button class="page-action-btn" @click="triggerUpload()" title="Upload file">📤</button><input type="file" id="gitea-upload-input" style="display:none" @change="doUpload($event)" multiple><button class="page-action-btn" @click="refreshTree()" title="Refresh">🔄</button><a href="/accounts/settings" class="topbar-btn" title="Settings">⚙</a>' %}
|
||||||
{% include '_header.html' %}
|
{% include '_header.html' %}
|
||||||
{% endblock %}
|
{% endblock %}
|
||||||
|
|
||||||
@@ -310,63 +310,41 @@ function giteaWorkspace() {
|
|||||||
async loadSidebarTree() {
|
async loadSidebarTree() {
|
||||||
try {
|
try {
|
||||||
var r = await fetch('/api/gitea/projects/' + this.owner + '/' + this.repo + '/tree');
|
var r = await fetch('/api/gitea/projects/' + this.owner + '/' + this.repo + '/tree');
|
||||||
if (!r.ok) return;
|
if (!r.ok) {
|
||||||
|
// If API fails (e.g. no Gitea token), set a message
|
||||||
|
var container = document.getElementById('sidebar-workspace-items');
|
||||||
|
if (container) container.innerHTML = '<li class="sidebar-item empty-hint"><span class="page-icon">🔗</span><span class="page-name text-dim">Connect Gitea to browse files</span></li>';
|
||||||
|
return;
|
||||||
|
}
|
||||||
var d = await r.json();
|
var d = await r.json();
|
||||||
var items = d.tree || [];
|
var items = d.tree || [];
|
||||||
var container = document.getElementById('sidebar-workspace-items');
|
var container = document.getElementById('sidebar-workspace-items');
|
||||||
if (!container) return;
|
if (!container) return;
|
||||||
|
// Ensure workspace section is visible
|
||||||
|
if (window.appState && window.appState.sectionsOpen && !window.appState.sectionsOpen.workspace) {
|
||||||
|
window.appState.sectionsOpen.workspace = true;
|
||||||
|
}
|
||||||
container.innerHTML = '';
|
container.innerHTML = '';
|
||||||
var self = this;
|
// Build tree HTML as string and set once (more performant)
|
||||||
items.forEach(function(item) {
|
var html = '';
|
||||||
|
for (var i = 0; i < items.length; i++) {
|
||||||
|
var item = items[i];
|
||||||
var icon = item.type === 'folder' ? '📁' : '📄';
|
var icon = item.type === 'folder' ? '📁' : '📄';
|
||||||
var li = document.createElement('li');
|
html += '<li class="sidebar-item" data-gitea-path="' + item.path + '" data-gitea-type="' + (item.type === 'folder' ? 'folder' : 'file') + '" data-gitea-sha="' + (item.sha || '') + '" style="padding-left:12px;cursor:pointer;display:flex;align-items:center;gap:4px;">';
|
||||||
li.className = 'sidebar-item';
|
html += '<span class="page-icon">' + icon + '</span>';
|
||||||
li.setAttribute('data-gitea-path', item.path);
|
html += '<span class="page-name">' + item.name + '</span>';
|
||||||
li.setAttribute('data-gitea-type', item.type === 'folder' ? 'folder' : 'file');
|
html += '</li>';
|
||||||
li.setAttribute('data-gitea-sha', item.sha || '');
|
}
|
||||||
li.style.cssText = 'padding-left:12px;cursor:pointer;display:flex;align-items:center;gap:4px;';
|
|
||||||
// Checkbox (hidden by default, visible in multi-select mode)
|
|
||||||
var cb = document.createElement('input');
|
|
||||||
cb.type = 'checkbox';
|
|
||||||
cb.className = 'gitea-checkbox';
|
|
||||||
cb.style.cssText = 'flex-shrink:0;margin:0;display:none;';
|
|
||||||
cb.addEventListener('click', function(ev) {
|
|
||||||
ev.stopPropagation();
|
|
||||||
self.selectItem(item.path, li, ev);
|
|
||||||
});
|
|
||||||
li.appendChild(cb);
|
|
||||||
// Icon
|
|
||||||
var iconSpan = document.createElement('span');
|
|
||||||
iconSpan.className = 'page-icon';
|
|
||||||
iconSpan.textContent = icon;
|
|
||||||
li.appendChild(iconSpan);
|
|
||||||
// Name (with double-click rename)
|
|
||||||
var nameSpan = document.createElement('span');
|
|
||||||
nameSpan.className = 'page-name';
|
|
||||||
nameSpan.textContent = item.name;
|
|
||||||
nameSpan.addEventListener('dblclick', function(ev) {
|
|
||||||
ev.preventDefault();
|
|
||||||
ev.stopPropagation();
|
|
||||||
self.startInlineRename(nameSpan, item.path, li);
|
|
||||||
});
|
|
||||||
li.appendChild(nameSpan);
|
|
||||||
container.appendChild(li);
|
|
||||||
});
|
|
||||||
// Add Private Pages link
|
// Add Private Pages link
|
||||||
var sep = document.createElement('li');
|
html += '<li style="border-top:1px solid var(--border);margin:8px 0;"></li>';
|
||||||
sep.style.cssText = 'border-top:1px solid var(--border);margin:8px 0;';
|
html += '<li class="sidebar-item" id="gitea-private-link" style="padding-left:12px;cursor:pointer;display:flex;align-items:center;gap:4px;">';
|
||||||
container.appendChild(sep);
|
html += '<span class="page-icon">🔒</span><span class="page-name">Private Pages</span></li>';
|
||||||
var pli = document.createElement('li');
|
container.innerHTML = html;
|
||||||
pli.className = 'sidebar-item';
|
// Re-attach event listeners
|
||||||
pli.style.cssText = 'padding-left:12px;cursor:pointer;';
|
this.setupSidebarClicks();
|
||||||
pli.innerHTML = '<span class="page-icon">🔒</span><span class="page-name">Private Pages</span>';
|
} catch(e) {
|
||||||
pli.addEventListener('click', function(e) {
|
console.error('Gitea sidebar tree load failed:', e);
|
||||||
e.preventDefault(); e.stopPropagation();
|
}
|
||||||
self.showPrivate = true; self.showFile = false; self.showEditor = false;
|
|
||||||
self.loadPrivatePages();
|
|
||||||
});
|
|
||||||
container.appendChild(pli);
|
|
||||||
} catch(e) { console.error('Sidebar tree load failed:', e); }
|
|
||||||
},
|
},
|
||||||
|
|
||||||
setupSidebarClicks() {
|
setupSidebarClicks() {
|
||||||
|
|||||||
@@ -2,35 +2,11 @@
|
|||||||
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
||||||
{% set page_icon = "📄" %}
|
{% set page_icon = "📄" %}
|
||||||
{% set page_title = page.title %}
|
{% set page_title = page.title %}
|
||||||
|
{% set right_actions = '<span class="topbar-edited" style="cursor:pointer;" @click="window.E && (window.E.activityOpen = !window.E.activityOpen)">Edited <span x-text="window.E && window.E.timeAgo || \'\'"></span> ▾</span><button class="topbar-btn share-btn" @click="window.E && (window.E.shareOpen = !window.E.shareOpen)">🔒 Share ▾</button><button class="topbar-btn" @click="window.E && window.E.copyPageLink()" title="Copy link">🔗</button><button class="topbar-btn star-btn" @click="window.E && window.E.toggleFavorite()">⭐</button><button class="topbar-btn" @click="window.E && (window.E.moreOpen = !window.E.moreOpen)" style="position:relative">⋯</button>' %}
|
||||||
{% include '_header.html' %}
|
{% include '_header.html' %}
|
||||||
{% endblock %} {% block content %}
|
{% endblock %} {% block content %}
|
||||||
<div class="page-editor-wrapper" x-data="editorState()">
|
<div class="page-editor-wrapper" x-data="editorState()">
|
||||||
<!-- ═══════════ Action Bar (Share, Copy, Favorite, More) ═══════════ -->
|
<!-- Share/More dialogs (in content area, triggered by header buttons) -->
|
||||||
<div class="page-topbar">
|
|
||||||
<div class="page-topbar-right" style="position: relative">
|
|
||||||
<span class="topbar-edited" style="cursor:pointer;" @click="activityOpen = !activityOpen">Edited <span x-text="timeAgo"></span> ▾</span>
|
|
||||||
<button
|
|
||||||
class="page-action-btn share-btn"
|
|
||||||
@click="shareOpen = !shareOpen"
|
|
||||||
>
|
|
||||||
🔒 Share <span class="chevron-down">▾</span>
|
|
||||||
</button>
|
|
||||||
<button
|
|
||||||
class="page-action-btn"
|
|
||||||
@click="copyPageLink"
|
|
||||||
title="Copy link"
|
|
||||||
>
|
|
||||||
🔗
|
|
||||||
</button>
|
|
||||||
<button class="page-action-btn star-btn" @click="toggleFavorite">
|
|
||||||
<span
|
|
||||||
x-text="favorited ? '⭐' : '☆'"
|
|
||||||
:class="{ starred: favorited }"
|
|
||||||
></span>
|
|
||||||
</button>
|
|
||||||
<button class="page-action-btn" @click="moreOpen = !moreOpen">
|
|
||||||
⋮
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- ═══════════ Share / Publish Dialog ═══════════ -->
|
<!-- ═══════════ Share / Publish Dialog ═══════════ -->
|
||||||
<div
|
<div
|
||||||
@@ -410,8 +386,6 @@ page_title %}{{ page.title }}{% endblock %} {% block topbar %}
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- ═══════════ Page Content ═══════════ -->
|
<!-- ═══════════ Page Content ═══════════ -->
|
||||||
<div class="page-cover-area">
|
<div class="page-cover-area">
|
||||||
|
|||||||
Reference in New Issue
Block a user