feat: Add hybrid player with frameset and pop-out options
- Add frameset mode with persistent audio player in bottom frame - Add localStorage preference system for user choice - Update all page navigation to work in both regular and frameset modes - Add enable/disable buttons for frameset mode - Fix redirect loops and template parameter issues
This commit is contained in:
parent
74cd3625f3
commit
01f5806959
|
|
@ -516,7 +516,7 @@
|
|||
("message" . "Listening history cleared successfully"))))
|
||||
|#
|
||||
|
||||
;; Front page
|
||||
;; Front page - regular view by default
|
||||
(define-page front-page #@"/" ()
|
||||
"Main front page"
|
||||
(let ((template-path (merge-pathnames "template/front-page.chtml"
|
||||
|
|
@ -537,6 +537,44 @@
|
|||
:now-playing-album "Startup Sounds"
|
||||
:now-playing-duration "∞")))
|
||||
|
||||
;; Frameset wrapper for persistent player mode
|
||||
(define-page frameset-wrapper #@"/frameset" ()
|
||||
"Frameset wrapper with persistent audio player"
|
||||
(let ((template-path (merge-pathnames "template/frameset-wrapper.chtml"
|
||||
(asdf:system-source-directory :asteroid))))
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:title "🎵 ASTEROID RADIO 🎵")))
|
||||
|
||||
;; Content frame - front page content without player
|
||||
(define-page front-page-content #@"/content" ()
|
||||
"Front page content (displayed in content frame)"
|
||||
(let ((template-path (merge-pathnames "template/front-page-content.chtml"
|
||||
(asdf:system-source-directory :asteroid))))
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:title "🎵 ASTEROID RADIO 🎵"
|
||||
:station-name "🎵 ASTEROID RADIO 🎵"
|
||||
:status-message "🟢 LIVE - Broadcasting asteroid music for hackers"
|
||||
:listeners "0"
|
||||
:stream-quality "128kbps MP3"
|
||||
:stream-base-url *stream-base-url*
|
||||
:now-playing-artist "The Void"
|
||||
:now-playing-track "Silence"
|
||||
:now-playing-album "Startup Sounds"
|
||||
:now-playing-duration "∞")))
|
||||
|
||||
;; Persistent audio player frame (bottom frame)
|
||||
(define-page audio-player-frame #@"/audio-player-frame" ()
|
||||
"Persistent audio player frame (bottom of page)"
|
||||
(let ((template-path (merge-pathnames "template/audio-player-frame.chtml"
|
||||
(asdf:system-source-directory :asteroid))))
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:stream-base-url *stream-base-url*
|
||||
:default-stream-url (concatenate 'string *stream-base-url* "/asteroid.aac")
|
||||
:default-stream-encoding "audio/aac")))
|
||||
|
||||
;; Configure static file serving for other files
|
||||
(define-page static #@"/static/(.*)" (:uri-groups (path))
|
||||
(serve-file (merge-pathnames (concatenate 'string "static/" path)
|
||||
|
|
@ -837,6 +875,18 @@
|
|||
:now-playing-album "Startup Sounds"
|
||||
:player-status "Stopped")))
|
||||
|
||||
;; Player content frame (for frameset mode)
|
||||
(define-page player-content #@"/player-content" ()
|
||||
"Player page content (displayed in content frame)"
|
||||
(let ((template-path (merge-pathnames "template/player-content.chtml"
|
||||
(asdf:system-source-directory :asteroid))))
|
||||
(clip:process-to-string
|
||||
(plump:parse (alexandria:read-file-into-string template-path))
|
||||
:title "Asteroid Radio - Web Player"
|
||||
:stream-base-url *stream-base-url*
|
||||
:default-stream-url (concatenate 'string *stream-base-url* "/asteroid.aac")
|
||||
:default-stream-encoding "audio/aac")))
|
||||
|
||||
(define-page popout-player #@"/popout-player" ()
|
||||
"Pop-out player window"
|
||||
(let ((template-path (merge-pathnames "template/popout-player.chtml"
|
||||
|
|
|
|||
|
|
@ -169,3 +169,30 @@ setInterval(function() {
|
|||
popoutWindow = null;
|
||||
}
|
||||
}, 1000);
|
||||
|
||||
// Frameset mode functionality
|
||||
function enableFramesetMode() {
|
||||
// Save preference
|
||||
localStorage.setItem('useFrameset', 'true');
|
||||
// Redirect to frameset wrapper
|
||||
window.location.href = '/asteroid/frameset';
|
||||
}
|
||||
|
||||
function disableFramesetMode() {
|
||||
// Clear preference
|
||||
localStorage.removeItem('useFrameset');
|
||||
// Redirect to regular view
|
||||
window.location.href = '/asteroid/';
|
||||
}
|
||||
|
||||
// Check if user prefers frameset mode on page load
|
||||
window.addEventListener('DOMContentLoaded', function() {
|
||||
const path = window.location.pathname;
|
||||
const isFramesetPage = path.includes('/frameset') || path.includes('/content') ||
|
||||
path.includes('/audio-player-frame') || path.includes('/player-content');
|
||||
|
||||
if (localStorage.getItem('useFrameset') === 'true' && !isFramesetPage && path === '/asteroid/') {
|
||||
// User wants frameset but is on regular front page, redirect
|
||||
window.location.href = '/asteroid/frameset';
|
||||
}
|
||||
});
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
<div class="container">
|
||||
<h1>🎛️ ADMIN DASHBOARD</h1>
|
||||
<div class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/player/">Player</a>
|
||||
<a href="/asteroid/profile">Profile</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/player-content" target="content-frame">Player</a>
|
||||
<a href="/asteroid/profile" target="content-frame">Profile</a>
|
||||
<a href="/asteroid/admin/users">👥 Users</a>
|
||||
<a href="/asteroid/logout" class="btn-logout">Logout</a>
|
||||
</div>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,174 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
|
||||
<style>
|
||||
body {
|
||||
margin: 0;
|
||||
padding: 10px;
|
||||
background: #1a1a1a;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
.persistent-player {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 15px;
|
||||
max-width: 100%;
|
||||
}
|
||||
.player-label {
|
||||
color: #00ff00;
|
||||
font-weight: bold;
|
||||
white-space: nowrap;
|
||||
}
|
||||
.quality-selector {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 5px;
|
||||
}
|
||||
.quality-selector label {
|
||||
color: #00ff00;
|
||||
font-size: 0.9em;
|
||||
}
|
||||
.quality-selector select {
|
||||
background: #2a2a2a;
|
||||
color: #00ff00;
|
||||
border: 1px solid #00ff00;
|
||||
padding: 3px 8px;
|
||||
font-family: 'Courier New', monospace;
|
||||
}
|
||||
audio {
|
||||
flex: 1;
|
||||
min-width: 200px;
|
||||
}
|
||||
.now-playing-mini {
|
||||
color: #00ff00;
|
||||
font-size: 0.9em;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
flex: 1;
|
||||
min-width: 300px;
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div class="persistent-player">
|
||||
<span class="player-label">🟢 LIVE:</span>
|
||||
|
||||
<div class="quality-selector">
|
||||
<input type="hidden" id="stream-base-url" lquery="(val stream-base-url)">
|
||||
<label for="stream-quality">Quality:</label>
|
||||
<select id="stream-quality" onchange="changeStreamQuality()">
|
||||
<option value="aac">AAC 96k</option>
|
||||
<option value="mp3">MP3 128k</option>
|
||||
<option value="low">MP3 64k</option>
|
||||
</select>
|
||||
</div>
|
||||
|
||||
<audio id="persistent-audio" controls preload="metadata">
|
||||
<source id="audio-source" lquery="(attr :src default-stream-url :type default-stream-encoding)">
|
||||
</audio>
|
||||
|
||||
<span class="now-playing-mini" id="mini-now-playing">Loading...</span>
|
||||
|
||||
<button onclick="disableFramesetMode()" style="background: #2a2a2a; color: #00ff00; border: 1px solid #00ff00; padding: 5px 10px; cursor: pointer; font-family: 'Courier New', monospace; font-size: 0.85em; white-space: nowrap;">
|
||||
✕ Disable
|
||||
</button>
|
||||
</div>
|
||||
|
||||
<script>
|
||||
// Configure audio element for better streaming
|
||||
document.addEventListener('DOMContentLoaded', function() {
|
||||
const audioElement = document.getElementById('persistent-audio');
|
||||
|
||||
// Try to enable low-latency mode if supported
|
||||
if ('mediaSession' in navigator) {
|
||||
navigator.mediaSession.metadata = new MediaMetadata({
|
||||
title: 'Asteroid Radio Live Stream',
|
||||
artist: 'Asteroid Radio',
|
||||
album: 'Live Broadcast'
|
||||
});
|
||||
}
|
||||
|
||||
// Add event listeners for debugging
|
||||
audioElement.addEventListener('waiting', function() {
|
||||
console.log('Audio buffering...');
|
||||
});
|
||||
|
||||
audioElement.addEventListener('playing', function() {
|
||||
console.log('Audio playing');
|
||||
});
|
||||
|
||||
audioElement.addEventListener('error', function(e) {
|
||||
console.error('Audio error:', e);
|
||||
});
|
||||
});
|
||||
|
||||
// Stream quality configuration
|
||||
function getStreamConfig(streamBaseUrl, encoding) {
|
||||
const config = {
|
||||
aac: {
|
||||
url: streamBaseUrl + '/asteroid.aac',
|
||||
type: 'audio/aac'
|
||||
},
|
||||
mp3: {
|
||||
url: streamBaseUrl + '/asteroid.mp3',
|
||||
type: 'audio/mpeg'
|
||||
},
|
||||
low: {
|
||||
url: streamBaseUrl + '/asteroid-low.mp3',
|
||||
type: 'audio/mpeg'
|
||||
}
|
||||
};
|
||||
return config[encoding];
|
||||
}
|
||||
|
||||
// Change stream quality
|
||||
function changeStreamQuality() {
|
||||
const selector = document.getElementById('stream-quality');
|
||||
const streamBaseUrl = document.getElementById('stream-base-url').value;
|
||||
const config = getStreamConfig(streamBaseUrl, selector.value);
|
||||
|
||||
const audioElement = document.getElementById('persistent-audio');
|
||||
const sourceElement = document.getElementById('audio-source');
|
||||
|
||||
const wasPlaying = !audioElement.paused;
|
||||
|
||||
sourceElement.src = config.url;
|
||||
sourceElement.type = config.type;
|
||||
audioElement.load();
|
||||
|
||||
if (wasPlaying) {
|
||||
audioElement.play().catch(e => console.log('Autoplay prevented:', e));
|
||||
}
|
||||
}
|
||||
|
||||
// Update mini now playing display
|
||||
async function updateMiniNowPlaying() {
|
||||
try {
|
||||
const response = await fetch('/api/asteroid/partial/now-playing-inline');
|
||||
if (response.ok) {
|
||||
const text = await response.text();
|
||||
document.getElementById('mini-now-playing').textContent = text;
|
||||
}
|
||||
} catch(error) {
|
||||
console.log('Could not fetch now playing:', error);
|
||||
}
|
||||
}
|
||||
|
||||
// Update every 10 seconds
|
||||
setTimeout(updateMiniNowPlaying, 1000);
|
||||
setInterval(updateMiniNowPlaying, 10000);
|
||||
|
||||
// Disable frameset mode function
|
||||
function disableFramesetMode() {
|
||||
// Clear preference
|
||||
localStorage.removeItem('useFrameset');
|
||||
// Redirect parent window to regular view
|
||||
window.parent.location.href = '/asteroid/';
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title lquery="(text title)">🎵 ASTEROID RADIO 🎵</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<script>
|
||||
// Prevent nested framesets - break out if we're already in a frame
|
||||
if (window.self !== window.top) {
|
||||
window.top.location.href = window.self.location.href;
|
||||
}
|
||||
</script>
|
||||
</head>
|
||||
<frameset rows="*,80" frameborder="0" border="0" framespacing="0">
|
||||
<frame src="/asteroid/content" name="content-frame" noresize>
|
||||
<frame src="/asteroid/audio-player-frame" name="player-frame" noresize scrolling="no">
|
||||
<noframes>
|
||||
<body>
|
||||
<p>Your browser does not support frames. Please use a modern browser or visit <a href="/asteroid/content">the main site</a>.</p>
|
||||
</body>
|
||||
</noframes>
|
||||
</frameset>
|
||||
</html>
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title data-text="title">🎵 ASTEROID RADIO 🎵</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
|
||||
<script src="/asteroid/static/js/auth-ui.js"></script>
|
||||
<script src="/asteroid/static/js/front-page.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<header>
|
||||
<h1 data-text="station-name">🎵 ASTEROID RADIO 🎵</h1>
|
||||
<nav class="nav">
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/player-content" target="content-frame">Player</a>
|
||||
<a href="/asteroid/status" target="content-frame">Status</a>
|
||||
<a href="/asteroid/profile" target="content-frame" data-show-if-logged-in>Profile</a>
|
||||
<a href="/asteroid/admin" target="content-frame" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/login" target="content-frame" data-show-if-logged-out>Login</a>
|
||||
<a href="/asteroid/register" target="content-frame" data-show-if-logged-out>Register</a>
|
||||
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout">Logout</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
||||
<main>
|
||||
<div class="status">
|
||||
<h2>Station Status</h2>
|
||||
<p data-text="status-message">🟢 LIVE - Broadcasting asteroid music for hackers</p>
|
||||
<p>Current listeners: <span data-text="listeners">0</span></p>
|
||||
<p>Stream quality: <span data-text="stream-quality">AAC 96kbps Stereo</span></p>
|
||||
</div>
|
||||
|
||||
<div class="live-stream">
|
||||
<h2 style="color: #00ff00;">🟢 LIVE STREAM</h2>
|
||||
<p><em>The live stream player is now in the persistent bar at the bottom of the page.</em></p>
|
||||
<p><strong>Stream URL:</strong> <code id="stream-url" lquery="(text default-stream-url)"></code></p>
|
||||
<p><strong>Format:</strong> <span id="stream-format" lquery="(text default-stream-encoding-desc)"></span></p>
|
||||
<p><strong>Status:</strong> <span id="stream-status" style="color: #00ff00;">● BROADCASTING</span></p>
|
||||
</div>
|
||||
|
||||
<div id="now-playing" class="now-playing"></div>
|
||||
</main>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -35,9 +35,14 @@
|
|||
<div class="live-stream">
|
||||
<div style="display: flex; justify-content: space-between; align-items: center; margin-bottom: 10px;">
|
||||
<h2 style="color: #00ff00; margin: 0;">🟢 LIVE STREAM</h2>
|
||||
<button id="popout-btn" class="btn btn-info" onclick="openPopoutPlayer()" style="font-size: 0.9em;">
|
||||
🗗 Pop Out Player
|
||||
</button>
|
||||
<div style="display: flex; gap: 10px;">
|
||||
<button id="popout-btn" class="btn btn-info" onclick="openPopoutPlayer()" style="font-size: 0.9em;">
|
||||
🗗 Pop Out Player
|
||||
</button>
|
||||
<button id="frameset-btn" class="btn btn-secondary" onclick="enableFramesetMode()" style="font-size: 0.9em;">
|
||||
🖼️ Enable Persistent Player
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Stream Quality Selector -->
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
<header>
|
||||
<h1>🎵 ASTEROID RADIO - LOGIN</h1>
|
||||
<nav class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/player">Player</a>
|
||||
<a href="/asteroid/status">Status</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/player-content" target="content-frame">Player</a>
|
||||
<a href="/asteroid/status" target="content-frame">Status</a>
|
||||
<a href="/asteroid/register">Register</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -0,0 +1,120 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<title data-text="title">Asteroid Radio - Web Player</title>
|
||||
<meta charset="utf-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1">
|
||||
<link rel="stylesheet" type="text/css" href="/asteroid/static/asteroid.css">
|
||||
<script src="/asteroid/static/js/auth-ui.js"></script>
|
||||
<script src="/asteroid/static/js/player.js"></script>
|
||||
</head>
|
||||
<body>
|
||||
<div class="container">
|
||||
<h1>🎵 WEB PLAYER</h1>
|
||||
<div class="nav">
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/profile" target="content-frame" data-show-if-logged-in>Profile</a>
|
||||
<a href="/asteroid/admin" target="content-frame" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/login" target="content-frame" data-show-if-logged-out>Login</a>
|
||||
<a href="/asteroid/register" target="content-frame" data-show-if-logged-out>Register</a>
|
||||
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout">Logout</a>
|
||||
</div>
|
||||
|
||||
<!-- Live Stream Section - Note about persistent player -->
|
||||
<div class="player-section">
|
||||
<h2 style="color: #00ff00;">🟢 Live Radio Stream</h2>
|
||||
<p><em>The live stream player is now in the persistent bar at the bottom of the page. It will continue playing as you navigate between pages!</em></p>
|
||||
</div>
|
||||
|
||||
<div id="now-playing" class="now-playing"></div>
|
||||
|
||||
<!-- Track Browser -->
|
||||
<div class="player-section">
|
||||
<h2>Personal Track Library</h2>
|
||||
<div class="track-browser">
|
||||
<input type="text" id="search-tracks" placeholder="Search tracks..." class="search-input">
|
||||
<select id="library-tracks-per-page" class="sort-select" onchange="changeLibraryTracksPerPage()" style="margin: 10px 0px;">
|
||||
<option value="10">10 per page</option>
|
||||
<option value="20" selected>20 per page</option>
|
||||
<option value="50">50 per page</option>
|
||||
</select>
|
||||
<div id="track-list" class="track-list">
|
||||
<div class="loading">Loading tracks...</div>
|
||||
</div>
|
||||
<!-- Pagination Controls -->
|
||||
<div id="library-pagination-controls" style="display: none; margin-top: 20px; text-align: center;">
|
||||
<button onclick="libraryGoToPage(1)" class="btn btn-secondary">« First</button>
|
||||
<button onclick="libraryPreviousPage()" class="btn btn-secondary">‹ Prev</button>
|
||||
<span id="library-page-info" style="margin: 0 15px; font-weight: bold;">Page 1 of 1</span>
|
||||
<button onclick="libraryNextPage()" class="btn btn-secondary">Next ›</button>
|
||||
<button onclick="libraryGoToLastPage()" class="btn btn-secondary">Last »</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Audio Player Widget -->
|
||||
<div class="player-section">
|
||||
<h2>Audio Player</h2>
|
||||
<div class="audio-player">
|
||||
<div class="now-playing">
|
||||
<div class="track-art">🎵</div>
|
||||
<div class="track-details">
|
||||
<div class="track-title" id="current-title">No track selected</div>
|
||||
<div class="track-artist" id="current-artist">Unknown Artist</div>
|
||||
<div class="track-album" id="current-album">Unknown Album</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<audio id="audio-player" controls preload="none" style="width: 100%; margin: 20px 0;">
|
||||
Your browser does not support the audio element.
|
||||
</audio>
|
||||
|
||||
<div class="player-controls">
|
||||
<button id="prev-btn" class="btn btn-secondary">⏮️ Previous</button>
|
||||
<button id="play-pause-btn" class="btn btn-primary">▶️ Play</button>
|
||||
<button id="next-btn" class="btn btn-secondary">⏭️ Next</button>
|
||||
<button id="shuffle-btn" class="btn btn-info">🔀 Shuffle</button>
|
||||
<button id="repeat-btn" class="btn btn-warning">🔁 Repeat</button>
|
||||
</div>
|
||||
|
||||
<div class="player-info">
|
||||
<div class="time-display">
|
||||
<span id="current-time">0:00</span> / <span id="total-time">0:00</span>
|
||||
</div>
|
||||
<div class="volume-control">
|
||||
<label for="volume-slider">🔊</label>
|
||||
<input type="range" id="volume-slider" min="0" max="100" value="50" class="volume-slider">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Playlist Management -->
|
||||
<div class="player-section">
|
||||
<h2>Playlists</h2>
|
||||
<div class="playlist-controls">
|
||||
<input type="text" id="new-playlist-name" placeholder="New playlist name..." class="playlist-input">
|
||||
<button id="create-playlist" class="btn btn-success">➕ Create Playlist</button>
|
||||
</div>
|
||||
|
||||
<div class="playlist-list">
|
||||
<div id="playlists-container">
|
||||
<div class="no-playlists">No playlists created yet.</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Queue -->
|
||||
<div class="player-section">
|
||||
<h2>Play Queue</h2>
|
||||
<div class="queue-controls">
|
||||
<button id="clear-queue" class="btn btn-danger">🗑️ Clear Queue</button>
|
||||
<button id="save-queue" class="btn btn-info">💾 Save as Playlist</button>
|
||||
</div>
|
||||
<div id="play-queue" class="play-queue">
|
||||
<div class="empty-queue">Queue is empty</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
|
|
@ -12,9 +12,9 @@
|
|||
<div class="container">
|
||||
<h1>🎵 WEB PLAYER</h1>
|
||||
<div class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/profile" data-show-if-logged-in>Profile</a>
|
||||
<a href="/asteroid/admin" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/profile" target="content-frame" data-show-if-logged-in>Profile</a>
|
||||
<a href="/asteroid/admin" target="content-frame" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/login" data-show-if-logged-out>Login</a>
|
||||
<a href="/asteroid/register" data-show-if-logged-out>Register</a>
|
||||
<a href="/asteroid/logout" data-show-if-logged-in class="btn-logout">Logout</a>
|
||||
|
|
|
|||
|
|
@ -12,9 +12,9 @@
|
|||
<div class="container">
|
||||
<h1>👤 USER PROFILE</h1>
|
||||
<div class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/player/">Player</a>
|
||||
<a href="/asteroid/admin/" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/player-content" target="content-frame">Player</a>
|
||||
<a href="/asteroid/admin" target="content-frame" data-show-if-admin>Admin</a>
|
||||
<a href="/asteroid/logout" class="btn-logout">Logout</a>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
|
|
@ -11,9 +11,9 @@
|
|||
<header>
|
||||
<h1>🎵 ASTEROID RADIO - REGISTER</h1>
|
||||
<nav class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/player">Player</a>
|
||||
<a href="/asteroid/status">Status</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/player-content" target="content-frame">Player</a>
|
||||
<a href="/asteroid/status" target="content-frame">Status</a>
|
||||
<a href="/asteroid/login">Login</a>
|
||||
</nav>
|
||||
</header>
|
||||
|
|
|
|||
|
|
@ -11,8 +11,8 @@
|
|||
<div class="container">
|
||||
<h1>👥 USER MANAGEMENT</h1>
|
||||
<div class="nav">
|
||||
<a href="/asteroid/">Home</a>
|
||||
<a href="/asteroid/admin">Admin</a>
|
||||
<a href="/asteroid/content" target="content-frame">Home</a>
|
||||
<a href="/asteroid/admin" target="content-frame">Admin</a>
|
||||
<a href="/asteroid/logout" class="btn-logout">Logout</a>
|
||||
</div>
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue