Palm tests, erase fix, swipe-to-add, size dialog, grid settings, docs #12
4 changed files with 46 additions and 7 deletions
|
|
@ -61,6 +61,7 @@
|
||||||
--shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 16px rgba(0, 0, 0, 0.08);
|
--shadow: 0 1px 2px rgba(0, 0, 0, 0.06), 0 4px 16px rgba(0, 0, 0, 0.08);
|
||||||
--page-line: rgba(0, 0, 0, 0.18);
|
--page-line: rgba(0, 0, 0, 0.18);
|
||||||
--grid-line: rgba(0, 0, 0, 0.05);
|
--grid-line: rgba(0, 0, 0, 0.05);
|
||||||
|
--grid-line-minor: rgba(0, 0, 0, 0.028);
|
||||||
--ghost: rgba(0, 0, 0, 0.045);
|
--ghost: rgba(0, 0, 0, 0.045);
|
||||||
--ghost-border: rgba(0, 0, 0, 0.12);
|
--ghost-border: rgba(0, 0, 0, 0.12);
|
||||||
--radius: 6px;
|
--radius: 6px;
|
||||||
|
|
@ -88,6 +89,7 @@
|
||||||
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35);
|
--shadow: 0 1px 2px rgba(0, 0, 0, 0.3), 0 6px 20px rgba(0, 0, 0, 0.35);
|
||||||
--page-line: rgba(255, 255, 255, 0.16);
|
--page-line: rgba(255, 255, 255, 0.16);
|
||||||
--grid-line: rgba(255, 255, 255, 0.04);
|
--grid-line: rgba(255, 255, 255, 0.04);
|
||||||
|
--grid-line-minor: rgba(255, 255, 255, 0.022);
|
||||||
--ghost: rgba(255, 255, 255, 0.04);
|
--ghost: rgba(255, 255, 255, 0.04);
|
||||||
--ghost-border: rgba(255, 255, 255, 0.14);
|
--ghost-border: rgba(255, 255, 255, 0.14);
|
||||||
color-scheme: dark;
|
color-scheme: dark;
|
||||||
|
|
|
||||||
|
|
@ -30,11 +30,28 @@
|
||||||
let stage: HTMLDivElement;
|
let stage: HTMLDivElement;
|
||||||
const cssVars = pageCssVars();
|
const cssVars = pageCssVars();
|
||||||
|
|
||||||
// Background grid: one cell per active page, aligned to its edges (A4 at the origin if none).
|
// Background grid: one cell per active page, aligned to its edges (A4 at the origin if none),
|
||||||
const grid = $derived.by(() => {
|
// 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 r = (doc.activeId && doc.rects.get(doc.activeId)) || { x: 0, y: 0, ...A4 };
|
||||||
const s = viewport.scale;
|
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 --------------------------------------------------------
|
// ---- autosave --------------------------------------------------------
|
||||||
|
|
@ -605,7 +622,7 @@
|
||||||
class:panning
|
class:panning
|
||||||
class:erasing={tools.tool === 'eraser'}
|
class:erasing={tools.tool === 'eraser'}
|
||||||
bind:this={stage}
|
bind:this={stage}
|
||||||
style="background-size: {grid.w}px {grid.h}px; background-position: {grid.x}px {grid.y}px"
|
style={gridStyle}
|
||||||
onpointerdown={onPointerDown}
|
onpointerdown={onPointerDown}
|
||||||
onpointermove={onPointerMove}
|
onpointermove={onPointerMove}
|
||||||
onpointerup={onPointerUp}
|
onpointerup={onPointerUp}
|
||||||
|
|
@ -760,9 +777,6 @@
|
||||||
user-select: none;
|
user-select: none;
|
||||||
-webkit-user-select: none;
|
-webkit-user-select: none;
|
||||||
background-color: var(--bg-canvas);
|
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) {
|
.stage :global(.cm-content) {
|
||||||
user-select: text;
|
user-select: text;
|
||||||
|
|
|
||||||
|
|
@ -83,6 +83,20 @@
|
||||||
<option value="paper">Paper</option>
|
<option value="paper">Paper</option>
|
||||||
</select>
|
</select>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div><div class="name">Background grid</div><div class="desc">Faint lines behind the pages, one cell per active page.</div></div>
|
||||||
|
<input type="checkbox" class="toggle" bind:checked={s.grid.show} onchange={save} />
|
||||||
|
</div>
|
||||||
|
<div class="row">
|
||||||
|
<div><div class="name">Grid subdivisions</div><div class="desc">Split each page-sized cell into a finer grid for sketching and lining things up.</div></div>
|
||||||
|
<select bind:value={s.grid.divisions} onchange={save} disabled={!s.grid.show}>
|
||||||
|
<option value={1}>None</option>
|
||||||
|
<option value={2}>2 × 2</option>
|
||||||
|
<option value={4}>4 × 4</option>
|
||||||
|
<option value={8}>8 × 8</option>
|
||||||
|
<option value={16}>16 × 16</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
{:else if tab === 'input'}
|
{:else if tab === 'input'}
|
||||||
<h2>Pen & touch</h2>
|
<h2>Pen & touch</h2>
|
||||||
<div class="row">
|
<div class="row">
|
||||||
|
|
|
||||||
|
|
@ -6,6 +6,12 @@ import { DEFAULT_PALM, type PalmOptions } from '$lib/ink/palm';
|
||||||
export type ThemePref = 'system' | 'light' | 'dark';
|
export type ThemePref = 'system' | 'light' | 'dark';
|
||||||
export type PageStylePref = 'paper' | 'match';
|
export type PageStylePref = 'paper' | 'match';
|
||||||
|
|
||||||
|
export interface GridSettings {
|
||||||
|
show: boolean;
|
||||||
|
/** Minor lines per page cell side (1 = page-sized cells only). */
|
||||||
|
divisions: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface GitHubSettings {
|
export interface GitHubSettings {
|
||||||
token: string;
|
token: string;
|
||||||
owner: string;
|
owner: string;
|
||||||
|
|
@ -18,6 +24,7 @@ export interface GitHubSettings {
|
||||||
interface SettingsData {
|
interface SettingsData {
|
||||||
theme: ThemePref;
|
theme: ThemePref;
|
||||||
pageStyle: PageStylePref;
|
pageStyle: PageStylePref;
|
||||||
|
grid: GridSettings;
|
||||||
fingerDraw: boolean;
|
fingerDraw: boolean;
|
||||||
palm: PalmOptions;
|
palm: PalmOptions;
|
||||||
github: GitHubSettings;
|
github: GitHubSettings;
|
||||||
|
|
@ -30,6 +37,7 @@ interface SettingsData {
|
||||||
const DEFAULTS: SettingsData = {
|
const DEFAULTS: SettingsData = {
|
||||||
theme: 'system',
|
theme: 'system',
|
||||||
pageStyle: 'match',
|
pageStyle: 'match',
|
||||||
|
grid: { show: true, divisions: 1 },
|
||||||
fingerDraw: true,
|
fingerDraw: true,
|
||||||
palm: DEFAULT_PALM,
|
palm: DEFAULT_PALM,
|
||||||
github: { token: '', owner: '', repo: '', branch: 'main', dir: '' },
|
github: { token: '', owner: '', repo: '', branch: 'main', dir: '' },
|
||||||
|
|
@ -48,6 +56,7 @@ function load(): SettingsData {
|
||||||
return {
|
return {
|
||||||
...DEFAULTS,
|
...DEFAULTS,
|
||||||
...saved,
|
...saved,
|
||||||
|
grid: { ...DEFAULTS.grid, ...saved.grid },
|
||||||
palm: { ...DEFAULTS.palm, ...saved.palm },
|
palm: { ...DEFAULTS.palm, ...saved.palm },
|
||||||
github: { ...DEFAULTS.github, ...saved.github }
|
github: { ...DEFAULTS.github, ...saved.github }
|
||||||
};
|
};
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue