Skip to content

Commit 0c2dc53

Browse files
authored
ENG 581 Add ability to change size/font in Discourse Shape (#348)
* Enhance DiscourseNodeUtil with size and font properties * Introduced FONT_SIZES and updated props to include size and fontFamily for DiscourseNodeShape. * Updated rendering logic to apply font styles based on new properties. * Refactored default values for size and fontFamily in the BaseDiscourseNodeUtil class. * Migration WIP * Refactor discourse migrations and update default properties * Consolidated migration functions into a single createMigrations function for better maintainability. * Updated default size and fontFamily properties in BaseDiscourseNodeUtil to "m" and "draw" respectively. * Adjusted migration logic to apply new properties consistently across node types.
1 parent 91c4ea6 commit 0c2dc53

4 files changed

Lines changed: 169 additions & 104 deletions

File tree

apps/roam/src/components/Export.tsx

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -345,7 +345,15 @@ const ExportDialog: ExportDialogComponent = ({
345345
rotation: 0,
346346
isLocked: false,
347347
type: nodeType,
348-
props: { w, h, uid: r.uid, title: String(r[firstColumnKey]), imageUrl },
348+
props: {
349+
w,
350+
h,
351+
uid: r.uid,
352+
title: String(r[firstColumnKey]),
353+
imageUrl,
354+
size: "m",
355+
fontFamily: "draw",
356+
},
349357
parentId: pageKey,
350358
y: shapeY,
351359
id: newShapeId,

apps/roam/src/components/canvas/DiscourseNodeUtil.tsx

Lines changed: 33 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,12 @@ import {
1515
FileHelpers,
1616
StateNode,
1717
TLStateNodeConstructor,
18+
TLDefaultSizeStyle,
19+
DefaultSizeStyle,
20+
T,
21+
FONT_FAMILIES,
22+
TLDefaultFontStyle,
23+
DefaultFontStyle,
1824
} from "tldraw";
1925
import React, { useState, useEffect, useRef } from "react";
2026
import { useExtensionAPI } from "roamjs-components/components/ExtensionApiContext";
@@ -43,6 +49,12 @@ const TEXT_PROPS = {
4349
padding: "0px",
4450
maxWidth: "auto",
4551
};
52+
const FONT_SIZES: Record<TLDefaultSizeStyle, number> = {
53+
m: 25,
54+
l: 38,
55+
xl: 48,
56+
s: 16,
57+
};
4658
// // FONT_FAMILIES.sans or tldraw_sans not working in toSvg()
4759
// // maybe check getSvg()
4860
// // in node_modules\@tldraw\tldraw\node_modules\@tldraw\editor\dist\cjs\lib\app\App.js
@@ -133,6 +145,8 @@ export type DiscourseNodeShape = TLBaseShape<
133145
uid: string;
134146
title: string;
135147
imageUrl?: string;
148+
size: TLDefaultSizeStyle;
149+
fontFamily: TLDefaultFontStyle;
136150
}
137151
>;
138152
export class BaseDiscourseNodeUtil extends ShapeUtil<DiscourseNodeShape> {
@@ -143,6 +157,17 @@ export class BaseDiscourseNodeUtil extends ShapeUtil<DiscourseNodeShape> {
143157
this.type = type;
144158
}
145159

160+
static override props = {
161+
w: T.number,
162+
h: T.number,
163+
// opacity: T.number,
164+
uid: T.string,
165+
title: T.string,
166+
imageUrl: T.optional(T.string),
167+
size: DefaultSizeStyle,
168+
fontFamily: DefaultFontStyle,
169+
};
170+
146171
override isAspectRatioLocked = () => false;
147172
override canResize = () => true;
148173
override canBind = () => true;
@@ -162,6 +187,8 @@ export class BaseDiscourseNodeUtil extends ShapeUtil<DiscourseNodeShape> {
162187
h: 64,
163188
uid: window.roamAlphaAPI.util.generateUID(),
164189
title: "",
190+
size: "m",
191+
fontFamily: "draw",
165192
};
166193
}
167194

@@ -476,7 +503,12 @@ export class BaseDiscourseNodeUtil extends ShapeUtil<DiscourseNodeShape> {
476503

477504
<div
478505
ref={contentRef}
479-
style={{ ...DEFAULT_STYLE_PROPS, maxWidth: "" }}
506+
style={{
507+
...DEFAULT_STYLE_PROPS,
508+
maxWidth: "",
509+
fontFamily: FONT_FAMILIES[shape.props.fontFamily],
510+
fontSize: FONT_SIZES[shape.props.size],
511+
}}
480512
>
481513
{alias
482514
? new RegExp(alias).exec(shape.props.title)?.[1] ||
Lines changed: 115 additions & 97 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
/* eslint-disable @typescript-eslint/no-unsafe-call */
2+
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
3+
/* eslint-disable @typescript-eslint/no-unsafe-return */
14
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
25
/* eslint-disable @typescript-eslint/naming-convention */
36
import {
@@ -13,118 +16,133 @@ import { getRelationColor } from "./DiscourseRelationUtil";
1316

1417
const SEQUENCE_ID_BASE = "com.roam-research.discourse-graphs";
1518

16-
export const createArrowShapeMigrations = ({
19+
export const createMigrations = ({
1720
allRelationIds,
1821
allAddReferencedNodeActions,
22+
allNodeTypes,
1923
}: {
2024
allRelationIds: string[];
2125
allAddReferencedNodeActions: string[];
26+
allNodeTypes: string[];
2227
}) => {
23-
const allShapeIds = [...allRelationIds, ...allAddReferencedNodeActions];
24-
return allShapeIds.map((shapeId) => {
25-
const versions = createMigrationIds(`${SEQUENCE_ID_BASE}.${shapeId}`, {
26-
ExtractBindings: 1,
27-
"2.3.0": 2,
28-
});
29-
return createMigrationSequence({
30-
sequenceId: `${SEQUENCE_ID_BASE}.${shapeId}`,
31-
sequence: [
32-
{
33-
id: versions["ExtractBindings"],
34-
scope: "store",
35-
up: (oldStore) => {
36-
type OldArrowTerminal =
37-
| { type: "point"; x: number; y: number }
38-
| {
39-
type: "binding";
40-
boundShapeId: TLShapeId;
41-
normalizedAnchor: VecModel;
42-
isExact: boolean;
43-
isPrecise: boolean;
44-
}
45-
// new type:
46-
| { type?: undefined; x: number; y: number };
28+
const allRelationShapeIds = [
29+
...allRelationIds,
30+
...allAddReferencedNodeActions,
31+
];
32+
const versions = createMigrationIds(`${SEQUENCE_ID_BASE}`, {
33+
ExtractBindings: 1,
34+
"2.3.0": 2,
35+
AddSizeAndFontFamily: 3,
36+
});
37+
return createMigrationSequence({
38+
sequenceId: `${SEQUENCE_ID_BASE}`,
39+
sequence: [
40+
{
41+
id: versions["ExtractBindings"],
42+
scope: "store",
43+
up: (oldStore) => {
44+
type OldArrowTerminal =
45+
| { type: "point"; x: number; y: number }
46+
| {
47+
type: "binding";
48+
boundShapeId: TLShapeId;
49+
normalizedAnchor: VecModel;
50+
isExact: boolean;
51+
isPrecise: boolean;
52+
}
53+
// new type:
54+
| { type?: undefined; x: number; y: number };
4755

48-
type OldArrow = TLBaseShape<
49-
string,
50-
{ start: OldArrowTerminal; end: OldArrowTerminal }
51-
>;
56+
type OldArrow = TLBaseShape<
57+
string,
58+
{ start: OldArrowTerminal; end: OldArrowTerminal }
59+
>;
5260

53-
const arrows = Object.values(oldStore).filter(
54-
(r: any): r is OldArrow =>
55-
r.typeName === "shape" &&
56-
"type" in r &&
57-
(allRelationIds.includes(r.type) ||
58-
allAddReferencedNodeActions.includes(r.type)),
59-
);
61+
const arrows = Object.values(oldStore).filter(
62+
(r: any): r is OldArrow =>
63+
r.typeName === "shape" &&
64+
"type" in r &&
65+
allRelationShapeIds.includes(r.type),
66+
);
6067

61-
for (const a of arrows) {
62-
const arrow = a as unknown as OldArrow;
63-
const { start, end } = arrow.props;
68+
for (const a of arrows) {
69+
const arrow = a as unknown as OldArrow;
70+
const { start, end } = arrow.props;
6471

65-
// TODO: do we have any that are not binding?
66-
if (start.type === "binding") {
67-
const id = createBindingId();
68-
const binding: RelationBinding = {
69-
typeName: "binding",
70-
id,
71-
type: arrow.type,
72-
fromId: arrow.id,
73-
toId: start.boundShapeId,
74-
meta: {},
75-
props: {
76-
terminal: "start",
77-
normalizedAnchor: start.normalizedAnchor,
78-
isExact: start.isExact || false,
79-
isPrecise: start.isPrecise || false,
80-
},
81-
};
82-
oldStore[id] = binding;
83-
} else {
84-
delete arrow.props.start.type;
85-
}
72+
// TODO: do we have any that are not binding?
73+
if (start.type === "binding") {
74+
const id = createBindingId();
75+
const binding: RelationBinding = {
76+
typeName: "binding",
77+
id,
78+
type: arrow.type,
79+
fromId: arrow.id,
80+
toId: start.boundShapeId,
81+
meta: {},
82+
props: {
83+
terminal: "start",
84+
normalizedAnchor: start.normalizedAnchor,
85+
isExact: start.isExact || false,
86+
isPrecise: start.isPrecise || false,
87+
},
88+
};
89+
oldStore[id] = binding;
90+
} else {
91+
delete arrow.props.start.type;
92+
}
8693

87-
// TODO: do we have any that are not binding?
88-
if (end.type === "binding") {
89-
const id = createBindingId();
90-
const binding: RelationBinding = {
91-
typeName: "binding",
92-
id,
93-
type: arrow.type,
94-
fromId: arrow.id,
95-
toId: end.boundShapeId,
96-
meta: {},
97-
props: {
98-
terminal: "end",
99-
normalizedAnchor: end.normalizedAnchor,
100-
isExact: end.isExact || false,
101-
isPrecise: end.isPrecise || false,
102-
},
103-
};
94+
// TODO: do we have any that are not binding?
95+
if (end.type === "binding") {
96+
const id = createBindingId();
97+
const binding: RelationBinding = {
98+
typeName: "binding",
99+
id,
100+
type: arrow.type,
101+
fromId: arrow.id,
102+
toId: end.boundShapeId,
103+
meta: {},
104+
props: {
105+
terminal: "end",
106+
normalizedAnchor: end.normalizedAnchor,
107+
isExact: end.isExact || false,
108+
isPrecise: end.isPrecise || false,
109+
},
110+
};
104111

105-
oldStore[id] = binding;
106-
} else {
107-
delete arrow.props.end.type;
108-
}
112+
oldStore[id] = binding;
113+
} else {
114+
delete arrow.props.end.type;
109115
}
110-
},
116+
}
117+
},
118+
},
119+
{
120+
id: versions["2.3.0"],
121+
scope: "record",
122+
filter: (r: any) => {
123+
return r.typeName === "shape" && allRelationShapeIds.includes(r.type);
111124
},
112-
{
113-
id: versions["2.3.0"],
114-
scope: "record",
115-
filter: (r: any) => r.type === shapeId && r.typeName === "shape",
116-
up: (arrow: any) => {
117-
arrow.props.start = { x: 0, y: 0 };
118-
arrow.props.end = { x: 0, y: 0 };
119-
arrow.props.labelPosition = 0.5;
120-
arrow.props.scale = 1;
125+
up: (arrow: any) => {
126+
arrow.props.start = { x: 0, y: 0 };
127+
arrow.props.end = { x: 0, y: 0 };
128+
arrow.props.labelPosition = 0.5;
129+
arrow.props.scale = 1;
121130

122-
const color = getRelationColor(arrow.props.text || "");
123-
arrow.props.color = color;
124-
arrow.props.labelColor = color;
125-
},
131+
const color = getRelationColor(arrow.props.text || "");
132+
arrow.props.color = color;
133+
arrow.props.labelColor = color;
134+
},
135+
},
136+
{
137+
id: versions["AddSizeAndFontFamily"],
138+
scope: "record",
139+
filter: (r: any) =>
140+
r.typeName === "shape" && allNodeTypes.includes(r.type),
141+
up: (shape: any) => {
142+
shape.props.size = "m";
143+
shape.props.fontFamily = "draw";
126144
},
127-
],
128-
});
145+
},
146+
],
129147
});
130148
};

apps/roam/src/components/canvas/Tldraw.tsx

Lines changed: 12 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -78,7 +78,7 @@ import {
7878
createAllRelationBindings,
7979
} from "./DiscourseRelationShape/DiscourseRelationBindings";
8080
import ConvertToDialog from "./ConvertToDialog";
81-
import { createArrowShapeMigrations } from "./DiscourseRelationShape/discourseRelationMigrations";
81+
import { createMigrations } from "./DiscourseRelationShape/discourseRelationMigrations";
8282
import ToastListener, { dispatchToastEvent } from "./ToastListener";
8383
import sendErrorEmail from "~/utils/sendErrorEmail";
8484
import { TLDRAW_DATA_ATTRIBUTE } from "./tldrawStyles";
@@ -348,13 +348,15 @@ const TldrawCanvas = ({ title }: { title: string }) => {
348348
const pageUid = useMemo(() => getPageUidByPageTitle(title), [title]);
349349
const arrowShapeMigrations = useMemo(
350350
() =>
351-
createArrowShapeMigrations({
351+
createMigrations({
352352
allRelationIds,
353353
allAddReferencedNodeActions,
354+
allNodeTypes: allNodes.map((node) => node.type),
354355
}),
355-
[allRelationIds, allAddReferencedNodeActions],
356+
[allRelationIds, allAddReferencedNodeActions, allNodes],
356357
);
357-
const migrations = [...arrowShapeMigrations];
358+
359+
const migrations = [arrowShapeMigrations];
358360
const { store, needsUpgrade, performUpgrade, error } = useRoamStore({
359361
migrations,
360362
customShapeUtils,
@@ -415,7 +417,12 @@ const TldrawCanvas = ({ title }: { title: string }) => {
415417
{
416418
type: nodeType.type,
417419
id: createShapeId(),
418-
props: { uid: e.detail.uid, title: e.detail.val },
420+
props: {
421+
uid: e.detail.uid,
422+
title: e.detail.val,
423+
size: "m",
424+
fontFamily: "draw",
425+
},
419426
...position,
420427
},
421428
]);

0 commit comments

Comments
 (0)