Skip to content

feat(tangle-cloud): unify app shell with tangle dapp#3264

Merged
drewstone merged 2 commits into
masterfrom
feat/tangle-cloud-unified-shell
Jun 8, 2026
Merged

feat(tangle-cloud): unify app shell with tangle dapp#3264
drewstone merged 2 commits into
masterfrom
feat/tangle-cloud-unified-shell

Conversation

@drewstone

Copy link
Copy Markdown
Contributor

Summary

  • replace the Cloud-only sidebar with the shared Tangle dapp sidebar/mobile sidebar
  • remove the fixed Cloud breadcrumb topbar and move wallet/network controls into the old dapp-style page chrome row
  • restore shared footer on Cloud pages
  • remove decorative blueprint monogram badges and the disconnected account initials placeholder

Why

The app looked unlike the Tangle dapp because the Blueprints page had been partially restored, but the shell, navigation, topbar, footer, and homepage/operator surfaces were still Cloud-specific chrome built on sandbox primitives. This makes the shared Tangle dapp shell the default frame again and leaves Cloud-specific code for behavior/data.

Verification

  • NX_DAEMON=false NX_SKIP_NX_CACHE=true yarn nx typecheck tangle-cloud
  • NX_DAEMON=false NX_SKIP_NX_CACHE=true yarn nx test tangle-cloud
  • NX_DAEMON=false NX_SKIP_NX_CACHE=true yarn nx build tangle-cloud
  • pre-push hook: lint/format/build passed
  • Playwright screenshots: /instances, /operators, /blueprints on desktop and mobile
  • checked: no fixed Cloud topbar, no blueprint monogram badges, no TC placeholder, no italic buttons, no horizontal overflow, Satoshi font and shared body-bg-dark active

@drewstone drewstone requested a review from AtelyPham as a code owner June 8, 2026 12:31
@netlify

netlify Bot commented Jun 8, 2026

Copy link
Copy Markdown

Deploy Preview for tangle-dapp canceled.

Name Link
🔨 Latest commit 40abbb0
🔍 Latest deploy log https://app.netlify.com/projects/tangle-dapp/deploys/6a26b982c94d400008150930

@netlify

netlify Bot commented Jun 8, 2026

Copy link
Copy Markdown

Deploy Preview for tangle-cloud ready!

Name Link
🔨 Latest commit 40abbb0
🔍 Latest deploy log https://app.netlify.com/projects/tangle-cloud/deploys/6a26b982adce630008a78232
😎 Deploy Preview https://deploy-preview-3264--tangle-cloud.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.
🤖 Make changes Run an agent on this branch

To edit notification comments on pull requests, go to your Netlify project configuration.

@netlify

netlify Bot commented Jun 8, 2026

Copy link
Copy Markdown

Deploy Preview for tangle-leaderboard canceled.

Name Link
🔨 Latest commit 40abbb0
🔍 Latest deploy log https://app.netlify.com/projects/tangle-leaderboard/deploys/6a26b982a274ad00089ca4a6

@tangletools

Copy link
Copy Markdown
Contributor

❌ Needs Work — d3787b16

Readiness 44/100 · Confidence 65/100 · 9 findings (2 high, 4 medium, 3 low)

deepseek glm aggregate
Readiness 47 44 44
Confidence 65 65 65
Correctness 47 44 44
Security 47 44 44
Testing 47 44 44
Architecture 47 44 44

Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision.

Blocking

🔴 HIGH Blueprint detail pages lose all top-nav controls (breadcrumb, CTA, mode picker) — apps/tangle-cloud/src/components/Header.tsx

The Header left slot that rendered useTopNavSlotContent() was removed (diff lines -56 to -59). IframeBlueprintLayout.tsx:198 publishes breadcrumb, mode picker, 'Create instance' CTA, Expand button, and Details button via useTopNavSlot(navContent), with the explicit design note at line 108-110: 'Blueprint identity + primary CTA + Details disclosure live in the global top nav.' With the consumer gone, these elements never render. Blueprint detail pages lose their entire in-header identity bar — no breadcrumb trail, no instance-creation CTA, no mode switching (for multi-mode blueprints), and no Details panel toggle. The IframeBlueprintLayout does no

🔴 HIGH Dual sidebar state: Layout and SideBarCmp manage expanded/collapsed independently — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:48-58 reads localStorage key 'tangle-cloud-sidebar-expanded' into isSidebarExpanded, then passes it as isExpandedByDefault to SideBarCmp. But SideBarCmp (libs/ui-components/src/components/SideBar/SideBar.tsx:55-59) uses its own useLocalStorageState('isSidebarOpen', { defaultValue: isExpandedByDefault }). When the user toggles the sidebar, SideBarCmp flips its own internal state AND calls onSideBarToggle(), which flips Layout's state. These two sources of truth can diverge because: (1) SideBarCmp's useEffect (line 63-74) re-syncs from a cookie on mount, potentially overwriting the isExpandedByDefault prop, and (2) the two localSto

