fix: remove CSS transform scaling from pinned shapes

Pinned shapes should only stay fixed in screen position, not fixed in
visual size. The CSS transform: scale() was causing shapes to appear
differently sized when pinned.

Now pinned shapes:
- Stay at a fixed screen position (don't move when panning)
- Scale normally with zoom (get bigger/smaller like other shapes)
- Don't change appearance when pin is toggled

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
Jeff Emmett 2025-12-16 12:11:45 -05:00
parent cc1928852f
commit 72c2e52ae7
2 changed files with 0 additions and 107 deletions

View File

@ -1,43 +0,0 @@
---
id: task-053
title: Fix user identity caching on logout/login
status: Done
assignee: []
created_date: '2025-12-15 23:40'
updated_date: '2025-12-15 23:40'
labels:
- bug-fix
- auth
- presence
dependencies: []
priority: high
---
## Description
<!-- SECTION:DESCRIPTION:BEGIN -->
Fixed issues with user identity state not being properly cleared/restored during logout and login cycles, causing duplicate cursors and stale presence data in the social network graph.
<!-- SECTION:DESCRIPTION:END -->
## Acceptance Criteria
<!-- AC:BEGIN -->
- [x] #1 Crypto keys and tldraw user IDs persist across logout (account data)
- [x] #2 Session-specific data cleared on logout (permissions, graph cache)
- [x] #3 No duplicate cursors when logging out and back in
- [x] #4 Tools load properly after login from logged-out state
- [x] #5 CryptIDDropdown and NetworkGraph reset state on logout
<!-- AC:END -->
## Implementation Notes
<!-- SECTION:NOTES:BEGIN -->
Implemented in commits df80a3f and related changes to Board.tsx.
Key changes:
- sessionPersistence.ts: Added session-logged-in and session-cleared events, preserve tldraw user IDs and crypto keys on logout
- Board.tsx: Check localStorage directly for auth in onMount, listen for session events
- CryptIDDropdown.tsx: Clear connections state on logout
- useNetworkGraph.ts: Clear graph cache on logout
The root cause was clearing tldraw-user-id-* keys on logout, which created new presence IDs on each login while old presence records persisted in Automerge.
<!-- SECTION:NOTES:END -->

View File

@ -64,8 +64,6 @@ export interface StandardizedToolWrapperProps {
onTagsChange?: (tags: string[]) => void
/** Whether tags can be edited */
tagsEditable?: boolean
/** Zoom level when the shape was pinned (for constant visual size) */
pinnedAtZoom?: number
}
/**
@ -92,67 +90,13 @@ export const StandardizedToolWrapper: React.FC<StandardizedToolWrapperProps> = (
tags = [],
onTagsChange,
tagsEditable = true,
pinnedAtZoom,
}) => {
const [isHoveringHeader, setIsHoveringHeader] = useState(false)
const [isEditingTags, setIsEditingTags] = useState(false)
const [editingTagInput, setEditingTagInput] = useState('')
const [zoomScale, setZoomScale] = useState(1)
const tagInputRef = useRef<HTMLInputElement>(null)
const isDarkMode = useIsDarkMode()
// Calculate zoom compensation scale when pinned
useEffect(() => {
if (!isPinnedToView || !editor) {
setZoomScale(1)
return
}
// Get pinnedAtZoom from shape meta if not passed as prop
let originalZoom = pinnedAtZoom
if (!originalZoom && shapeId) {
const shape = editor.getShape(shapeId)
originalZoom = (shape?.meta as any)?.pinnedAtZoom
}
if (!originalZoom) {
setZoomScale(1)
return
}
const updateScale = () => {
const currentZoom = editor.getCamera().z
// Scale inversely to zoom to maintain constant visual size
const scale = originalZoom / currentZoom
setZoomScale(scale)
}
// Initial scale calculation
updateScale()
// Listen for camera changes
const handleChange = () => {
updateScale()
}
// Use requestAnimationFrame for smooth updates
let rafId: number | null = null
const throttledUpdate = () => {
if (rafId) return
rafId = requestAnimationFrame(() => {
updateScale()
rafId = null
})
}
editor.on('change' as any, throttledUpdate)
return () => {
editor.off('change' as any, throttledUpdate)
if (rafId) cancelAnimationFrame(rafId)
}
}, [isPinnedToView, editor, shapeId, pinnedAtZoom])
// Handle Esc key to exit maximize mode
useEffect(() => {
if (!isMaximized || !onMaximize) return
@ -229,11 +173,6 @@ export const StandardizedToolWrapper: React.FC<StandardizedToolWrapperProps> = (
? `${primaryColor}15` // 15% opacity
: `${primaryColor}10` // 10% opacity
// Calculate transform for pinned shapes
const pinnedTransform = isPinnedToView && zoomScale !== 1
? `scale(${zoomScale})`
: undefined
const wrapperStyle: React.CSSProperties = {
width: typeof width === 'number' ? `${width}px` : width,
height: isMinimized ? 40 : (typeof height === 'number' ? `${height}px` : height), // Minimized height is just the header
@ -251,9 +190,6 @@ export const StandardizedToolWrapper: React.FC<StandardizedToolWrapperProps> = (
pointerEvents: 'auto',
transition: isPinnedToView ? 'box-shadow 0.2s ease' : 'height 0.2s ease, box-shadow 0.2s ease',
boxSizing: 'border-box',
// Apply zoom compensation transform for pinned shapes
transform: pinnedTransform,
transformOrigin: 'top left',
}
const headerStyle: React.CSSProperties = {