fOERbico/docs/relilab-nostr-formular.html

1010 lines
34 KiB
HTML
Raw Normal View History

<!DOCTYPE html>
<html lang="de">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>relilab Session einreichen</title>
<!-- Fonts -->
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Yanone+Kaffeesatz:wght@300;400;500;600;700&family=Source+Sans+3:wght@300;400;500;600&display=swap" rel="stylesheet">
<!-- EasyMDE Markdown Editor -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/easymde/2.18.0/easymde.min.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/easymde/2.18.0/easymde.min.js" defer></script>
<style>
:root {
--rl-blue: #34b2f6;
--rl-purple: #d225f8;
--rl-orange: #ff8103;
--rl-pink: #e54d9a;
--rl-dark: #1a1a2e;
--rl-card: #ffffff;
--rl-bg: #f4f6fb;
--rl-text: #2d2d3a;
--rl-muted: #7a7a8e;
--rl-border: #e0e4ef;
--rl-success: #22c55e;
--rl-error: #ef4444;
--gradient-main: linear-gradient(135deg, var(--rl-blue), var(--rl-purple), var(--rl-pink), var(--rl-orange));
}
* { margin: 0; padding: 0; box-sizing: border-box; }
body {
font-family: 'Source Sans 3', sans-serif;
background: var(--rl-bg);
color: var(--rl-text);
min-height: 100vh;
line-height: 1.6;
}
/* ====== HEADER ====== */
.header {
background: var(--rl-dark);
position: relative;
overflow: hidden;
padding: 2rem 1.5rem 3rem;
text-align: center;
}
.header::before {
content: '';
position: absolute;
top: 0; left: 0; right: 0; bottom: 0;
background: var(--gradient-main);
opacity: 0.12;
}
.header::after {
content: '';
position: absolute;
bottom: -2px; left: 0; right: 0;
height: 40px;
background: var(--rl-bg);
clip-path: ellipse(55% 100% at 50% 100%);
}
.header-logo {
position: relative;
z-index: 1;
height: 64px;
margin-bottom: 1rem;
filter: drop-shadow(0 2px 8px rgba(0,0,0,0.3));
}
.header h1 {
font-family: 'Yanone Kaffeesatz', sans-serif;
font-weight: 700;
font-size: 2.4rem;
color: #fff;
position: relative;
z-index: 1;
letter-spacing: 0.02em;
}
.header h1 span {
background: var(--gradient-main);
-webkit-background-clip: text;
-webkit-text-fill-color: transparent;
background-clip: text;
}
.header p {
font-family: 'Yanone Kaffeesatz', sans-serif;
font-weight: 300;
font-size: 1.25rem;
color: rgba(255,255,255,0.7);
position: relative;
z-index: 1;
margin-top: 0.25rem;
}
/* ====== MAIN CONTAINER ====== */
.container {
max-width: 740px;
margin: -1rem auto 3rem;
padding: 0 1.25rem;
position: relative;
z-index: 2;
}
/* ====== SECTIONS ====== */
.form-section {
background: var(--rl-card);
border-radius: 16px;
padding: 2rem 2rem 1.5rem;
margin-bottom: 1.25rem;
box-shadow: 0 1px 4px rgba(0,0,0,0.04), 0 8px 24px rgba(0,0,0,0.04);
border: 1px solid var(--rl-border);
transition: box-shadow 0.3s ease;
}
.form-section:hover {
box-shadow: 0 2px 8px rgba(0,0,0,0.06), 0 12px 32px rgba(0,0,0,0.06);
}
.section-label {
font-family: 'Yanone Kaffeesatz', sans-serif;
font-weight: 600;
font-size: 1.35rem;
color: var(--rl-dark);
margin-bottom: 1.25rem;
display: flex;
align-items: center;
gap: 0.5rem;
}
.section-label .icon {
width: 28px;
height: 28px;
border-radius: 8px;
display: flex;
align-items: center;
justify-content: center;
font-size: 0.95rem;
flex-shrink: 0;
}
.icon-blue { background: rgba(52,178,246,0.12); color: var(--rl-blue); }
.icon-purple { background: rgba(210,37,248,0.12); color: var(--rl-purple); }
.icon-orange { background: rgba(255,129,3,0.12); color: var(--rl-orange); }
.icon-pink { background: rgba(229,77,154,0.12); color: var(--rl-pink); }
/* ====== FORM ELEMENTS ====== */
.field { margin-bottom: 1.25rem; }
.field:last-child { margin-bottom: 0; }
label {
display: block;
font-weight: 500;
font-size: 0.92rem;
color: var(--rl-text);
margin-bottom: 0.35rem;
}
label .optional {
font-weight: 400;
color: var(--rl-muted);
font-size: 0.82rem;
}
label .required {
color: var(--rl-pink);
}
input[type="text"],
input[type="email"],
input[type="url"],
input[type="date"],
input[type="time"],
input[type="password"],
select {
width: 100%;
padding: 0.65rem 0.9rem;
border: 1.5px solid var(--rl-border);
border-radius: 10px;
font-family: 'Source Sans 3', sans-serif;
font-size: 0.95rem;
color: var(--rl-text);
background: #fff;
transition: border-color 0.2s, box-shadow 0.2s;
outline: none;
}
input:focus, select:focus {
border-color: var(--rl-blue);
box-shadow: 0 0 0 3px rgba(52,178,246,0.12);
}
input::placeholder { color: var(--rl-muted); opacity: 0.7; }
.row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 1rem;
}
@media (max-width: 520px) {
.row { grid-template-columns: 1fr; }
}
/* ====== FILE UPLOAD ====== */
.file-drop {
border: 2px dashed var(--rl-border);
border-radius: 12px;
padding: 2rem;
text-align: center;
cursor: pointer;
transition: border-color 0.2s, background 0.2s;
position: relative;
}
.file-drop:hover, .file-drop.dragover {
border-color: var(--rl-blue);
background: rgba(52,178,246,0.04);
}
.file-drop.has-file {
border-color: var(--rl-success);
background: rgba(34,197,94,0.04);
}
.file-drop input[type="file"] {
position: absolute;
inset: 0;
opacity: 0;
cursor: pointer;
}
.file-drop-icon { font-size: 2rem; margin-bottom: 0.5rem; }
.file-drop-text { font-size: 0.9rem; color: var(--rl-muted); }
.file-drop-text strong { color: var(--rl-blue); }
.file-preview {
margin-top: 1rem;
display: none;
}
.file-preview img {
max-width: 100%;
max-height: 200px;
border-radius: 8px;
box-shadow: 0 2px 8px rgba(0,0,0,0.1);
}
.file-preview .file-name {
font-size: 0.85rem;
color: var(--rl-muted);
margin-top: 0.5rem;
}
.file-remove {
display: inline-block;
margin-top: 0.5rem;
font-size: 0.82rem;
color: var(--rl-error);
cursor: pointer;
text-decoration: underline;
background: none;
border: none;
font-family: inherit;
}
/* ====== CC LICENSE SELECT ====== */
.license-grid {
display: flex;
flex-direction: column;
gap: 0.5rem;
}
.license-option {
display: flex;
align-items: center;
gap: 0.65rem;
padding: 0.55rem 0.85rem;
border-radius: 10px;
cursor: pointer;
border: 1.5px solid transparent;
transition: all 0.2s;
font-size: 0.9rem;
}
.license-option:hover {
background: rgba(0,0,0,0.02);
}
.license-option input[type="radio"] {
accent-color: var(--rl-blue);
width: 16px;
height: 16px;
flex-shrink: 0;
}
.license-option.selected {
border-color: var(--rl-blue);
background: rgba(52,178,246,0.06);
}
.license-green {
background: rgba(34,197,94,0.06);
border-color: rgba(34,197,94,0.2);
}
.license-green:hover { background: rgba(34,197,94,0.1); }
.license-green.selected {
border-color: var(--rl-success);
background: rgba(34,197,94,0.12);
}
.license-red {
background: rgba(239,68,68,0.04);
border-color: rgba(239,68,68,0.15);
}
.license-red:hover { background: rgba(239,68,68,0.08); }
.license-red.selected {
border-color: var(--rl-error);
background: rgba(239,68,68,0.1);
}
.license-badge {
font-family: 'Yanone Kaffeesatz', sans-serif;
font-weight: 600;
font-size: 0.72rem;
padding: 0.15rem 0.45rem;
border-radius: 4px;
text-transform: uppercase;
letter-spacing: 0.04em;
flex-shrink: 0;
}
.badge-green { background: rgba(34,197,94,0.15); color: #16a34a; }
.badge-red { background: rgba(239,68,68,0.12); color: #dc2626; }
/* ====== CHECKBOX GRID (Zielgruppe) ====== */
.checkbox-grid {
display: flex;
flex-wrap: wrap;
gap: 0.5rem;
}
.chip {
display: flex;
align-items: center;
gap: 0.4rem;
padding: 0.4rem 0.85rem;
border-radius: 50px;
border: 1.5px solid var(--rl-border);
cursor: pointer;
font-size: 0.88rem;
transition: all 0.2s;
user-select: none;
}
.chip:hover { border-color: var(--rl-purple); background: rgba(210,37,248,0.04); }
.chip input[type="checkbox"] { display: none; }
.chip.active {
border-color: var(--rl-purple);
background: rgba(210,37,248,0.1);
color: var(--rl-purple);
font-weight: 500;
}
.chip .checkmark { font-size: 0.75rem; display: none; }
.chip.active .checkmark { display: inline; }
/* ====== TOGGLE / VIDEOKONFERENZ ====== */
.toggle-row {
display: flex;
align-items: center;
gap: 0.75rem;
margin-bottom: 1rem;
}
.toggle {
position: relative;
width: 44px;
height: 24px;
flex-shrink: 0;
}
.toggle input { opacity: 0; width: 0; height: 0; }
.toggle-slider {
position: absolute;
cursor: pointer;
inset: 0;
background: var(--rl-border);
border-radius: 24px;
transition: background 0.25s;
}
.toggle-slider::before {
content: '';
position: absolute;
height: 18px;
width: 18px;
left: 3px;
bottom: 3px;
background: white;
border-radius: 50%;
transition: transform 0.25s;
box-shadow: 0 1px 3px rgba(0,0,0,0.15);
}
.toggle input:checked + .toggle-slider {
background: var(--rl-orange);
}
.toggle input:checked + .toggle-slider::before {
transform: translateX(20px);
}
.toggle-label {
font-size: 0.9rem;
color: var(--rl-text);
}
.custom-url-field {
display: none;
margin-top: 0.75rem;
padding: 0.85rem;
border-radius: 10px;
background: rgba(255,129,3,0.04);
border: 1px solid rgba(255,129,3,0.15);
}
.custom-url-field.visible { display: block; }
.zoom-default {
font-size: 0.85rem;
color: var(--rl-muted);
margin-top: 0.35rem;
}
.zoom-default a { color: var(--rl-blue); text-decoration: none; }
.zoom-default a:hover { text-decoration: underline; }
/* ====== SUBMIT ====== */
.submit-section {
text-align: center;
padding: 1.5rem 2rem 2rem;
}
.submit-btn {
font-family: 'Yanone Kaffeesatz', sans-serif;
font-weight: 700;
font-size: 1.35rem;
letter-spacing: 0.03em;
padding: 0.85rem 3rem;
border: none;
border-radius: 50px;
color: #fff;
background: var(--gradient-main);
background-size: 200% 200%;
cursor: pointer;
transition: all 0.3s;
box-shadow: 0 4px 16px rgba(52,178,246,0.25);
position: relative;
overflow: hidden;
}
.submit-btn:hover {
background-position: 100% 0;
box-shadow: 0 6px 24px rgba(210,37,248,0.3);
transform: translateY(-1px);
}
.submit-btn:active { transform: translateY(0); }
.submit-btn:disabled {
opacity: 0.6;
cursor: not-allowed;
transform: none;
}
.submit-btn .spinner {
display: none;
width: 20px;
height: 20px;
border: 2.5px solid rgba(255,255,255,0.3);
border-top-color: #fff;
border-radius: 50%;
animation: spin 0.7s linear infinite;
margin-right: 0.5rem;
vertical-align: middle;
}
@keyframes spin { to { transform: rotate(360deg); } }
.submit-btn.loading .spinner { display: inline-block; }
.submit-btn.loading .btn-text { opacity: 0.8; }
/* ====== STATUS MESSAGES ====== */
.status-msg {
margin-top: 1.25rem;
padding: 1rem 1.25rem;
border-radius: 12px;
font-size: 0.92rem;
display: none;
animation: fadeIn 0.3s ease;
}
@keyframes fadeIn { from { opacity: 0; transform: translateY(8px); } to { opacity: 1; transform: translateY(0); } }
.status-msg.success {
display: block;
background: rgba(34,197,94,0.08);
border: 1px solid rgba(34,197,94,0.25);
color: #16a34a;
}
.status-msg.error {
display: block;
background: rgba(239,68,68,0.08);
border: 1px solid rgba(239,68,68,0.2);
color: #dc2626;
}
/* ====== EASYMDE OVERRIDES ====== */
.EasyMDEContainer .CodeMirror {
border-radius: 10px;
border-color: var(--rl-border);
font-family: 'Source Sans 3', sans-serif;
font-size: 0.95rem;
min-height: 120px;
}
.EasyMDEContainer .CodeMirror-focused {
border-color: var(--rl-blue);
box-shadow: 0 0 0 3px rgba(52,178,246,0.12);
}
.EasyMDEContainer .editor-toolbar {
border-color: var(--rl-border);
border-radius: 10px 10px 0 0;
}
.EasyMDEContainer .editor-toolbar button:hover {
background: rgba(52,178,246,0.08);
}
.editor-toolbar button.active, .editor-toolbar button:hover {
border-color: var(--rl-blue);
}
/* ====== FOOTER ====== */
.footer {
text-align: center;
padding: 1.5rem;
font-size: 0.8rem;
color: var(--rl-muted);
}
.footer a { color: var(--rl-blue); text-decoration: none; }
/* ====== RESPONSIVE ====== */
@media (max-width: 520px) {
.header h1 { font-size: 1.8rem; }
.form-section { padding: 1.5rem 1.25rem 1.25rem; }
.submit-btn { width: 100%; }
}
</style>
</head>
<body>
<!-- ====== HEADER ====== -->
<header class="header">
<img src="https://relilab.org/wp-content/uploads/2021/06/Design-ohne-Titel.png" alt="relilab Logo" class="header-logo">
<h1><span>Session</span> einreichen</h1>
<p>Erstelle ein Nostr-Kalender-Event für das relilab</p>
</header>
<!-- ====== FORM ====== -->
<main class="container">
<form id="eventForm" novalidate>
<!-- KONTAKT -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-blue"></span>
Kontakt
</div>
<div class="field">
<label for="email">E-Mail-Adresse <span class="optional">(optional)</span></label>
<input type="email" id="email" name="email" placeholder="deine@email.de">
</div>
</div>
<!-- SESSION -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-purple">📋</span>
Session-Details
</div>
<div class="field">
<label for="title">Session-Titel <span class="required">*</span></label>
<input type="text" id="title" name="title" placeholder="z.B. KI im Religionsunterricht" required>
</div>
<div class="field">
<label for="summary">Kurzbeschreibung <span class="optional">(optional)</span></label>
<textarea id="summary" name="summary"></textarea>
</div>
<div class="field">
<label for="content">Inhaltsbeschreibung <span class="optional">(optional)</span></label>
<textarea id="content" name="content"></textarea>
</div>
</div>
<!-- BILD -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-orange">🖼</span>
Beitragsbild
</div>
<div class="field">
<div class="file-drop" id="fileDrop">
<input type="file" id="image" name="image" accept="image/jpeg,image/png,image/webp">
<div class="file-drop-icon">📷</div>
<div class="file-drop-text">Bild hierher ziehen oder <strong>klicken</strong> zum Auswählen<br><small>JPG, PNG oder WebP</small></div>
</div>
<div class="file-preview" id="filePreview">
<img id="previewImg" src="" alt="Vorschau">
<div class="file-name" id="fileName"></div>
<button type="button" class="file-remove" id="fileRemove">Bild entfernen</button>
</div>
</div>
<div id="imageMetaFields" style="display:none;">
<div class="field">
<label for="imageCredit">Bildquelle / Credit <span class="optional">(optional)</span></label>
<input type="text" id="imageCredit" name="imageCredit" placeholder="z.B. Foto: Max Mustermann">
</div>
<div class="field">
<label>Creative-Commons-Lizenz <span class="required">*</span></label>
<div class="license-grid" id="licenseGrid">
<!-- Grün (empfohlen) -->
<label class="license-option license-green">
<input type="radio" name="license" value="CC0">
<span class="license-badge badge-green">empfohlen</span>
<span><strong>CC0</strong> Public Domain / Keine Rechte vorbehalten</span>
</label>
<label class="license-option license-green">
<input type="radio" name="license" value="CC BY 4.0">
<span class="license-badge badge-green">empfohlen</span>
<span><strong>CC BY</strong> Namensnennung</span>
</label>
<label class="license-option license-green">
<input type="radio" name="license" value="CC BY-SA 4.0">
<span class="license-badge badge-green">empfohlen</span>
<span><strong>CC BY-SA</strong> Namensnennung, Weitergabe unter gleichen Bedingungen</span>
</label>
<!-- Rot (einschränkend) -->
<label class="license-option license-red">
<input type="radio" name="license" value="CC BY-NC 4.0">
<span class="license-badge badge-red">einschränkend</span>
<span><strong>CC BY-NC</strong> Nicht kommerziell</span>
</label>
<label class="license-option license-red">
<input type="radio" name="license" value="CC BY-NC-SA 4.0">
<span class="license-badge badge-red">einschränkend</span>
<span><strong>CC BY-NC-SA</strong> Nicht kommerziell, Weitergabe unter gleichen Bed.</span>
</label>
<label class="license-option license-red">
<input type="radio" name="license" value="CC BY-ND 4.0">
<span class="license-badge badge-red">einschränkend</span>
<span><strong>CC BY-ND</strong> Keine Bearbeitung</span>
</label>
<label class="license-option license-red">
<input type="radio" name="license" value="CC BY-NC-ND 4.0">
<span class="license-badge badge-red">einschränkend</span>
<span><strong>CC BY-NC-ND</strong> Nicht kommerziell, Keine Bearbeitung</span>
</label>
</div>
</div>
</div>
</div>
<!-- DATUM & ZEIT -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-pink">📅</span>
Datum & Uhrzeit
</div>
<div class="row">
<div class="field">
<label for="startDate">Start-Datum <span class="required">*</span></label>
<input type="date" id="startDate" name="startDate" required>
</div>
<div class="field">
<label for="startTime">Start-Uhrzeit <span class="required">*</span></label>
<input type="time" id="startTime" name="startTime" required>
</div>
</div>
<div class="row">
<div class="field">
<label for="endDate">End-Datum <span class="required">*</span></label>
<input type="date" id="endDate" name="endDate" required>
</div>
<div class="field">
<label for="endTime">End-Uhrzeit <span class="required">*</span></label>
<input type="time" id="endTime" name="endTime" required>
</div>
</div>
</div>
<!-- VIDEOKONFERENZ -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-blue">🎥</span>
Videokonferenz
</div>
<div class="zoom-default">
Standard: <a href="https://relilab.org/live/" target="_blank" rel="noopener">relilab-Zoom (relilab.org/live)</a>
</div>
<div class="toggle-row" style="margin-top: 0.75rem;">
<label class="toggle">
<input type="checkbox" id="customZoom">
<span class="toggle-slider"></span>
</label>
<span class="toggle-label">Veranstaltung findet <strong>nicht</strong> im relilab-Zoom statt</span>
</div>
<div class="custom-url-field" id="customUrlField">
<div class="field">
<label for="customUrl">Videokonferenz-URL <span class="required">*</span></label>
<input type="url" id="customUrl" name="customUrl" placeholder="https://meet.example.com/...">
</div>
</div>
</div>
<!-- ZIELGRUPPE -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-purple">🎯</span>
Zielgruppe
</div>
<div class="checkbox-grid" id="audienceGrid">
<label class="chip"><input type="checkbox" name="audience" value="elementar"><span class="checkmark"></span> Elementar</label>
<label class="chip"><input type="checkbox" name="audience" value="Grundschule"><span class="checkmark"></span> Grundschule</label>
<label class="chip"><input type="checkbox" name="audience" value="Sek1"><span class="checkmark"></span> Sek 1</label>
<label class="chip"><input type="checkbox" name="audience" value="Sek2"><span class="checkmark"></span> Sek 2</label>
<label class="chip"><input type="checkbox" name="audience" value="BRU"><span class="checkmark"></span> BRU</label>
<label class="chip"><input type="checkbox" name="audience" value="Erwachsenenbildung"><span class="checkmark"></span> Erwachsenenbildung</label>
<label class="chip"><input type="checkbox" name="audience" value="Hochschule"><span class="checkmark"></span> Hochschule</label>
</div>
</div>
<!-- HASHTAGS -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-orange">🏷</span>
Hashtags / Kategorien
</div>
<div class="field">
<label for="hashtags">Hashtags <span class="optional">(kommagetrennt, optional)</span></label>
<input type="text" id="hashtags" name="hashtags" placeholder="z.B. ki, religionsunterricht, digital">
</div>
</div>
<!-- AUTH -->
<div class="form-section">
<div class="section-label">
<span class="icon icon-pink">🔑</span>
Authentifizierung
</div>
<div class="field">
<label for="token">Zugangs-Token <span class="required">*</span></label>
<input type="password" id="token" name="token" placeholder="Dein Passwort / Token" required>
</div>
</div>
<!-- SUBMIT -->
<div class="form-section submit-section">
<button type="submit" class="submit-btn" id="submitBtn">
<span class="spinner"></span>
<span class="btn-text">Session veröffentlichen</span>
</button>
<div class="status-msg" id="statusMsg"></div>
</div>
</form>
</main>
<footer class="footer">
relilab Religionspädagogisches Labor · Powered by <a href="https://nostr.com" target="_blank" rel="noopener">Nostr</a>
</footer>
<script>
// ============================================
// KONFIGURATION Webhook-URL hier eintragen!
// ============================================
const WEBHOOK_URL = 'https://DEIN-N8N-SERVER.example.com/webhook/nostr-calendar-event';
document.addEventListener('DOMContentLoaded', () => {
// ============================================
// WYSIWYG Editors (EasyMDE)
// ============================================
let summaryEditor, contentEditor;
function initEditors() {
if (typeof EasyMDE === 'undefined') {
// Fallback: retry after a short delay
setTimeout(initEditors, 200);
return;
}
summaryEditor = new EasyMDE({
element: document.getElementById('summary'),
placeholder: 'Kurzer Teaser-Text zur Session…',
spellChecker: false,
status: false,
toolbar: ['bold', 'italic', 'link', '|', 'preview'],
minHeight: '80px',
});
contentEditor = new EasyMDE({
element: document.getElementById('content'),
placeholder: 'Ausführliche Beschreibung der Session-Inhalte…',
spellChecker: false,
status: ['lines', 'words'],
toolbar: ['bold', 'italic', 'heading', '|', 'unordered-list', 'ordered-list', '|', 'link', 'image', '|', 'preview', 'side-by-side'],
minHeight: '160px',
});
}
initEditors();
// ============================================
// AUTO-FILL: Start → End
// ============================================
const startDate = document.getElementById('startDate');
const startTime = document.getElementById('startTime');
const endDate = document.getElementById('endDate');
const endTime = document.getElementById('endTime');
let endManuallyEdited = false;
startDate.addEventListener('change', () => {
if (!endManuallyEdited || endDate.value === '' || endDate.value === startDate.dataset.prev) {
endDate.value = startDate.value;
}
startDate.dataset.prev = startDate.value;
});
startTime.addEventListener('change', () => {
if (!endManuallyEdited || endTime.value === '' || endTime.value === startTime.dataset.prev) {
endTime.value = startTime.value;
}
startTime.dataset.prev = startTime.value;
});
endDate.addEventListener('input', () => { endManuallyEdited = true; });
endTime.addEventListener('input', () => { endManuallyEdited = true; });
// ============================================
// FILE UPLOAD / PREVIEW
// ============================================
const fileDrop = document.getElementById('fileDrop');
const fileInput = document.getElementById('image');
const filePreview = document.getElementById('filePreview');
const previewImg = document.getElementById('previewImg');
const fileNameEl = document.getElementById('fileName');
const fileRemove = document.getElementById('fileRemove');
const imageMetaFields = document.getElementById('imageMetaFields');
function showImagePreview(file) {
const reader = new FileReader();
reader.onload = (e) => {
previewImg.src = e.target.result;
fileNameEl.textContent = file.name + ' (' + (file.size / 1024).toFixed(0) + ' KB)';
filePreview.style.display = 'block';
fileDrop.classList.add('has-file');
imageMetaFields.style.display = 'block';
};
reader.readAsDataURL(file);
}
fileInput.addEventListener('change', (e) => {
if (e.target.files.length > 0) showImagePreview(e.target.files[0]);
});
fileDrop.addEventListener('dragover', (e) => { e.preventDefault(); fileDrop.classList.add('dragover'); });
fileDrop.addEventListener('dragleave', () => { fileDrop.classList.remove('dragover'); });
fileDrop.addEventListener('drop', (e) => {
e.preventDefault();
fileDrop.classList.remove('dragover');
if (e.dataTransfer.files.length > 0) {
fileInput.files = e.dataTransfer.files;
showImagePreview(e.dataTransfer.files[0]);
}
});
fileRemove.addEventListener('click', () => {
fileInput.value = '';
filePreview.style.display = 'none';
fileDrop.classList.remove('has-file');
imageMetaFields.style.display = 'none';
});
// ============================================
// LICENSE SELECTION HIGHLIGHT
// ============================================
document.querySelectorAll('#licenseGrid .license-option').forEach(opt => {
const radio = opt.querySelector('input[type="radio"]');
radio.addEventListener('change', () => {
document.querySelectorAll('#licenseGrid .license-option').forEach(o => o.classList.remove('selected'));
opt.classList.add('selected');
});
});
// ============================================
// AUDIENCE CHIPS
// ============================================
document.querySelectorAll('#audienceGrid .chip').forEach(chip => {
chip.addEventListener('click', (e) => {
// Let the checkbox toggle naturally, then update class
setTimeout(() => {
const cb = chip.querySelector('input[type="checkbox"]');
chip.classList.toggle('active', cb.checked);
}, 0);
});
});
// ============================================
// CUSTOM ZOOM TOGGLE
// ============================================
const customZoom = document.getElementById('customZoom');
const customUrlField = document.getElementById('customUrlField');
customZoom.addEventListener('change', () => {
customUrlField.classList.toggle('visible', customZoom.checked);
if (!customZoom.checked) {
document.getElementById('customUrl').value = '';
}
});
// ============================================
// FORM SUBMISSION
// ============================================
const form = document.getElementById('eventForm');
const submitBtn = document.getElementById('submitBtn');
const statusMsg = document.getElementById('statusMsg');
form.addEventListener('submit', async (e) => {
e.preventDefault();
statusMsg.className = 'status-msg';
statusMsg.style.display = 'none';
// Validation
const title = document.getElementById('title').value.trim();
const sDate = startDate.value;
const sTime = startTime.value;
const eDate = endDate.value;
const eTime = endTime.value;
const token = document.getElementById('token').value;
if (!title) return showError('Bitte gib einen Session-Titel ein.');
if (!sDate || !sTime) return showError('Bitte gib Start-Datum und -Uhrzeit ein.');
if (!eDate || !eTime) return showError('Bitte gib End-Datum und -Uhrzeit ein.');
if (!token) return showError('Bitte gib den Zugangs-Token ein.');
// Check end > start
const startTs = new Date(sDate + 'T' + sTime).getTime() / 1000;
const endTs = new Date(eDate + 'T' + eTime).getTime() / 1000;
if (endTs < startTs) return showError('Das End-Datum/Zeit muss nach dem Start liegen.');
// Custom URL required?
if (customZoom.checked && !document.getElementById('customUrl').value.trim()) {
return showError('Bitte gib eine Videokonferenz-URL ein.');
}
// License required if image?
if (fileInput.files.length > 0) {
const selectedLicense = document.querySelector('input[name="license"]:checked');
if (!selectedLicense) return showError('Bitte wähle eine Creative-Commons-Lizenz für das Bild.');
}
// Build payload
const audiences = Array.from(document.querySelectorAll('input[name="audience"]:checked')).map(cb => cb.value);
const hashtagsRaw = document.getElementById('hashtags').value.trim();
const hashtags = hashtagsRaw ? hashtagsRaw.split(',').map(t => t.trim().toLowerCase()).filter(Boolean) : [];
const payload = {
token: token,
email: document.getElementById('email').value.trim(),
title: title,
summary: summaryEditor ? summaryEditor.value() : document.getElementById('summary').value,
content: contentEditor ? contentEditor.value() : document.getElementById('content').value,
startTimestamp: startTs,
endTimestamp: endTs,
location: customZoom.checked ? document.getElementById('customUrl').value.trim() : 'https://relilab.org/live/',
audiences: audiences,
hashtags: hashtags,
imageCredit: document.getElementById('imageCredit').value.trim(),
license: fileInput.files.length > 0 ? document.querySelector('input[name="license"]:checked')?.value || '' : '',
};
// Build FormData (for image upload)
const formData = new FormData();
formData.append('data', JSON.stringify(payload));
if (fileInput.files.length > 0) {
formData.append('image', fileInput.files[0]);
}
// Submit
submitBtn.disabled = true;
submitBtn.classList.add('loading');
try {
const res = await fetch(WEBHOOK_URL, {
method: 'POST',
body: formData,
});
const result = await res.json();
if (res.ok && result.success) {
showSuccess('Session erfolgreich veröffentlicht! 🎉' + (result.eventId ? '<br><small>Event-ID: ' + result.eventId.substring(0, 16) + '…</small>' : ''));
form.reset();
summaryEditor && summaryEditor.value('');
contentEditor && contentEditor.value('');
filePreview.style.display = 'none';
fileDrop.classList.remove('has-file');
imageMetaFields.style.display = 'none';
customUrlField.classList.remove('visible');
document.querySelectorAll('.chip').forEach(c => c.classList.remove('active'));
document.querySelectorAll('.license-option').forEach(o => o.classList.remove('selected'));
endManuallyEdited = false;
} else {
showError(result.error || 'Fehler beim Veröffentlichen. Bitte versuche es erneut.');
}
} catch (err) {
showError('Verbindungsfehler: ' + err.message);
} finally {
submitBtn.disabled = false;
submitBtn.classList.remove('loading');
}
});
function showError(msg) {
statusMsg.className = 'status-msg error';
statusMsg.innerHTML = msg;
statusMsg.style.display = 'block';
statusMsg.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
function showSuccess(msg) {
statusMsg.className = 'status-msg success';
statusMsg.innerHTML = msg;
statusMsg.style.display = 'block';
statusMsg.scrollIntoView({ behavior: 'smooth', block: 'nearest' });
}
}); // end DOMContentLoaded
</script>
</body>
</html>