Other

🟠 MEDIUM --cloud-sidebar-width variable set to 16rem but SideBarCmp is 18rem (w-72) — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:79-80 sets --cloud-sidebar-width: 16rem (equivalent to Tailwind's w-64) when sidebar is expanded. But the new SideBarCmp from @tangle-network/ui-components uses w-72 = 18rem (SideBar.tsx:95). The CSS fallback in styles.css:235 is also 16rem. The variable offsets wallet connect modals (and any centered dialog) by half the sidebar width. With 16rem instead of 18rem, every centered dialog is offset by 1rem (16px) to the left of true content-area center when the sidebar is expanded. Fix: change '16rem' to '18rem' on line 80.

🟠 MEDIUM TopNavSlot context is published but never consumed — dead wiring — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:94 still wraps the entire app in <TopNavSlotProvider>. Header.tsx previously called useTopNavSlotContent() (removed in this diff, line -48). But IframeBlueprintLayout.tsx:198 still calls useTopNavSlot(navContent) to publish content into the slot. Since nothing reads from useTopNavSlotContent() anymore, that published content silently vanishes — the iframe blueprint page's contextual nav is lost. This is a functional regression. Fix: either restore a consumer in the layout (e.g., render the slot content above the main content area), or remove TopNavSlotProvider from Layout and clean up all publishers.

🟠 MEDIUM isSidebarExpanded desyncs from SideBarCmp internal state on page reload — apps/tangle-cloud/src/components/Layout.tsx

Layout initializes isSidebarExpanded from localStorage key tangle-cloud-sidebar-expanded (lines 48-57), but the new onExpandedChange callback on line 102 toggles state without persisting to localStorage. Meanwhile, SideBarCmp internally manages its own state via useLocalStorageState('isSidebarOpen', ...) (SideBar.tsx:55-59), persisting on every toggle. After first toggle in this new code, tangle-cloud-sidebar-expanded is stale forever. On reload: layout reads stale value → initializes isSidebarExpanded w

🟠 MEDIUM Sidebar onExpandedChange signature narrowed — toggle callback loses expanded state — apps/tangle-cloud/src/components/Sidebar.tsx

Sidebar.tsx:29 changed onExpandedChange from (isExpanded: boolean) => void to () => void. The callback no longer communicates whether the sidebar is now expanded or collapsed. Layout.tsx:102 works around this with () => setIsSidebarExpanded((value) => !value), but this flips its own state independently of SideBarCmp's actual state, compounding the dual-state issue from the first finding. If SideBarCmp's internal state ever differs (e.g., due to the cookie sync effect), Layout's toggle will flip in the wrong direction.

🟡 LOW Dead code: TopNavSlotProvider and useTopNavSlot with no consumer — apps/tangle-cloud/src/components/Header.tsx

Header.tsx diff removes the only consumer of useTopNavSlotContent() (the left slot div at old lines 56-59). TopNavSlotProvider still wraps the app tree in Layout.tsx:94, and IframeBlueprintLayout.tsx:198 still computes and publishes nav content via useTopNavSlot. Both are dead work — the provider adds a context render overhead, and the blueprint detail page computes a useMemo'd JSX fragment that never renders. Fix: either remove TopNavSlotProvider/useTopNavSlot and the orphaned publish call, or restore the consumer.

🟡 LOW MobileSidebar rendered unconditionally on every page load (lg:hidden only) — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:120 renders <MobileSidebar /> inside the content area on every page. It uses a Radix Dialog internally, so the trigger button is always in the DOM even on desktop. The lg:hidden class hides it visually, but the component still mounts and initializes state. This is minor but could be wrapped in a lazy import or portal to avoid mounting the Dialog root on desktop viewports.

🟡 LOW AccountStatsCard disconnected state changed from 'sandbox' to 'elevated' Card variant — apps/tangle-cloud/src/pages/instances/AccountStatsCard.tsx

AccountStatsCard.tsx:142 uses variant="sandbox" for the connected state card, but the disconnected state (line 116) uses variant="elevated". This creates a visual inconsistency when the wallet connects/disconnects — the card style changes from elevated to sandbox. This may be intentional (to differentiate states) but should be confirmed by design review.


tangletools · 2026-06-08T12:41:54Z · trace

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

❌ 2 Blocking Findings — d3787b16

Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 5 changed files. Global verifier still owns final merge decision.

Full immutable report for this review: trace

Summary comment for this run: full summary


tangletools · 2026-06-08T12:41:54Z · immutable trace

@tangletools

Copy link
Copy Markdown
Contributor

✅ No Blockers — 40abbb00

Readiness 72/100 · Confidence 65/100 · 6 findings (4 medium, 2 low)

deepseek glm aggregate
Readiness 72 72 72
Confidence 65 65 65
Correctness 72 72 72
Security 72 72 72
Testing 72 72 72
Architecture 72 72 72

Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision.

🟠 MEDIUM Dual theme management: useDarkMode + manual DOM sync — apps/tangle-cloud/src/components/Layout.tsx

Lines 40–41 and 54–61: Layout reads theme via useDarkMode('dark') (which internally toggles document.documentElement.classList and persists to localStorage theme key), then the useEffect on lines 54–61 redundantly re-applies classList.toggle('dark'), colorScheme, and data-sandbox-* attributes. The classList and localStorage writes are now duplicated — useDarkMode already manages both. The data-sandbox-theme / data-sandbox-ui attributes and colorScheme still need the effect, but the dark clas

🟠 MEDIUM Sidebar expanded state tracked with different localStorage key than shared SideBarCmp — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:47-51 initializes isSidebarExpanded from 'tangle-cloud-sidebar-expanded' key. SideBarCmp (libs/ui-components/src/components/SideBar/SideBar.tsx:55-60) manages its own internal state via useLocalStorageState(SIDEBAR_OPEN_KEY='isSidebarOpen'). These are two different keys that can hold different values on first load. After first toggle, both flips synchronize via the onSideBarToggle callback. However the --cloud-sidebar-width CSS variable (Layout.tsx:71-74) reads Layout's local state, and could reflect a wrong value initially if the keys diverge, causing Radix-portaled dialogs to be offset incorrectly.

🟠 MEDIUM Stale sidebar-expand localStorage key — apps/tangle-cloud/src/components/Layout.tsx

Lines 47–51: Layout initializes isSidebarExpanded by reading the legacy key tangle-cloud-sidebar-expanded, but the new SideBarCmp component (libs/ui-components SideBar.tsx:55) persists its own expand state under SIDEBAR_OPEN_KEY = 'isSidebarOpen'. The two keys diverge after first toggle — Layout's state reads the old key once, then toggles in-memory only, while SideBarCmp writes to the new key. The setIsSidebarExpanded in Layout's onExpandedChange (line 95) updates Layout's own useState but does NOT write t

🟠 MEDIUM TopNavSlot provider wraps entire app with zero consumers — apps/tangle-cloud/src/components/Layout.tsx

Layout.tsx:87 wraps children in . Header.tsx removed its useTopNavSlotContent() call (the reader side). useTopNavSlot is still called in IframeBlueprintLayout.tsx:198 (the writer), but nothing reads the published content — useTopNavSlotContent and useTopNavEntity have zero consumers across the entire workspace. The context tree is dead weight, and any nav content published by detail pages is silently discarded. Remove the TopNavSlotProvider wrapper and the TopNavSlot.tsx module if no reader will be restored.

🟡 LOW Breadcrumb trail and theme toggle removed with no migration path — apps/tangle-cloud/src/components/Header.tsx

The entire getHeaderTrail, HeaderTrail, and ThemeToggle components were deleted. ThemeToggle is now handled by the shared SideBarCmp (SideBar.tsx:182 renders <ThemeToggle />). Breadcrumb navigation is removed entirely — the header is now only action buttons. If any page relied on useTopNavSlot for contextual breadcrumb content, it still compiles (the provider still exists in Layout.tsx:87) but the content is never rendered. IframeBlueprintLayout.tsx:198 still calls useTopNavSlot(navContent) which silently publishes to a now-unused slot. This is dead code, not a bug, but worth noting for cleanup.

🟡 LOW Removed OS-level color-scheme preference fallback at app init — apps/tangle-cloud/src/main.tsx

main.tsx:34 sets initialTheme = storedTheme ?? legacyTheme ?? 'dark', always defaulting to 'dark'. The old code (removed) checked window.matchMedia('(prefers-color-scheme: light)') to default to 'light' for users with light OS preference and no stored theme. The shared useDarkMode hook (libs/ui-components/src/hooks/useDarkMode.ts) also defaults to 'dark' but does check prefers-color-scheme in its DOM effect — creating a potential flash: main.tsx sets 'dark' class, then React/useDarkMode effect may remove it for light-preference users. Low impact since most users will have a stored theme after migration.


tangletools · 2026-06-08T12:53:23Z · trace

@tangletools tangletools dismissed their stale review June 8, 2026 12:53

Superseded by re-review — no blocking findings on latest commit.

@tangletools tangletools left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

✅ Approved — 6 non-blocking findings — 40abbb00

Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision. | Full multi-shot audit completed 1/1 planned shots over 6 changed files. Global verifier still owns final merge decision.

Full immutable report for this review: trace

Summary comment for this run: full summary


tangletools · 2026-06-08T12:53:23Z · immutable trace

@drewstone drewstone merged commit 5c1c44a into master Jun 8, 2026
21 checks passed
@drewstone drewstone deleted the feat/tangle-cloud-unified-shell branch June 8, 2026 13:48
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