diff --git a/.gitea/workflows/deploy.yaml b/.gitea/workflows/deploy.yaml
index 58e7ac0..9a96a52 100644
--- a/.gitea/workflows/deploy.yaml
+++ b/.gitea/workflows/deploy.yaml
@@ -91,6 +91,11 @@ jobs:
# already on PATH from `npm i -g pnpm` (gitea-runners.md §4).
cd web
pnpm install --frozen-lockfile
+ # The web half's counterpart to `cargo fmt --check` above. It skips
+ # src/api/generated (.prettierignore) — ts-rs owns those files and
+ # regenerates them in its own style, so formatting them here would be
+ # undone on the next `cargo test` and fail the drift gate above.
+ pnpm format:check
pnpm lint
pnpm build
diff --git a/web/.prettierignore b/web/.prettierignore
new file mode 100644
index 0000000..b462b3f
--- /dev/null
+++ b/web/.prettierignore
@@ -0,0 +1,7 @@
+# Written by ts-rs from the Rust entities crate when `cargo test -p
+# blackbeard-entities` runs, and checked for drift in CI. Formatting them here
+# would be undone by the next regeneration, and the "generated types are
+# current" gate would then fail on every build.
+src/api/generated/
+
+dist/
diff --git a/web/package.json b/web/package.json
index 225f9ef..eb0cd8c 100644
--- a/web/package.json
+++ b/web/package.json
@@ -10,6 +10,7 @@
"preview": "vite preview",
"lint": "eslint .",
"format": "prettier --write src",
+ "format:check": "prettier --check src",
"typecheck": "tsc -b --noEmit"
},
"dependencies": {
diff --git a/web/src/App.tsx b/web/src/App.tsx
index a3d7e89..c5343fc 100644
--- a/web/src/App.tsx
+++ b/web/src/App.tsx
@@ -56,7 +56,10 @@ export default function App() {
// Default to the busiest chain we can actually track — the list is ordered
// by node count, and an untracked chain has nothing behind it.
const chain = route.chain ?? state.chains.find((c) => c.tracking === 'full')?.id ?? null
- const info = useMemo(() => state.chains.find((c) => c.id === chain) ?? null, [state.chains, chain])
+ const info = useMemo(
+ () => state.chains.find((c) => c.id === chain) ?? null,
+ [state.chains, chain],
+ )
useWatch(chain, route.window)
@@ -67,16 +70,14 @@ export default function App() {
: `/${merged.chain ?? ''}/${merged.window}`
}, [])
- const selectMiner = useCallback(
- (miner: string) => {
- // Keep the chain and window; the miner panel opens above the board rather
- // than replacing the page, so the standings stay visible behind it.
- setRoute((r) => ({ ...r, miner }))
- },
- [],
- )
+ const selectMiner = useCallback((miner: string) => {
+ // Keep the chain and window; the miner panel opens above the board rather
+ // than replacing the page, so the standings stay visible behind it.
+ setRoute((r) => ({ ...r, miner }))
+ }, [])
- const interval = state.summary?.block_interval_seconds ?? state.summary?.target_block_time_seconds ?? 6
+ const interval =
+ state.summary?.block_interval_seconds ?? state.summary?.target_block_time_seconds ?? 6
const activeWindow = WINDOWS.find((w) => w.id === route.window) ?? WINDOWS[1]!
return (
@@ -199,7 +200,10 @@ function Sigil() {
stroke="var(--data)"
strokeWidth="1.6"
/>
-