Skip to content

Commit fb5d0cd

Browse files
committed
Merge branch 'dev' into main
2 parents 51cada5 + ca9dbf7 commit fb5d0cd

File tree

21 files changed

+516
-84
lines changed

21 files changed

+516
-84
lines changed

.vscode/settings.json

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,5 +7,6 @@
77
"eslint.validate": ["javascript", "typescript"],
88
"typescript.tsdk": "node_modules/typescript/lib",
99
"vue.features.codeActions.enable": false,
10-
"java.configuration.updateBuildConfiguration": "interactive"
10+
"java.configuration.updateBuildConfiguration": "interactive",
11+
"testing.automaticallyOpenPeekView": "never"
1112
}

apps/client/package.json

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,7 @@
8282
"qrcode": "1.5.1",
8383
"quasar": "npm:@deepnotes/[email protected]",
8484
"serialize-javascript": "6.0.0",
85+
"showdown": "^2.1.0",
8586
"superjson": "npm:@deepnotes/[email protected]",
8687
"turndown": "^7.1.2",
8788
"unilogr": "0.0.27",
@@ -108,6 +109,7 @@
108109
"@types/marked": "4.0.8",
109110
"@types/node-fetch": "^2.6.3",
110111
"@types/qrcode": "1.5.0",
112+
"@types/showdown": "^2.0.1",
111113
"@types/turndown": "^5.0.1",
112114
"@types/zxcvbn": "4.4.1",
113115
"@vue/devtools": "6.4.5",

apps/client/src/code/pages/page/arrows/arrow-creation.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ import {
1010

1111
import { ISerialArrow } from '../../serialization';
1212
import { makeSlim } from '../../slim';
13+
import { roundTimeToMinutes } from '../notes/date';
1314
import type { PageNote } from '../notes/note';
1415
import type { Page } from '../page';
1516
import type { IArrowCollabInput, PageArrow } from './arrow';
@@ -126,6 +127,9 @@ export class PageArrowCreation {
126127
this.fakeArrow.react.collab.label,
127128
);
128129

130+
newCollab.createdAt = roundTimeToMinutes(Date.now());
131+
newCollab.editedAt = null;
132+
129133
// Insert arrow into document
130134

131135
const arrowId = nanoid();

apps/client/src/code/pages/page/arrows/arrow.ts

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,9 @@ export const IArrowCollab = once(() =>
5959
color: z.string().default('grey'),
6060

6161
readOnly: z.boolean().default(false),
62+
63+
createdAt: z.number().nullable().default(null),
64+
editedAt: z.number().nullable().default(null),
6265
}),
6366
);
6467
export type IArrowCollabInput = z.input<ReturnType<typeof IArrowCollab>>;
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
import { roundToMultiple } from 'src/code/utils/math';
2+
3+
export function roundTimeToMinutes(value: number): number {
4+
return roundToMultiple(value, {
5+
base: 60 * 1000,
6+
roundFunc: Math.floor,
7+
});
8+
}

apps/client/src/code/pages/page/notes/dragging.ts

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { refProp, watchUntilTrue } from '@stdlib/vue';
44
import type { UnwrapRef } from 'vue';
55

66
import type { Page } from '../page';
7+
import { roundTimeToMinutes } from './date';
78

