feat: Printable character sheet
This commit is contained in:
@@ -451,6 +451,9 @@ export default function CharacterSheet() {
|
|||||||
<span className={`save-status${saveStatus ? " show" : ""}`}>
|
<span className={`save-status${saveStatus ? " show" : ""}`}>
|
||||||
Saved!
|
Saved!
|
||||||
</span>
|
</span>
|
||||||
|
<button className="btn-print" onClick={() => window.print()}>
|
||||||
|
⎙ Print
|
||||||
|
</button>
|
||||||
<button
|
<button
|
||||||
className="btn-theme"
|
className="btn-theme"
|
||||||
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
|
onClick={() => setTheme((t) => (t === "light" ? "dark" : "light"))}
|
||||||
|
|||||||
@@ -1075,6 +1075,25 @@ input[type="number"] {
|
|||||||
box-shadow: 0 0 8px rgba(26, 122, 118, 0.35);
|
box-shadow: 0 0 8px rgba(26, 122, 118, 0.35);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── PRINT BUTTON ────────────────────────────────── */
|
||||||
|
.btn-print {
|
||||||
|
font-family: var(--font-display);
|
||||||
|
font-size: 0.55rem;
|
||||||
|
letter-spacing: 0.12em;
|
||||||
|
text-transform: uppercase;
|
||||||
|
padding: 7px 12px;
|
||||||
|
cursor: pointer;
|
||||||
|
border: 1px solid var(--border-bright);
|
||||||
|
background: transparent;
|
||||||
|
color: var(--text-dim);
|
||||||
|
transition: all 0.2s;
|
||||||
|
}
|
||||||
|
|
||||||
|
.btn-print:hover {
|
||||||
|
border-color: var(--teal-dim);
|
||||||
|
color: var(--teal);
|
||||||
|
}
|
||||||
|
|
||||||
/* ── THEME TOGGLE BUTTON ─────────────────────────── */
|
/* ── THEME TOGGLE BUTTON ─────────────────────────── */
|
||||||
.btn-theme {
|
.btn-theme {
|
||||||
font-family: var(--font-display);
|
font-family: var(--font-display);
|
||||||
@@ -1137,3 +1156,176 @@ input[type="number"] {
|
|||||||
::-webkit-scrollbar-thumb:hover {
|
::-webkit-scrollbar-thumb:hover {
|
||||||
background: var(--teal-dim);
|
background: var(--teal-dim);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* ── PRINT ───────────────────────────────────────── */
|
||||||
|
|
||||||
|
/* Content is shrunk to fit one page via a smaller root font-size (shrinks all
|
||||||
|
rem-sized text/spacing) plus tighter print-specific paddings — NOT via
|
||||||
|
zoom/transform tricks, since browsers don't reliably honor those during
|
||||||
|
print layout, which previously caused content to overflow the page and get
|
||||||
|
clipped on the right edge. .page is always kept at width: 100% so it can
|
||||||
|
never exceed the printable area. */
|
||||||
|
@page {
|
||||||
|
size: letter portrait;
|
||||||
|
margin: 0.4in 0.5in;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media print {
|
||||||
|
:root {
|
||||||
|
--bg: #fff;
|
||||||
|
--surface: #fff;
|
||||||
|
--surface2: #f9f9f9;
|
||||||
|
--surface3: #f3f3f3;
|
||||||
|
--border: #ccc;
|
||||||
|
--border-bright: #aaa;
|
||||||
|
--teal: #1a7a76;
|
||||||
|
--teal-dim: #1a7a76;
|
||||||
|
--gold: #8a6520;
|
||||||
|
--gold-dim: #8a6520;
|
||||||
|
--text: #111;
|
||||||
|
--text-dim: #555;
|
||||||
|
--text-bright: #000;
|
||||||
|
--crisis: #c0392b;
|
||||||
|
font-size: 65%;
|
||||||
|
}
|
||||||
|
|
||||||
|
* {
|
||||||
|
-webkit-print-color-adjust: exact;
|
||||||
|
print-color-adjust: exact;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
background: #fff !important;
|
||||||
|
background-image: none !important;
|
||||||
|
font-size: 11px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide all screen-only chrome */
|
||||||
|
header,
|
||||||
|
.url-banner,
|
||||||
|
#page-manage {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Each tab prints as one portrait page, never wider than the page */
|
||||||
|
.page {
|
||||||
|
display: block !important;
|
||||||
|
width: 100% !important;
|
||||||
|
max-width: none !important;
|
||||||
|
margin: 0 !important;
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
box-sizing: border-box !important;
|
||||||
|
overflow: hidden;
|
||||||
|
page-break-after: always;
|
||||||
|
break-after: page;
|
||||||
|
page-break-inside: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
#page-spells {
|
||||||
|
page-break-after: avoid;
|
||||||
|
break-after: avoid;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tighten spacing so content fits within the page */
|
||||||
|
.section {
|
||||||
|
padding: 6px 10px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.section-title {
|
||||||
|
margin-bottom: 5px !important;
|
||||||
|
padding-bottom: 4px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field {
|
||||||
|
margin-bottom: 5px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
margin-bottom: 2px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-2,
|
||||||
|
.grid-3 {
|
||||||
|
gap: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Flex/grid items default to min-width: auto (their content's intrinsic
|
||||||
|
size), which can force the container wider than the page and clip the
|
||||||
|
right edge. Overriding to 0 lets every item shrink to fit. */
|
||||||
|
.page * {
|
||||||
|
min-width: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.field-row {
|
||||||
|
gap: 8px !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Make inputs look clean for print — just an underline, no box */
|
||||||
|
input[type="text"],
|
||||||
|
input:not([type]),
|
||||||
|
input[type="number"],
|
||||||
|
textarea,
|
||||||
|
select {
|
||||||
|
background: transparent !important;
|
||||||
|
border: none !important;
|
||||||
|
border-bottom: 1px solid #bbb !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
padding: 1px 2px !important;
|
||||||
|
color: #000 !important;
|
||||||
|
min-height: unset !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
textarea {
|
||||||
|
resize: none !important;
|
||||||
|
overflow: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Hide interactive-only buttons */
|
||||||
|
.add-btn,
|
||||||
|
.spell-del-btn,
|
||||||
|
.btn-print,
|
||||||
|
.btn-theme,
|
||||||
|
.btn-save,
|
||||||
|
.btn-load,
|
||||||
|
.save-status {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Calc buttons inside vital-block */
|
||||||
|
.vital-block > .add-btn {
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* XP / FP visuals */
|
||||||
|
.xp-bar-wrap {
|
||||||
|
background: #eee !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.xp-bar {
|
||||||
|
background: #1a7a76 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fp-pip {
|
||||||
|
border-color: #999 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.fp-pip.filled {
|
||||||
|
background: #1a7a76 !important;
|
||||||
|
box-shadow: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Status / discipline toggles */
|
||||||
|
.status-item.active-status {
|
||||||
|
background: #ddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.disc-item.checked {
|
||||||
|
background: #ddd !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Tables */
|
||||||
|
th, td {
|
||||||
|
border-color: #ccc !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user