style.css aktualisiert
Für den neuen Bearbeite-Modus angepasst.
This commit is contained in:
parent
b5a5432668
commit
7caed0f0e7
1 changed files with 188 additions and 166 deletions
354
style.css
354
style.css
|
|
@ -1,169 +1,191 @@
|
||||||
:root {
|
document.addEventListener('DOMContentLoaded', function () {
|
||||||
--primary-color: #ff9999;
|
const presetContainer = document.getElementById('preset-container');
|
||||||
--header-height: 120px;
|
const stopButton = document.querySelector('.stop-button');
|
||||||
--padding-top: calc(10px + var(--header-height));
|
const currentStationName = document.getElementById('current-station-name');
|
||||||
--box-shadow: 0 2px 4px rgba(0, 0, 0, 0.1);
|
const presetModal = document.getElementById('preset-modal');
|
||||||
}
|
const tableBody = document.querySelector('#sortable-tbody');
|
||||||
|
const editPresetsButton = document.getElementById('edit-presets-button');
|
||||||
|
let currentSound = null;
|
||||||
|
let presets = [];
|
||||||
|
|
||||||
body {
|
initializeFooter();
|
||||||
font-family: Arial, sans-serif;
|
loadPresets();
|
||||||
text-align: center;
|
initializeEventListeners();
|
||||||
margin: 0;
|
|
||||||
padding: 20px;
|
|
||||||
padding-top: var(--padding-top);
|
|
||||||
}
|
|
||||||
|
|
||||||
.header {
|
function initializeFooter() {
|
||||||
background-color: #FFFFE3;
|
const currentYear = new Date().getFullYear();
|
||||||
height: var(--header-height);
|
document.getElementById('current-year').textContent = currentYear;
|
||||||
padding-bottom: 10px;
|
document.getElementById('server-name').textContent = window.location.hostname;
|
||||||
position: fixed;
|
|
||||||
top: 0;
|
|
||||||
left: 0;
|
|
||||||
width: 100%;
|
|
||||||
z-index: 1000;
|
|
||||||
box-shadow: var(--box-shadow);
|
|
||||||
}
|
|
||||||
|
|
||||||
.titel {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
gap: 10px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.titel img {
|
|
||||||
height: 30px;
|
|
||||||
width: auto;
|
|
||||||
}
|
|
||||||
|
|
||||||
.hidden {
|
|
||||||
display: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-button {
|
|
||||||
background-color: var(--primary-color);
|
|
||||||
color: #fff;
|
|
||||||
font-weight: bold;
|
|
||||||
border: none;
|
|
||||||
border-radius: 5px;
|
|
||||||
height: 30px;
|
|
||||||
padding: 4px 10px;
|
|
||||||
font-size: 18px;
|
|
||||||
margin: 0;
|
|
||||||
margin-left: auto;
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
position: relative;
|
|
||||||
top: -2px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.stop-button:focus {
|
|
||||||
outline: none;
|
|
||||||
box-shadow: 0 0 5px rgba(255, 77, 77, 0.75);
|
|
||||||
}
|
|
||||||
|
|
||||||
.current-station {
|
|
||||||
font-weight: bold;
|
|
||||||
font-size: 16px;
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
#aktueller-sender {
|
|
||||||
background-color: #d2f8d2;
|
|
||||||
border-radius: 5px;
|
|
||||||
padding: 10px 20px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-button, .delete-button, .move-button {
|
|
||||||
display: none; /* Standardmäßig ausgeblendet */
|
|
||||||
}
|
|
||||||
|
|
||||||
.edit-button.hidden, .delete-button.hidden, .move-button.hidden {
|
|
||||||
display: inline-block; /* Wird angezeigt, wenn die Klasse 'hidden' entfernt wird */
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
.preset-container {
|
|
||||||
display: grid;
|
|
||||||
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
|
|
||||||
grid-gap: 20px;
|
|
||||||
margin-top: 30px;
|
|
||||||
margin-bottom: 30px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-item {
|
|
||||||
background-color: #f1f1f1;
|
|
||||||
padding: 15px;
|
|
||||||
border-radius: 5px;
|
|
||||||
box-shadow: var(--box-shadow);
|
|
||||||
cursor: pointer;
|
|
||||||
transition: background-color 0.3s ease;
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-item h3 {
|
|
||||||
margin: 0;
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-item button {
|
|
||||||
margin-left: 2px;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-item:hover {
|
|
||||||
background-color: #e6e6e6;
|
|
||||||
box-shadow: 0 4px 8px rgba(0, 0, 0, 0.15);
|
|
||||||
}
|
|
||||||
|
|
||||||
.new-preset-container {
|
|
||||||
margin-bottom: 15px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.button-container {
|
|
||||||
margin-bottom: 5px;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-set {
|
|
||||||
margin: 0;
|
|
||||||
text-align: center;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-set a {
|
|
||||||
color: #666;
|
|
||||||
text-decoration: underline;
|
|
||||||
}
|
|
||||||
|
|
||||||
.preset-set a:hover {
|
|
||||||
text-decoration: underline;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer {
|
|
||||||
display: flex;
|
|
||||||
align-items: center;
|
|
||||||
justify-content: center;
|
|
||||||
margin: 20px 0;
|
|
||||||
font-size: 12px;
|
|
||||||
color: #666;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer a {
|
|
||||||
color: #666;
|
|
||||||
text-decoration: none;
|
|
||||||
}
|
|
||||||
|
|
||||||
.footer a:hover {
|
|
||||||
text-decoration: none;
|
|
||||||
color: #333;
|
|
||||||
}
|
|
||||||
|
|
||||||
@media (max-width: 600px) {
|
|
||||||
.preset-container {
|
|
||||||
grid-template-columns: 1fr;
|
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
function updateTitle(stationName) {
|
||||||
|
document.title = stationName ? `${stationName} - Radioplayer mit Presets` : "Radioplayer mit Presets";
|
||||||
|
}
|
||||||
|
|
||||||
|
function initializeEventListeners() {
|
||||||
|
stopButton.addEventListener('click', stopPlayback);
|
||||||
|
editPresetsButton.addEventListener('click', openModal);
|
||||||
|
}
|
||||||
|
|
||||||
|
async function loadPresets() {
|
||||||
|
presets = JSON.parse(localStorage.getItem('presets')) || [];
|
||||||
|
if (presets.length === 0) {
|
||||||
|
try {
|
||||||
|
const response = await fetch('webradio_presets.json');
|
||||||
|
if (!response.ok) throw new Error('Datei konnte nicht geladen werden');
|
||||||
|
presets = await response.json();
|
||||||
|
localStorage.setItem('presets', JSON.stringify(presets));
|
||||||
|
} catch (error) {
|
||||||
|
alert('Fehler beim Laden der Presets: ' + error.message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
displayPresets(presets);
|
||||||
|
renderPresets();
|
||||||
|
initSortable();
|
||||||
|
}
|
||||||
|
|
||||||
|
function displayPresets(presets) {
|
||||||
|
presetContainer.innerHTML = '';
|
||||||
|
presets.forEach(preset => addNewPreset(preset.name, preset.url));
|
||||||
|
}
|
||||||
|
|
||||||
|
function addNewPreset(name, url) {
|
||||||
|
const presetItem = document.createElement('div');
|
||||||
|
presetItem.classList.add('preset-item');
|
||||||
|
presetItem.dataset.streamUrl = url;
|
||||||
|
presetItem.innerHTML = `<h3>${name}</h3>`;
|
||||||
|
presetItem.addEventListener('click', () => playStream(url, presetItem));
|
||||||
|
presetContainer.appendChild(presetItem);
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderPresets() {
|
||||||
|
tableBody.innerHTML = '';
|
||||||
|
presets.forEach((preset, index) => {
|
||||||
|
const row = document.createElement('tr');
|
||||||
|
row.setAttribute('data-index', index);
|
||||||
|
row.innerHTML = `
|
||||||
|
<td class="drag-handle">☰</td>
|
||||||
|
<td><input type="text" value="${preset.name}" onchange="changeName(${index}, this.value)"></td>
|
||||||
|
<td><input type="text" value="${preset.url}" onchange="changeURL(${index}, this.value)"></td>
|
||||||
|
<td><button class="delete-btn" onclick="deletePreset(${index})"><i class="fas fa-trash-alt" style="color:grey"></i></button></td>
|
||||||
|
`;
|
||||||
|
tableBody.appendChild(row);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function playStream(url, item) {
|
||||||
|
stopPlayback();
|
||||||
|
currentSound = new Howl({
|
||||||
|
src: [url],
|
||||||
|
html5: true,
|
||||||
|
volume: 0.5,
|
||||||
|
onplay: () => {
|
||||||
|
stopButton.classList.remove('hidden');
|
||||||
|
updateTitle(item.querySelector('h3').textContent);
|
||||||
|
currentStationName.textContent = 'Es läuft: ' + item.querySelector('h3').textContent;
|
||||||
|
},
|
||||||
|
onstop: () => {
|
||||||
|
stopButton.classList.add('hidden');
|
||||||
|
currentStationName.textContent = 'Wähle einen Sender aus';
|
||||||
|
updateTitle('');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
currentSound.play();
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPlayback() {
|
||||||
|
if (currentSound) {
|
||||||
|
currentSound.stop();
|
||||||
|
currentSound = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function openModal() {
|
||||||
|
presetModal.classList.remove('hidden');
|
||||||
|
presetModal.style.display = 'block';
|
||||||
|
renderPresets();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.closeModal = function() {
|
||||||
|
presetModal.classList.add('hidden');
|
||||||
|
presetModal.style.display = 'none';
|
||||||
|
}
|
||||||
|
|
||||||
|
window.addPreset = function() {
|
||||||
|
presets.push({ name: 'Neuer Sender', url: '' });
|
||||||
|
renderPresets();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.changeName = function(index, newName) {
|
||||||
|
presets[index].name = newName;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.changeURL = function(index, newURL) {
|
||||||
|
presets[index].url = newURL;
|
||||||
|
}
|
||||||
|
|
||||||
|
window.deletePreset = function(index) {
|
||||||
|
presets.splice(index, 1);
|
||||||
|
renderPresets();
|
||||||
|
}
|
||||||
|
|
||||||
|
window.saveAndClose = function() {
|
||||||
|
savePresets();
|
||||||
|
closeModal();
|
||||||
|
location.reload();
|
||||||
|
}
|
||||||
|
|
||||||
|
function savePresets() {
|
||||||
|
localStorage.setItem('presets', JSON.stringify(presets));
|
||||||
|
}
|
||||||
|
|
||||||
|
function initSortable() {
|
||||||
|
const sortable = new Sortable(tableBody, {
|
||||||
|
handle: '.drag-handle',
|
||||||
|
animation: 150,
|
||||||
|
onEnd: function (evt) {
|
||||||
|
const newOrder = Array.from(tableBody.children).map(row => parseInt(row.getAttribute('data-index')));
|
||||||
|
presets = newOrder.map(index => presets[index]);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
window.exportPreset = function() {
|
||||||
|
const presetsJSON = JSON.stringify(presets, null, 2);
|
||||||
|
const blob = new Blob([presetsJSON], { type: 'application/json' });
|
||||||
|
const url = URL.createObjectURL(blob);
|
||||||
|
const a = document.createElement('a');
|
||||||
|
a.href = url;
|
||||||
|
a.download = 'radio_presets.json';
|
||||||
|
document.body.appendChild(a);
|
||||||
|
a.click();
|
||||||
|
document.body.removeChild(a);
|
||||||
|
URL.revokeObjectURL(url);
|
||||||
|
}
|
||||||
|
|
||||||
|
window.importPreset = function() {
|
||||||
|
const input = document.createElement('input');
|
||||||
|
input.type = 'file';
|
||||||
|
input.accept = 'application/json';
|
||||||
|
input.onchange = function(event) {
|
||||||
|
const file = event.target.files[0];
|
||||||
|
if (file) {
|
||||||
|
const reader = new FileReader();
|
||||||
|
reader.onload = function(e) {
|
||||||
|
try {
|
||||||
|
const importedPresets = JSON.parse(e.target.result);
|
||||||
|
presets = importedPresets;
|
||||||
|
localStorage.setItem('presets', JSON.stringify(presets));
|
||||||
|
renderPresets();
|
||||||
|
displayPresets(presets);
|
||||||
|
location.reload();
|
||||||
|
} catch (error) {
|
||||||
|
alert('Fehler beim Importieren der Presets: Ungültige Datei.');
|
||||||
|
}
|
||||||
|
};
|
||||||
|
reader.readAsText(file);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
input.click();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue