feat: Printable character sheet
This commit is contained in:
@@ -451,6 +451,9 @@ export default function CharacterSheet() {
|
||||
<span className={`save-status${saveStatus ? " show" : ""}`}>
|
||||
Saved!
|
||||
</span>
|
||||
<button className="btn-print" onClick={() => window.print()}>
|
||||
⎙ Print
|
||||
</button>
|
||||
<button
|
||||
className="btn-theme"
|
||||
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);
|
||||
}
|
||||
|
||||
/* ── 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 ─────────────────────────── */
|
||||
.btn-theme {
|
||||
font-family: var(--font-display);
|
||||
@@ -1137,3 +1156,176 @@ input[type="number"] {
|
||||
::-webkit-scrollbar-thumb:hover {
|
||||
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