Add help FAQ modal and i18n help content
This commit is contained in:
@@ -170,6 +170,11 @@ function setupHandlers() {
|
||||
adminClose.addEventListener("click", () => togglePanel(false));
|
||||
}
|
||||
|
||||
const helpChip = $("help-chip");
|
||||
if (helpChip) {
|
||||
helpChip.addEventListener("click", () => openFaqModal());
|
||||
}
|
||||
|
||||
const resultsToggle = $("results-open");
|
||||
if (resultsToggle) {
|
||||
resultsToggle.addEventListener("change", async (e) => {
|
||||
@@ -378,3 +383,97 @@ function bindNavButtons() {
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function faqTree() {
|
||||
return [
|
||||
{
|
||||
title: t("help.cat.gettingStarted"),
|
||||
items: [
|
||||
{ q: t("help.q.join"), a: t("help.a.join") },
|
||||
{ q: t("help.q.adminKey"), a: t("help.a.adminKey") },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t("help.cat.suggest"),
|
||||
items: [
|
||||
{ q: t("help.q.limit"), a: t("help.a.limit") },
|
||||
{ q: t("help.q.editNames"), a: t("help.a.editNames") },
|
||||
{ q: t("help.q.mediaRules"), a: t("help.a.mediaRules") },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t("help.cat.vote"),
|
||||
items: [
|
||||
{ q: t("help.q.howVote"), a: t("help.a.howVote") },
|
||||
{ q: t("help.q.finalize"), a: t("help.a.finalize") },
|
||||
{ q: t("help.q.linkedVotes"), a: t("help.a.linkedVotes") },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t("help.cat.results"),
|
||||
items: [
|
||||
{ q: t("help.q.resultsLocked"), a: t("help.a.resultsLocked") },
|
||||
{ q: t("help.q.resultsContent"), a: t("help.a.resultsContent") },
|
||||
],
|
||||
},
|
||||
{
|
||||
title: t("help.cat.admin"),
|
||||
items: [
|
||||
{ q: t("help.q.openResults"), a: t("help.a.openResults") },
|
||||
{ q: t("help.q.linkDuplicates"), a: t("help.a.linkDuplicates") },
|
||||
{ q: t("help.q.grantJoker"), a: t("help.a.grantJoker") },
|
||||
{ q: t("help.q.reset"), a: t("help.a.reset") },
|
||||
],
|
||||
},
|
||||
];
|
||||
}
|
||||
|
||||
function openFaqModal() {
|
||||
const overlay = document.createElement("div");
|
||||
overlay.className = "edit-modal";
|
||||
const panel = document.createElement("div");
|
||||
panel.className = "edit-panel faq-panel";
|
||||
panel.innerHTML = `
|
||||
<div class="edit-header">
|
||||
<h3>${t("help.title")}</h3>
|
||||
<button class="lightbox-close" aria-label="${t("modal.close")}">x</button>
|
||||
</div>
|
||||
<div class="edit-body">
|
||||
<p class="faq-intro">${t("help.intro")}</p>
|
||||
<div class="faq-list"></div>
|
||||
</div>
|
||||
`;
|
||||
|
||||
const list = panel.querySelector(".faq-list");
|
||||
faqTree().forEach((section) => {
|
||||
const sec = document.createElement("details");
|
||||
sec.className = "faq-section";
|
||||
const summary = document.createElement("summary");
|
||||
summary.textContent = section.title;
|
||||
sec.appendChild(summary);
|
||||
|
||||
const itemsWrap = document.createElement("div");
|
||||
itemsWrap.className = "faq-items";
|
||||
section.items.forEach((item) => {
|
||||
const qd = document.createElement("details");
|
||||
qd.className = "faq-item";
|
||||
const qs = document.createElement("summary");
|
||||
qs.textContent = item.q;
|
||||
const ans = document.createElement("p");
|
||||
ans.textContent = item.a;
|
||||
qd.append(qs, ans);
|
||||
itemsWrap.appendChild(qd);
|
||||
});
|
||||
|
||||
sec.appendChild(itemsWrap);
|
||||
list.appendChild(sec);
|
||||
});
|
||||
|
||||
const close = () => overlay.remove();
|
||||
overlay.addEventListener("click", (e) => {
|
||||
if (e.target.classList.contains("edit-modal") || e.target.classList.contains("lightbox-close")) close();
|
||||
});
|
||||
|
||||
overlay.appendChild(panel);
|
||||
document.body.appendChild(overlay);
|
||||
}
|
||||
|
||||
@@ -114,6 +114,16 @@ button .chip {
|
||||
border-color: #a83a35;
|
||||
}
|
||||
|
||||
.help-chip {
|
||||
background: #dff3ff;
|
||||
border-color: #b6ddff;
|
||||
color: #0f3a6f;
|
||||
font-weight: 700;
|
||||
}
|
||||
.help-chip:hover {
|
||||
background: #cde8ff;
|
||||
}
|
||||
|
||||
.nav-btn {
|
||||
min-width: 64px;
|
||||
font-weight: 700;
|
||||
|
||||
@@ -76,3 +76,41 @@
|
||||
.preview-card {
|
||||
pointer-events: none;
|
||||
}
|
||||
|
||||
.faq-panel .faq-list {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 8px;
|
||||
}
|
||||
.faq-intro {
|
||||
margin-top: 0;
|
||||
margin-bottom: 12px;
|
||||
color: #5b4a32;
|
||||
}
|
||||
.faq-section {
|
||||
border: 1px solid #e3d4bd;
|
||||
border-radius: 10px;
|
||||
padding: 8px 10px;
|
||||
background: #fff7ec;
|
||||
}
|
||||
.faq-section > summary {
|
||||
font-weight: 700;
|
||||
cursor: pointer;
|
||||
}
|
||||
.faq-items {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
gap: 6px;
|
||||
padding-top: 6px;
|
||||
margin-left: 6px;
|
||||
}
|
||||
.faq-item {
|
||||
border: 1px solid #eedec3;
|
||||
border-radius: 8px;
|
||||
padding: 6px 8px;
|
||||
background: #ffffff;
|
||||
}
|
||||
.faq-item > summary {
|
||||
font-weight: 600;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
@@ -76,6 +76,7 @@
|
||||
<span class="counts" id="counts">—</span>
|
||||
</div>
|
||||
<div class="status-right">
|
||||
<button id="help-chip" class="chip icon help-chip" type="button" aria-label="Help" title="Help" data-i18n="help.label" data-i18n-attr="aria-label,title">?</button>
|
||||
<div class="lang-switch" id="lang-switch-status">
|
||||
<button class="lang-button chip icon" type="button" aria-label="Language" title="Language">🌐</button>
|
||||
<div class="lang-menu hidden">
|
||||
|
||||
@@ -158,6 +158,42 @@ const translations = {
|
||||
"modal.close": "Close",
|
||||
|
||||
"lightbox.close": "Close",
|
||||
"help.label": "Help",
|
||||
"help.title": "FAQ & tips",
|
||||
"help.intro": "Expand a section to see answers for players and admins.",
|
||||
"help.cat.gettingStarted": "Getting started",
|
||||
"help.cat.suggest": "Suggest phase",
|
||||
"help.cat.vote": "Vote phase",
|
||||
"help.cat.results": "Results phase",
|
||||
"help.cat.admin": "Admin tools",
|
||||
"help.q.join": "How do I join?",
|
||||
"help.a.join": "Register with a username, password, and display name. Then log in with the same credentials.",
|
||||
"help.q.adminKey": "What is the admin key?",
|
||||
"help.a.adminKey": "If your host shares the admin key, enter it during registration to unlock admin controls.",
|
||||
"help.q.limit": "How many games can I add?",
|
||||
"help.a.limit": "Up to 5 suggestions per player. A joker lets you add one extra during the vote phase.",
|
||||
"help.q.editNames": "Can I edit or delete suggestions later?",
|
||||
"help.a.editNames": "Game names lock after leaving Suggest. Optional fields stay editable; admins can edit or delete any time.",
|
||||
"help.q.mediaRules": "Any rules for links and images?",
|
||||
"help.a.mediaRules": "Use http(s) links. Screenshots must end with an image file (png, jpg, gif, webp, avif). Invalid links are rejected.",
|
||||
"help.q.howVote": "How do votes work?",
|
||||
"help.a.howVote": "Move the 0–10 slider for each game. Your score and emoji update immediately.",
|
||||
"help.q.finalize": "What does finalize do?",
|
||||
"help.a.finalize": "Finalize locks your votes until you unfinalize. You must score every game first.",
|
||||
"help.q.linkedVotes": "What are linked games?",
|
||||
"help.a.linkedVotes": "Admins can link duplicates. Changing one linked slider updates all siblings; votes are shared.",
|
||||
"help.q.resultsLocked": "Why can't I see results?",
|
||||
"help.a.resultsLocked": "Results stay hidden until an admin opens them. You move to Results automatically when unlocked.",
|
||||
"help.q.resultsContent": "What do results show?",
|
||||
"help.a.resultsContent": "A leaderboard with averages, vote counts, your own score, and any links or media for each game.",
|
||||
"help.q.openResults": "How do I open or close results?",
|
||||
"help.a.openResults": "Admins toggle results on the Admin panel. Opening moves everyone to Results; closing sends players back to Vote and clears finalizations.",
|
||||
"help.q.linkDuplicates": "How do I merge duplicates?",
|
||||
"help.a.linkDuplicates": "In Vote, pick two games under Admin › Link games. Linking clears votes for that group and unfinalizes affected players.",
|
||||
"help.q.grantJoker": "When should I grant a joker?",
|
||||
"help.a.grantJoker": "Grant a joker during Vote to let a player add one extra suggestion; their finalized state resets.",
|
||||
"help.q.reset": "Reset vs factory reset?",
|
||||
"help.a.reset": "Reset clears suggestions/votes and phases but keeps players. Factory reset wipes everything, including players, and reseeds the app.",
|
||||
},
|
||||
de: {
|
||||
"lang.label": "Sprache",
|
||||
@@ -318,6 +354,42 @@ const translations = {
|
||||
"modal.close": "Schließen",
|
||||
|
||||
"lightbox.close": "Schließen",
|
||||
"help.label": "Hilfe",
|
||||
"help.title": "FAQ & Tipps",
|
||||
"help.intro": "Klappe einen Abschnitt auf, um Antworten für Spieler und Admins zu sehen.",
|
||||
"help.cat.gettingStarted": "Erste Schritte",
|
||||
"help.cat.suggest": "Phase Vorschlagen",
|
||||
"help.cat.vote": "Phase Bewerten",
|
||||
"help.cat.results": "Phase Ergebnisse",
|
||||
"help.cat.admin": "Admin-Werkzeuge",
|
||||
"help.q.join": "Wie kann ich mitmachen?",
|
||||
"help.a.join": "Registriere dich mit Benutzername, Passwort und Anzeigenamen. Danach mit denselben Daten anmelden.",
|
||||
"help.q.adminKey": "Was ist der Admin-Schlüssel?",
|
||||
"help.a.adminKey": "Wenn der Host dir den Admin-Schlüssel gibt, trage ihn bei der Registrierung ein, um Admin-Rechte zu erhalten.",
|
||||
"help.q.limit": "Wie viele Spiele darf ich hinzufügen?",
|
||||
"help.a.limit": "Bis zu 5 Vorschläge pro Spieler. Ein Joker erlaubt während der Abstimmung einen zusätzlichen Vorschlag.",
|
||||
"help.q.editNames": "Kann ich Vorschläge später ändern oder löschen?",
|
||||
"help.a.editNames": "Spieltitel sind nach Verlassen der Vorschlagsphase gesperrt. Optionale Felder bleiben bearbeitbar; Admins können jederzeit ändern oder löschen.",
|
||||
"help.q.mediaRules": "Gibt es Regeln für Links und Bilder?",
|
||||
"help.a.mediaRules": "Nutze http(s)-Links. Screenshots müssen auf eine Bilddatei enden (png, jpg, gif, webp, avif). Ungültige Links werden abgelehnt.",
|
||||
"help.q.howVote": "Wie funktioniert die Abstimmung?",
|
||||
"help.a.howVote": "Bewege den 0–10 Schieberegler für jedes Spiel. Deine Wertung und das Emoji aktualisieren sich sofort.",
|
||||
"help.q.finalize": "Was bedeutet Abschließen?",
|
||||
"help.a.finalize": "Abschließen sperrt deine Stimmen, bis du wieder öffnest. Zuerst müssen alle Spiele bewertet sein.",
|
||||
"help.q.linkedVotes": "Was sind verknüpfte Spiele?",
|
||||
"help.a.linkedVotes": "Admins können Duplikate verknüpfen. Ein Regler ändert dann die Stimmen aller verknüpften Spiele gemeinsam.",
|
||||
"help.q.resultsLocked": "Warum sehe ich keine Ergebnisse?",
|
||||
"help.a.resultsLocked": "Ergebnisse bleiben verborgen, bis ein Admin sie freigibt. Danach wechselst du automatisch zur Ergebnisphase.",
|
||||
"help.q.resultsContent": "Was zeigen die Ergebnisse?",
|
||||
"help.a.resultsContent": "Eine Rangliste mit Durchschnitt, Stimmenanzahl, deiner eigenen Stimme sowie Links und Medien pro Spiel.",
|
||||
"help.q.openResults": "Wie öffne oder schließe ich Ergebnisse?",
|
||||
"help.a.openResults": "Admins schalten im Admin-Bereich die Ergebnisse frei. Öffnen bringt alle in die Ergebnisphase; Schließen schickt Spieler zurück zur Abstimmung und entfernt Finalisierungen.",
|
||||
"help.q.linkDuplicates": "Wie verbinde ich Duplikate?",
|
||||
"help.a.linkDuplicates": "In der Abstimmungsphase zwei Spiele unter Admin › Spiele verknüpfen auswählen. Verknüpfen löscht die Stimmen dieser Gruppe und öffnet betroffene Spieler erneut.",
|
||||
"help.q.grantJoker": "Wann sollte ich einen Joker vergeben?",
|
||||
"help.a.grantJoker": "Vergib während der Abstimmung einen Joker, damit ein Spieler einen zusätzlichen Vorschlag machen kann; seine Finalisierung wird zurückgesetzt.",
|
||||
"help.q.reset": "Reset vs. Werkseinstellung?",
|
||||
"help.a.reset": "Reset löscht Vorschläge/Stimmen und Phasen, behält aber Spieler. Werkseinstellung entfernt alles inklusive Spieler und setzt die App neu auf.",
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user