From 1d3aa7ff2222cb51c0f331289c30e7d8c563d446 Mon Sep 17 00:00:00 2001 From: Jessica Claire Edwards Date: Mon, 1 Jun 2026 14:13:16 +0100 Subject: [PATCH 1/3] feat(dotcom): link signed-in logo to tldraw.dev and track logo clicks (#8979) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to extend the tldraw.com → tldraw.dev logo link to signed-in users, this PR makes the sidebar workspace logo an external link to tldraw.dev, and routes both logo links through the shared `ExternalLink` wrapper so they emit click analytics consistently. It follows up #8938, which repointed the logo only on the anonymous editor panel (where the logo sits in the top-left). **Signed-in logo (new link).** Signed-in users never see the anonymous panel's logo — for them the logo lives in the sidebar via `TlaSidebarWorkspaceLink`, which until now was a non-clickable `
`. It now renders `ExternalLink` to `https://tldraw.dev`, opening in a new tab with `target="_blank"`, `rel="noopener noreferrer"`, and an `aria-label` (the logo is image-only). It reuses the same `utm_campaign=top-left-logo` value as #8938 so both logos roll up together on tldraw.dev's side. **Anonymous logo (tracking + consistency).** #8938 used a raw `` for the anon top-left logo, which had no click tracking. It now uses `ExternalLink` too, so both surfaces emit PostHog events — `top-left-logo-clicked` (anon) and `sidebar-logo-clicked` (signed-in) — distinct names so the two can be segmented, while the shared UTM campaign still attributes them together. This also moves `target`/`rel` into the wrapper rather than hand-maintained attributes. Relates to #8871. Follows up #8938. ### Change type - [x] `improvement` ### Test plan 1. **Signed in** (`yarn dev-app`, then sign in): click the tldraw logo at the top of the left sidebar. 2. **Anonymous** (logged out, shared file, or published file): click the tldraw logo in the top-left of the editor. 3. In both cases confirm a new tab opens at `https://tldraw.dev?utm_source=dotcom&utm_medium=organic&utm_campaign=top-left-logo`, and the original tab stays on tldraw.com. 4. Inspect each logo's `` element: `target="_blank"`, `rel="noopener noreferrer"`, `aria-label="tldraw.dev"`. - [ ] Unit tests - [ ] End to end tests ### Release notes - Link the tldraw logo in the signed-in sidebar to tldraw.dev. ### Code changes | Section | LOC change | | --- | --- | | Apps | +15 / -8 | Co-authored-by: Jessica Claire Edwards --- .../components/TlaEditor/TlaEditorTopLeftPanel.tsx | 10 +++++----- .../TlaSidebar/components/TlaSidebarWorkspaceLink.tsx | 11 +++++++++-- .../src/tla/components/TlaSidebar/sidebar.module.css | 2 +- 3 files changed, 15 insertions(+), 8 deletions(-) diff --git a/apps/dotcom/client/src/tla/components/TlaEditor/TlaEditorTopLeftPanel.tsx b/apps/dotcom/client/src/tla/components/TlaEditor/TlaEditorTopLeftPanel.tsx index 8cc6ea316431..328c6e454e34 100644 --- a/apps/dotcom/client/src/tla/components/TlaEditor/TlaEditorTopLeftPanel.tsx +++ b/apps/dotcom/client/src/tla/components/TlaEditor/TlaEditorTopLeftPanel.tsx @@ -44,6 +44,7 @@ import { TLAppUiEventSource, useTldrawAppUiEvents } from '../../utils/app-ui-eve import { getIsCoarsePointer } from '../../utils/getIsCoarsePointer' import { defineMessages, useIntl, useMsg } from '../../utils/i18n' import { TlaSignInDialog } from '../dialogs/TlaSignInDialog' +import { ExternalLink } from '../ExternalLink/ExternalLink' import { CookieConsentMenuItem, GiveUsFeedbackMenuItem, @@ -106,15 +107,14 @@ export function TlaEditorTopLeftPanelAnonymous() { return ( <> - - + {anonFileName && ( <> + -
+ ) } diff --git a/apps/dotcom/client/src/tla/components/TlaSidebar/sidebar.module.css b/apps/dotcom/client/src/tla/components/TlaSidebar/sidebar.module.css index 5cb70f8daa1a..367a20fc5ef0 100644 --- a/apps/dotcom/client/src/tla/components/TlaSidebar/sidebar.module.css +++ b/apps/dotcom/client/src/tla/components/TlaSidebar/sidebar.module.css @@ -236,7 +236,7 @@ flex: 0 0 auto; } -/* Workspace link (sort of) */ +/* Workspace link */ .sidebarWorkspaceButton { background: none; From dfdd9d3ed2e53de36ce91cc2decfe43ae1effe22 Mon Sep 17 00:00:00 2001 From: Kostya Farber Date: Mon, 1 Jun 2026 14:26:36 +0100 Subject: [PATCH 2/3] trigger working next npm package (#8975) ### Change type - [ ] `bugfix` - [ ] `improvement` - [ ] `feature` - [ ] `api` - [x] `other` --- apps/dotcom/client/src/main.tsx | 1 - 1 file changed, 1 deletion(-) diff --git a/apps/dotcom/client/src/main.tsx b/apps/dotcom/client/src/main.tsx index 850a6f239e81..2afdfd1a5962 100644 --- a/apps/dotcom/client/src/main.tsx +++ b/apps/dotcom/client/src/main.tsx @@ -44,7 +44,6 @@ createRoot(document.getElementById('root')!).render( ) showConsoleBranding() - try { // we have a dummy service worker that unregisters itself immediately // this was needed to remove the service worker we used to have from the cache From de4d42d4341b3ed57c563021f1a3d3d603a195df Mon Sep 17 00:00:00 2001 From: Kevin Ingersoll Date: Mon, 1 Jun 2026 14:54:00 +0100 Subject: [PATCH 3/3] test(dotcom): fix flaky e2e sign-out (#8966) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In order to stop the dotcom `not-logged-in.spec.ts › can sign out` e2e test from intermittently failing, this PR de-flakes the sidebar sign-out fixture. The fixture located the button with a loose `getByText('Sign out')` and clicked it without waiting for the Radix user-settings dropdown to finish opening. Playwright could therefore click mid-animation ("element is not stable") or match a node that re-portals and detaches ("element is detached from the DOM"). The fix targets the stable testid the menu item already renders (`dialog.sign-out`, from the `TldrawUiMenuItem` `${sourceId}.${id}` convention) and waits for the dropdown menu content to become visible in `openUserSettingsMenu()` before any child-item click, so child clicks no longer race the open animation. The change is confined to the e2e fixture; no project-wide `reducedMotion` override is used, so `cookie-consent.spec.ts` (which relies on animations running) is unaffected. ### Change type - [x] `other` ### Test plan 1. From `apps/dotcom/client`, run the sign-out test repeatedly to confirm the flake is gone: `yarn e2e --grep "can sign out" --repeat-each=5` 2. Or from the repo root: `yarn e2e-dotcom`. - [x] End to end tests ### Code changes | Section | LOC change | | ------- | ---------- | | Tests | +3 / -1 | --- apps/dotcom/client/e2e/fixtures/Sidebar.ts | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/apps/dotcom/client/e2e/fixtures/Sidebar.ts b/apps/dotcom/client/e2e/fixtures/Sidebar.ts index 2d23d35406b2..a5e294b6688c 100644 --- a/apps/dotcom/client/e2e/fixtures/Sidebar.ts +++ b/apps/dotcom/client/e2e/fixtures/Sidebar.ts @@ -24,7 +24,7 @@ export class Sidebar { this.helpMenu = this.page.getByTestId('tla-sidebar-help-menu-trigger') this.themeButton = this.page.getByTestId('dialog-sub.help menu color-scheme-button') this.darkModeButton = this.page.getByText('Dark') - this.signOutButton = this.page.getByText('Sign out') + this.signOutButton = this.page.getByTestId('dialog.sign-out') } async isVisible() { @@ -62,6 +62,8 @@ export class Sidebar { async openUserSettingsMenu() { await this.userSettingsMenu.hover() await this.userSettingsMenu.click() + // Wait for the dropdown content to mount before child-item clicks race the open animation. + await expect(this.page.getByRole('menu')).toBeVisible() } @step