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.
This commit is contained in:
@@ -743,6 +743,10 @@ td.break { word-break: break-all; font-size: 0.8rem; }
|
||||
code { background: var(--surface-raised); padding: 0.1rem var(--space-1);
|
||||
border-radius: var(--radius); font-size: 0.85rem; }
|
||||
|
||||
/* The link is long and the button must stay reachable next to it on a narrow admin window. */
|
||||
.invitecell { display: flex; align-items: center; gap: var(--space-2); flex-wrap: wrap; }
|
||||
.invitecell code { word-break: break-all; }
|
||||
|
||||
/* --- toasts --- */
|
||||
|
||||
.toasts { position: fixed; right: var(--space-4); bottom: var(--space-4); z-index: 1000;
|
||||
|
||||
+30
-2
@@ -13,8 +13,11 @@
|
||||
<tbody>
|
||||
{{range .Data.Invites}}
|
||||
<tr>
|
||||
<td>
|
||||
<a href="{{.Link}}">{{.Link}}</a>
|
||||
<!-- Not a link: an invite is something to send, never to follow. A click used to open the
|
||||
join form in the admin's own browser, which is never what was wanted. -->
|
||||
<td class="invitecell">
|
||||
<code>{{.Link}}</code>
|
||||
<button type="button" class="ghost" onclick="copyInvite(this)">Kopioi</button>
|
||||
</td>
|
||||
<td class="nowrap"><span class="dot on"></span> käyttämätön</td>
|
||||
<td>{{fidate .CreatedAt}}</td>
|
||||
@@ -87,4 +90,29 @@
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<script>
|
||||
// The clipboard API needs a secure context. Over the documented SSH tunnel the origin is
|
||||
// localhost, which qualifies; reached any other way it is missing, so selecting the text is the
|
||||
// fallback — the admin presses Ctrl+C instead of being left with a button that does nothing.
|
||||
function copyInvite(button) {
|
||||
const link = button.previousElementSibling;
|
||||
const done = () => {
|
||||
button.textContent = 'Kopioitu';
|
||||
setTimeout(() => { button.textContent = 'Kopioi'; }, 1500);
|
||||
};
|
||||
if (navigator.clipboard) {
|
||||
navigator.clipboard.writeText(link.textContent).then(done, () => selectText(link));
|
||||
} else {
|
||||
selectText(link);
|
||||
}
|
||||
}
|
||||
|
||||
function selectText(el) {
|
||||
const range = document.createRange();
|
||||
range.selectNodeContents(el);
|
||||
const sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange(range);
|
||||
}
|
||||
</script>
|
||||
{{end}}
|
||||
|
||||
@@ -62,7 +62,7 @@
|
||||
<footer class="sitefooter">
|
||||
{{if .Member}}
|
||||
<!-- The server already knows where they were, so the path travels in the link — no JS. -->
|
||||
<a href="/report?from={{.Path}}">Ilmoita ongelmasta</a> ·
|
||||
<a href="/report?from={{.Path}}">Ongelmia? Ideoita? Palautetta?</a> ·
|
||||
{{end}}
|
||||
<span class="slogan">We know good music, baby!</span>
|
||||
<span class="copyright">© Kessinen</span>
|
||||
|
||||
@@ -1,13 +1,13 @@
|
||||
{{define "content"}}
|
||||
<h1>Palaute</h1>
|
||||
<p class="muted">Kerro mikä on rikki tai ärsyttää. Ei kategorioita eikä prioriteetteja — yksi
|
||||
virke riittää.</p>
|
||||
<p class="muted">Ongelmat, ideat ja kaikki muu palaute samaan paikkaan. Ei kategorioita eikä
|
||||
prioriteetteja — yksi virke riittää.</p>
|
||||
|
||||
<form method="post" action="/report" class="stack">
|
||||
<input type="hidden" name="from" value="{{.Data.From}}">
|
||||
<label>Palaute
|
||||
<textarea name="body" rows="6" maxlength="2000" required autofocus
|
||||
placeholder="Esim. soitin ei toimi puhelimella."></textarea>
|
||||
placeholder="Esim. soittimeen kaipaisi kelausta."></textarea>
|
||||
</label>
|
||||
<button type="submit">Lähetä palaute</button>
|
||||
</form>
|
||||
|
||||
+2
-1
@@ -74,7 +74,8 @@
|
||||
{{with $s.Description}}<p class="intro">{{.}}</p>{{end}}
|
||||
{{end}}
|
||||
|
||||
{{with $s.SourceURL}}<p class="muted small"><a href="{{.}}" rel="noreferrer">Kuuntele YouTubessa</a></p>{{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
|
||||
|
||||
Reference in New Issue
Block a user