update typescript errors for vercel
This commit is contained in:
parent
f8e4647e1a
commit
4815fa4a23
|
|
@ -130,5 +130,6 @@ The Fathom transcript shape includes:
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -81,5 +81,6 @@ You can also manually edit the environment by:
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -97,23 +97,29 @@ export function applyAutomergePatchesToTLStore(
|
|||
}
|
||||
}
|
||||
|
||||
const record = updatedObjects[id] || (existingRecord ? JSON.parse(JSON.stringify(existingRecord)) : defaultRecord)
|
||||
let record = updatedObjects[id] || (existingRecord ? JSON.parse(JSON.stringify(existingRecord)) : defaultRecord)
|
||||
|
||||
// CRITICAL: Ensure typeName matches ID pattern (fixes misclassification)
|
||||
// Note: obsidian_vault records are skipped above, so we don't need to handle them here
|
||||
if (typeof id === 'string') {
|
||||
let correctTypeName = record.typeName
|
||||
if (id.startsWith('shape:') && record.typeName !== 'shape') {
|
||||
record.typeName = 'shape'
|
||||
correctTypeName = 'shape'
|
||||
} else if (id.startsWith('page:') && record.typeName !== 'page') {
|
||||
record.typeName = 'page'
|
||||
correctTypeName = 'page'
|
||||
} else if (id.startsWith('camera:') && record.typeName !== 'camera') {
|
||||
record.typeName = 'camera'
|
||||
correctTypeName = 'camera'
|
||||
} else if (id.startsWith('instance:') && record.typeName !== 'instance') {
|
||||
record.typeName = 'instance'
|
||||
correctTypeName = 'instance'
|
||||
} else if (id.startsWith('pointer:') && record.typeName !== 'pointer') {
|
||||
record.typeName = 'pointer'
|
||||
correctTypeName = 'pointer'
|
||||
} else if (id.startsWith('document:') && record.typeName !== 'document') {
|
||||
record.typeName = 'document'
|
||||
correctTypeName = 'document'
|
||||
}
|
||||
|
||||
// Create new object with correct typeName if it changed
|
||||
if (correctTypeName !== record.typeName) {
|
||||
record = { ...record, typeName: correctTypeName }
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -219,19 +219,19 @@ export class CloudflareNetworkAdapter extends NetworkAdapter {
|
|||
// We need to handle both binary and text messages
|
||||
if (event.data instanceof ArrayBuffer) {
|
||||
console.log('🔌 CloudflareAdapter: Received binary message (Automerge protocol)')
|
||||
// Handle binary Automerge sync messages - pass directly to Repo
|
||||
// Automerge Repo expects binary sync messages as ArrayBuffer
|
||||
// Handle binary Automerge sync messages - convert ArrayBuffer to Uint8Array
|
||||
// Automerge Repo expects binary sync messages as Uint8Array
|
||||
this.emit('message', {
|
||||
type: 'sync',
|
||||
data: event.data
|
||||
data: new Uint8Array(event.data)
|
||||
})
|
||||
} else if (event.data instanceof Blob) {
|
||||
// Handle Blob messages (convert to ArrayBuffer)
|
||||
// Handle Blob messages (convert to Uint8Array)
|
||||
event.data.arrayBuffer().then((buffer) => {
|
||||
console.log('🔌 CloudflareAdapter: Received Blob message, converted to ArrayBuffer')
|
||||
console.log('🔌 CloudflareAdapter: Received Blob message, converted to Uint8Array')
|
||||
this.emit('message', {
|
||||
type: 'sync',
|
||||
data: buffer
|
||||
data: new Uint8Array(buffer)
|
||||
})
|
||||
})
|
||||
} else {
|
||||
|
|
|
|||
|
|
@ -1488,7 +1488,7 @@ export function useAutomergeStoreV2({
|
|||
for (const record of failedRecords) {
|
||||
try {
|
||||
// Additional cleanup for failed records - create deep copy
|
||||
const fixedRecord = JSON.parse(JSON.stringify(record))
|
||||
let fixedRecord = JSON.parse(JSON.stringify(record))
|
||||
|
||||
// Fix instance records specifically
|
||||
if (fixedRecord.typeName === 'instance') {
|
||||
|
|
|
|||
|
|
@ -143,13 +143,13 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
|
|||
return {
|
||||
status: isLoading ? 'loading' : 'not-synced',
|
||||
connectionStatus: 'offline',
|
||||
store: null
|
||||
store: undefined
|
||||
}
|
||||
}
|
||||
|
||||
return {
|
||||
status: 'synced',
|
||||
connectionStatus: 'online',
|
||||
status: 'synced-remote' as const,
|
||||
connectionStatus: 'online' as const,
|
||||
store
|
||||
}
|
||||
}, [store, isLoading])
|
||||
|
|
@ -164,5 +164,5 @@ export function useAutomergeSync(config: AutomergeSyncConfig): TLStoreWithStatus
|
|||
return {
|
||||
...storeWithStatus,
|
||||
presence
|
||||
}
|
||||
} as TLStoreWithStatus & { presence: typeof presence }
|
||||
}
|
||||
|
|
|
|||
|
|
@ -197,7 +197,7 @@ export const StandardizedToolWrapper: React.FC<StandardizedToolWrapperProps> = (
|
|||
onPointerDown={handleHeaderPointerDown}
|
||||
onMouseEnter={() => setIsHoveringHeader(true)}
|
||||
onMouseLeave={() => setIsHoveringHeader(false)}
|
||||
onMouseDown={(e) => {
|
||||
onMouseDown={(_e) => {
|
||||
// Ensure selection happens on mouse down for immediate visual feedback
|
||||
if (editor && shapeId && !isSelected) {
|
||||
editor.setSelectedShapes([shapeId])
|
||||
|
|
|
|||
|
|
@ -258,5 +258,6 @@ export const LocationDashboard: React.FC = () => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -229,5 +229,6 @@ export const LocationMap: React.FC<LocationMapProps> = ({
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -8,7 +8,7 @@ import {
|
|||
import React from "react"
|
||||
import { ShareLocation } from "./ShareLocation"
|
||||
|
||||
export function LocationShareDialog({ onClose }: TLUiDialogProps) {
|
||||
export function LocationShareDialog({ onClose: _onClose }: TLUiDialogProps) {
|
||||
return (
|
||||
<>
|
||||
<TldrawUiDialogHeader>
|
||||
|
|
|
|||
|
|
@ -171,5 +171,6 @@ export const LocationViewer: React.FC<LocationViewerProps> = ({ shareToken }) =>
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -138,5 +138,6 @@ export const ShareSettingsComponent: React.FC<ShareSettingsProps> = ({ onSetting
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -413,5 +413,6 @@
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -30,21 +30,21 @@ declare global {
|
|||
}
|
||||
|
||||
interface SpeechRecognitionResultList {
|
||||
length: number
|
||||
readonly length: number
|
||||
item(index: number): SpeechRecognitionResult
|
||||
[index: number]: SpeechRecognitionResult
|
||||
}
|
||||
|
||||
interface SpeechRecognitionResult {
|
||||
length: number
|
||||
readonly length: number
|
||||
item(index: number): SpeechRecognitionAlternative
|
||||
[index: number]: SpeechRecognitionAlternative
|
||||
isFinal: boolean
|
||||
readonly isFinal: boolean
|
||||
}
|
||||
|
||||
interface SpeechRecognitionAlternative {
|
||||
transcript: string
|
||||
confidence: number
|
||||
readonly transcript: string
|
||||
readonly confidence: number
|
||||
}
|
||||
|
||||
var SpeechRecognition: {
|
||||
|
|
|
|||
|
|
@ -155,7 +155,7 @@ export class HoloSphereService {
|
|||
let unsubscribe: (() => void) | undefined = undefined
|
||||
if (this.sphere.subscribe) {
|
||||
try {
|
||||
unsubscribe = this.sphere.subscribe(holon, lens, (data: any, key?: string) => {
|
||||
const subscribeResult = this.sphere.subscribe(holon, lens, (data: any, key?: string) => {
|
||||
subscriptionActive = true
|
||||
console.log(`📥 Subscription callback fired for ${lens}:`, { data, key, dataType: typeof data, isObject: typeof data === 'object', isArray: Array.isArray(data) })
|
||||
|
||||
|
|
@ -183,7 +183,18 @@ export class HoloSphereService {
|
|||
console.log(`📥 Current collected data for ${lens}:`, Object.keys(collectedData).length, 'keys')
|
||||
}
|
||||
})
|
||||
// Handle Promise if subscribe returns one
|
||||
if (subscribeResult instanceof Promise) {
|
||||
subscribeResult.then((result) => {
|
||||
unsubscribe = result?.unsubscribe || undefined
|
||||
console.log(`✅ Subscribe called successfully for ${lens}`)
|
||||
}).catch((err) => {
|
||||
console.error(`❌ Error in subscribe promise for ${lens}:`, err)
|
||||
})
|
||||
} else {
|
||||
unsubscribe = subscribeResult?.unsubscribe || undefined
|
||||
console.log(`✅ Subscribe called successfully for ${lens}`)
|
||||
}
|
||||
} catch (subError) {
|
||||
console.error(`❌ Error calling subscribe for ${lens}:`, subError)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -66,9 +66,10 @@ export class LocationStorageService {
|
|||
private async ensureDirectory(path: string[]): Promise<void> {
|
||||
try {
|
||||
const dirPath = odd.path.directory(...path);
|
||||
const exists = await this.fs.exists(dirPath as any);
|
||||
const fs = this.fs as any;
|
||||
const exists = await fs.exists(dirPath);
|
||||
if (!exists) {
|
||||
await this.fs.mkdir(dirPath as any);
|
||||
await fs.mkdir(dirPath);
|
||||
}
|
||||
} catch (error) {
|
||||
console.error('Error ensuring directory:', error);
|
||||
|
|
@ -81,10 +82,11 @@ export class LocationStorageService {
|
|||
*/
|
||||
async saveLocation(location: LocationData): Promise<void> {
|
||||
try {
|
||||
const filePath = odd.path.file(...this.locationsPath, `${location.id}.json`);
|
||||
const filePath = (odd.path as any).file(...this.locationsPath, `${location.id}.json`);
|
||||
const content = new TextEncoder().encode(JSON.stringify(location, null, 2));
|
||||
await this.fs.write(filePath as any, content as any);
|
||||
await this.fs.publish();
|
||||
const fs = this.fs as any;
|
||||
await fs.write(filePath, content);
|
||||
await fs.publish();
|
||||
} catch (error) {
|
||||
console.error('Error saving location:', error);
|
||||
throw error;
|
||||
|
|
@ -96,12 +98,13 @@ export class LocationStorageService {
|
|||
*/
|
||||
async getLocation(locationId: string): Promise<LocationData | null> {
|
||||
try {
|
||||
const filePath = odd.path.file(...this.locationsPath, `${locationId}.json`);
|
||||
const exists = await this.fs.exists(filePath as any);
|
||||
const filePath = (odd.path as any).file(...this.locationsPath, `${locationId}.json`);
|
||||
const fs = this.fs as any;
|
||||
const exists = await fs.exists(filePath);
|
||||
if (!exists) {
|
||||
return null;
|
||||
}
|
||||
const content = await this.fs.read(filePath as any);
|
||||
const content = await fs.read(filePath);
|
||||
const text = new TextDecoder().decode(content as Uint8Array);
|
||||
return JSON.parse(text) as LocationData;
|
||||
} catch (error) {
|
||||
|
|
@ -116,12 +119,13 @@ export class LocationStorageService {
|
|||
async createShare(share: LocationShare): Promise<void> {
|
||||
try {
|
||||
// Save share metadata in private directory
|
||||
const sharePath = odd.path.file(...this.sharesPath, `${share.id}.json`);
|
||||
const sharePath = (odd.path as any).file(...this.sharesPath, `${share.id}.json`);
|
||||
const shareContent = new TextEncoder().encode(JSON.stringify(share, null, 2));
|
||||
await this.fs.write(sharePath as any, shareContent as any);
|
||||
const fs = this.fs as any;
|
||||
await fs.write(sharePath, shareContent);
|
||||
|
||||
// Create public reference file for share validation (only token, not full data)
|
||||
const publicSharePath = odd.path.file(...this.publicSharesPath, `${share.shareToken}.json`);
|
||||
const publicSharePath = (odd.path as any).file(...this.publicSharesPath, `${share.shareToken}.json`);
|
||||
const publicShareRef = {
|
||||
shareToken: share.shareToken,
|
||||
shareId: share.id,
|
||||
|
|
@ -129,9 +133,9 @@ export class LocationStorageService {
|
|||
expiresAt: share.expiresAt,
|
||||
};
|
||||
const publicContent = new TextEncoder().encode(JSON.stringify(publicShareRef, null, 2));
|
||||
await this.fs.write(publicSharePath as any, publicContent as any);
|
||||
await fs.write(publicSharePath, publicContent);
|
||||
|
||||
await this.fs.publish();
|
||||
await fs.publish();
|
||||
} catch (error) {
|
||||
console.error('Error creating share:', error);
|
||||
throw error;
|
||||
|
|
@ -144,24 +148,25 @@ export class LocationStorageService {
|
|||
async getShareByToken(shareToken: string): Promise<LocationShare | null> {
|
||||
try {
|
||||
// First check public reference
|
||||
const publicSharePath = odd.path.file(...this.publicSharesPath, `${shareToken}.json`);
|
||||
const publicExists = await this.fs.exists(publicSharePath as any);
|
||||
const publicSharePath = (odd.path as any).file(...this.publicSharesPath, `${shareToken}.json`);
|
||||
const fs = this.fs as any;
|
||||
const publicExists = await fs.exists(publicSharePath);
|
||||
if (!publicExists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const publicContent = await this.fs.read(publicSharePath as any);
|
||||
const publicContent = await fs.read(publicSharePath);
|
||||
const publicText = new TextDecoder().decode(publicContent as Uint8Array);
|
||||
const publicRef = JSON.parse(publicText);
|
||||
|
||||
// Now get full share from private directory
|
||||
const sharePath = odd.path.file(...this.sharesPath, `${publicRef.shareId}.json`);
|
||||
const shareExists = await this.fs.exists(sharePath as any);
|
||||
const sharePath = (odd.path as any).file(...this.sharesPath, `${publicRef.shareId}.json`);
|
||||
const shareExists = await fs.exists(sharePath);
|
||||
if (!shareExists) {
|
||||
return null;
|
||||
}
|
||||
|
||||
const shareContent = await this.fs.read(sharePath as any);
|
||||
const shareContent = await fs.read(sharePath);
|
||||
const shareText = new TextDecoder().decode(shareContent as Uint8Array);
|
||||
return JSON.parse(shareText) as LocationShare;
|
||||
} catch (error) {
|
||||
|
|
@ -176,12 +181,13 @@ export class LocationStorageService {
|
|||
async getAllShares(): Promise<LocationShare[]> {
|
||||
try {
|
||||
const dirPath = odd.path.directory(...this.sharesPath);
|
||||
const exists = await this.fs.exists(dirPath as any);
|
||||
const fs = this.fs as any;
|
||||
const exists = await fs.exists(dirPath);
|
||||
if (!exists) {
|
||||
return [];
|
||||
}
|
||||
|
||||
const files = await this.fs.ls(dirPath as any);
|
||||
const files = await fs.ls(dirPath);
|
||||
const shares: LocationShare[] = [];
|
||||
|
||||
for (const fileName of Object.keys(files)) {
|
||||
|
|
@ -206,12 +212,13 @@ export class LocationStorageService {
|
|||
*/
|
||||
private async getShareById(shareId: string): Promise<LocationShare | null> {
|
||||
try {
|
||||
const sharePath = odd.path.file(...this.sharesPath, `${shareId}.json`);
|
||||
const exists = await this.fs.exists(sharePath as any);
|
||||
const sharePath = (odd.path as any).file(...this.sharesPath, `${shareId}.json`);
|
||||
const fs = this.fs as any;
|
||||
const exists = await fs.exists(sharePath);
|
||||
if (!exists) {
|
||||
return null;
|
||||
}
|
||||
const content = await this.fs.read(sharePath as any);
|
||||
const content = await fs.read(sharePath);
|
||||
const text = new TextDecoder().decode(content as Uint8Array);
|
||||
return JSON.parse(text) as LocationShare;
|
||||
} catch (error) {
|
||||
|
|
|
|||
|
|
@ -43,5 +43,6 @@ export interface GeolocationPosition {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -206,7 +206,7 @@ export function Board() {
|
|||
const store = {
|
||||
store: storeWithHandle.store,
|
||||
status: storeWithHandle.status,
|
||||
connectionStatus: storeWithHandle.connectionStatus,
|
||||
...('connectionStatus' in storeWithHandle ? { connectionStatus: storeWithHandle.connectionStatus } : {}),
|
||||
error: storeWithHandle.error
|
||||
}
|
||||
const automergeHandle = storeWithHandle.handle
|
||||
|
|
@ -405,11 +405,11 @@ export function Board() {
|
|||
const isInputFocused = (target && (
|
||||
target.tagName === 'INPUT' ||
|
||||
target.tagName === 'TEXTAREA' ||
|
||||
target.isContentEditable
|
||||
(target instanceof HTMLElement && target.isContentEditable)
|
||||
)) || (activeElement && (
|
||||
activeElement.tagName === 'INPUT' ||
|
||||
activeElement.tagName === 'TEXTAREA' ||
|
||||
activeElement.isContentEditable
|
||||
(activeElement instanceof HTMLElement && activeElement.isContentEditable)
|
||||
));
|
||||
|
||||
// If an input is focused, let it handle Escape (don't prevent default)
|
||||
|
|
|
|||
|
|
@ -25,5 +25,6 @@ export const LocationDashboardRoute: React.FC = () => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -25,5 +25,6 @@ export const LocationShareCreate: React.FC = () => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -39,5 +39,6 @@ export const LocationShareView: React.FC = () => {
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -79,8 +79,8 @@ interface Message {
|
|||
// Update the ChatBox component to accept userName
|
||||
export const ChatBox: React.FC<IChatBoxShape["props"]> = ({
|
||||
roomId,
|
||||
w,
|
||||
h,
|
||||
w: _w,
|
||||
h: _h,
|
||||
userName,
|
||||
}) => {
|
||||
const [messages, setMessages] = useState<Message[]>([])
|
||||
|
|
|
|||
|
|
@ -113,6 +113,15 @@ export class FathomTranscriptShape extends BaseBoxShapeUtil<IFathomTranscript> {
|
|||
return `${minutes}:${remainingSeconds.toString().padStart(2, '0')}`
|
||||
}
|
||||
|
||||
const buttonStyle: React.CSSProperties = {
|
||||
padding: '4px 8px',
|
||||
fontSize: '10px',
|
||||
border: '1px solid #ccc',
|
||||
borderRadius: '4px',
|
||||
backgroundColor: 'white',
|
||||
cursor: 'pointer',
|
||||
}
|
||||
|
||||
// Custom header content with meeting info and toggle buttons
|
||||
const headerContent = (
|
||||
<div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', width: '100%', gap: '8px' }}>
|
||||
|
|
|
|||
|
|
@ -981,7 +981,7 @@ export class ObsNoteShape extends BaseBoxShapeUtil<IObsNoteShape> {
|
|||
/**
|
||||
* Sanitize props to ensure all values are JSON serializable
|
||||
*/
|
||||
private static sanitizeProps(props: Partial<IObsNoteShape['props']>): IObsNoteShape['props'] {
|
||||
public static sanitizeProps(props: Partial<IObsNoteShape['props']>): IObsNoteShape['props'] {
|
||||
// Ensure tags is a proper string array
|
||||
const tags = Array.isArray(props.tags)
|
||||
? props.tags.filter(tag => typeof tag === 'string').map(tag => String(tag))
|
||||
|
|
|
|||
|
|
@ -125,6 +125,10 @@ export class HolonIdle extends StateNode {
|
|||
|
||||
override onExit = () => {
|
||||
this.cleanupTooltip()
|
||||
// Clean up event listeners
|
||||
if ((this as any).cleanup) {
|
||||
;(this as any).cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
private cleanupTooltip = () => {
|
||||
|
|
@ -278,123 +282,6 @@ export class HolonIdle extends StateNode {
|
|||
}
|
||||
}
|
||||
|
||||
private createHolonShape(clickX?: number, clickY?: number) {
|
||||
try {
|
||||
// Store current camera position to prevent it from changing
|
||||
const currentCamera = this.editor.getCamera()
|
||||
this.editor.stopCameraAnimation()
|
||||
|
||||
// Standardized size: 700x400 (matches default props to fit ID and button)
|
||||
const shapeWidth = 700
|
||||
const shapeHeight = 400
|
||||
|
||||
// Use click position if available, otherwise fall back to viewport center
|
||||
let baseX: number
|
||||
let baseY: number
|
||||
|
||||
if (clickX !== undefined && clickY !== undefined) {
|
||||
// Position new Holon shape at click location (centered on click)
|
||||
baseX = clickX - shapeWidth / 2 // Center the shape on click
|
||||
baseY = clickY - shapeHeight / 2 // Center the shape on click
|
||||
console.log('📍 HolonTool: Calculated base position from click:', { clickX, clickY, baseX, baseY, shapeWidth, shapeHeight })
|
||||
} else {
|
||||
// Fallback to viewport center if no click coordinates
|
||||
const viewport = this.editor.getViewportPageBounds()
|
||||
const centerX = viewport.x + viewport.w / 2
|
||||
const centerY = viewport.y + viewport.h / 2
|
||||
baseX = centerX - shapeWidth / 2 // Center the shape
|
||||
baseY = centerY - shapeHeight / 2 // Center the shape
|
||||
}
|
||||
|
||||
// Find existing Holon shapes for naming
|
||||
const allShapes = this.editor.getCurrentPageShapes()
|
||||
const existingHolonShapes = allShapes.filter(s => s.type === 'Holon')
|
||||
|
||||
// ALWAYS use click position directly when provided - user clicked where they want it
|
||||
// Skip collision detection entirely for user clicks to ensure it appears exactly where clicked
|
||||
let finalX = baseX
|
||||
let finalY = baseY
|
||||
|
||||
if (clickX !== undefined && clickY !== undefined) {
|
||||
// User clicked - ALWAYS use that exact position, no collision detection
|
||||
// This ensures the shape appears exactly where the user clicked
|
||||
finalX = baseX
|
||||
finalY = baseY
|
||||
console.log('📍 Using click position directly (no collision check):', {
|
||||
clickPosition: { x: clickX, y: clickY },
|
||||
shapePosition: { x: finalX, y: finalY },
|
||||
shapeSize: { w: shapeWidth, h: shapeHeight }
|
||||
})
|
||||
} else {
|
||||
// For fallback (no click), use collision detection
|
||||
const position = findNonOverlappingPosition(
|
||||
this.editor,
|
||||
baseX,
|
||||
baseY,
|
||||
shapeWidth,
|
||||
shapeHeight
|
||||
)
|
||||
finalX = position.x
|
||||
finalY = position.y
|
||||
console.log('📍 No click position - using collision detection:', { finalX, finalY })
|
||||
}
|
||||
|
||||
// Default coordinates (can be changed by user)
|
||||
const defaultLat = 40.7128 // NYC
|
||||
const defaultLng = -74.0060
|
||||
const defaultResolution = 7 // City level
|
||||
|
||||
console.log('📍 HolonTool: Final position for shape:', { finalX, finalY, wasOverlap: clickX !== undefined && clickY !== undefined && (finalX !== baseX || finalY !== baseY) })
|
||||
|
||||
const holonShape = this.editor.createShape({
|
||||
type: 'Holon',
|
||||
x: finalX,
|
||||
y: finalY,
|
||||
props: {
|
||||
w: shapeWidth,
|
||||
h: shapeHeight,
|
||||
name: `Holon ${existingHolonShapes.length + 1}`,
|
||||
description: '',
|
||||
latitude: defaultLat,
|
||||
longitude: defaultLng,
|
||||
resolution: defaultResolution,
|
||||
holonId: '',
|
||||
isConnected: false,
|
||||
isEditing: true,
|
||||
selectedLens: 'general',
|
||||
data: {},
|
||||
connections: [],
|
||||
lastUpdated: Date.now()
|
||||
}
|
||||
})
|
||||
|
||||
console.log('✅ Created Holon shape:', holonShape.id)
|
||||
|
||||
// Restore camera position if it changed
|
||||
const newCamera = this.editor.getCamera()
|
||||
if (currentCamera.x !== newCamera.x || currentCamera.y !== newCamera.y || currentCamera.z !== newCamera.z) {
|
||||
this.editor.setCamera(currentCamera, { animation: { duration: 0 } })
|
||||
}
|
||||
|
||||
// Select the new shape
|
||||
setTimeout(() => {
|
||||
// Preserve camera position when selecting
|
||||
const cameraBeforeSelect = this.editor.getCamera()
|
||||
this.editor.stopCameraAnimation()
|
||||
this.editor.setSelectedShapes([`shape:${holonShape.id}`] as any)
|
||||
this.editor.setCurrentTool('select')
|
||||
// Restore camera if it changed during selection
|
||||
const cameraAfterSelect = this.editor.getCamera()
|
||||
if (cameraBeforeSelect.x !== cameraAfterSelect.x || cameraBeforeSelect.y !== cameraAfterSelect.y || cameraBeforeSelect.z !== cameraAfterSelect.z) {
|
||||
this.editor.setCamera(cameraBeforeSelect, { animation: { duration: 0 } })
|
||||
}
|
||||
}, 100)
|
||||
|
||||
} catch (error) {
|
||||
console.error('❌ Error creating Holon shape:', error)
|
||||
}
|
||||
}
|
||||
|
||||
private addRefreshAllListener() {
|
||||
// Listen for refresh-all-holons event
|
||||
const handleRefreshAll = async () => {
|
||||
|
|
@ -439,11 +326,4 @@ export class HolonIdle extends StateNode {
|
|||
// Store cleanup function for later use
|
||||
;(this as any).cleanup = cleanup
|
||||
}
|
||||
|
||||
onExit() {
|
||||
// Clean up event listeners
|
||||
if ((this as any).cleanup) {
|
||||
;(this as any).cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -21,6 +21,38 @@ export class ObsNoteTool extends StateNode {
|
|||
this.addRefreshAllListener()
|
||||
}
|
||||
}
|
||||
|
||||
private addRefreshAllListener() {
|
||||
// Listen for refresh-all-obsnotes event
|
||||
const handleRefreshAll = async () => {
|
||||
const shapeUtil = new ObsNoteShape(this.editor)
|
||||
shapeUtil.editor = this.editor
|
||||
|
||||
const result = await shapeUtil.refreshAllFromVault()
|
||||
if (result.success > 0) {
|
||||
alert(`✅ Refreshed ${result.success} notes from vault!${result.failed > 0 ? ` (${result.failed} failed)` : ''}`)
|
||||
} else {
|
||||
alert('❌ Failed to refresh any notes. Check console for details.')
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('refresh-all-obsnotes', handleRefreshAll)
|
||||
|
||||
// Clean up listener when tool is deselected
|
||||
const cleanup = () => {
|
||||
window.removeEventListener('refresh-all-obsnotes', handleRefreshAll)
|
||||
}
|
||||
|
||||
// Store cleanup function for later use
|
||||
;(this as any).cleanup = cleanup
|
||||
}
|
||||
|
||||
onExit() {
|
||||
// Clean up event listeners
|
||||
if ((this as any).cleanup) {
|
||||
;(this as any).cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export class ObsNoteIdle extends StateNode {
|
||||
|
|
@ -101,6 +133,10 @@ export class ObsNoteIdle extends StateNode {
|
|||
|
||||
override onExit = () => {
|
||||
this.cleanupTooltip()
|
||||
// Clean up event listeners
|
||||
if ((this as any).cleanup) {
|
||||
;(this as any).cleanup()
|
||||
}
|
||||
}
|
||||
|
||||
private cleanupTooltip = () => {
|
||||
|
|
@ -182,36 +218,4 @@ export class ObsNoteIdle extends StateNode {
|
|||
console.error('❌ Error creating ObsidianBrowser shape:', error)
|
||||
}
|
||||
}
|
||||
|
||||
private addRefreshAllListener() {
|
||||
// Listen for refresh-all-obsnotes event
|
||||
const handleRefreshAll = async () => {
|
||||
const shapeUtil = new ObsNoteShape(this.editor)
|
||||
shapeUtil.editor = this.editor
|
||||
|
||||
const result = await shapeUtil.refreshAllFromVault()
|
||||
if (result.success > 0) {
|
||||
alert(`✅ Refreshed ${result.success} notes from vault!${result.failed > 0 ? ` (${result.failed} failed)` : ''}`)
|
||||
} else {
|
||||
alert('❌ Failed to refresh any notes. Check console for details.')
|
||||
}
|
||||
}
|
||||
|
||||
window.addEventListener('refresh-all-obsnotes', handleRefreshAll)
|
||||
|
||||
// Clean up listener when tool is deselected
|
||||
const cleanup = () => {
|
||||
window.removeEventListener('refresh-all-obsnotes', handleRefreshAll)
|
||||
}
|
||||
|
||||
// Store cleanup function for later use
|
||||
;(this as any).cleanup = cleanup
|
||||
}
|
||||
|
||||
onExit() {
|
||||
// Clean up event listeners
|
||||
if ((this as any).cleanup) {
|
||||
;(this as any).cleanup()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,4 +1,4 @@
|
|||
import { Editor, TLShape, Box } from "@tldraw/tldraw"
|
||||
import { Editor, TLShape, Box, TLShapeId } from "@tldraw/tldraw"
|
||||
|
||||
/**
|
||||
* Check if two boxes overlap
|
||||
|
|
@ -20,8 +20,9 @@ function boxesOverlap(
|
|||
* Get the bounding box of a shape
|
||||
*/
|
||||
function getShapeBounds(editor: Editor, shape: TLShape | string): Box | null {
|
||||
const shapeId = typeof shape === 'string' ? shape : shape.id
|
||||
return editor.getShapePageBounds(shapeId)
|
||||
const shapeId = typeof shape === 'string' ? (shape as TLShapeId) : shape.id
|
||||
const bounds = editor.getShapePageBounds(shapeId)
|
||||
return bounds ?? null
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -70,7 +71,7 @@ export function resolveOverlaps(editor: Editor, shapeId: string): void {
|
|||
const newY = shapeBox.y // Keep same Y position
|
||||
|
||||
editor.updateShape({
|
||||
id: shapeId,
|
||||
id: shapeId as TLShapeId,
|
||||
type: shape.type,
|
||||
x: newX,
|
||||
y: newY,
|
||||
|
|
@ -90,7 +91,7 @@ export function resolveOverlaps(editor: Editor, shapeId: string): void {
|
|||
if (boxesOverlap(newShapeBox, otherBox, 20)) {
|
||||
const newY2 = otherBox.y + otherBox.h + 20
|
||||
editor.updateShape({
|
||||
id: shapeId,
|
||||
id: shapeId as TLShapeId,
|
||||
type: shape.type,
|
||||
x: shapeBox.x, // Keep original X
|
||||
y: newY2,
|
||||
|
|
|
|||
|
|
@ -60,5 +60,6 @@ echo " npm run dev"
|
|||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -562,7 +562,7 @@ const router = AutoRouter<IRequest, [env: Environment, ctx: ExecutionContext]>({
|
|||
})
|
||||
}
|
||||
|
||||
const data = await response.json()
|
||||
const data = await response.json() as { data?: any[] }
|
||||
console.log('Fathom API success, data length:', data?.data?.length || 0)
|
||||
return new Response(JSON.stringify(data), {
|
||||
headers: { 'Content-Type': 'application/json' }
|
||||
|
|
|
|||
Loading…
Reference in New Issue