Sfoglia il codice sorgente

Fixes deleting pages, adds local file saving / loading

main
Steve Ruiz 3 anni fa
parent
commit
61f56b984e

+ 0
- 2
components/canvas/bounds/handles.tsx Vedi File

@@ -25,8 +25,6 @@ export default function Handles() {
25 25
 
26 26
   const center = getShapeUtils(shape).getCenter(shape)
27 27
 
28
-  console.log(shape)
29
-
30 28
   return (
31 29
     <g transform={`rotate(${shape.rotation * (180 / Math.PI)},${center})`}>
32 30
       {Object.values(shape.handles).map((handle) => (

+ 8
- 1
hooks/useKeyboardEvents.ts Vedi File

@@ -134,7 +134,11 @@ export default function useKeyboardEvents() {
134 134
         }
135 135
         case 's': {
136 136
           if (metaKey(e)) {
137
-            state.send('SAVED', getKeyboardEventInfo(e))
137
+            if (e.shiftKey) {
138
+              state.send('SAVED_AS_TO_FILESYSTEM', getKeyboardEventInfo(e))
139
+            } else {
140
+              state.send('SAVED', getKeyboardEventInfo(e))
141
+            }
138 142
           }
139 143
           break
140 144
         }
@@ -187,6 +191,9 @@ export default function useKeyboardEvents() {
187 191
         }
188 192
         case 'l': {
189 193
           if (metaKey(e)) {
194
+            if (e.shiftKey) {
195
+              state.send('LOADED_FROM_FILE_STSTEM', getKeyboardEventInfo(e))
196
+            }
190 197
           } else {
191 198
             state.send('SELECTED_LINE_TOOL', getKeyboardEventInfo(e))
192 199
           }

+ 1
- 0
package.json Vedi File

@@ -18,6 +18,7 @@
18 18
     "@radix-ui/react-tooltip": "^0.0.18",
19 19
     "@state-designer/react": "^1.7.3",
20 20
     "@stitches/react": "^0.1.9",
21
+    "browser-fs-access": "^0.17.3",
21 22
     "framer-motion": "^4.1.16",
22 23
     "ismobilejs": "^1.1.1",
23 24
     "next": "10.2.0",

+ 2
- 2
state/commands/change-page.ts Vedi File

@@ -13,9 +13,9 @@ export default function changePage(data: Data, pageId: string) {
13 13
       category: 'canvas',
14 14
       manualSelection: true,
15 15
       do(data) {
16
-        storage.savePage(data, data.currentPageId)
16
+        storage.savePage(data, data.document.id, prevPageId)
17 17
         data.currentPageId = pageId
18
-        storage.loadPage(data, data.currentPageId)
18
+        storage.loadPage(data)
19 19
       },
20 20
       undo(data) {
21 21
         data.currentPageId = prevPageId

+ 1
- 1
state/commands/create-page.ts Vedi File

@@ -19,7 +19,7 @@ export default function createPage(data: Data) {
19 19
         data.document.pages[page.id] = page
20 20
         data.pageStates[page.id] = pageState
21 21
         data.currentPageId = page.id
22
-        storage.savePage(data, page.id)
22
+        storage.savePage(data, data.document.id, page.id)
23 23
       },
24 24
       undo(data) {
25 25
         const { page, currentPageId } = snapshot

+ 9
- 8
state/commands/delete-page.ts Vedi File

@@ -5,6 +5,7 @@ import { current } from 'immer'
5 5
 import { getPage, getSelectedShapes } from 'utils/utils'
6 6
 import { getShapeUtils } from 'lib/shape-utils'
7 7
 import * as vec from 'utils/vec'
8
+import storage from 'state/storage'
8 9
 
9 10
 export default function changePage(data: Data, pageId: string) {
10 11
   const snapshot = getSnapshot(data, pageId)
@@ -18,11 +19,13 @@ export default function changePage(data: Data, pageId: string) {
18 19
         data.currentPageId = snapshot.nextPageId
19 20
         delete data.document.pages[pageId]
20 21
         delete data.pageStates[pageId]
22
+        storage.loadPage(data, snapshot.nextPageId)
21 23
       },
22 24
       undo(data) {
23 25
         data.currentPageId = snapshot.currentPageId
24 26
         data.document.pages[pageId] = snapshot.page
25 27
         data.pageStates[pageId] = snapshot.pageState
28
+        storage.loadPage(data, snapshot.currentPageId)
26 29
       },
27 30
     })
28 31
   )
@@ -37,16 +40,14 @@ function getSnapshot(data: Data, pageId: string) {
37 40
 
38 41
   const isCurrent = currentPageId === pageId
39 42
 
40
-  const nextIndex = isCurrent
41
-    ? page.childIndex === 0
42
-      ? 1
43
-      : page.childIndex - 1
44
-    : document.pages[currentPageId].childIndex
43
+  // const nextIndex = isCurrent
44
+  //   ? page.childIndex === 0
45
+  //     ? 1
46
+  //     : page.childIndex - 1
47
+  //   : document.pages[currentPageId].childIndex
45 48
 
46 49
   const nextPageId = isCurrent
47
-    ? Object.values(document.pages).find(
48
-        (page) => page.childIndex === nextIndex
49
-      )!.id
50
+    ? Object.values(document.pages).filter((page) => page.id !== pageId)[0]?.id // TODO: should be at nextIndex
50 51
     : cData.currentPageId
51 52
 
52 53
   return {

+ 1
- 1
state/commands/draw.ts Vedi File

@@ -10,7 +10,7 @@ export default function drawCommand(data: Data, id: string) {
10 10
   history.execute(
11 11
     data,
12 12
     new Command({
13
-      name: 'set_points',
13
+      name: 'create_draw_shape',
14 14
       category: 'canvas',
15 15
       manualSelection: true,
16 16
       do(data, initial) {

+ 2
- 2
state/commands/move-to-page.ts Vedi File

@@ -71,7 +71,7 @@ export default function nudgeCommand(data: Data, newPageId: string) {
71 71
         getPageState(data, fromPageId).selectedIds.clear()
72 72
 
73 73
         // Save the "from" page
74
-        storage.savePage(data, fromPageId)
74
+        storage.savePage(data, data.document.id, fromPageId)
75 75
 
76 76
         // Load the "to" page
77 77
         storage.loadPage(data, toPageId)
@@ -124,7 +124,7 @@ export default function nudgeCommand(data: Data, newPageId: string) {
124 124
 
125 125
         getPageState(data, fromPageId).selectedIds.clear()
126 126
 
127
-        storage.savePage(data, fromPageId)
127
+        storage.savePage(data, data.document.id, fromPageId)
128 128
 
129 129
         storage.loadPage(data, toPageId)
130 130
 

+ 2
- 0
state/data.ts Vedi File

@@ -2,6 +2,8 @@ import { Data, ShapeType } from 'types'
2 2
 import shapeUtils from 'lib/shape-utils'
3 3
 
4 4
 export const defaultDocument: Data['document'] = {
5
+  id: '0001',
6
+  name: 'My Document',
5 7
   pages: {
6 8
     page1: {
7 9
       id: 'page1',

+ 3
- 3
state/history.ts Vedi File

@@ -23,7 +23,7 @@ class History<T extends Data> {
23 23
       this.pointer = this.maxLength - 1
24 24
     }
25 25
 
26
-    storage.save(data)
26
+    storage.saveToLocalStorage(data)
27 27
   }
28 28
 
29 29
   undo = (data: T) => {
@@ -32,7 +32,7 @@ class History<T extends Data> {
32 32
     command.undo(data)
33 33
     if (this.disabled) return
34 34
     this.pointer--
35
-    storage.save(data)
35
+    storage.saveToLocalStorage(data)
36 36
   }
37 37
 
38 38
   redo = (data: T) => {
@@ -41,7 +41,7 @@ class History<T extends Data> {
41 41
     command.redo(data, false)
42 42
     if (this.disabled) return
43 43
     this.pointer++
44
-    storage.save(data)
44
+    storage.saveToLocalStorage(data)
45 45
   }
46 46
 
47 47
   disable = () => {

+ 12
- 12
state/inputs.tsx Vedi File

@@ -1,6 +1,6 @@
1 1
 import React from 'react'
2 2
 import { PointerInfo } from 'types'
3
-import { isDarwin } from 'utils/utils'
3
+import { isDarwin, getPoint } from 'utils/utils'
4 4
 
5 5
 const DOUBLE_CLICK_DURATION = 300
6 6
 
@@ -17,8 +17,8 @@ class Inputs {
17 17
     const info = {
18 18
       target,
19 19
       pointerId: touch.identifier,
20
-      origin: [touch.clientX, touch.clientY],
21
-      point: [touch.clientX, touch.clientY],
20
+      origin: getPoint(touch),
21
+      point: getPoint(touch),
22 22
       pressure: 0.5,
23 23
       shiftKey,
24 24
       ctrlKey,
@@ -42,7 +42,7 @@ class Inputs {
42 42
     const info = {
43 43
       ...prev,
44 44
       pointerId: touch.identifier,
45
-      point: [touch.clientX, touch.clientY],
45
+      point: getPoint(touch),
46 46
       pressure: 0.5,
47 47
       shiftKey,
48 48
       ctrlKey,
@@ -63,8 +63,8 @@ class Inputs {
63 63
     const info = {
64 64
       target,
65 65
       pointerId: e.pointerId,
66
-      origin: [e.clientX, e.clientY],
67
-      point: [e.clientX, e.clientY],
66
+      origin: getPoint(e),
67
+      point: getPoint(e),
68 68
       pressure: e.pressure || 0.5,
69 69
       shiftKey,
70 70
       ctrlKey,
@@ -84,8 +84,8 @@ class Inputs {
84 84
     const info = {
85 85
       target,
86 86
       pointerId: e.pointerId,
87
-      origin: [e.clientX, e.clientY],
88
-      point: [e.clientX, e.clientY],
87
+      origin: getPoint(e),
88
+      point: getPoint(e),
89 89
       pressure: e.pressure || 0.5,
90 90
       shiftKey,
91 91
       ctrlKey,
@@ -104,7 +104,7 @@ class Inputs {
104 104
     const info = {
105 105
       ...prev,
106 106
       pointerId: e.pointerId,
107
-      point: [e.clientX, e.clientY],
107
+      point: getPoint(e),
108 108
       pressure: e.pressure || 0.5,
109 109
       shiftKey,
110 110
       ctrlKey,
@@ -126,8 +126,8 @@ class Inputs {
126 126
 
127 127
     const info = {
128 128
       ...prev,
129
-      origin: prev?.origin || [e.clientX, e.clientY],
130
-      point: [e.clientX, e.clientY],
129
+      origin: prev?.origin || getPoint(e),
130
+      point: getPoint(e),
131 131
       pressure: e.pressure || 0.5,
132 132
       shiftKey,
133 133
       ctrlKey,
@@ -144,7 +144,7 @@ class Inputs {
144 144
 
145 145
   wheel(e: WheelEvent) {
146 146
     const { shiftKey, ctrlKey, metaKey, altKey } = e
147
-    return { point: [e.clientX, e.clientY], shiftKey, ctrlKey, metaKey, altKey }
147
+    return { point: getPoint(e), shiftKey, ctrlKey, metaKey, altKey }
148 148
   }
149 149
 
150 150
   canAccept(pointerId: PointerEvent['pointerId']) {

+ 1
- 1
state/sessions/draw-session.ts Vedi File

@@ -72,7 +72,7 @@ export default class BrushSession extends BaseSession {
72 72
 
73 73
     point = vec.med(this.previous, point)
74 74
 
75
-    const next = [...vec.sub(point, this.origin), pressure]
75
+    const next = vec.round([...vec.sub(point, this.origin), pressure])
76 76
 
77 77
     // Don't add duplicate points
78 78
     if (vec.isEqual(this.last, next)) return

+ 32
- 8
state/state.ts Vedi File

@@ -172,15 +172,19 @@ const state = createState({
172 172
         CHANGED_PAGE: 'changePage',
173 173
         CREATED_PAGE: ['clearSelectedIds', 'createPage'],
174 174
         DELETED_PAGE: { unless: 'hasOnlyOnePage', do: 'deletePage' },
175
+        LOADED_FROM_FILE: 'loadDocumentFromJson',
175 176
       },
176 177
       initial: 'selecting',
177 178
       states: {
178 179
         selecting: {
179 180
           onEnter: 'setActiveToolSelect',
180 181
           on: {
181
-            SAVED: 'forceSave',
182 182
             UNDO: 'undo',
183 183
             REDO: 'redo',
184
+            SAVED: 'forceSave',
185
+            LOADED_FROM_FILE_STSTEM: 'loadFromFileSystem',
186
+            SAVED_TO_FILESYSTEM: 'saveToFileSystem',
187
+            SAVED_AS_TO_FILESYSTEM: 'saveAsToFileSystem',
184 188
             SAVED_CODE: 'saveCode',
185 189
             DELETED: 'deleteSelection',
186 190
             INCREASED_CODE_FONT_SIZE: 'increaseCodeFontSize',
@@ -433,8 +437,12 @@ const state = createState({
433 437
                       do: 'createShape',
434 438
                       to: 'draw.editing',
435 439
                     },
436
-                    UNDO: { do: 'undo' },
437
-                    REDO: { do: 'redo' },
440
+                    UNDO: 'undo',
441
+                    REDO: 'redo',
442
+                    SAVED: 'forceSave',
443
+                    LOADED_FROM_FILE_STSTEM: 'loadFromFileSystem',
444
+                    SAVED_TO_FILESYSTEM: 'saveToFileSystem',
445
+                    SAVED_AS_TO_FILESYSTEM: 'saveAsToFileSystem',
438 446
                   },
439 447
                 },
440 448
                 editing: {
@@ -1474,25 +1482,41 @@ const state = createState({
1474 1482
 
1475 1483
     /* ---------------------- Data ---------------------- */
1476 1484
 
1485
+    saveToFileSystem(data) {
1486
+      storage.saveToFileSystem(data)
1487
+    },
1488
+
1489
+    saveAsToFileSystem(data) {
1490
+      storage.saveAsToFileSystem(data)
1491
+    },
1492
+
1493
+    loadFromFileSystem() {
1494
+      storage.loadDocumentFromFilesystem()
1495
+    },
1496
+
1497
+    loadDocumentFromJson(data, payload: { restoredData: any }) {
1498
+      storage.load(data, payload.restoredData)
1499
+    },
1500
+
1477 1501
     forceSave(data) {
1478
-      storage.save(data)
1502
+      storage.saveToLocalStorage(data)
1479 1503
     },
1480 1504
 
1481 1505
     savePage(data) {
1482
-      storage.savePage(data, data.currentPageId)
1506
+      storage.savePage(data)
1483 1507
     },
1484 1508
 
1485 1509
     loadPage(data) {
1486
-      storage.loadPage(data, data.currentPageId)
1510
+      storage.loadPage(data)
1487 1511
     },
1488 1512
 
1489 1513
     saveCode(data, payload: { code: string }) {
1490 1514
       data.document.code[data.currentCodeFileId].code = payload.code
1491
-      storage.save(data)
1515
+      storage.saveToLocalStorage(data)
1492 1516
     },
1493 1517
 
1494 1518
     restoreSavedData(data) {
1495
-      storage.load(data)
1519
+      storage.loadDocumentFromLocalStorage(data)
1496 1520
     },
1497 1521
 
1498 1522
     clearBoundsRotation(data) {

+ 178
- 62
state/storage.ts Vedi File

@@ -1,67 +1,190 @@
1
-import { Data, Page, PageState } from 'types'
1
+import * as fa from 'browser-fs-access'
2
+import { Data, Page, PageState, TLDocument } from 'types'
2 3
 import { setToArray } from 'utils/utils'
4
+import state from './state'
5
+import { v4 as uuid } from 'uuid'
3 6
 
4
-const CURRENT_VERSION = 'code_slate_0.0.4'
7
+const CURRENT_VERSION = 'code_slate_0.0.5'
5 8
 const DOCUMENT_ID = '0001'
6 9
 
7
-function storageId(label: string, id: string) {
8
-  return `${CURRENT_VERSION}_doc_${DOCUMENT_ID}_${label}_${id}`
10
+function storageId(label: string, fileId: string, id: string) {
11
+  return `${CURRENT_VERSION}_doc_${fileId}_${label}_${id}`
9 12
 }
10 13
 
11 14
 class Storage {
12
-  // Saving
13
-  load(data: Data, id = CURRENT_VERSION) {
14
-    if (typeof window === 'undefined') return
15
-    if (typeof localStorage === 'undefined') return
15
+  load(data: Data, restoredData: any) {
16
+    // Empty shapes in state for each page
17
+    for (let key in restoredData.document.pages) {
18
+      restoredData.document.pages[key].shapes = {}
19
+    }
16 20
 
17
-    // Load data from local storage
18
-    const savedData = localStorage.getItem(id)
21
+    // Empty page states for each page
22
+    for (let key in restoredData.pageStates) {
23
+      restoredData.document.pages[key].shapes = {}
24
+    }
19 25
 
20
-    if (savedData !== null) {
21
-      const restoredData = JSON.parse(savedData)
26
+    data.document = {} as TLDocument
27
+    data.pageStates = {}
22 28
 
23
-      // Empty shapes in state for each page
24
-      for (let key in restoredData.document.pages) {
25
-        restoredData.document.pages[key].shapes = {}
26
-      }
29
+    // Merge restored data into state
30
+    Object.assign(data, restoredData)
27 31
 
28
-      // Empty page states for each page
29
-      for (let key in restoredData.pageStates) {
30
-        restoredData.document.pages[key].shapes = {}
31
-      }
32
+    // Minor migrtation: add id and name to document
33
+    data.document = {
34
+      id: 'document0',
35
+      name: 'My Document',
36
+      ...restoredData.document,
37
+    }
38
+
39
+    // Load current page
40
+    this.loadPage(data, data.currentPageId)
41
+  }
42
+
43
+  async loadDocumentFromFilesystem() {
44
+    const blob = await fa.fileOpen({
45
+      description: 'tldraw files',
46
+    })
32 47
 
33
-      // Merge restored data into state
34
-      Object.assign(data, restoredData)
48
+    const text = await getTextFromBlob(blob)
35 49
 
36
-      // Load current page
37
-      this.loadPage(data, data.currentPageId)
50
+    const restoredData = JSON.parse(text)
51
+
52
+    if (restoredData === null) {
53
+      console.warn('Could not load that data.')
54
+      return
38 55
     }
56
+
57
+    state.send('LOADED_FROM_FILE', { restoredData })
39 58
   }
40 59
 
41
-  save = (data: Data, id = CURRENT_VERSION) => {
60
+  loadDocumentFromLocalStorage(data: Data, fileId = DOCUMENT_ID) {
42 61
     if (typeof window === 'undefined') return
43 62
     if (typeof localStorage === 'undefined') return
44 63
 
64
+    // Load data from local storage
65
+    const savedData = localStorage.getItem(fileId)
66
+
67
+    if (savedData === null) return false
68
+
69
+    const restoredData = JSON.parse(savedData)
70
+
71
+    this.load(data, restoredData)
72
+  }
73
+
74
+  getDataToSave = (data: Data) => {
45 75
     const dataToSave: any = { ...data }
46 76
 
47
-    // Don't save pageStates
77
+    for (let pageId in data.document) {
78
+      const savedPage = localStorage.getItem(
79
+        storageId(data.document.id, 'page', pageId)
80
+      )
81
+
82
+      if (savedPage !== null) {
83
+        const restored: Page = JSON.parse(savedPage)
84
+        dataToSave.document.pages[pageId] = restored
85
+      }
86
+    }
87
+
48 88
     dataToSave.pageStates = {}
49 89
 
90
+    return JSON.stringify(dataToSave, null, 2)
91
+  }
92
+
93
+  saveToLocalStorage = (data: Data, id = data.document.id) => {
94
+    if (typeof window === 'undefined') return
95
+    if (typeof localStorage === 'undefined') return
96
+
50 97
     // Save current data to local storage
51
-    localStorage.setItem(id, JSON.stringify(dataToSave))
98
+    localStorage.setItem(id, this.getDataToSave(data))
99
+
100
+    // Save current page too
101
+    this.savePage(data, id, data.currentPageId)
102
+
103
+    state.send('SAVED_FILE_TO_LOCAL_STORAGE')
104
+  }
105
+
106
+  saveAsToFileSystem = (data: Data) => {
107
+    // Create a new document id when saving to the file system
108
+    this.saveToFileSystem(data, uuid())
109
+  }
110
+
111
+  saveToFileSystem = (data: Data, id = data.document.id) => {
112
+    // Save to local storage first
113
+    this.saveToLocalStorage(data, id)
114
+
115
+    const json = this.getDataToSave(data)
116
+
117
+    const blob = new Blob([json], {
118
+      type: 'application/vnd.tldraw+json',
119
+    })
120
+
121
+    fa.fileSave(blob, {
122
+      fileName: `${data.document.name}.tldr`,
123
+      description: 'tldraw file',
124
+      extensions: ['.tldr'],
125
+    })
126
+      .then(() => {
127
+        state.send('SAVED_FILE_TO_FILE_SYSTEM')
128
+      })
129
+      .catch((e) => {
130
+        state.send('CANCELLED_SAVE', { reason: e.message })
131
+      })
132
+  }
133
+
134
+  loadPageFromLocalStorage(fileId: string, pageId: string) {
135
+    let restored: Page
136
+
137
+    const savedPage = localStorage.getItem(storageId(fileId, 'page', pageId))
138
+
139
+    if (savedPage !== null) {
140
+      restored = JSON.parse(savedPage)
141
+    } else {
142
+      restored = {
143
+        id: pageId,
144
+        type: 'page',
145
+        childIndex: 0,
146
+        name: 'Page',
147
+        shapes: {},
148
+      }
149
+    }
52 150
 
53
-    // Save current page
54
-    this.savePage(data, data.currentPageId)
151
+    return restored
55 152
   }
56 153
 
57
-  savePage(data: Data, pageId: string) {
154
+  loadPageStateFromLocalStorage(fileId: string, pageId: string) {
155
+    let restored: PageState
156
+
157
+    const savedPageState = localStorage.getItem(
158
+      storageId(fileId, 'pageState', pageId)
159
+    )
160
+
161
+    if (savedPageState !== null) {
162
+      restored = JSON.parse(savedPageState)
163
+      restored.selectedIds = new Set(restored.selectedIds)
164
+    } else {
165
+      restored = {
166
+        camera: {
167
+          point: [0, 0],
168
+          zoom: 1,
169
+        },
170
+        selectedIds: new Set([]),
171
+      }
172
+    }
173
+
174
+    return restored
175
+  }
176
+
177
+  savePage(data: Data, fileId = data.document.id, pageId = data.currentPageId) {
58 178
     if (typeof window === 'undefined') return
59 179
     if (typeof localStorage === 'undefined') return
60 180
 
61 181
     // Save page
62 182
     const page = data.document.pages[pageId]
63 183
 
64
-    localStorage.setItem(storageId('page', pageId), JSON.stringify(page))
184
+    localStorage.setItem(
185
+      storageId(fileId, 'page', pageId),
186
+      JSON.stringify(page)
187
+    )
65 188
 
66 189
     // Save page state
67 190
 
@@ -80,39 +203,20 @@ class Storage {
80 203
     }
81 204
 
82 205
     localStorage.setItem(
83
-      storageId('pageState', pageId),
206
+      storageId(fileId, 'pageState', pageId),
84 207
       JSON.stringify(pageState)
85 208
     )
86 209
   }
87 210
 
88
-  loadPage(data: Data, pageId: string) {
211
+  loadPage(data: Data, pageId = data.currentPageId) {
89 212
     if (typeof window === 'undefined') return
90 213
     if (typeof localStorage === 'undefined') return
91 214
 
92
-    // Load page and merge into state
93
-    const savedPage = localStorage.getItem(storageId('page', pageId))
94
-
95
-    if (savedPage !== null) {
96
-      const restored: Page = JSON.parse(savedPage)
97
-      data.document.pages[pageId] = restored
98
-    }
215
+    const fileId = data.document.id
99 216
 
100
-    // Load page state and merge into state
101
-    const savedPageState = localStorage.getItem(storageId('pageState', pageId))
217
+    data.document.pages[pageId] = this.loadPageFromLocalStorage(fileId, pageId)
102 218
 
103
-    if (savedPageState !== null) {
104
-      const restored: PageState = JSON.parse(savedPageState)
105
-      restored.selectedIds = new Set(restored.selectedIds)
106
-      data.pageStates[pageId] = restored
107
-    } else {
108
-      data.pageStates[pageId] = {
109
-        camera: {
110
-          point: [0, 0],
111
-          zoom: 1,
112
-        },
113
-        selectedIds: new Set([]),
114
-      }
115
-    }
219
+    data.pageStates[pageId] = this.loadPageStateFromLocalStorage(fileId, pageId)
116 220
 
117 221
     // Empty shapes in state for other pages
118 222
     for (let key in data.document.pages) {
@@ -120,13 +224,7 @@ class Storage {
120 224
       data.document.pages[key].shapes = {}
121 225
     }
122 226
 
123
-    // Empty page states for other pages
124
-    for (let key in data.pageStates) {
125
-      if (key === pageId) continue
126
-      data.document.pages[key].shapes = {}
127
-    }
128
-
129
-    // Update camera
227
+    // Update camera for the new page state
130 228
     document.documentElement.style.setProperty(
131 229
       '--camera-zoom',
132 230
       data.pageStates[data.currentPageId].camera.zoom.toString()
@@ -137,3 +235,21 @@ class Storage {
137 235
 const storage = new Storage()
138 236
 
139 237
 export default storage
238
+
239
+async function getTextFromBlob(blob: Blob): Promise<string> {
240
+  // Return blob as text if a text file.
241
+  if ('text' in Blob) return blob.text()
242
+
243
+  // Return blob as text if a text file.
244
+  return new Promise((resolve) => {
245
+    const reader = new FileReader()
246
+
247
+    reader.onloadend = () => {
248
+      if (reader.readyState === FileReader.DONE) {
249
+        resolve(reader.result as string)
250
+      }
251
+    }
252
+
253
+    reader.readAsText(blob, 'utf8')
254
+  })
255
+}

+ 8
- 4
types.ts Vedi File

@@ -28,10 +28,7 @@ export interface Data {
28 28
   currentParentId: string
29 29
   currentCodeFileId: string
30 30
   codeControls: Record<string, CodeControl>
31
-  document: {
32
-    pages: Record<string, Page>
33
-    code: Record<string, CodeFile>
34
-  }
31
+  document: TLDocument
35 32
   pageStates: Record<string, PageState>
36 33
 }
37 34
 
@@ -39,6 +36,13 @@ export interface Data {
39 36
 /*                      Document                      */
40 37
 /* -------------------------------------------------- */
41 38
 
39
+export interface TLDocument {
40
+  id: string
41
+  name: string
42
+  pages: Record<string, Page>
43
+  code: Record<string, CodeFile>
44
+}
45
+
42 46
 export interface Page {
43 47
   id: string
44 48
   type: 'page'

+ 10
- 0
utils/utils.ts Vedi File

@@ -1758,3 +1758,13 @@ export function getTopParentId(data: Data, id: string): string {
1758 1758
 export function uniqueArray<T extends string | number | Symbol>(...items: T[]) {
1759 1759
   return Array.from(new Set(items).values())
1760 1760
 }
1761
+
1762
+export function getPoint(
1763
+  e: PointerEvent | React.PointerEvent | Touch | React.Touch | WheelEvent
1764
+) {
1765
+  return [
1766
+    Number(e.clientX.toPrecision(4)),
1767
+    Number(e.clientY.toPrecision(4)),
1768
+    'pressure' in e ? e.pressure || 0.5 : 0.5,
1769
+  ]
1770
+}

+ 1
- 6
utils/vec.ts Vedi File

@@ -339,13 +339,8 @@ export function clockwise(p1: number[], pc: number[], p2: number[]) {
339 339
   return isLeft(p1, pc, p2) > 0
340 340
 }
341 341
 
342
-const rounds = [1, 10, 100, 1000]
343
-
344 342
 export function round(a: number[], d = 2) {
345
-  return [
346
-    Math.round(a[0] * rounds[d]) / rounds[d],
347
-    Math.round(a[1] * rounds[d]) / rounds[d],
348
-  ]
343
+  return a.map((v) => +v.toFixed(d))
349 344
 }
350 345
 
351 346
 /**

+ 5
- 0
yarn.lock Vedi File

@@ -2567,6 +2567,11 @@ brorand@^1.0.1, brorand@^1.1.0:
2567 2567
   resolved "https://registry.yarnpkg.com/brorand/-/brorand-1.1.0.tgz#12c25efe40a45e3c323eb8675a0a0ce57b22371f"
2568 2568
   integrity sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=
2569 2569
 
2570
+browser-fs-access@^0.17.3:
2571
+  version "0.17.3"
2572
+  resolved "https://registry.yarnpkg.com/browser-fs-access/-/browser-fs-access-0.17.3.tgz#f91447b0b74bb8d224a8b01a7d18bd090468ef1d"
2573
+  integrity sha512-zrEWlsaQf3RKAeLjA6veRzTtf8ge3dFfun50RI74kSWKQKnJaioPc4I8oPzO6rDNiR0CJUI+oORuPOFMUkr0+g==
2574
+
2570 2575
 browser-process-hrtime@^1.0.0:
2571 2576
   version "1.0.0"
2572 2577
   resolved "https://registry.yarnpkg.com/browser-process-hrtime/-/browser-process-hrtime-1.0.0.tgz#3c9b4b7d782c8121e56f10106d84c0d0ffc94626"

Loading…
Annulla
Salva