From 5ec853bfb00794d8ac257b8f20168f00916d98d7 Mon Sep 17 00:00:00 2001 From: Antti Urpelainen Date: Mon, 15 Jun 2026 19:24:42 +0300 Subject: [PATCH 1/4] fix: surface atlas overflow to the user via toast Replace the dev-only console.warn with an error toast so users actually see when glyphs did not fit in the atlas. --- src/features/editor/AtlasFloat.tsx | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/features/editor/AtlasFloat.tsx b/src/features/editor/AtlasFloat.tsx index 1fbd1f6..98cbdfd 100644 --- a/src/features/editor/AtlasFloat.tsx +++ b/src/features/editor/AtlasFloat.tsx @@ -35,6 +35,7 @@ export const AtlasFloat = ({ open, onClose }: Props): React.JSX.Element => { const atlasEfficiency = useStore((state) => state.atlasEfficiency); const setAtlasResult = useStore((state) => state.setAtlasResult); const exportSelection = useStore((state) => state.exportSelection); + const addToast = useStore((state) => state.addToast); const { packAtlas } = useAtlas(); @@ -67,7 +68,7 @@ export const AtlasFloat = ({ open, onClose }: Props): React.JSX.Element => { ); if (unpacked.length > 0) { - console.warn(`${unpacked.length} glyphs did not fit in atlas`); + addToast(`${unpacked.length} glyphs did not fit in atlas`, 'error'); } setAtlasResult(placements, imageData, packedWidth, packedHeight, efficiency); From ab11cdbcc8526e1879a5d501721391502aba5ea4 Mon Sep 17 00:00:00 2001 From: Antti Urpelainen Date: Mon, 15 Jun 2026 19:24:46 +0300 Subject: [PATCH 2/4] refactor: extract shared PixelInput from padding/spacing fields PaddingFields and SpacingFields each declared an identical pixel input component. Consolidate into a single PixelInput module. --- src/features/home/PaddingFields.tsx | 34 +++++------------------------ src/features/home/PixelInput.tsx | 28 ++++++++++++++++++++++++ src/features/home/SpacingFields.tsx | 30 +++---------------------- 3 files changed, 36 insertions(+), 56 deletions(-) create mode 100644 src/features/home/PixelInput.tsx diff --git a/src/features/home/PaddingFields.tsx b/src/features/home/PaddingFields.tsx index 2463645..25575af 100644 --- a/src/features/home/PaddingFields.tsx +++ b/src/features/home/PaddingFields.tsx @@ -1,32 +1,8 @@ import React from 'react'; -import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -const PaddingInput = ({ - label, - value, - onChange, -}: { - label: string; - value: number; - onChange: (value: number) => void; -}): React.JSX.Element => ( -
- {label} -
- onChange(Number(event.target.value))} - /> - px -
-
-); +import { PixelInput } from './PixelInput'; export const PaddingFields = ({ top, @@ -53,13 +29,13 @@ export const PaddingFields = ({

Extra space around each glyph.

- +
- +
- +
- +
diff --git a/src/features/home/PixelInput.tsx b/src/features/home/PixelInput.tsx new file mode 100644 index 0000000..15c6935 --- /dev/null +++ b/src/features/home/PixelInput.tsx @@ -0,0 +1,28 @@ +import React from 'react'; + +import { Input } from '@/components/ui/input'; + +export const PixelInput = ({ + label, + value, + onChange, +}: { + label: string; + value: number; + onChange: (value: number) => void; +}): React.JSX.Element => ( +
+ {label} +
+ onChange(Number(event.target.value))} + /> + px +
+
+); diff --git a/src/features/home/SpacingFields.tsx b/src/features/home/SpacingFields.tsx index 6163e64..0c1f5f5 100644 --- a/src/features/home/SpacingFields.tsx +++ b/src/features/home/SpacingFields.tsx @@ -1,32 +1,8 @@ import React from 'react'; -import { Input } from '@/components/ui/input'; import { Label } from '@/components/ui/label'; -const SpacingInput = ({ - label, - value, - onChange, -}: { - label: string; - value: number; - onChange: (value: number) => void; -}): React.JSX.Element => ( -
- {label} -
- onChange(Number(event.target.value))} - /> - px -
-
-); +import { PixelInput } from './PixelInput'; export const SpacingFields = ({ x, @@ -44,8 +20,8 @@ export const SpacingFields = ({

Extra gap between glyphs in the atlas.

- - + +
); From ca96757e781b953a3a8b060ad1b0d7434699f7b0 Mon Sep 17 00:00:00 2001 From: Antti Urpelainen Date: Mon, 15 Jun 2026 19:24:52 +0300 Subject: [PATCH 3/4] chore: clear remaining eslint errors Narrow Slider onValueChange via typeof instead of Array.isArray so TS keeps the union narrowed (Array.isArray widens to any[]), and add the blank lines required by padding-line-between-statements in main. --- src/features/editor/glyph-list/GlyphList.tsx | 2 +- src/features/editor/toolbar/EditorToolbar.tsx | 2 +- src/main.tsx | 2 ++ 3 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/features/editor/glyph-list/GlyphList.tsx b/src/features/editor/glyph-list/GlyphList.tsx index 63e4bfd..d770a4f 100644 --- a/src/features/editor/glyph-list/GlyphList.tsx +++ b/src/features/editor/glyph-list/GlyphList.tsx @@ -395,7 +395,7 @@ export const GlyphList = ({ max={255} step={1} onValueChange={(value: number | readonly number[]) => { - const next = Array.isArray(value) ? value[0] : value; + const next = typeof value === 'number' ? value : value[0]; setGlyphAlphaThreshold(glyph, next); }} diff --git a/src/features/editor/toolbar/EditorToolbar.tsx b/src/features/editor/toolbar/EditorToolbar.tsx index 2589b82..cfd52bd 100644 --- a/src/features/editor/toolbar/EditorToolbar.tsx +++ b/src/features/editor/toolbar/EditorToolbar.tsx @@ -141,7 +141,7 @@ export const EditorToolbar = ({ return; } - const next = Array.isArray(value) ? value[0] : value; + const next = typeof value === 'number' ? value : value[0]; const settings = { ...currentProject.settings, alphaThreshold: next }; updateCurrentProject({ settings }); diff --git a/src/main.tsx b/src/main.tsx index e85fe1f..8dd0395 100644 --- a/src/main.tsx +++ b/src/main.tsx @@ -11,8 +11,10 @@ import App from './App.tsx'; document.documentElement.classList.add('dark'); const spaRedirect = sessionStorage.getItem('spa-redirect'); + if (spaRedirect) { sessionStorage.removeItem('spa-redirect'); + if (spaRedirect.startsWith(import.meta.env.BASE_URL)) { history.replaceState(null, '', spaRedirect); } From ae5751e71ad323740efda5faae0d5e7d920784fd Mon Sep 17 00:00:00 2001 From: Antti Urpelainen Date: Mon, 15 Jun 2026 19:26:51 +0300 Subject: [PATCH 4/4] ci: run eslint on every pull request Adds a lint job that runs on pull_request to main. ESLint exits non-zero on any error, failing the check so the PR cannot be merged once the new check is marked required in the branch ruleset. --- .github/workflows/ci.yml | 23 +++++++++++++++++++++++ 1 file changed, 23 insertions(+) create mode 100644 .github/workflows/ci.yml diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml new file mode 100644 index 0000000..1897dc9 --- /dev/null +++ b/.github/workflows/ci.yml @@ -0,0 +1,23 @@ +name: CI + +on: + pull_request: + branches: [main] + workflow_dispatch: + +jobs: + lint: + runs-on: ubuntu-latest + steps: + - uses: actions/checkout@v4 + + - uses: pnpm/action-setup@v4 + + - uses: actions/setup-node@v4 + with: + node-version: 22 + cache: pnpm + + - run: pnpm install --frozen-lockfile + + - run: pnpm lint