init
release-tag / release-image (push) Successful in 1m55s

This commit is contained in:
2026-05-14 13:38:41 +02:00
parent 5d1ced594d
commit be7bd79fc7
16 changed files with 1434 additions and 1 deletions
+36
View File
@@ -0,0 +1,36 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}} · SEND.NRW Chat</title>
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
<div class="shell">
<header class="topbar"><a class="brand" href="/rooms">Go HTMX Chat</a></header>
<main class="center-card">
<section class="card login-card">
<p class="eyebrow">Willkommen</p>
<h1>Einloggen</h1>
{{if .Error}}<div class="error">{{.Error}}</div>{{end}}
{{if eq .AuthMode "oidc"}}
<p class="muted">Melde dich mit deinem Pocket-ID-Konto an. Die App nutzt OpenID Connect/OAuth2 und speichert nur eine signierte lokale Session.</p>
<a class="button-link" href="/auth/login">Mit Pocket ID anmelden</a>
{{else}}
<p class="muted">Lokaler Entwicklungsmodus: Wähle nur einen Anzeigenamen. Für Pocket ID setze <code>AUTH_MODE=oidc</code>.</p>
<form hx-post="/login" hx-target="body" method="post" class="stack">
<label>
Anzeigename
<input name="username" autocomplete="nickname" placeholder="z. B. Jan" autofocus required minlength="2" maxlength="24">
</label>
<button type="submit">Chat starten</button>
</form>
{{end}}
</section>
</main>
</div>
</body>
</html>
+9
View File
@@ -0,0 +1,9 @@
{{define "partials/message.html"}}
<article class="message">
<div class="avatar">{{initial .Username}}</div>
<div class="bubble">
<div class="meta"><strong>{{.Username}}</strong><time>{{formatTime .CreatedAt}}</time></div>
<p>{{.Body}}</p>
</div>
</article>
{{end}}
+63
View File
@@ -0,0 +1,63 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}} · SEND.NRW Chat</title>
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
<div class="shell">
<header class="topbar">
<a class="brand" href="/rooms">SEND.NRW Chat</a>
<form method="post" action="/logout">
<span class="user-pill">{{.Username}}</span>
<button class="ghost" type="submit">Logout</button>
</form>
</header>
<main class="chat-page">
<aside class="card sidebar">
<a class="back" href="/rooms">← Zur Raumliste</a>
<p class="eyebrow">Chatraum</p>
<h1>{{.Room.Name}}</h1>
<p class="muted">{{.Room.Description}}</p>
<div class="hint"></div>
</aside>
<section class="chat-card card">
<div id="messages" class="messages">
{{range .Messages}}
{{template "partials/message.html" .}}
{{else}}
<div class="empty">Noch keine Nachrichten. Schreib die erste.</div>
{{end}}
</div>
<form id="message-form" class="message-form" hx-post="/rooms/{{.Room.ID}}/messages" hx-swap="none" hx-on::after-request="if(event.detail.successful) this.reset()">
<input name="body" placeholder="Nachricht schreiben …" autocomplete="off" required maxlength="2000">
<button type="submit">Senden</button>
</form>
</section>
</main>
</div>
<script>
(function () {
const messages = document.getElementById('messages');
const source = new EventSource('/rooms/{{.Room.ID}}/events');
function scrollDown() { messages.scrollTop = messages.scrollHeight; }
source.addEventListener('message', function (event) {
const data = JSON.parse(event.data);
const empty = messages.querySelector('.empty');
if (empty) empty.remove();
messages.insertAdjacentHTML('beforeend', data.html);
scrollDown();
});
window.addEventListener('beforeunload', function () { source.close(); });
scrollDown();
})();
</script>
</body>
</html>
+48
View File
@@ -0,0 +1,48 @@
<!doctype html>
<html lang="de">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>{{.Title}} · SEND.NRW Chat</title>
<script src="https://unpkg.com/htmx.org@1.9.12"></script>
<link rel="stylesheet" href="/static/app.css">
</head>
<body>
<div class="shell">
<header class="topbar">
<a class="brand" href="/rooms">SEND.NRW Chat</a>
<form method="post" action="/logout">
<span class="user-pill">{{.Username}}</span>
<button class="ghost" type="submit">Logout</button>
</form>
</header>
<main class="grid-page">
<section class="hero card">
<div>
<p class="eyebrow">Räume</p>
<h1>Wähle einen Chatraum</h1>
<p class="muted">Nachrichten werden persistent gespeichert und live per Server-Sent Events verteilt.</p>
</div>
</section>
<section class="room-grid">
{{range .Rooms}}
<a class="room-card" href="/rooms/{{.ID}}">
<h2>{{.Name}}</h2>
<p>{{.Description}}</p>
</a>
{{end}}
</section>
<section class="card hero">
<h2>Neuen Raum erstellen</h2>
<form hx-post="/rooms" method="post" class="stack two-col-form">
<label>Name<input name="name" placeholder="Projekt Alpha" required minlength="2" maxlength="40"></label>
<label>Beschreibung<input name="description" placeholder="Worum geht es hier?" maxlength="120"></label>
<button type="submit">Raum erstellen</button>
</form>
</section>
</main>
</div>
</body>
</html>