89
export interface IDraggingReact {
910
active: boolean;
@@ -19,6 +20,9 @@ export class NoteDragging {
1920

2021
react: UnwrapRef<IDraggingReact>;
2122

23+
initialRegionId?: string;
24+
finalRegionId?: string;
25+
2226
private _cancelPointerEvents?: () => void;
2327

2428
constructor(input: { page: Page }) {
@@ -67,6 +71,9 @@ export class NoteDragging {
6771
private _dragStart = async (event: PointerEvent) => {
6872
this.react.active = true;
6973

74+
this.initialRegionId = this.page.activeRegion.react.value.id;
75+
this.finalRegionId = this.page.id;
76+
7077
// Update note dragging states
7178

7279
for (const selectedNote of this.page.selection.react.notes) {
@@ -204,6 +211,18 @@ export class NoteDragging {
204211
}
205212

206213
private _dragFinish = () => {
214+
if (this.react.active && this.finalRegionId !== this.initialRegionId) {
215+
const date = roundTimeToMinutes(Date.now());
216+
217+
this.page.collab.doc.transact(() => {
218+
for (const selectedNote of this.page.selection.react.notes) {
219+
if (date !== this.page.collab.store.notes[selectedNote.id]?.movedAt) {
220+
this.page.collab.store.notes[selectedNote.id].movedAt = date;
221+
}
222+
}
223+
});
224+
}
225+
207226
this.react.active = false;
208227

209228
for (const selectedNote of this.page.selection.react.notes) {

apps/client/src/code/pages/page/notes/dropping.ts

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Vec2 } from '@stdlib/misc';
22

33
import type { Page } from '../page';
4+
import { roundTimeToMinutes } from './date';
45
import type { PageNote } from './note';
56

67
export class NoteDropping {
@@ -11,20 +12,28 @@ export class NoteDropping {
1112
}
1213

1314
async perform(parentNote: PageNote, dropIndex?: number) {
15+
this.page.dragging.finalRegionId = parentNote.id;
16+
1417
this.page.collab.doc.transact(() => {
1518
const containerWorldPos = parentNote.getContainerWorldRect()?.topLeft;
1619

1720
if (containerWorldPos == null) {
1821
return;
1922
}
2023

24+
const date = roundTimeToMinutes(Date.now());
25+
2126
for (const selectedNote of this.page.selection.react.notes) {
2227
const newPos = new Vec2(selectedNote.react.collab.pos).sub(
2328
containerWorldPos,
2429
);
2530

2631
selectedNote.react.collab.pos.x = newPos.x;
2732
selectedNote.react.collab.pos.y = newPos.y;
33+
34+
if (date !== this.page.collab.store.notes[selectedNote.id]?.movedAt) {
35+
this.page.collab.store.notes[selectedNote.id].movedAt = date;
36+
}
2837
}
2938
});
3039

apps/client/src/code/pages/page/notes/note-collab.ts

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,6 +83,10 @@ export const INoteCollab = once(() =>
8383
.default({}),
8484

8585
zIndex: z.number().default(-1),
86+
87+
createdAt: z.number().nullable().default(null),
88+
editedAt: z.number().nullable().default(null),
89+
movedAt: z.number().nullable().default(null),
8690
}),
8791
),
8892
);

apps/client/src/code/pages/page/notes/note.ts

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -202,10 +202,14 @@ export class PageNote extends PageElem() implements IPageRegion {
202202
}),
203203

204204
notes: computed(() =>
205-
this.page.notes.fromIds(this.react.collab?.noteIds ?? [], this.id),
205+
this.react.collab?.container.enabled
206+
? this.page.notes.fromIds(this.react.collab?.noteIds ?? [], this.id)
207+
: [],
206208
),
207209
arrows: computed(() =>
208-
this.page.arrows.fromIds(this.react.collab?.arrowIds ?? []),
210+
this.react.collab?.container.enabled
211+
? this.page.arrows.fromIds(this.react.collab?.arrowIds ?? [])
212+
: [],
209213
),
210214
elems: computed(() =>
211215
(this.react.notes as (PageNote | PageArrow)[]).concat(

apps/client/src/code/pages/page/notes/notes.ts

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { Vec2 } from '@stdlib/misc';
2+
import { watchUntilTrue } from '@stdlib/vue';
23
import type { Y } from '@syncedstore/core';
34
import { getYjsValue } from '@syncedstore/core';
45
import type { Factories } from 'src/code/factories';
@@ -113,28 +114,34 @@ export class PageNotes {
113114
);
114115
}
115116

116-
async create(
117-
region: PageRegion,
118-
worldPos: Vec2,
119-
center = true,
120-
destIndex?: number,
121-
) {
117+
async create(params: {
118+
region: PageRegion;
119+
worldPos?: Vec2;
120+
center?: boolean;
121+
destIndex?: number;
122+
edit?: boolean;
123+
}) {
122124
if (this.page.react.readOnly) {
123125
return;
124126
}
125127

126128
const note = this.page.app.serialization.deserialize(
127129
internals.pages.defaultNote,
128-
region,
129-
destIndex,
130+
params.region,
131+
params?.destIndex,
130132
).notes[0];
131133

132-
await this.page.editing.start(note);
134+
await nextTick();
135+
await watchUntilTrue(() => note.react.loaded);
133136

134-
note.react.collab.pos.x = worldPos.x;
135-
note.react.collab.pos.y = worldPos.y;
137+
if (params.edit !== false) {
138+
await this.page.editing.start(note);
139+
}
140+
141+
note.react.collab.pos.x = params?.worldPos?.x ?? 0;
142+
note.react.collab.pos.y = params?.worldPos?.y ?? 0;
136143

137-
if (center) {
144+
if (params?.center !== false) {
138145
const worldSize = note.getWorldRect('note-frame')?.size;
139146

140147
if (worldSize != null) {

0 commit comments

Comments
 (0)