+
+
+
@@ -389,37 +216,29 @@
const API = '/api';
let token = localStorage.getItem('ld_token') || '';
let username = localStorage.getItem('ld_user') || '';
-let currentPlaylist = null;
+let currentPlaylistId = null;
+let currentTab = 'public';
-// ── Auth UI ──
function updateAuthUI() {
- const lbl = document.getElementById('user-label');
- const btnLogin = document.getElementById('btn-login');
- const btnLogout = document.getElementById('btn-logout');
- if (token) {
- lbl.textContent = username;
- btnLogin.style.display = 'none';
- btnLogout.style.display = '';
- } else {
- lbl.textContent = '';
- btnLogin.style.display = '';
- btnLogout.style.display = 'none';
- }
+ document.getElementById('btn-login').style.display = token ? 'none' : '';
+ document.getElementById('btn-logout').style.display = token ? '' : 'none';
+ document.getElementById('tab-mine').style.display = token ? '' : 'none';
+ document.getElementById('user-label').textContent = token ? username : '';
+ if (!token && currentTab === 'mine') switchTab('public');
}
document.getElementById('btn-login').onclick = () =>
document.getElementById('login-modal').classList.add('open');
-
document.getElementById('btn-cancel-login').onclick = () =>
document.getElementById('login-modal').classList.remove('open');
-
document.getElementById('btn-logout').onclick = () => {
token = ''; username = '';
- localStorage.removeItem('ld_token');
- localStorage.removeItem('ld_user');
+ localStorage.removeItem('ld_token'); localStorage.removeItem('ld_user');
updateAuthUI();
};
-
+document.getElementById('inp-pass').onkeydown = e => {
+ if (e.key === 'Enter') document.getElementById('btn-do-login').click();
+};
document.getElementById('btn-do-login').onclick = async () => {
const user = document.getElementById('inp-user').value.trim();
const pass = document.getElementById('inp-pass').value;
@@ -427,64 +246,129 @@ document.getElementById('btn-do-login').onclick = async () => {
msg.innerHTML = '';
try {
const fd = new FormData();
- fd.append('username', user);
- fd.append('password', pass);
+ fd.append('username', user); fd.append('password', pass);
const r = await fetch(`${API}/auth/login`, { method: 'POST', body: fd });
const d = await r.json();
if (!r.ok) throw new Error(d.detail || 'Login fejlede');
- token = d.access_token;
- username = user;
- localStorage.setItem('ld_token', token);
- localStorage.setItem('ld_user', username);
+ token = d.access_token; username = user;
+ localStorage.setItem('ld_token', token); localStorage.setItem('ld_user', username);
document.getElementById('login-modal').classList.remove('open');
updateAuthUI();
- msg.innerHTML = '';
+ loadMyPlaylists();
} catch(e) {
msg.innerHTML = `
${e.message}
`;
}
};
-// ── Load playlister ──
-async function loadPlaylists() {
- const grid = document.getElementById('grid');
+function switchTab(tab) {
+ currentTab = tab;
+ document.querySelectorAll('.tab').forEach(t =>
+ t.classList.toggle('active', t.dataset.tab === tab));
+ document.getElementById('pane-public').style.display = tab === 'public' ? '' : 'none';
+ document.getElementById('pane-mine').style.display = tab === 'mine' ? '' : 'none';
+ if (tab === 'public') {
+ document.getElementById('hero-title').innerHTML = 'Public
playlister';
+ document.getElementById('hero-sub').textContent = 'Browse og kopiér playlister delt af LineDance Player-brugere.';
+ } else {
+ document.getElementById('hero-title').innerHTML = 'Mine
playlister';
+ document.getElementById('hero-sub').textContent = 'Administrér synlighed på dine playlister.';
+ }
+}
+document.querySelectorAll('.tab').forEach(t => t.onclick = () => switchTab(t.dataset.tab));
+
+async function loadPublicPlaylists() {
+ const grid = document.getElementById('grid-public');
try {
const r = await fetch(`${API}/sharing/public`);
const lists = await r.json();
- if (!lists.length) {
- grid.innerHTML = '
Ingen public playlister endnu.
';
- return;
- }
+ if (!lists.length) { grid.innerHTML = '
Ingen public playlister endnu.
'; return; }
grid.innerHTML = lists.map(p => `
-
+
${esc(p.name)}
@ ${esc(p.owner)}
- ${p.song_count} sange
+ ${p.song_count} sange
+ public
-
- `).join('');
+
`).join('');
grid.querySelectorAll('.card').forEach(c =>
- c.onclick = () => openDetail(c.dataset.id)
- );
+ c.onclick = () => openDetail(c.dataset.id, false));
} catch(e) {
grid.innerHTML = `
Kunne ikke hente playlister.
${e.message}
`;
}
}
-// ── Detail ──
-async function openDetail(id) {
- currentPlaylist = id;
- document.getElementById('detail').classList.add('open');
- document.getElementById('d-songs').innerHTML =
- '
';
+async function loadMyPlaylists() {
+ const grid = document.getElementById('grid-mine');
+ grid.innerHTML = '
';
try {
- const r = await fetch(`${API}/sharing/playlists/${id}`);
+ const r = await fetch(`${API}/projects/my`, {
+ headers: { 'Authorization': `Bearer ${token}` }
+ });
+ if (!r.ok) throw new Error('Ikke autoriseret');
+ const lists = await r.json();
+ if (!lists.length) { grid.innerHTML = '
Ingen playlister endnu.
'; return; }
+ grid.innerHTML = lists.map(p => {
+ const vis = p.visibility || 'private';
+ const bc = vis === 'public' ? 'green' : vis === 'shared' ? 'orange' : 'muted';
+ const bl = vis === 'public' ? 'public' : vis === 'shared' ? 'delt' : 'privat';
+ const sc = p.song_count || (p.songs || []).length || 0;
+ return `
+
+
${esc(p.name)}
+
+ ${sc} sange
+ ${bl}
+
+
+
+
+
+
`;
+ }).join('');
+ } catch(e) {
+ grid.innerHTML = `
Kunne ikke hente playlister.
${e.message}
`;
+ }
+}
+
+async function toggleVis(id, current) {
+ const newVis = current === 'public' ? 'private' : 'public';
+ try {
+ const r = await fetch(`${API}/sharing/playlists/${id}/visibility?visibility=${newVis}`, {
+ method: 'PATCH', headers: { 'Authorization': `Bearer ${token}` }
+ });
+ if (!r.ok) throw new Error('Fejl');
+ const badge = document.getElementById(`vis-badge-${id}`);
+ const btn = document.getElementById(`vis-btn-${id}`);
+ if (newVis === 'public') {
+ badge.className = 'badge green'; badge.textContent = 'public';
+ btn.className = 'btn sm danger'; btn.textContent = 'Gør privat';
+ btn.onclick = () => toggleVis(id, 'public');
+ } else {
+ badge.className = 'badge muted'; badge.textContent = 'privat';
+ btn.className = 'btn sm'; btn.textContent = 'Gør public';
+ btn.onclick = () => toggleVis(id, 'private');
+ }
+ loadPublicPlaylists();
+ } catch(e) { alert('Fejl: ' + e.message); }
+}
+
+async function openDetail(id, isOwn) {
+ currentPlaylistId = id;
+ document.getElementById('btn-copy').style.display = isOwn ? 'none' : '';
+ document.getElementById('detail').classList.add('open');
+ document.getElementById('d-songs').innerHTML = '
';
+ try {
+ const headers = token ? { 'Authorization': `Bearer ${token}` } : {};
+ const r = await fetch(`${API}/sharing/playlists/${id}`, { headers });
const p = await r.json();
document.getElementById('d-title').textContent = p.name;
- document.getElementById('d-meta').textContent =
- `${p.songs.length} sange · ${p.owner || ''}`;
+ document.getElementById('d-meta').textContent = `${p.songs.length} sange${p.owner ? ' · @ '+p.owner : ''}`;
document.getElementById('d-songs').innerHTML = p.songs.length
- ? p.songs.map((s, i) => `
+ ? p.songs.map((s,i) => `
${i+1}
@@ -493,59 +377,43 @@ async function openDetail(id) {
${s.dance_override ? `
${esc(s.dance_override)}` : ''}
`).join('')
- : '
Ingen sange i listen.
';
+ : '
Ingen sange.
';
} catch(e) {
- document.getElementById('d-songs').innerHTML =
- `
Kunne ikke hente detaljer.
`;
+ document.getElementById('d-songs').innerHTML = '
Kunne ikke hente detaljer.
';
}
}
function closeDetail() {
document.getElementById('detail').classList.remove('open');
- currentPlaylist = null;
+ currentPlaylistId = null;
}
-
document.getElementById('btn-close-detail').onclick = closeDetail;
document.getElementById('btn-close-detail2').onclick = closeDetail;
document.getElementById('detail').onclick = e => {
if (e.target === document.getElementById('detail')) closeDetail();
};
-// ── Kopiér ──
document.getElementById('btn-copy').onclick = async () => {
- if (!token) {
- document.getElementById('login-modal').classList.add('open');
- return;
- }
+ if (!token) { document.getElementById('login-modal').classList.add('open'); return; }
const btn = document.getElementById('btn-copy');
- btn.disabled = true;
- btn.textContent = 'Kopierer...';
+ btn.disabled = true; btn.textContent = 'Kopierer...';
try {
- const r = await fetch(`${API}/sharing/playlists/${currentPlaylist}/copy`, {
- method: 'POST',
- headers: { 'Authorization': `Bearer ${token}` }
+ const r = await fetch(`${API}/sharing/playlists/${currentPlaylistId}/copy`, {
+ method: 'POST', headers: { 'Authorization': `Bearer ${token}` }
});
const d = await r.json();
if (!r.ok) throw new Error(d.detail || 'Fejl');
- btn.textContent = '✓ Kopieret!';
- btn.style.background = 'var(--green)';
- setTimeout(() => {
- btn.textContent = 'Kopiér til min konto';
- btn.style.background = '';
- btn.disabled = false;
- }, 2500);
- } catch(e) {
- btn.textContent = '⚠ ' + e.message;
- btn.disabled = false;
- }
+ btn.textContent = '✓ Kopieret!'; btn.style.background = 'var(--green)';
+ setTimeout(() => { btn.textContent = 'Kopiér til min konto'; btn.style.background = ''; btn.disabled = false; }, 2500);
+ loadMyPlaylists();
+ } catch(e) { btn.textContent = '⚠ ' + e.message; btn.disabled = false; }
};
-function esc(s) {
- return (s||'').replace(/&/g,'&').replace(//g,'>');
-}
+function esc(s) { return (s||'').replace(/&/g,'&').replace(//g,'>'); }
updateAuthUI();
-loadPlaylists();
+loadPublicPlaylists();
+if (token) loadMyPlaylists();