Lower, readable table buttons; keep DM buttons in player view
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HJhXuLD2Z6hv3Wqeq9UL9K
This commit is contained in:
@@ -618,6 +618,7 @@ def install(api, db, current_user, lobby_for, dm_only, hub, event, store_dir: Pa
|
|||||||
"vision": {"los": ctx["los"], "empty": ctx["empty"], "rev": ctx["rev"], "fog": ctx.get("fog")}}
|
"vision": {"los": ctx["los"], "empty": ctx["empty"], "rev": ctx["rev"], "fog": ctx.get("fog")}}
|
||||||
if ctx["is_dm"]:
|
if ctx["is_dm"]:
|
||||||
res["los_on"] = bool(lobby["los"])
|
res["los_on"] = bool(lobby["los"])
|
||||||
|
res["wall_count"] = len(ctx["walls"])
|
||||||
res["sight"] = lobby["sight"] if lobby["sight"] is not None else m["sight"]
|
res["sight"] = lobby["sight"] if lobby["sight"] is not None else m["sight"]
|
||||||
res["sight_map"] = m["sight"]
|
res["sight_map"] = m["sight"]
|
||||||
res["fog_on"] = bool(lobby["fog"])
|
res["fog_on"] = bool(lobby["fog"])
|
||||||
|
|||||||
@@ -916,19 +916,19 @@ function LobbyView({ id, rules, user }) {
|
|||||||
{lobby.members.map((m) => <option key={m.username} value={m.username}>View as {m.character?.name || m.username}</option>)}
|
{lobby.members.map((m) => <option key={m.username} value={m.username}>View as {m.character?.name || m.username}</option>)}
|
||||||
</select>
|
</select>
|
||||||
)}
|
)}
|
||||||
{lobby.is_dm && mapState.walls?.length > 0 && mapState.los_on && <>
|
{lobby.is_dm && mapState.wall_count > 0 && mapState.los_on && <>
|
||||||
<label className="small sightrange" title="How far players see, in squares (0 = unlimited). Resets to the map's value when you switch maps."><input type="number" min="0" max="1000" key={mapState.sight} defaultValue={mapState.sight} aria-label="Sight range in squares"
|
<label className="small sightrange" title="How far players see, in squares (0 = unlimited). Resets to the map's value when you switch maps."><input type="number" min="0" max="1000" key={mapState.sight} defaultValue={mapState.sight} aria-label="Sight range in squares"
|
||||||
onBlur={(e) => e.target.value !== String(mapState.sight) && act(`/api/lobbies/${id}/sight`, 'PUT', { range: e.target.value }, () => loadMap())} onKeyDown={(e) => e.key === 'Enter' && e.currentTarget.blur()} /> sq.</label>
|
onBlur={(e) => e.target.value !== String(mapState.sight) && act(`/api/lobbies/${id}/sight`, 'PUT', { range: e.target.value }, () => loadMap())} onKeyDown={(e) => e.key === 'Enter' && e.currentTarget.blur()} /> sq.</label>
|
||||||
<button className={mapState.fog_on ? 'on' : 'ghost'} aria-pressed={!!mapState.fog_on} onClick={() => act(`/api/lobbies/${id}/sight`, 'PUT', { fog: !mapState.fog_on }, () => loadMap())} title="Fog of war: players keep a dim memory of what they have seen">Fog</button>
|
<button className={mapState.fog_on ? 'on' : 'ghost'} aria-pressed={!!mapState.fog_on} onClick={() => act(`/api/lobbies/${id}/sight`, 'PUT', { fog: !mapState.fog_on }, () => loadMap())} title="Fog of war: players keep a dim memory of what they have seen">Fog</button>
|
||||||
{mapState.fog_on && <button className="ghost" onClick={() => window.confirm('Forget everything the players have explored?') && act(`/api/lobbies/${id}/explored`, 'DELETE', undefined, () => loadMap())} title="Forget the explored ground">↺</button>}
|
{mapState.fog_on && <button className="ghost" onClick={() => window.confirm('Forget everything the players have explored?') && act(`/api/lobbies/${id}/explored`, 'DELETE', undefined, () => loadMap())} title="Forget the explored ground">↺</button>}
|
||||||
</>}
|
</>}
|
||||||
{full && mapState.walls?.length > 0 && mapState.los_on && <button className={rv ? 'on' : 'ghost'} aria-pressed={!!rv} onClick={() => setRv(rv ? null : { origin: null, target: null, hover: null, fov: 90, to: null })} title="Show players a far away area: click the spot, then click where it ends">👁 Reveal</button>}
|
{lobby.is_dm && mapState.wall_count > 0 && mapState.los_on && <button disabled={!full} className={rv ? 'on' : 'ghost'} aria-pressed={!!rv} onClick={() => setRv(rv ? null : { origin: null, target: null, hover: null, fov: 90, to: null })} title={full ? 'Show players a far away area: click the spot, then click where it ends' : 'Switch to the full view to use this'}>👁 Reveal</button>}
|
||||||
{lobby.is_dm && mapState.walls?.length > 0 && <button className={mapState.los_on ? 'on' : 'ghost'} aria-pressed={!!mapState.los_on} onClick={() => act(`/api/lobbies/${id}/sight`, 'PUT', { on: !mapState.los_on }, () => loadMap())} title="Line of sight: players only see what their character can see">Sight {mapState.los_on ? 'on' : 'off'}</button>}
|
{lobby.is_dm && mapState.wall_count > 0 && <button className={mapState.los_on ? 'on' : 'ghost'} aria-pressed={!!mapState.los_on} onClick={() => act(`/api/lobbies/${id}/sight`, 'PUT', { on: !mapState.los_on }, () => loadMap())} title="Line of sight: players only see what their character can see">Sight {mapState.los_on ? 'on' : 'off'}</button>}
|
||||||
{full && mapState.walls?.length > 0 && <button className={showWalls ? 'on' : 'ghost'} aria-pressed={showWalls} onClick={() => setShowWalls(!showWalls)} title="Show walls and doors (click a door to open or close it)">Walls</button>}
|
{lobby.is_dm && mapState.wall_count > 0 && <button disabled={!full} className={showWalls ? 'on' : 'ghost'} aria-pressed={showWalls} onClick={() => setShowWalls(!showWalls)} title="Show walls and doors (click a door to open or close it)">Walls</button>}
|
||||||
<button className={showGrid ? 'on' : 'ghost'} aria-pressed={showGrid} onClick={() => setShowGrid(!showGrid)}>Grid</button>
|
<button className={showGrid ? 'on' : 'ghost'} aria-pressed={showGrid} onClick={() => setShowGrid(!showGrid)}>Grid</button>
|
||||||
{full && <button className="ghost" onClick={addToken}>+ Token</button>}
|
{lobby.is_dm && <button className="ghost" onClick={addToken}>+ Token</button>}
|
||||||
{full && <button className={npcPick ? 'on' : 'ghost'} onClick={() => { setNpcPick(!npcPick); setPropPick(false) }}>+ NPC</button>}
|
{lobby.is_dm && <button className={npcPick ? 'on' : 'ghost'} onClick={() => { setNpcPick(!npcPick); setPropPick(false) }}>+ NPC</button>}
|
||||||
{full && <button className={propPick ? 'on' : 'ghost'} onClick={() => { setPropPick(!propPick); setNpcPick(false) }} title="Decor such as chests, tables or doors">+ Prop</button>}
|
{lobby.is_dm && <button className={propPick ? 'on' : 'ghost'} onClick={() => { setPropPick(!propPick); setNpcPick(false) }} title="Decor such as chests, tables or doors">+ Prop</button>}
|
||||||
</div>
|
</div>
|
||||||
{full && (rv || mapState.reveals?.length > 0) && (
|
{full && (rv || mapState.reveals?.length > 0) && (
|
||||||
<div className="tokenpanel mapui revealpanel">
|
<div className="tokenpanel mapui revealpanel">
|
||||||
|
|||||||
@@ -629,3 +629,10 @@ textarea.pwrite:focus { box-shadow: 0 0 0 1px var(--pg); }
|
|||||||
.tokenform .mini { min-height: 0; padding: .15rem .5rem; }
|
.tokenform .mini { min-height: 0; padding: .15rem .5rem; }
|
||||||
.tokenlist .tokrow > button:first-child { width: auto; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
.tokenlist .tokrow > button:first-child { width: auto; flex: 1; min-width: 0; overflow: hidden; text-overflow: ellipsis; }
|
||||||
.tokenlist .tokrow > button.mini { width: auto; flex: none; }
|
.tokenlist .tokrow > button.mini { width: auto; flex: none; }
|
||||||
|
/* table tool buttons: low and readable on the dark map */
|
||||||
|
.maptools button, .maptools select { padding: .1rem .5rem; font-size: .76rem; line-height: 1.2; height: 1.6rem; min-height: 0; }
|
||||||
|
.maptools button.ghost, .maptools select { background: rgba(20,22,26,.85); color: #f1f1f1; border: 1px solid rgba(255,255,255,.35); }
|
||||||
|
.maptools button.on { background: var(--accent, #2f7d32); color: #fff; border-color: transparent; }
|
||||||
|
.maptools button:disabled { opacity: .45; }
|
||||||
|
.maptools .sightrange input { height: 1.6rem; padding: 0 .3rem; }
|
||||||
|
.maptools .sightrange { color: #f1f1f1; }
|
||||||
|
|||||||
Reference in New Issue
Block a user