Per review: isReply() flagged any e tag as a reply, including one
marked "mention" — a citation, not a thread reply per NIP-10. That
would have hidden quote-notes from the Feed/Profile timelines they
belong in. Also fixed rootReference()'s docstring, which claimed to
fall back to the *last* positional e tag when the code (correctly)
uses the first.
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BYiUtZMQeA5RHggQw73wto
Per NIP-10 a kind-1 event with an `e` tag is a reply, but the Feed and
Profile timelines rendered every kind-1 event with no such check, so
replies showed up indistinguishable from root posts. `isReply()` was
already written for this in nostrUtils but never used anywhere.
Fixes#20
Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01BYiUtZMQeA5RHggQw73wto
The switcher only focused the window it was given. `FOCUS_WINDOW` raises
and focuses but never un-minimizes, while the mobile shell renders a
window only when it is focused *and* not minimized — so picking a
minimized app updated the URL and the document title (both follow
`focusedId`) while the home screen stayed on screen.
Restore a minimized window instead of merely focusing it, the same way the
menu bar's Window menu and the command palette already do.
Fixes#15
Claude-Session: https://claude.ai/code/session_01Trku191Ww2a2YmDWQF3fTS
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
`mapWindow` flagged the state as changed whenever the target window id
matched, even when the updater handed the very same window object back.
`SET_TITLE` is guarded against a no-op title, but that guard was defeated:
the reducer still returned a fresh state object, so the context value
changed, every consumer re-rendered, and each app's `setTitle` effect —
keyed on a `setTitle` callback that the mobile shell re-created on every
render — dispatched `SET_TITLE` again. That loop ran continuously while an
app was open on mobile; opening the app-switcher Sheet on top of it made
Radix re-attach its composed refs on every one of those renders until
React bailed out with "Maximum update depth exceeded" and the
ErrorBoundary took over.
Only count a window as changed when the updater actually returned a
different object, and memoise the mobile shell's `setTitle`/`setParams`
per window, matching what `WindowFrame` already does.
Fixes#14
Claude-Session: https://claude.ai/code/session_01Trku191Ww2a2YmDWQF3fTS
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
Raising a window made it visibly jump to the top-left corner and animate
back. Two things combined: the enter keyframes animated `transform`, which
overrode the inline `translate3d` a window's position is applied with, and
the window layer rendered the z-sorted list, so focusing a window moved its
DOM node and made the browser replay that animation.
Animate the standalone `scale` property instead — it composes with the
inline transform rather than replacing it — scope the animation to
`.os-window` (it was hitting every child of the layer, including the snap
preview, which is positioned the same way), and render windows in their
stable creation order, since the inline `z-index` already handles stacking.
Fixes#13
Claude-Session: https://claude.ai/code/session_01Trku191Ww2a2YmDWQF3fTS
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
* new web os frontend
* add docs
* Add CNAME and restore NIP-05 nostr.json for GitHub Pages
The Pages custom domain (layer.systems) is only stored in repo settings;
a CNAME file in the build output makes it survive Pages reconfiguration.
Restore public/.well-known/nostr.json, which this branch had dropped —
removing it would break the existing NIP-05 identifiers on layer.systems.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YtQoCzkP7Bo8nruhxojPi
* Ignore eslint and tsc build caches
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YtQoCzkP7Bo8nruhxojPi
* Rebrand page title and metadata to LAYER.systems
The site ships on layer.systems, so the document title, meta and OG
description, and the web manifest now carry that name instead of
"Nostr OS". OsShell sets the title at runtime, so it is updated too —
otherwise the tab would fall back to the old branding after hydration.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YtQoCzkP7Bo8nruhxojPi
* Rename remaining visible "Nostr OS" strings to LAYER.systems
Covers the About window heading, the mobile shell header and the app
icon's aria-label, so the visible branding matches the page title.
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_014YtQoCzkP7Bo8nruhxojPi
---------
Co-authored-by: Claude Opus 5 <noreply@anthropic.com>
- Updated @radix-ui/react-dialog from ^1.1.2 to ^1.1.15
- Updated @radix-ui/react-separator from ^1.1.0 to ^1.1.8
- Updated @radix-ui/react-slot from ^1.1.0 to ^1.2.4
- Updated @radix-ui/react-tooltip from ^1.1.4 to ^1.2.8
- Added a new hook `useIsMobile` to determine if the viewport is mobile-sized
- Refactored tailwind.config.ts for better readability and maintainability