Compare commits
2
Commits
141c5597c4
...
35bdfc1f67
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
35bdfc1f67 | ||
|
|
f64da5ac86 |
No files matched your search
@@ -1,40 +1,52 @@
|
|||||||
import CopyField from './CopyField.jsx';
|
import CopyField from './CopyField.jsx';
|
||||||
|
|
||||||
|
function regenerate(act, target, label) {
|
||||||
|
if (!window.confirm(`Neuen Code für ${label} erzeugen? Der alte Link funktioniert dann nicht mehr. Bereits beigetretene Spieler bleiben im Team.`)) return;
|
||||||
|
act('codes/regenerate', { target }, `Neuer Code für ${label}`);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Einladungslink eines Teams, steht für den Organisator unten in der Team-Karte. */
|
||||||
|
export function TeamInvite({ state, side, act, busy }) {
|
||||||
|
const { codes, links } = state.organizer;
|
||||||
|
const open = !['finished', 'cancelled'].includes(state.status);
|
||||||
|
const name = state.teams[side].name;
|
||||||
|
return (
|
||||||
|
<div className={`invite team-invite team-${side}`}>
|
||||||
|
<div className="invite-head">
|
||||||
|
<strong>Einladung</strong>
|
||||||
|
<span className="invite-code">{codes[side]}</span>
|
||||||
|
{open && <button className="link-btn" disabled={!!busy} onClick={() => regenerate(act, side, name)}>Neuer Code</button>}
|
||||||
|
</div>
|
||||||
|
<CopyField value={links[side]} />
|
||||||
|
<p className="small muted">Führt nur in {name}. Nur an dieses Team weitergeben.</p>
|
||||||
|
</div>
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
export default function OrganizerPanel({ state, act, busy, matchId, token }) {
|
export default function OrganizerPanel({ state, act, busy, matchId, token }) {
|
||||||
const { codes, links } = state.organizer;
|
const { codes, links } = state.organizer;
|
||||||
const open = !['finished', 'cancelled'].includes(state.status);
|
const open = !['finished', 'cancelled'].includes(state.status);
|
||||||
const orgLink = `${window.location.origin}/m/${matchId}#org=${token}`;
|
const orgLink = `${window.location.origin}/m/${matchId}#org=${token}`;
|
||||||
|
const label = 'Zuschauer (Stream, Kommentatoren)';
|
||||||
const regen = (target, label) =>
|
|
||||||
window.confirm(`Neuen Code für ${label} erzeugen? Der alte Link funktioniert dann nicht mehr. Bereits beigetretene Spieler bleiben im Team.`) &&
|
|
||||||
act('codes/regenerate', { target }, `Neuer Code für ${label}`);
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="panel organizer-panel">
|
<section className="panel organizer-panel">
|
||||||
<h2>Einladungen</h2>
|
<h2>Einladungen</h2>
|
||||||
<p className="small muted">Jeder Link führt nur in das jeweilige Team. Gib ihn ausschließlich an dieses Team weiter.</p>
|
<p className="small muted">Die Einladungslinks der Teams stehen unten in der jeweiligen Team-Karte.</p>
|
||||||
{[
|
<div className="invite spectator">
|
||||||
['A', state.teams.A.name, 'team-A'],
|
|
||||||
['B', state.teams.B.name, 'team-B'],
|
|
||||||
['spectator', 'Zuschauer (Stream, Kommentatoren)', 'spectator'],
|
|
||||||
].map(([key, label, cls]) => (
|
|
||||||
<div key={key} className={`invite ${cls}`}>
|
|
||||||
<div className="invite-head">
|
<div className="invite-head">
|
||||||
<strong>{label}</strong>
|
<strong>{label}</strong>
|
||||||
<span className="invite-code">{codes[key]}</span>
|
<span className="invite-code">{codes.spectator}</span>
|
||||||
{open && <button className="link-btn" disabled={!!busy} onClick={() => regen(key, label)}>Neuer Code</button>}
|
{open && <button className="link-btn" disabled={!!busy} onClick={() => regenerate(act, 'spectator', label)}>Neuer Code</button>}
|
||||||
</div>
|
</div>
|
||||||
<CopyField value={links[key]} />
|
<CopyField value={links.spectator} />
|
||||||
{key === 'spectator' && (
|
|
||||||
<div className="stream-link">
|
<div className="stream-link">
|
||||||
<CopyField label="Stream-Übersicht (als Browserquelle in OBS, 1920×1080)" value={links.stream} />
|
<CopyField label="Stream-Übersicht (als Browserquelle in OBS, 1920×1080)" value={links.stream} />
|
||||||
<a className="btn btn-sm" href={links.stream} target="_blank" rel="noreferrer">Stream-Ansicht öffnen</a>
|
<a className="btn btn-sm" href={links.stream} target="_blank" rel="noreferrer">Stream-Ansicht öffnen</a>
|
||||||
<CopyField label="Match-Übersicht (nur dieses Match, ohne Zuschauercode)" value={links.overview} />
|
<CopyField label="Match-Übersicht (nur dieses Match, ohne Zuschauercode)" value={links.overview} />
|
||||||
<a className="btn btn-sm" href={links.overview} target="_blank" rel="noreferrer">Match-Übersicht öffnen</a>
|
<a className="btn btn-sm" href={links.overview} target="_blank" rel="noreferrer">Match-Übersicht öffnen</a>
|
||||||
</div>
|
</div>
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
))}
|
|
||||||
<details className="org-link">
|
<details className="org-link">
|
||||||
<summary>Organisator-Zugang auf einem anderen Gerät öffnen</summary>
|
<summary>Organisator-Zugang auf einem anderen Gerät öffnen</summary>
|
||||||
<p className="small muted">Dieser Link gibt volle Kontrolle über das Match. Nicht weitergeben.</p>
|
<p className="small muted">Dieser Link gibt volle Kontrolle über das Match. Nicht weitergeben.</p>
|
||||||
|
|||||||
@@ -1,3 +1,4 @@
|
|||||||
|
import { TeamInvite } from './OrganizerPanel.jsx';
|
||||||
export default function TeamCard({ team, side, state, viewer, isOrg, act, busy }) {
|
export default function TeamCard({ team, side, state, viewer, isOrg, act, busy }) {
|
||||||
const isOwnTeam = viewer.team === side;
|
const isOwnTeam = viewer.team === side;
|
||||||
const inLobby = state.status === 'lobby';
|
const inLobby = state.status === 'lobby';
|
||||||
@@ -59,6 +60,7 @@ export default function TeamCard({ team, side, state, viewer, isOrg, act, busy }
|
|||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
{inLobby && !readiness.enough && <p className="small muted">Es fehlen noch {team.teamSize - readiness.count} Spieler.</p>}
|
{inLobby && !readiness.enough && <p className="small muted">Es fehlen noch {team.teamSize - readiness.count} Spieler.</p>}
|
||||||
|
{isOrg && state.organizer && <TeamInvite state={state} side={side} act={act} busy={busy} />}
|
||||||
</section>
|
</section>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@@ -775,3 +775,7 @@ input:focus, select:focus { border-color: var(--link); outline: none; }
|
|||||||
.knife-connect { display: flex; flex-wrap: wrap; align-items: end; gap: 8px 12px; margin-top: 10px; }
|
.knife-connect { display: flex; flex-wrap: wrap; align-items: end; gap: 8px 12px; margin-top: 10px; }
|
||||||
.knife-connect > :first-child { flex: 1 1 260px; }
|
.knife-connect > :first-child { flex: 1 1 260px; }
|
||||||
.knife-actions { margin-top: 10px; gap: 8px; flex-wrap: wrap; }
|
.knife-actions { margin-top: 10px; gap: 8px; flex-wrap: wrap; }
|
||||||
|
.team-invite { margin-top: 12px; padding-right: 0; }
|
||||||
|
.team-invite .copy-row { flex-wrap: wrap; }
|
||||||
|
.team-invite .copy-row code { flex: 1 1 100%; font-size: .78rem; white-space: normal; word-break: break-all; overflow: visible; }
|
||||||
|
.team-invite p { margin: 6px 0 0; }
|
||||||
Reference in new issue
Block a user