Lobby: sheet theme switch in the tab bar, remove extra toolbar
Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01HJhXuLD2Z6hv3Wqeq9UL9K
This commit is contained in:
+31
-13
@@ -1,10 +1,30 @@
|
||||
import { useLayoutEffect, useMemo, useRef, useState } from 'react'
|
||||
import { useLayoutEffect, useMemo, useRef, useState, useSyncExternalStore } from 'react'
|
||||
import Tip from './Tip.jsx'
|
||||
import { compute, effectiveRules, kitItems, normalize } from './calc.js'
|
||||
import { explainAttr, explainCapacity, explainCarry, explainDerived, explainSkill } from './explain.js'
|
||||
|
||||
const PAPER_PX = 794 // 210 mm at 96 dpi
|
||||
|
||||
// Light/dark choice for the sheet, shared by all sheets and switches on the page and remembered in the browser
|
||||
const THEME_KEY = 'aw_sheettheme'
|
||||
const listeners = new Set()
|
||||
const readTheme = () => { try { return localStorage.getItem(THEME_KEY) === 'dark' } catch { return false } }
|
||||
let darkNow = readTheme()
|
||||
export function useSheetTheme() {
|
||||
const dark = useSyncExternalStore((cb) => { listeners.add(cb); return () => listeners.delete(cb) }, () => darkNow)
|
||||
const set = (d) => { darkNow = d; try { localStorage.setItem(THEME_KEY, d ? 'dark' : 'light') } catch { /* storage may be blocked */ } listeners.forEach((f) => f()) }
|
||||
return [dark, set]
|
||||
}
|
||||
export function ThemeSwitch() {
|
||||
const [dark, setDark] = useSheetTheme()
|
||||
return (
|
||||
<span className="seg" role="group" aria-label="Sheet colours">
|
||||
<button className={dark ? 'ghost' : 'on'} onClick={() => setDark(false)} title="Light sheet">Light</button>
|
||||
<button className={dark ? 'on' : 'ghost'} onClick={() => setDark(true)} title="Dark sheet (prints light)">Dark</button>
|
||||
</span>
|
||||
)
|
||||
}
|
||||
|
||||
// Opens the sheet pages in a clean window (only the paper, A4, no margins) and starts the print dialog:
|
||||
// "Save as PDF" there gives an A4 PDF that looks exactly like the screen.
|
||||
export function printSheet(root, title) {
|
||||
@@ -48,14 +68,13 @@ const Pips = ({ n, locked }) => (
|
||||
)
|
||||
|
||||
// The character sheet as A4 pages (page 1: attributes and skills, page 2: talents, mutations, equipment, notes).
|
||||
export default function PaperSheet({ data, baseRules, tools }) {
|
||||
export default function PaperSheet({ data, baseRules, tools, bare }) {
|
||||
const ch = useMemo(() => normalize(data, baseRules), [data, baseRules])
|
||||
const rules = useMemo(() => effectiveRules(baseRules, ch), [baseRules, ch])
|
||||
const c = useMemo(() => compute(ch, rules), [ch, rules])
|
||||
const x = { ch, rules, c }
|
||||
const root = useRef(null)
|
||||
const [dark, setDark] = useState(() => { try { return localStorage.getItem('aw_sheettheme') === 'dark' } catch { return false } })
|
||||
const pickTheme = (d) => { setDark(d); try { localStorage.setItem('aw_sheettheme', d ? 'dark' : 'light') } catch { /* storage may be blocked */ } }
|
||||
const [dark] = useSheetTheme()
|
||||
|
||||
const prof = rules.professions.find((p) => p.id === ch.profession)
|
||||
const cls = rules.classes.find((k) => k.id === ch.class_id)
|
||||
@@ -73,16 +92,15 @@ export default function PaperSheet({ data, baseRules, tools }) {
|
||||
|
||||
return (
|
||||
<div className="papersheet">
|
||||
<div className="papertools">
|
||||
{tools}
|
||||
<span className="toolright">
|
||||
<span className="seg" role="group" aria-label="Sheet colours">
|
||||
<button className={dark ? 'ghost' : 'on'} onClick={() => pickTheme(false)} title="Light sheet">Light</button>
|
||||
<button className={dark ? 'on' : 'ghost'} onClick={() => pickTheme(true)} title="Dark sheet (prints light)">Dark</button>
|
||||
{!bare && (
|
||||
<div className="papertools">
|
||||
{tools}
|
||||
<span className="toolright">
|
||||
<ThemeSwitch />
|
||||
<button className="ghost" onClick={() => printSheet(root.current, name)} title="Opens the pages for printing, choose Save as PDF there">Print / PDF (A4)</button>
|
||||
</span>
|
||||
<button className="ghost" onClick={() => printSheet(root.current, name)} title="Opens the pages for printing, choose Save as PDF there">Print / PDF (A4)</button>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
<Fit rootRef={root} dark={dark}>
|
||||
<section className="paper">
|
||||
<header className="phead">
|
||||
|
||||
Reference in New Issue
Block a user