Add a help modal to the application.
A new modal for help has been implemented to guide users in navigating the app. It includes detailed instructions, explanations for status symbols and note-taking, and is accessible via a new "Help" button in the UI. Styling updates and utility functions for the modal have also been added.
This commit is contained in:
@@ -89,9 +89,9 @@ function AdminPanel() {
|
|||||||
{open && (
|
{open && (
|
||||||
<div style={styles.modalOverlay} onMouseDown={closeModal}>
|
<div style={styles.modalOverlay} onMouseDown={closeModal}>
|
||||||
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
||||||
<div style={{ display: "flex", justifyContent: "space-between", alignItems: "center", gap: 10 }}>
|
<div style={styles.modalHeader}>
|
||||||
<div style={{ fontWeight: 1000, color: "#20140c" }}>Neuen User anlegen</div>
|
<div style={{ fontWeight: 1000, color: "#20140c" }}>Neuen User anlegen</div>
|
||||||
<button onClick={closeModal} style={styles.secondaryBtn}>Schließen</button>
|
<button onClick={closeModal} style={styles.modalCloseBtn} aria-label="Schließen">✕</button>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div style={{ marginTop: 12, display: "grid", gap: 10 }}>
|
<div style={{ marginTop: 12, display: "grid", gap: 10 }}>
|
||||||
@@ -144,6 +144,9 @@ export default function App() {
|
|||||||
const [gameId, setGameId] = useState(null);
|
const [gameId, setGameId] = useState(null);
|
||||||
const [sheet, setSheet] = useState(null);
|
const [sheet, setSheet] = useState(null);
|
||||||
|
|
||||||
|
// ✅ Hilfe Modal State
|
||||||
|
const [helpOpen, setHelpOpen] = useState(false);
|
||||||
|
|
||||||
const load = async () => {
|
const load = async () => {
|
||||||
const m = await api("/auth/me");
|
const m = await api("/auth/me");
|
||||||
setMe(m);
|
setMe(m);
|
||||||
@@ -300,6 +303,8 @@ export default function App() {
|
|||||||
return "#20140c";
|
return "#20140c";
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const closeHelp = () => setHelpOpen(false);
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={styles.page}>
|
<div style={styles.page}>
|
||||||
<div style={styles.shell}>
|
<div style={styles.shell}>
|
||||||
@@ -317,14 +322,15 @@ export default function App() {
|
|||||||
|
|
||||||
{me.role === "admin" && <AdminPanel />}
|
{me.role === "admin" && <AdminPanel />}
|
||||||
|
|
||||||
|
{/* Spiel + Hilfe */}
|
||||||
<div style={{ marginTop: 14 }}>
|
<div style={{ marginTop: 14 }}>
|
||||||
<div style={styles.card}>
|
<div style={styles.card}>
|
||||||
<div style={styles.sectionHeader}>Spiel</div>
|
<div style={styles.sectionHeader}>Spiel</div>
|
||||||
<div style={{ padding: 12 }}>
|
<div style={{ padding: 12, display: "flex", gap: 10, alignItems: "center" }}>
|
||||||
<select
|
<select
|
||||||
value={gameId || ""}
|
value={gameId || ""}
|
||||||
onChange={(e) => setGameId(e.target.value)}
|
onChange={(e) => setGameId(e.target.value)}
|
||||||
style={styles.input}
|
style={{ ...styles.input, flex: 1 }}
|
||||||
>
|
>
|
||||||
{games.map((g) => (
|
{games.map((g) => (
|
||||||
<option key={g.id} value={g.id}>
|
<option key={g.id} value={g.id}>
|
||||||
@@ -332,10 +338,91 @@ export default function App() {
|
|||||||
</option>
|
</option>
|
||||||
))}
|
))}
|
||||||
</select>
|
</select>
|
||||||
|
|
||||||
|
<button
|
||||||
|
onClick={() => setHelpOpen(true)}
|
||||||
|
style={styles.helpBtn}
|
||||||
|
title="Hilfe"
|
||||||
|
aria-label="Hilfe"
|
||||||
|
>
|
||||||
|
Hilfe
|
||||||
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
{/* Hilfe Modal */}
|
||||||
|
{helpOpen && (
|
||||||
|
<div style={styles.modalOverlay} onMouseDown={closeHelp}>
|
||||||
|
<div style={styles.modalCard} onMouseDown={(e) => e.stopPropagation()}>
|
||||||
|
<div style={styles.modalHeader}>
|
||||||
|
<div style={{ fontWeight: 1000, color: "#20140c" }}>Hilfe</div>
|
||||||
|
<button onClick={closeHelp} style={styles.modalCloseBtn} aria-label="Schließen">✕</button>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.helpBody}>
|
||||||
|
<div style={styles.helpSectionTitle}>1) Namen anklicken (Status)</div>
|
||||||
|
<div style={styles.helpText}>
|
||||||
|
Tippe auf einen Namen, um den Status zu wechseln. Reihenfolge:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.helpList}>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={{ ...styles.helpBadge, background: "rgba(0,170,60,0.12)", color: "#0b6a1e" }}>✓</span>
|
||||||
|
<div><b>Grün</b> = bestätigt / fix richtig</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={{ ...styles.helpBadge, background: "rgba(255,0,0,0.10)", color: "#b10000" }}>X</span>
|
||||||
|
<div><b>Rot</b> = ausgeschlossen / fix falsch</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={{ ...styles.helpBadge, background: "rgba(120,120,120,0.14)", color: "#444" }}>?</span>
|
||||||
|
<div><b>Grau</b> = unsicher / „vielleicht“</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={{ ...styles.helpBadge, background: "rgba(255,255,255,0.35)", color: "#20140c" }}> </span>
|
||||||
|
<div><b>Leer</b> = unknown / noch nicht bewertet</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.helpDivider} />
|
||||||
|
|
||||||
|
<div style={styles.helpSectionTitle}>2) i / m / s Button (Notiz)</div>
|
||||||
|
<div style={styles.helpText}>
|
||||||
|
Rechts pro Zeile gibt es einen Button, der durch diese Werte rotiert:
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.helpList}>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={styles.helpMiniTag}>i</span>
|
||||||
|
<div><b>i</b> = „Ich habe diese Geheimkarte“</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={styles.helpMiniTag}>m</span>
|
||||||
|
<div><b>m</b> = „Geheimkarte aus dem mittleren Deck“</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={styles.helpMiniTag}>s</span>
|
||||||
|
<div><b>s</b> = „Ein anderer Spieler hat diese Karte“</div>
|
||||||
|
</div>
|
||||||
|
<div style={styles.helpListRow}>
|
||||||
|
<span style={styles.helpMiniTag}>—</span>
|
||||||
|
<div><b>—</b> = keine Notiz</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div style={styles.helpDivider} />
|
||||||
|
|
||||||
|
<div style={styles.helpText}>
|
||||||
|
|
||||||
|
Tipp: Jeder Spieler sieht nur seine eigenen Notizen – andere Spieler können nicht in deinen Zettel schauen.
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{/* Sheet */}
|
||||||
<div style={{ marginTop: 14, display: "grid", gap: 14 }}>
|
<div style={{ marginTop: 14, display: "grid", gap: 14 }}>
|
||||||
{sections.map((sec) => (
|
{sections.map((sec) => (
|
||||||
<div key={sec.key} style={styles.card}>
|
<div key={sec.key} style={styles.card}>
|
||||||
@@ -350,7 +437,6 @@ export default function App() {
|
|||||||
background: getRowBg(e.status),
|
background: getRowBg(e.status),
|
||||||
}}
|
}}
|
||||||
>
|
>
|
||||||
{/* ✅ Klick Cycle */}
|
|
||||||
<div
|
<div
|
||||||
onClick={() => cycleStatus(e)}
|
onClick={() => cycleStatus(e)}
|
||||||
style={{
|
style={{
|
||||||
@@ -364,12 +450,10 @@ export default function App() {
|
|||||||
{e.label}
|
{e.label}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* ✅ NUR 1 Status-Spalte */}
|
|
||||||
<div style={{ ...styles.statusCell, color: getStatusSymbolColor(e.status) }}>
|
<div style={{ ...styles.statusCell, color: getStatusSymbolColor(e.status) }}>
|
||||||
{getStatusSymbol(e.status)}
|
{getStatusSymbol(e.status)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* i/m/s */}
|
|
||||||
<button onClick={() => toggleTag(e)} style={styles.tagBtn} title="i → m → s → leer">
|
<button onClick={() => toggleTag(e)} style={styles.tagBtn} title="i → m → s → leer">
|
||||||
{e.note_tag || "—"}
|
{e.note_tag || "—"}
|
||||||
</button>
|
</button>
|
||||||
@@ -437,7 +521,7 @@ const styles = {
|
|||||||
},
|
},
|
||||||
row: {
|
row: {
|
||||||
display: "grid",
|
display: "grid",
|
||||||
gridTemplateColumns: "1fr 46px 56px", // ✅ Name | Status | i/m/s
|
gridTemplateColumns: "1fr 46px 56px",
|
||||||
gap: 8,
|
gap: 8,
|
||||||
padding: "10px 12px",
|
padding: "10px 12px",
|
||||||
alignItems: "center",
|
alignItems: "center",
|
||||||
@@ -463,6 +547,15 @@ const styles = {
|
|||||||
background: "linear-gradient(180deg, rgba(255,255,255,0.55), rgba(0,0,0,0.06))",
|
background: "linear-gradient(180deg, rgba(255,255,255,0.55), rgba(0,0,0,0.06))",
|
||||||
cursor: "pointer",
|
cursor: "pointer",
|
||||||
},
|
},
|
||||||
|
helpBtn: {
|
||||||
|
padding: "10px 12px",
|
||||||
|
borderRadius: 12,
|
||||||
|
border: "1px solid rgba(0,0,0,0.25)",
|
||||||
|
background: "linear-gradient(180deg, rgba(255,255,255,0.75), rgba(0,0,0,0.06))",
|
||||||
|
fontWeight: 1000,
|
||||||
|
cursor: "pointer",
|
||||||
|
whiteSpace: "nowrap",
|
||||||
|
},
|
||||||
input: {
|
input: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
padding: 10,
|
padding: 10,
|
||||||
@@ -521,7 +614,7 @@ const styles = {
|
|||||||
},
|
},
|
||||||
modalCard: {
|
modalCard: {
|
||||||
width: "100%",
|
width: "100%",
|
||||||
maxWidth: 520,
|
maxWidth: 560,
|
||||||
borderRadius: 18,
|
borderRadius: 18,
|
||||||
border: "1px solid rgba(0,0,0,0.25)",
|
border: "1px solid rgba(0,0,0,0.25)",
|
||||||
background: "linear-gradient(180deg, rgba(255,255,255,0.72), rgba(255,255,255,0.42))",
|
background: "linear-gradient(180deg, rgba(255,255,255,0.72), rgba(255,255,255,0.42))",
|
||||||
@@ -529,4 +622,78 @@ const styles = {
|
|||||||
padding: 14,
|
padding: 14,
|
||||||
backdropFilter: "blur(6px)",
|
backdropFilter: "blur(6px)",
|
||||||
},
|
},
|
||||||
|
modalHeader: {
|
||||||
|
display: "flex",
|
||||||
|
justifyContent: "space-between",
|
||||||
|
alignItems: "center",
|
||||||
|
gap: 10,
|
||||||
|
},
|
||||||
|
modalCloseBtn: {
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
borderRadius: 12,
|
||||||
|
border: "1px solid rgba(0,0,0,0.25)",
|
||||||
|
background: "linear-gradient(180deg, rgba(255,255,255,0.85), rgba(0,0,0,0.06))",
|
||||||
|
fontWeight: 1000,
|
||||||
|
cursor: "pointer",
|
||||||
|
lineHeight: "38px",
|
||||||
|
textAlign: "center",
|
||||||
|
},
|
||||||
|
|
||||||
|
// Help modal content
|
||||||
|
helpBody: {
|
||||||
|
marginTop: 10,
|
||||||
|
paddingTop: 4,
|
||||||
|
maxHeight: "70vh",
|
||||||
|
overflow: "auto",
|
||||||
|
},
|
||||||
|
helpSectionTitle: {
|
||||||
|
fontWeight: 1000,
|
||||||
|
color: "#20140c",
|
||||||
|
marginTop: 10,
|
||||||
|
marginBottom: 6,
|
||||||
|
},
|
||||||
|
helpText: {
|
||||||
|
color: "#20140c",
|
||||||
|
opacity: 0.9,
|
||||||
|
lineHeight: 1.35,
|
||||||
|
},
|
||||||
|
helpList: {
|
||||||
|
marginTop: 10,
|
||||||
|
display: "grid",
|
||||||
|
gap: 8,
|
||||||
|
},
|
||||||
|
helpListRow: {
|
||||||
|
display: "grid",
|
||||||
|
gridTemplateColumns: "42px 1fr",
|
||||||
|
gap: 10,
|
||||||
|
alignItems: "center",
|
||||||
|
},
|
||||||
|
helpBadge: {
|
||||||
|
display: "inline-flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
borderRadius: 12,
|
||||||
|
border: "1px solid rgba(0,0,0,0.18)",
|
||||||
|
fontWeight: 1100,
|
||||||
|
fontSize: 18,
|
||||||
|
},
|
||||||
|
helpMiniTag: {
|
||||||
|
display: "inline-flex",
|
||||||
|
alignItems: "center",
|
||||||
|
justifyContent: "center",
|
||||||
|
width: 38,
|
||||||
|
height: 38,
|
||||||
|
borderRadius: 12,
|
||||||
|
border: "1px solid rgba(0,0,0,0.18)",
|
||||||
|
background: "rgba(255,255,255,0.55)",
|
||||||
|
fontWeight: 1100,
|
||||||
|
},
|
||||||
|
helpDivider: {
|
||||||
|
margin: "14px 0",
|
||||||
|
height: 1,
|
||||||
|
background: "rgba(0,0,0,0.12)",
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user