Skip to content

Commit 7f55b72

Browse files
Jing-yilinclaude
andcommitted
Review fixes: board hashes skip non-files, jump buttons off in another project, theme follows other windows
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
1 parent 854319c commit 7f55b72

4 files changed

Lines changed: 30 additions & 18 deletions

File tree

‎canvas/server/boards.ts‎

Lines changed: 10 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ export const boardHash = (file: string) =>
1313
/**
1414
* What each board in a boards directory holds, by `<slug>/<file>.html`: a generator writes every
1515
* board on each run, and only the ones whose bytes changed are news. An unreadable or missing
16-
* folder holds none.
16+
* folder holds none, and a dot-file or a folder named like a board is no board.
1717
*/
1818
export function hashBoards(canvasesDir: string) {
1919
const list = (dir: string) => {
@@ -25,12 +25,15 @@ export function hashBoards(canvasesDir: string) {
2525
};
2626
const hashes = new Map<string, string>();
2727
for (const slug of list(canvasesDir))
28-
for (const name of list(path.join(canvasesDir, slug)))
29-
if (name.endsWith(".html"))
30-
hashes.set(
31-
`${slug}/${name}`.normalize("NFC"),
32-
boardHash(path.join(canvasesDir, slug, name)),
33-
);
28+
for (const name of list(path.join(canvasesDir, slug))) {
29+
const file = path.join(canvasesDir, slug, name);
30+
if (
31+
name.endsWith(".html") &&
32+
!name.startsWith(".") &&
33+
fs.statSync(file, { throwIfNoEntry: false })?.isFile()
34+
)
35+
hashes.set(`${slug}/${name}`.normalize("NFC"), boardHash(file));
36+
}
3437
return hashes;
3538
}
3639

‎canvas/src/App.tsx‎

Lines changed: 4 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ import {
1515
renderPlaintextFromRichText,
1616
toRichText,
1717
type Editor,
18+
type TLPage,
1819
type TLPageId,
1920
type TLAsset,
2021
type TLAssetStore,
@@ -1208,13 +1209,9 @@ export default function App() {
12081209
// (canvas.json). Its own canvas first, where the library puts it. None when it has gone
12091210
// since the reply, deleted or renamed by a later one.
12101211
const slug = board.split("/")[0];
1211-
const pages = editor
1212-
.getPages()
1213-
.sort(
1214-
(a, b) =>
1215-
Number(b.meta.canvasSlug === slug) -
1216-
Number(a.meta.canvasSlug === slug),
1217-
);
1212+
const own = (page: TLPage) =>
1213+
Number(String(page.meta.canvasSlug).normalize("NFC") === slug);
1214+
const pages = editor.getPages().sort((a, b) => own(b) - own(a));
12181215
for (const page of pages)
12191216
for (const id of editor.getPageShapeIds(page)) {
12201217
const shape = editor.getShape(id)!;

‎canvas/src/ChatPanel.tsx‎

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -258,9 +258,10 @@ interface Attached {
258258
/**
259259
* What a reply made or changed, each a button that finds it on the canvas: blue for a new board
260260
* and green for a rewritten one, as their rings are there. Folded to three rows when there are
261-
* more, which a generator rewriting every board makes common.
261+
* more, which a generator rewriting every board makes common. Off when the reply's project is not
262+
* the one in front, whose canvas would not have them.
262263
*/
263-
function MadeBoards({ made }: { made: MadeBoard[] }) {
264+
function MadeBoards({ made, away }: { made: MadeBoard[]; away: boolean }) {
264265
const list = useRef<HTMLDivElement>(null);
265266
const [open, setOpen] = useState(false);
266267
const [folds, setFolds] = useState(false);
@@ -279,7 +280,12 @@ function MadeBoards({ made }: { made: MadeBoard[] }) {
279280
key={m.board}
280281
type="button"
281282
data-made={m.status}
282-
title={`Show ${m.board} on the canvas`}
283+
disabled={away}
284+
title={
285+
away
286+
? `${m.board} is in another project`
287+
: `Show ${m.board} on the canvas`
288+
}
283289
onClick={() =>
284290
window.dispatchEvent(
285291
new CustomEvent(FOCUS_BOARD, { detail: m.board }),
@@ -1404,7 +1410,7 @@ export function ChatPanel(props: {
14041410
),
14051411
)}
14061412
{t.end?.made && t.end.made.length > 0 && (
1407-
<MadeBoards made={t.end.made} />
1413+
<MadeBoards made={t.end.made} away={t.project !== project} />
14081414
)}
14091415
{!t.end ? (
14101416
<p className="sp-chat-dim">Working…</p>

‎canvas/src/ThemeSwitcher.tsx‎

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,12 @@ export function ThemeSwitcher() {
1616
const [theme, setTheme] = useState(storedTheme);
1717
// The app starts on the OS's until the page says, since the pick lives in the page's storage.
1818
useEffect(() => window.startup?.theme(storedTheme()), []);
19+
// Picked in another window of the same app, which shares the storage.
20+
useEffect(() => {
21+
const follow = () => setTheme(storedTheme());
22+
window.addEventListener("storage", follow);
23+
return () => window.removeEventListener("storage", follow);
24+
}, []);
1925
return (
2026
<div className="sp-theme" role="radiogroup" aria-label="Theme">
2127
{CHOICES.map(([value, label, Icon]) => (

0 commit comments

Comments
 (0)