v2.8.0 WIP: create/upload files + commit history + labels sync
- POST /api/gitea/projects/{owner}/{repo}/upload (binary upload)
- get_file_commits() in GiteaClient
- GET /api/gitea/projects/{owner}/{repo}/commits (per-file history)
- POST .../sync-labels (Gitea labels → FlowDeck tags)
- New file form + upload button in gitea_workspace.html topbar
This commit is contained in:
@@ -529,6 +529,8 @@
|
||||
contextMenu: { visible: false, x: 0, y: 0, pageId: null, pageName: '' },
|
||||
contextActions: {},
|
||||
showNewPageMenu: false,
|
||||
selectedItems: [],
|
||||
lastClickedIndex: -1,
|
||||
|
||||
// ── Workspace tree context menu ──
|
||||
wsCtx: { visible: false, x: 0, y: 0, id: null, name: '', isFolder: false },
|
||||
@@ -1027,6 +1029,71 @@
|
||||
window.addEventListener('pageshow', function(e) {
|
||||
if (e.persisted) applySavedTheme();
|
||||
});
|
||||
|
||||
// ═══════════ GLOBAL KEYBOARD SHORTCUTS ═══════════
|
||||
document.addEventListener('keydown', function(e) {
|
||||
var tag = (document.activeElement && document.activeElement.tagName) || '';
|
||||
var editable = tag === 'INPUT' || tag === 'TEXTAREA' || (document.activeElement && document.activeElement.isContentEditable);
|
||||
// Don't intercept when typing in inputs unless it's Escape
|
||||
if (editable && e.key !== 'Escape') return;
|
||||
// Don't intercept when a modal prompt is open
|
||||
if (document.querySelector('.modal-overlay:not([style*="display:none"])')) return;
|
||||
|
||||
var appEl = document.querySelector('[x-data]');
|
||||
var data = appEl && appEl.__x ? appEl.__x.$data : null;
|
||||
|
||||
if (e.ctrlKey && e.key === 'n') {
|
||||
e.preventDefault();
|
||||
if (data && data.newPageInWorkspace) data.newPageInWorkspace();
|
||||
else if (data && data.newPage) data.newPage('Private');
|
||||
}
|
||||
else if (e.key === 'Enter' && !editable) {
|
||||
var activeSidebar = document.querySelector('.sidebar-item.active');
|
||||
if (activeSidebar) {
|
||||
e.preventDefault();
|
||||
activeSidebar.click();
|
||||
}
|
||||
}
|
||||
else if (e.key === 'F2') {
|
||||
e.preventDefault();
|
||||
// Trigger rename: dispatch dblclick on active item's name span
|
||||
var nameSpan = document.querySelector('.sidebar-item.active .page-name');
|
||||
if (nameSpan) {
|
||||
nameSpan.dispatchEvent(new MouseEvent('dblclick', { bubbles: true }));
|
||||
} else if (data && data.wsCtx && data.wsCtx.id) {
|
||||
// Workspace tree item: trigger rename via context menu
|
||||
data.wsCtxAction('rename');
|
||||
}
|
||||
}
|
||||
else if (e.key === 'Delete' && !editable) {
|
||||
e.preventDefault();
|
||||
var delItem = document.querySelector('.sidebar-item.active');
|
||||
if (delItem && delItem.dataset.pageId && data) {
|
||||
data.contextMenu.pageId = delItem.dataset.pageId;
|
||||
data.contextMenu.pageName = delItem.dataset.pageName || delItem.querySelector('.page-name')?.textContent || '';
|
||||
data.contextAction('delete');
|
||||
} else if (delItem && delItem.dataset.giteaPath) {
|
||||
// Gitea file: dispatch custom event
|
||||
delItem.dispatchEvent(new CustomEvent('gitea-delete', { bubbles: true }));
|
||||
}
|
||||
}
|
||||
else if (e.key === 'Escape') {
|
||||
// Close card modal
|
||||
if (typeof closeModal === 'function') closeModal();
|
||||
// Close context menus
|
||||
if (data) {
|
||||
if (data.contextMenu) data.contextMenu.visible = false;
|
||||
if (data.wsCtx) data.wsCtx.visible = false;
|
||||
if (data.showNewPageMenu) data.showNewPageMenu = false;
|
||||
}
|
||||
}
|
||||
else if (e.ctrlKey && e.key === 's') {
|
||||
e.preventDefault();
|
||||
// Try to find and click a save/commit button
|
||||
var saveBtn = document.querySelector('.btn-primary, button:contains("Save"), button:contains("Commit")');
|
||||
if (saveBtn) saveBtn.click();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
<script src="/static/js/app.js?v=2.4.6" defer></script>
|
||||
{% block scripts %}{% endblock %}
|
||||
|
||||
Reference in New Issue
Block a user