refactor: Shared Links als Card-Grid mit Card-Menü (wie Cronjobs)
- index.html: shared-links-list → card-grid - dashboard.js: Cards mit card-compact, card-menu-dropdown, fa-cog statt fa-robot - dashboard.css: 60 Zeilen shared-link-*/danger-icon CSS entfernt (nutzt card-Styles)
This commit is contained in:
1 parent
38a8223228
commit
8a9293218b
3 files changed
+55
-84
No files matched your search
@@ -256,66 +256,6 @@
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
/* Shared Links */
|
||||
|
||||
.shared-links-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: var(--badge-spacing);
|
||||
}
|
||||
|
||||
.shared-link-row {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: var(--box-spacing);
|
||||
padding: var(--box-padding);
|
||||
background: var(--f3-bg);
|
||||
border: var(--border-width) solid var(--f3-border);
|
||||
border-radius: var(--border-radius);
|
||||
}
|
||||
|
||||
.shared-link-info {
|
||||
flex: 1;
|
||||
min-width: 0;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: calc(var(--badge-spacing) / 2);
|
||||
}
|
||||
|
||||
.shared-link-preview {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.shared-link-preview .fa {
|
||||
opacity: var(--semi-transparent);
|
||||
margin-right: calc(var(--badge-spacing) / 2);
|
||||
}
|
||||
|
||||
.shared-link-meta {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
gap: var(--box-spacing);
|
||||
opacity: var(--semi-transparent);
|
||||
font-size: calc(var(--font-size) * 0.9);
|
||||
}
|
||||
|
||||
.shared-link-actions {
|
||||
display: flex;
|
||||
gap: var(--badge-spacing);
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.danger-icon {
|
||||
color: var(--dangerous);
|
||||
opacity: var(--semi-transparent);
|
||||
}
|
||||
|
||||
.danger-icon:hover {
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
/* Compact cards (no image) */
|
||||
.card-compact {
|
||||
padding: var(--box-padding);
|
||||
|
||||
+1
-1
@@ -84,7 +84,7 @@
|
||||
<div class="section-header">
|
||||
<h2>Geteilte Links</h2>
|
||||
</div>
|
||||
<div class="shared-links-list" id="sharedLinksList"></div>
|
||||
<div class="card-grid" id="sharedLinksCards"></div>
|
||||
</section>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -329,45 +329,76 @@ registerPage('dashboard', {
|
||||
// Shared Links
|
||||
const shares = await apiListShares();
|
||||
const sharedSection = document.getElementById('sharedLinksSection');
|
||||
const sharedList = document.getElementById('sharedLinksList');
|
||||
const sharedGrid = document.getElementById('sharedLinksCards');
|
||||
if (shares.length > 0) {
|
||||
sharedSection.hidden = false;
|
||||
sharedList.innerHTML = '';
|
||||
sharedGrid.innerHTML = '';
|
||||
for (const s of shares) {
|
||||
const row = document.createElement('div');
|
||||
row.className = 'shared-link-row';
|
||||
const card = document.createElement('div');
|
||||
card.className = 'card card-compact';
|
||||
const shareUrl = `${location.origin}/#shared/${s.shareToken}`;
|
||||
const modeLabel = s.includeContext ? 'Thread' : 'Einzeln';
|
||||
const roleIcon = s.role === 'user' ? 'fa-user' : 'fa-robot';
|
||||
row.innerHTML = `
|
||||
<div class="shared-link-info">
|
||||
<span class="shared-link-preview"><i class="fa ${roleIcon}"></i> ${esc(s.preview || '(leer)')}</span>
|
||||
<span class="shared-link-meta">
|
||||
${s.sessionName ? `<span><i class="fa fa-comment"></i> ${esc(s.sessionName)}</span>` : ''}
|
||||
<span><i class="fa fa-${s.includeContext ? 'comments' : 'comment-o'}"></i> ${modeLabel}</span>
|
||||
<span><i class="fa fa-clock-o"></i> ${formatDate(s.createdAt)}</span>
|
||||
</span>
|
||||
const roleIcon = s.role === 'user' ? 'fa-user' : 'fa-cog';
|
||||
|
||||
card.innerHTML = `
|
||||
<div class="card-body">
|
||||
<div class="card-title-row">
|
||||
<span class="card-title"><i class="fa ${roleIcon}"></i> ${esc(s.preview || '(leer)')}</span>
|
||||
<div class="card-menu">
|
||||
<button class="card-menu-trigger icon-btn"><i class="fa fa-ellipsis-v"></i></button>
|
||||
<div class="card-menu-dropdown" hidden>
|
||||
<button class="card-menu-item" data-action="copy"><i class="fa fa-clipboard"></i> Link kopieren</button>
|
||||
<button class="card-menu-item" data-action="open"><i class="fa fa-external-link"></i> Öffnen</button>
|
||||
<button class="card-menu-item" data-action="delete"><i class="fa fa-trash"></i> Löschen</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="card-meta">
|
||||
${s.sessionName ? `<span class="card-meta-item"><i class="fa fa-comment"></i> ${esc(s.sessionName)}</span>` : ''}
|
||||
<span class="card-meta-item"><i class="fa fa-${s.includeContext ? 'comments' : 'comment-o'}"></i> ${modeLabel}</span>
|
||||
<span class="card-meta-item"><i class="fa fa-clock-o"></i> ${formatDate(s.createdAt)}</span>
|
||||
</div>
|
||||
<div class="shared-link-actions">
|
||||
<button class="icon-btn" data-action="copy" title="Link kopieren"><i class="fa fa-clipboard"></i></button>
|
||||
<button class="icon-btn" data-action="open" title="Öffnen"><i class="fa fa-external-link"></i></button>
|
||||
<button class="icon-btn danger-icon" data-action="delete" title="Link löschen"><i class="fa fa-trash"></i></button>
|
||||
</div>
|
||||
`;
|
||||
row.querySelector('[data-action="copy"]').addEventListener('click', async () => {
|
||||
|
||||
const menuTrigger = card.querySelector('.card-menu-trigger');
|
||||
const menuDropdown = card.querySelector('.card-menu-dropdown');
|
||||
menuTrigger.addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
closeAllCardMenus();
|
||||
const rect = menuTrigger.getBoundingClientRect();
|
||||
menuDropdown.hidden = false;
|
||||
const dropRect = menuDropdown.getBoundingClientRect();
|
||||
menuDropdown.style.top = `${rect.bottom + 4}px`;
|
||||
menuDropdown.style.left = `${rect.right - dropRect.width}px`;
|
||||
if (rect.bottom + 4 + dropRect.height > window.innerHeight) {
|
||||
menuDropdown.style.top = `${rect.top - dropRect.height - 4}px`;
|
||||
}
|
||||
const finalRect = menuDropdown.getBoundingClientRect();
|
||||
if (finalRect.left < 0) menuDropdown.style.left = '8px';
|
||||
});
|
||||
|
||||
menuDropdown.querySelector('[data-action="copy"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
await navigator.clipboard.writeText(shareUrl);
|
||||
showToast('Link kopiert!');
|
||||
});
|
||||
row.querySelector('[data-action="open"]').addEventListener('click', () => {
|
||||
menuDropdown.querySelector('[data-action="open"]').addEventListener('click', (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
window.open(shareUrl, '_blank');
|
||||
});
|
||||
row.querySelector('[data-action="delete"]').addEventListener('click', async () => {
|
||||
menuDropdown.querySelector('[data-action="delete"]').addEventListener('click', async (e) => {
|
||||
e.stopPropagation();
|
||||
menuDropdown.hidden = true;
|
||||
await apiDeleteShare(s.shareToken);
|
||||
row.remove();
|
||||
if (sharedList.children.length === 0) sharedSection.hidden = true;
|
||||
card.remove();
|
||||
if (sharedGrid.children.length === 0) sharedSection.hidden = true;
|
||||
showToast('Link gelöscht');
|
||||
});
|
||||
sharedList.appendChild(row);
|
||||
|
||||
sharedGrid.appendChild(card);
|
||||
}
|
||||
}
|
||||
},
|
||||
|
||||
Reference in new issue
Block a user