Skip to content

feat(studio): add left sidebar with Compositions and Assets tabs#94

Merged
miguel-heygen merged 1 commit intomainfrom
studio/6-left-sidebar
Mar 28, 2026
Merged

feat(studio): add left sidebar with Compositions and Assets tabs#94
miguel-heygen merged 1 commit intomainfrom
studio/6-left-sidebar

Conversation

@miguel-heygen
Copy link
Copy Markdown
Collaborator

@miguel-heygen miguel-heygen commented Mar 27, 2026

Summary

  • Add collapsible left sidebar with Compositions and Assets tabs
  • Compositions tab lists all sub-compositions with thumbnail previews and navigation
  • Clicking a composition opens it in the code editor AND navigates the preview to show that composition
  • Assets tab categorizes project files by type (images, fonts, media)
  • Race condition guard on composition fetch with functional state update
  • Thumbnail error fallback shows name initial instead of empty box

Test plan

  • Sidebar opens/closes with smooth transition
  • Compositions tab lists files from project API
  • Clicking a composition changes the preview iframe to that composition
  • Assets tab categorizes files by type

🤖 Generated with Claude Code

Copy link
Copy Markdown
Collaborator

@vanceingalls vanceingalls left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Overall: Clean, well-scoped PR. The sidebar structure is solid and the component decomposition (LeftSidebar → CompositionsTab + AssetsTab) is the right approach. A few things to tighten up:


App.tsx — file content fetch on composition select

The fetch-on-click pattern has a race condition:

setEditingFile({ path: comp, content: null });
fetch(`/api/projects/${projectId}/files/${comp}`)
  .then((r) => r.json())
  .then((data) => setEditingFile({ path: comp, content: data.content }))
  .catch(() => {});

If the user clicks two compositions quickly, the second click sets content: null but the first fetch may resolve after the second one, overwriting the correct content. Consider aborting previous fetches with AbortController, or check that path still matches when the fetch resolves.

Also: .catch(() => {}) silently swallows errors. At minimum log to console so debugging is possible.


CompositionsTab.tsx — thumbnail error handling

onError={(e) => {
  (e.target as HTMLImageElement).style.display = "none";
}}

This hides the image on error but leaves an empty 16x9 box. Consider showing a fallback (composition name initials, or a file icon) instead of an invisible element.


AssetsTab.tsx — file size info mentioned in PR description but not implemented

The PR description says "Assets tab shows project images, fonts, and media files with file size info" but the component doesn't display file sizes anywhere. Either add it or update the PR description.


LeftSidebar.tsx — hardcoded width

style={{ width: 240 }}

This works but consider making it a constant or CSS variable so it's easy to find if the design changes. Minor.


AssetsTab.tsx — inline SVG icons

The four icon variants (video, audio, image, file) are ~60 lines of inline SVG. These would be cleaner as a shared icon component or imported from @phosphor-icons/react which is already in the project deps. Not blocking but reduces duplication if more icons are needed.


LeftSidebar.tsx — keyboard shortcuts could conflict

Cmd+1 and Cmd+2 are commonly used by browsers (switch tabs). The e.preventDefault() will override browser behavior. Consider using a less conflicting shortcut or making it configurable.

Copy link
Copy Markdown
Collaborator Author

miguel-heygen commented Mar 28, 2026

Merge activity

@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch 2 times, most recently from 787e40c to 41a804f Compare March 28, 2026 17:47
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch 3 times, most recently from 3ebfd91 to 91e509a Compare March 28, 2026 18:05
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch from 91e509a to 15974c2 Compare March 28, 2026 18:12
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch 2 times, most recently from 0840b63 to 4252f7a Compare March 28, 2026 18:27
@miguel-heygen miguel-heygen force-pushed the studio/5-edit-range branch 2 times, most recently from 02e7dbc to f6d18b0 Compare March 28, 2026 19:40
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch from 4252f7a to 717d292 Compare March 28, 2026 19:41
@miguel-heygen miguel-heygen force-pushed the studio/5-edit-range branch 2 times, most recently from d6fe76f to b372691 Compare March 28, 2026 19:45
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch from 717d292 to f553966 Compare March 28, 2026 19:45
@miguel-heygen miguel-heygen changed the base branch from studio/5-edit-range to graphite-base/94 March 28, 2026 19:50
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch from f553966 to 4567dad Compare March 28, 2026 19:50
@graphite-app graphite-app Bot changed the base branch from graphite-base/94 to main March 28, 2026 19:51
@miguel-heygen miguel-heygen force-pushed the studio/6-left-sidebar branch from 4567dad to 3ab9c2b Compare March 28, 2026 19:51
@miguel-heygen miguel-heygen merged commit 9ae239d into main Mar 28, 2026
14 of 15 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants