Add background grid settings

Appearance now has a toggle for the background grid and a choice of
subdivisions (none, 2×2 up to 16×16) that split each page-sized cell
into fainter lines. Subdivisions are left out when zoomed so far out
that they would be under 8 px apart.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01GaoZtJQZwLXkEgWs8twCia
This commit is contained in:
agent 2026-09-27 21:31:12 +00:00
parent f018012cdd
commit 3d29255d0c
4 changed files with 46 additions and 7 deletions

View file

@ -30,11 +30,28 @@
let stage: HTMLDivElement;
const cssVars = pageCssVars();
// Background grid: one cell per active page, aligned to its edges (A4 at the origin if none).
const grid = $derived.by(() => {
// Background grid: one cell per active page, aligned to its edges (A4 at the origin if none),
// optionally split into fainter subdivisions.
const gridStyle = $derived.by(() => {
const g = settings.data.grid;
if (!g.show) return '';
const r = (doc.activeId && doc.rects.get(doc.activeId)) || { x: 0, y: 0, ...A4 };
const s = viewport.scale;
return { w: r.width * s, h: r.height * s, x: viewport.x + r.x * s, y: viewport.y + r.y * s };
const w = r.width * s;
const h = r.height * s;
const lines = (color: string) => [
`linear-gradient(to right, ${color} 1px, transparent 1px)`,
`linear-gradient(to bottom, ${color} 1px, transparent 1px)`
];
const images = lines('var(--grid-line)');
const sizes = [`${w}px ${h}px`, `${w}px ${h}px`];
// Leave out subdivisions once they'd be too dense to read.
const n = g.divisions;
if (n > 1 && Math.min(w, h) / n >= 8) {
images.push(...lines('var(--grid-line-minor)'));
sizes.push(`${w / n}px ${h / n}px`, `${w / n}px ${h / n}px`);
}
return `background-image: ${images.join(', ')}; background-size: ${sizes.join(', ')}; background-position: ${viewport.x + r.x * s}px ${viewport.y + r.y * s}px`;
});
// ---- autosave --------------------------------------------------------
@ -605,7 +622,7 @@
class:panning
class:erasing={tools.tool === 'eraser'}
bind:this={stage}
style="background-size: {grid.w}px {grid.h}px; background-position: {grid.x}px {grid.y}px"
style={gridStyle}
onpointerdown={onPointerDown}
onpointermove={onPointerMove}
onpointerup={onPointerUp}
@ -760,9 +777,6 @@
user-select: none;
-webkit-user-select: none;
background-color: var(--bg-canvas);
background-image:
linear-gradient(to right, var(--grid-line) 1px, transparent 1px),
linear-gradient(to bottom, var(--grid-line) 1px, transparent 1px);
}
.stage :global(.cm-content) {
user-select: text;