Files
Levyraati26_go/templates/song.html
T
Esa Kataja 60660849c7 Make the invite copyable and widen what feedback invites
Three fixes from using the admin panel and the site:

- The invite link was an anchor, but an invite is something to send, not to
  follow — clicking it opened the join form in the admin's own browser. It
  is now the URL beside a Kopioi button. The handler reads the text out of
  the sibling element rather than interpolating the URL into JS, so there is
  nothing to escape, and where the clipboard API is missing (it needs a
  secure context, which the documented SSH tunnel to localhost provides) it
  selects the text instead of leaving a button that does nothing.
- "Ilmoita ongelmasta" framed the feedback form as a bug tracker when it is
  meant to take ideas and general feedback too. The footer now asks
  "Ongelmia? Ideoita? Palautetta?", and the page it leads to answers all
  three: the ingress covers ideas explicitly and the placeholder suggests a
  feature rather than a fault.
- "Kuuntele YouTubessa" opens in a new tab. Leaving the page mid-review
  would lose whatever is already typed into the review form.
2026-08-02 20:57:34 +03:00

181 lines
7.1 KiB
HTML

{{define "content"}}
{{$s := .Data}}
<h1>{{$s.Title}}</h1>
<p class="by">{{$s.Artist}}</p>
<!-- Four different kinds of fact, so four labelled cells rather than one run of text. "Oma
kappale" belongs here as the submitter, not as a badge: it is a fact about you. -->
<dl class="spec">
<div><dt>Genre</dt><dd>{{$s.GenreLabel}}</dd></div>
<div><dt>Kesto</dt><dd>{{$s.Length}}</dd></div>
<div><dt>Lähetti</dt>
<dd>{{if $s.Own}}sinä{{else}}<a href="/profile/{{$s.SubmitterID}}">{{$s.Submitter}}</a>{{end}}</dd>
</div>
<div><dt>Julkaistu</dt><dd>{{fiday $s.CreatedAt}}</dd></div>
</dl>
{{if $s.CanEdit}}
<details class="editbox">
<summary>Muokkaa tietoja</summary>
<form method="post" action="/songs/{{$s.ID}}" class="stack">
<label>Nimi <input name="title" value="{{$s.Title}}" maxlength="100" required></label>
<label>Esittäjä <input name="artist" value="{{$s.Artist}}" maxlength="100" required></label>
<label>Genre
<select name="genre" required>
{{$current := $s.Genre}}
{{range $s.Genres}}
<option value="{{.Code}}" {{if eq .Code $current}}selected{{end}}>{{.Label}}</option>
{{end}}
</select>
</label>
<label>Esittely <textarea name="description" rows="4" maxlength="2000">{{$s.Description}}</textarea></label>
<button type="submit">Tallenna</button>
</form>
<form method="post" action="/songs/{{$s.ID}}/delete"
onsubmit="return confirm('Poistetaanko kappale lopullisesti?')">
<button type="submit" class="ghost danger">Poista kappale</button>
</form>
<p class="muted small">Muokkaus ja poisto ovat mahdollisia vain ennen ensimmäistä arvostelua.</p>
</details>
{{else if $s.Own}}
<p class="muted small">Kappaletta on jo arvosteltu, joten tietoja ei voi enää muuttaa.</p>
{{end}}
{{if $s.CanReview}}
<!-- The channel strip: the fader is the score, the panel beside it is everything else you do
while the track plays. -->
<form method="post" action="/songs/{{$s.ID}}/review" class="strip">
{{template "fader" 50}}
<div class="deck">
{{template "player" $s}}
{{with $s.Description}}<p class="intro">{{.}}</p>{{end}}
<!-- Two panes when the song has lyrics: read on the left, write on the right, so following
the words costs no scrolling. Without lyrics the pane is absent, not empty. -->
<div class="panes{{if not $s.Lyrics}} solo{{end}}">
{{if $s.Lyrics}}
<div class="lyricspane">{{template "lyricsview" $s}}</div>
{{end}}
<div class="writepane">
<label class="grow">Arvostelu
<textarea name="text" maxlength="5000" required placeholder="Mitä kuulit?"></textarea>
</label>
<div class="deckfoot">
<button type="submit">Tallenna arvostelu</button>
<span class="muted small">Muiden pisteet paljastuvat kun tallennat omasi. Voit muokata
tai poistaa arvostelusi 30 minuutin ajan.</span>
</div>
</div>
</div>
</div>
</form>
{{else}}
{{template "player" $s}}
{{with $s.Description}}<p class="intro">{{.}}</p>{{end}}
{{end}}
{{/* New tab: leaving the page mid-review would lose whatever is already typed in the form. */}}
{{with $s.SourceURL}}<p class="muted small"><a href="{{.}}" target="_blank" rel="noreferrer">Kuuntele YouTubessa</a></p>{{end}}
{{if and (not $s.CanReview) (or $s.Lyrics $s.Own)}}
<!-- Only when the review strip is not already showing them: while reviewing, the lyrics live in
the left pane. This panel is for reading afterwards and for the submitter's edits. -->
<details class="lyrics">
<summary>Sanoitukset{{if not $s.Lyrics}} <span class="muted small">— ei vielä lisätty</span>{{end}}</summary>
{{if $s.Lyrics}}<pre class="lyricstext">{{lyricstext $s.Lyrics}}</pre>{{end}}
{{if $s.Own}}
<form method="post" action="/songs/{{$s.ID}}/lyrics" class="stack">
<label>Muokkaa sanoituksia
<textarea name="lyrics" rows="10" maxlength="20000"
placeholder="Liitä sanoitukset tähän.">{{$s.Lyrics}}</textarea>
</label>
<button type="submit">Tallenna sanoitukset</button>
</form>
<p class="muted small">Sanoituksia voi muokata vielä arvostelujenkin jälkeen.</p>
{{end}}
</details>
{{end}}
{{if $s.ViewerReview}}
<section>
<h2>Oma arvostelusi</h2>
{{with $s.ViewerReview}}
{{if .CanEdit}}
<form method="post" action="/reviews/{{.ID}}" class="strip">
<input type="hidden" name="from" value="/songs/{{$s.ID}}">
{{template "fader" .Score}}
<div class="deck">
<label class="grow">Arvostelu
<textarea name="text" rows="6" maxlength="5000" required>{{.Text}}</textarea>
</label>
<div class="deckfoot">
<button type="submit">Päivitä</button>
<span class="muted small">Muokkausaika päättyy {{fidate .EditableUntil}}.</span>
</div>
</div>
</form>
<form method="post" action="/reviews/{{.ID}}/delete"
onsubmit="return confirm('Poistetaanko arvostelu?')">
<input type="hidden" name="from" value="/songs/{{$s.ID}}">
<button type="submit" class="ghost danger">Poista arvostelu</button>
</form>
{{else}}
<p class="score">{{.Score}}</p>
<p class="reviewtext">{{.Text}}</p>
<p class="muted small">Muokkausaika on päättynyt.</p>
{{end}}
{{end}}
</section>
{{end}}
<section>
<h2>Arvostelut{{if $s.ReviewCount}} ({{$s.ReviewCount}}){{end}}</h2>
{{if $s.Revealed}}
{{if $s.Reviews}}
<!-- One channel per reviewer: the spread across the row is what "divisive" looks like. -->
<div class="channels">
{{range $i, $r := $s.Reviews}}
<div class="chan{{if $r.Own}} own{{end}}" style="--v: {{$r.Score}}; --i: {{$i}}">
<span class="chan-track"><span class="chan-cap"></span></span>
<span class="chan-score">{{$r.Score}}</span>
<span class="chan-who" title="{{$r.Reviewer}}">{{$r.Initials}}</span>
</div>
{{end}}
{{if $s.Average}}
<div class="chan avg" style="--v: {{score $s.Average}}">
<span class="chan-track"><span class="chan-cap"></span></span>
<span class="chan-score">{{score $s.Average}}</span>
<span class="chan-who">ka.</span>
</div>
{{end}}
</div>
{{range $s.Reviews}}
<article class="review{{if .Own}} own{{end}}">
<header>
<span class="avatar small">{{.Initials}}</span>
<span class="who">{{.Reviewer}}</span>
<span class="score">{{.Score}}</span>
<span class="meta">{{fidate .CreatedAt}}</span>
</header>
<p>{{.Text}}</p>
</article>
{{end}}
{{else}}
<p class="muted">Kukaan ei ole vielä arvostellut tätä kappaletta.</p>
{{end}}
{{else}}
<p class="sealed-note">
<span class="sealed" aria-hidden="true"></span>
Muiden pisteet ja arvostelut paljastuvat kun kirjoitat omasi.
{{if $s.ReviewCount}}Arvosteluja on {{$s.ReviewCount}}.{{end}}
</p>
{{end}}
</section>
{{if $s.NextInQueue}}
<p class="nextup"><a href="/songs/{{$s.NextInQueue}}">Seuraava jonossa →</a></p>
{{end}}
{{end}}