Foundation: Mac OS 1984 desktop — maximize, windows, shell, menus, context menus - #2
Merged
Merged
Conversation
…lans CLAUDE.md: correct boot description, BootSequence→BootScreen component name, and .woff2→.woff font path. Add pointer to DESKTOP-PLAN.md. DESKTOP-PLAN.md: fix container-type (inline-size→size for cqh support), correct Phase 4 branching (apps branch from mac-os-1984-desktop, not pre-app-foundation), fix branch tree diagram, drop redundant isSelected from WindowState, collapse isMaximized two-step into direct context usage. MOBILE-PLAN.md: initial planning document for iPhone OS 1 mobile experience. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
…mobile gate - Window positions stored as container percentages (0–1) instead of pixels so they scale automatically on maximize toggle - isMaximized state lifted from WindowManager context to page.tsx, passed as props to IMacG3Frame and Desktop - Maximize trigger simplified to chin button only (removed menu bar option) - Clarified mobile never advances past welcome phase - Drag listeners attached to document to prevent fast-drag cursor loss Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
POSTHOG-RESEARCH.md: architectural reference notes on PostHog.com's desktop-OS implementation (state model, window chrome, desktop shell, styling primitives). Compiled via parallel subagent exploration of the posthog.com repo. DESKTOP-PLAN.md updates inspired by the research: - Derived focused window (no stored activeWindowId) — top of z-stack IS the focused window via useMemo - Contiguous zIndex reshuffle on focusApp (no counter drift) - 5px click-vs-drag threshold on draggable title bars - Lazy content mount after window entry animation - Zoom-from-origin open animation using clicked-icon Rect - Cascade-on-open position spec and close-normalizes-zIndex rule - Menu bar z-index sits above window stack - Reduced-motion covers maximize + open + close animations - Inspiration & Anti-patterns section (7 patterns adopted, 9 rejected, 4 future enhancements) - Readiness Checklist marking PR #1 ready and app content blockers CLAUDE.md: note that dev server is always running and should not be started by automation. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces the `'desktop'` screen phase and maximize mode as the foundation for the interactive Mac OS 1984 desktop experience. Screen phases: - ScreenPhase gains `'desktop'` - Welcome screen renders without its menu bar (menu bar moves to the desktop phase in Phase 2+3) - Desktop viewports auto-advance from `'welcome'` → `'desktop'` after a brief hold; mobile stays on welcome permanently Maximize mode: - `isMaximized` state lifted to `page.tsx`, passed to IMacG3Frame and CRTScreen as props (per DESKTOP-PLAN architecture) - Chin button on the iMac frame toggles maximize; a floating Restore button appears when maximized so the control stays reachable after the chin hides - IMacG3Frame hides body/chin/stand when maximized; CRTScreen expands to fill the viewport - CRTScreen gains `container-type: size` to enable cqw/cqh-based window sizing in later phases - All transitions respect prefers-reduced-motion Containing-block fix: - The initial intro scale animation is released after 700ms (new `introDone` state), so a persistent `transform: scale(1)` no longer creates a containing block that traps the maximized IMacG3Frame's `position: fixed, inset: 0`. Assets (user-provided): - public/app-icons/: 1-bit SVGs for calculator, control-panel, finder, journal, music, notepad, trash, world-map (browser icon pending) - public/apple-icon.svg - public/cv/Raj_Dholakia_Resume_FullStack.pdf Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Introduces the full interactive desktop — draggable windows,
placeholder apps, icon grid, and a dynamic menu bar that adapts to
the focused app. This is the last piece of the foundation PR before
app PRs can branch off in parallel.
Window manager (app/components/desktop/window-manager.tsx)
- React Context holding a windows record, selectedIconId, and an
hasOpenedAnyApp flag
- Derived activeWindowId via useMemo — top of z-stack is the focused
window; no separate focus field to sync
- focusApp does a contiguous zIndex reshuffle (no counter drift)
- closeApp re-normalizes zIndex so gaps never appear
- Cascade-on-open: first window at {12%, 14%}, +3% per next, wraps
back to base past {60%, 55%}
- moveWindow clears fromOrigin so the zoom animation can't replay
App registry (app/components/desktop/app-registry.tsx)
- Typed AppDefinition/MenuConfig/MenuItem/Rect
- All 8 apps registered with the user-provided 1-bit SVG icons
(browser.svg now included)
- clamp() + cqw/cqh sizes per the DESKTOP-PLAN
- Shared ComingSoon placeholder component until Phase 4 replaces it
- FINDER_DEFAULT_MENUS exported for the fallback menu bar state
Window component (app/components/desktop/window.tsx)
- Title bar with striped-active pattern, close box with an inline-SVG
X, focus-on-click
- Drag uses direct DOM transform: translate3d() during the move,
rAF-throttled; only the final position is committed via moveWindow
on mouseup. Avoids re-rendering every context consumer per frame.
- 5px click-vs-drag threshold so taps don't jitter the window
- One-frame `transition: none` skip on drag commit so the window
snaps to the new position without a ghost animation
- Zoom-from-origin open animation: first render at the clicked icon's
CRT-relative rect, then flipped to the cascaded position on the
next frame so CSS interpolates the delta
- Lazy content mount — app component only renders after the entry
animation completes (skipped under prefers-reduced-motion)
- Drag is constrained to the CRT screen bounds via container ref
DesktopIcon (app/components/desktop/desktop-icon.tsx)
- Single click selects (invert colors), double click opens and
captures the icon's rect for the zoom-from-origin animation
- `large` prop scales the icon/label up when the desktop is maximized
Desktop shell (app/components/desktop/desktop.tsx)
- Wraps children in WindowManagerProvider
- 2-column icon grid in the top-right so all 8 apps fit in the small
CRT; icons scale up in maximize mode
- Decorative Trash bottom-right with pointer-events: none
- Windows layer renders every open window; click on bare desktop
deselects the active icon
MaximizeNudge (app/components/desktop/maximize-nudge.tsx)
- Small Mac-style tip dialog that appears once after the first app
opens, suggesting Full Screen. Auto-dismisses when user maximizes
or clicks Not Now. Persisted to sessionStorage.
Menu bar refactor (app/components/menu-bar.tsx)
- Now reads derived activeWindowId from WindowManagerContext
- Apple-glyph menu always leftmost (SVG apple)
- Falls back to Finder defaults when no window is focused
- Per-app menuItems (when provided) override the defaults
- z-index 9999 so dropdowns cover windows
- No longer mounted in welcome-screen.tsx
page.tsx
- Desktop phase now renders <Desktop /> (the real shell) instead of
the Phase 1 placeholder text
- Under-construction indicator removed from the welcome screen
Assets
- public/app-icons/browser.svg added to round out all 8 app icons
Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Trash was previously a decorative element pinned bottom-right with pointer-events: none. It's now a real entry in APP_REGISTRY with a Coming Soon placeholder component and a Finder-style status bar. Desktop shell renders Trash as a normal DesktopIcon at bottom-right (filtered out of the top-right 2-column grid so layout is preserved), so single-click selects and double-click opens with the usual zoom-from-origin animation. DESKTOP-PLAN.md Decision #11 updated to match — Trash is clickable but not functional beyond opening. Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Scaffolds the shadcn/ui context-menu component (app/components/ui/ context-menu.tsx) and wires it into desktop icons and the bare desktop surface. shadcn component - Installed via `shadcn add context-menu` which added @radix-ui/react-context-menu to package.json - File rewritten to drop the lucide-react dependency and the Tailwind v3 theme tokens (bg-popover, rounded-md, animate-in, …) that don't exist in our Tailwind v4 alpha setup - Same export surface as stock shadcn, restyled inline with Mac OS 1 aesthetics: Chicago font, white bg, 1px black border, 2px black drop shadow, text glyphs (▶, ✓, ●) in place of lucide icons - Hover/keyboard-focus highlighting driven by Radix's data-highlighted attribute via a small rule in global.css Right-click handlers - DesktopIcon: App name label → Open, Get Info, Duplicate, Move to Trash. Right-click also selects the icon so it shows the highlight state before the menu opens. Icon is split into DesktopIcon (handles context menu + data) and IconButton (forwardRef button used by ContextMenuTrigger asChild). - Desktop surface: Curly OS label → Go Full Screen / Restore Screen (live-toggles based on isMaximized), Clean Up Desktop, Change Wallpaper, About This Macintosh. Wrapped the desktop container in ContextMenu/ContextMenuTrigger so empty-area right-clicks work. Icon highlight fixes - whiteSpace: normal on the label so two-word names (Curly Browser, Control Panel, Note Pad, World Map) wrap at the space and the black selection background covers the whole label instead of overflowing the button width - outline: none on the icon button so the browser's default blue focus ring doesn't appear after a right-click - Removed the filter: invert(1) on icon images when selected — the label highlight alone is enough; the icon art stays untouched Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
Deploying with
|
| Status | Name | Latest Commit | Preview URL | Updated (UTC) |
|---|---|---|---|---|
| ✅ Deployment successful! View logs |
raj-portfolio | f0d56cf | Commit Preview URL Branch Preview URL |
Apr 15 2026, 10:54 PM |
Boot icon - SIZING.macIconSize reduced ~30% (100 → 70 desktop, 60 → 42 mobile) so the Happy Mac on the boot screen sits more comfortably in the CRT frame. Chin toggle - The chin used to be stacked (CD slot on top, separate circular button below) and the button was only rendered on welcome/desktop phases. This caused a visible chin-height shift when the screen transitioned out of boot. Now there is no separate button — the CD slot itself IS the maximize toggle. Always rendered (disabled during boot) so the chin height is constant across phases. - Hover brightens the slot with a soft white glow to hint at interactivity without breaking the iMac hardware aesthetic. - aria-label flips between "Maximize screen" and "Restore screen". Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
First PR of the Mac OS 1984 desktop rebuild. This is the full foundation — after this merges, each app (Calculator, Note Pad, etc.) can branch off in parallel from
feat/mac-os-1984-desktopper the strategy inDESKTOP-PLAN.md.Brings the site from a static "Welcome to Macintosh" screen to a working interactive desktop with draggable windows, a dynamic menu bar, right-click menus, and maximize-to-viewport mode. All 8 app icons are registered with "Coming Soon" placeholders ready to be replaced per-app.
Also included: research notes on PostHog.com's desktop-OS architecture and the resulting architectural decisions that shaped this implementation.
What's in it
Foundation (Phase 1) —
8a1c10eScreenPhasegains'desktop'; welcome → desktop auto-advance on desktop viewports; mobile stays on welcome permanentlyisMaximizedstate lifted topage.tsx, passed as propscontainer-type: sizeforcqw/cqhwindow sizingprefers-reduced-motiontransformdoesn't trapposition: fixeddescendantsWindow system + Desktop shell (Phase 2+3) —
d63b92bWindowManagerProvidercontext — derived focus (top of z-stack), contiguous zIndex reshuffle on focus, close normalizes zIndex, cascade-on-openapp-registry.tsx— typed registry with all 8 apps using user-provided 1-bit SVG icons andclamp()+cqw/cqhsizesWindowcomponent — title bar with striped-active pattern, SVG X close box, 5px click-vs-drag threshold, direct DOMtransform: translate3dduring drag (rAF-throttled, no re-renders per frame), zoom-from-origin open animation, lazy content mount after entry animationDesktopIcon— single-click select, double-click open with icon rect captured for the zoom animationDesktopshell — 2-column icon grid top-right, clickable Trash bottom-right, windows layerMenuBarrefactor — Apple menu + Finder defaults, per-app overrides via registry, reads derivedactiveWindowIdfrom context, z-index above windowsMaximizeNudge— one-shot tip dialog after first app openClickable Trash —
d4d5d86Right-click context menus —
de0414dDocs —
66ff622POSTHOG-RESEARCH.md— architectural reference for PostHog.com's desktop-OS implementation (state model, window chrome, shell, styling)DESKTOP-PLAN.mdupdates incorporating learnings (derived focus, contiguous zIndex, 5px drag threshold, lazy content mount, zoom-from-origin, cascade spec, close normalization, menu bar z-index, readiness checklist, inspiration & anti-patterns section)CLAUDE.md— note that the dev server is always runningTest plan
🤖 Generated with Claude Code