@agent-native/core 0.164.15 → 0.164.17
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/corpus/README.md +1 -1
- package/corpus/templates/analytics/netlify.toml +4 -0
- package/corpus/templates/clips/actions/request-transcript.ts +10 -6
- package/corpus/templates/content/app/components/editor/BubbleToolbar.tsx +298 -3
- package/corpus/templates/content/app/components/editor/VisualEditor.tsx +3 -0
- package/corpus/templates/content/app/components/editor/extensions/NotionExtensions.tsx +18 -4
- package/corpus/templates/content/app/i18n-data.ts +160 -0
- package/corpus/templates/content/docs/solutions/2026-08-18-colored-text-highlighting-shape.md +693 -0
- package/corpus/templates/content/package.json +1 -0
- package/corpus/templates/content/shared/nfm.ts +14 -3
- package/corpus/templates/factory/AGENTS.md +24 -29
- package/corpus/templates/factory/actions/get-slack-feedback-context.ts +8 -28
- package/corpus/templates/factory/actions/get-triage-config.ts +1 -0
- package/corpus/templates/factory/actions/govern-agent-native-pull-request.ts +67 -59
- package/corpus/templates/factory/actions/list-triage-items.ts +6 -1
- package/corpus/templates/factory/actions/reconcile-triage-run.ts +7 -1
- package/corpus/templates/factory/actions/save-triage-config.ts +27 -7
- package/corpus/templates/factory/actions/start-builder-for-item.ts +113 -31
- package/corpus/templates/factory/actions/view-screen.ts +12 -0
- package/corpus/templates/factory/app/components/factory/FactorySettingsView.tsx +457 -0
- package/corpus/templates/factory/app/components/factory/FactoryWorkspaceActions.tsx +53 -0
- package/corpus/templates/factory/app/components/layout/Layout.tsx +2 -0
- package/corpus/templates/factory/app/components/layout/Sidebar.tsx +3 -1
- package/corpus/templates/factory/app/hooks/use-navigation-state.ts +10 -7
- package/corpus/templates/factory/app/i18n/en-US.ts +3 -0
- package/corpus/templates/factory/app/routes/agents.tsx +22 -1
- package/corpus/templates/factory/app/routes/factory-settings.tsx +34 -0
- package/corpus/templates/factory/app/routes/factory.tsx +33 -323
- package/corpus/templates/factory/server/connectors/slack.ts +62 -0
- package/corpus/templates/factory/server/db/schema.ts +1 -0
- package/corpus/templates/factory/server/lib/slack-feedback-prompt.ts +30 -0
- package/corpus/templates/factory/server/plugins/agent-chat.ts +9 -8
- package/corpus/templates/factory/server/plugins/factory-migrations.ts +7 -0
- package/corpus/templates/factory/server/plugins/factory-scheduler-job.ts +43 -25
- package/corpus/templates/factory/server/triage/ai-services-git.ts +2 -0
- package/corpus/templates/factory/server/triage/pr-monitor.ts +2 -1
- package/corpus/templates/factory/server/triage/pr-policy.ts +197 -19
- package/corpus/templates/factory/server/triage/review-skill-alignment.ts +127 -0
- package/corpus/templates/factory/server/triage/slack-client.ts +79 -6
- package/dist/client/MultiTabAssistantChat.js +28 -1
- package/dist/client/use-chat-threads.d.ts +1 -0
- package/dist/client/use-chat-threads.js +13 -3
- package/dist/collab/awareness.d.ts +2 -2
- package/dist/notifications/routes.d.ts +3 -3
- package/dist/observability/routes.d.ts +5 -5
- package/dist/progress/routes.d.ts +1 -1
- package/dist/server/agent-engine-api-key-route.d.ts +1 -1
- package/dist/server/auth.js +2 -2
- package/dist/server/realtime-token.d.ts +1 -1
- package/dist/server/transcribe-voice.d.ts +1 -1
- package/dist/vite/client.js +2 -0
- package/package.json +1 -1
package/corpus/README.md
CHANGED
|
@@ -22,6 +22,10 @@ AGENT_CHAT_DURABLE_BACKGROUND = "true"
|
|
|
22
22
|
AGENT_NATIVE_HOSTED_HARNESS = "true"
|
|
23
23
|
AGENT_NATIVE_ENABLE_KEEP_WARM = "1"
|
|
24
24
|
AGENT_NATIVE_DISABLE_KEEP_WARM_BACKGROUND = "1"
|
|
25
|
+
# Keep the public shell close to the current deploy. A stale shell can retain
|
|
26
|
+
# hashed modulepreload URLs after a Netlify asset publish and leave the app on
|
|
27
|
+
# its loading screen while those chunks return 404.
|
|
28
|
+
AGENT_NATIVE_SSR_CACHE = "30s"
|
|
25
29
|
# Analytics owns its schema at release time (`migrate:production` above), so
|
|
26
30
|
# production request functions skip migrations. Preview functions still run
|
|
27
31
|
# request-path migrations because previews do not run the production release
|
|
@@ -1526,18 +1526,22 @@ const requestTranscriptAction = defineAction({
|
|
|
1526
1526
|
transcribeWithBuilderModelFallback({
|
|
1527
1527
|
audioBytes: audioMedia.audioBytes,
|
|
1528
1528
|
mimeType: audioMedia.mimeType,
|
|
1529
|
-
diarize:
|
|
1529
|
+
diarize: true,
|
|
1530
1530
|
instructions: SPEECH_ONLY_TRANSCRIPTION_INSTRUCTIONS,
|
|
1531
1531
|
timeoutMs: builderTranscriptionTimeoutMs(rec.durationMs),
|
|
1532
1532
|
}),
|
|
1533
1533
|
);
|
|
1534
1534
|
|
|
1535
1535
|
const segments = (builderResult.segments ?? [])
|
|
1536
|
-
.map((s) =>
|
|
1537
|
-
|
|
1538
|
-
|
|
1539
|
-
|
|
1540
|
-
|
|
1536
|
+
.map((s) => {
|
|
1537
|
+
const speaker = s.speakerLabel?.trim();
|
|
1538
|
+
return {
|
|
1539
|
+
startMs: s.startMs,
|
|
1540
|
+
endMs: s.endMs,
|
|
1541
|
+
text: s.text.trim(),
|
|
1542
|
+
...(speaker ? { speaker } : {}),
|
|
1543
|
+
};
|
|
1544
|
+
})
|
|
1541
1545
|
.filter((segment) => segment.text);
|
|
1542
1546
|
const normalizedTranscript = normalizeProviderTranscript(
|
|
1543
1547
|
builderResult.text,
|
|
@@ -60,6 +60,109 @@ type SelectionFillRange = {
|
|
|
60
60
|
};
|
|
61
61
|
|
|
62
62
|
type TextStyle = "paragraph" | 1 | 2 | 3 | 4 | 5 | 6;
|
|
63
|
+
type ColorAttribute = "color" | "bgColor";
|
|
64
|
+
type ColorName =
|
|
65
|
+
| "gray"
|
|
66
|
+
| "brown"
|
|
67
|
+
| "orange"
|
|
68
|
+
| "yellow"
|
|
69
|
+
| "green"
|
|
70
|
+
| "blue"
|
|
71
|
+
| "purple"
|
|
72
|
+
| "pink"
|
|
73
|
+
| "red";
|
|
74
|
+
|
|
75
|
+
const COLOR_NAMES: ColorName[] = [
|
|
76
|
+
"gray",
|
|
77
|
+
"brown",
|
|
78
|
+
"orange",
|
|
79
|
+
"yellow",
|
|
80
|
+
"green",
|
|
81
|
+
"blue",
|
|
82
|
+
"purple",
|
|
83
|
+
"pink",
|
|
84
|
+
"red",
|
|
85
|
+
];
|
|
86
|
+
|
|
87
|
+
export function getSelectionNotionSpanAttribute(
|
|
88
|
+
editor: Editor,
|
|
89
|
+
attribute: ColorAttribute,
|
|
90
|
+
): string | null | "mixed" {
|
|
91
|
+
const { from, to } = editor.state.selection;
|
|
92
|
+
const markType = editor.state.schema.marks.notionSpan;
|
|
93
|
+
if (!markType) return null;
|
|
94
|
+
|
|
95
|
+
let observed: string | null = null;
|
|
96
|
+
let hasObserved = false;
|
|
97
|
+
let mixed = false;
|
|
98
|
+
|
|
99
|
+
editor.state.doc.nodesBetween(from, to, (node, _position, parent) => {
|
|
100
|
+
if (!node.isText || !parent?.type.allowsMarkType(markType)) return;
|
|
101
|
+
const mark = node.marks.find((candidate) => candidate.type === markType);
|
|
102
|
+
const value = (mark?.attrs[attribute] as string | null | undefined) ?? null;
|
|
103
|
+
if (!hasObserved) {
|
|
104
|
+
observed = value;
|
|
105
|
+
hasObserved = true;
|
|
106
|
+
} else if (observed !== value) {
|
|
107
|
+
mixed = true;
|
|
108
|
+
}
|
|
109
|
+
});
|
|
110
|
+
|
|
111
|
+
return mixed ? "mixed" : observed;
|
|
112
|
+
}
|
|
113
|
+
|
|
114
|
+
export function selectionHasColorableText(
|
|
115
|
+
state: EditorState,
|
|
116
|
+
from: number,
|
|
117
|
+
to: number,
|
|
118
|
+
) {
|
|
119
|
+
const markType = state.schema.marks.notionSpan;
|
|
120
|
+
if (!markType) return false;
|
|
121
|
+
|
|
122
|
+
let hasText = false;
|
|
123
|
+
state.doc.nodesBetween(from, to, (node, _position, parent) => {
|
|
124
|
+
if (node.isText && parent?.type.allowsMarkType(markType)) hasText = true;
|
|
125
|
+
return !hasText;
|
|
126
|
+
});
|
|
127
|
+
return hasText;
|
|
128
|
+
}
|
|
129
|
+
|
|
130
|
+
export function setSelectionNotionSpanAttribute(
|
|
131
|
+
editor: Editor,
|
|
132
|
+
attribute: ColorAttribute,
|
|
133
|
+
value: string | null,
|
|
134
|
+
) {
|
|
135
|
+
const { state } = editor;
|
|
136
|
+
const { from, to } = state.selection;
|
|
137
|
+
const markType = state.schema.marks.notionSpan;
|
|
138
|
+
if (!markType || from === to) return false;
|
|
139
|
+
|
|
140
|
+
const transaction = state.tr;
|
|
141
|
+
state.doc.nodesBetween(from, to, (node, position, parent) => {
|
|
142
|
+
if (!node.isText || !parent?.type.allowsMarkType(markType)) return;
|
|
143
|
+
const start = Math.max(from, position);
|
|
144
|
+
const end = Math.min(to, position + node.nodeSize);
|
|
145
|
+
if (start >= end) return;
|
|
146
|
+
|
|
147
|
+
const existing = node.marks.find((mark) => mark.type === markType);
|
|
148
|
+
const attrs = { ...existing?.attrs, [attribute]: value };
|
|
149
|
+
transaction.removeMark(start, end, markType);
|
|
150
|
+
if (
|
|
151
|
+
attrs.color ||
|
|
152
|
+
attrs.bgColor ||
|
|
153
|
+
attrs.underline ||
|
|
154
|
+
attrs.href ||
|
|
155
|
+
(attrs.attrsJson && attrs.attrsJson !== "{}")
|
|
156
|
+
) {
|
|
157
|
+
transaction.addMark(start, end, markType.create(attrs));
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
161
|
+
if (!transaction.docChanged) return false;
|
|
162
|
+
editor.view.dispatch(transaction);
|
|
163
|
+
editor.commands.focus();
|
|
164
|
+
return true;
|
|
165
|
+
}
|
|
63
166
|
|
|
64
167
|
function activeTextStyle(editor: Editor): TextStyle {
|
|
65
168
|
for (const level of [1, 2, 3, 4, 5, 6] as const) {
|
|
@@ -119,8 +222,16 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
119
222
|
const [showLinkInput, setShowLinkInput] = useState(false);
|
|
120
223
|
const [linkUrl, setLinkUrl] = useState("");
|
|
121
224
|
const [textStyleOpen, setTextStyleOpen] = useState(false);
|
|
225
|
+
const [colorOpen, setColorOpen] = useState(false);
|
|
226
|
+
const [colorRevision, setColorRevision] = useState(0);
|
|
227
|
+
const [recentColor, setRecentColor] = useState<{
|
|
228
|
+
attribute: ColorAttribute;
|
|
229
|
+
value: string;
|
|
230
|
+
} | null>(null);
|
|
122
231
|
const textStyleSelection = useRef<{ from: number; to: number } | null>(null);
|
|
232
|
+
const colorSelection = useRef<{ from: number; to: number } | null>(null);
|
|
123
233
|
const textStyleApplied = useRef(false);
|
|
234
|
+
const colorApplied = useRef(false);
|
|
124
235
|
const restoreEditorFocusOnClose = useRef(false);
|
|
125
236
|
const [textStyle, setTextStyle] = useState<TextStyle>(() =>
|
|
126
237
|
activeTextStyle(editor),
|
|
@@ -129,8 +240,12 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
129
240
|
useEffect(() => {
|
|
130
241
|
const syncTextStyle = () => {
|
|
131
242
|
setTextStyle(activeTextStyle(editor));
|
|
243
|
+
setColorRevision((revision) => revision + 1);
|
|
132
244
|
const { from, to } = editor.state.selection;
|
|
133
|
-
if (from !== to)
|
|
245
|
+
if (from !== to) {
|
|
246
|
+
textStyleSelection.current = { from, to };
|
|
247
|
+
colorSelection.current = { from, to };
|
|
248
|
+
}
|
|
134
249
|
};
|
|
135
250
|
editor.on("selectionUpdate", syncTextStyle);
|
|
136
251
|
editor.on("transaction", syncTextStyle);
|
|
@@ -199,6 +314,82 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
199
314
|
setTextStyleOpen(false);
|
|
200
315
|
};
|
|
201
316
|
|
|
317
|
+
const applyColor = (attribute: ColorAttribute, value: string | null) => {
|
|
318
|
+
if (colorSelection.current) {
|
|
319
|
+
editor.commands.setTextSelection(colorSelection.current);
|
|
320
|
+
}
|
|
321
|
+
if (!setSelectionNotionSpanAttribute(editor, attribute, value)) return;
|
|
322
|
+
if (value) setRecentColor({ attribute, value });
|
|
323
|
+
colorApplied.current = true;
|
|
324
|
+
setColorOpen(false);
|
|
325
|
+
};
|
|
326
|
+
|
|
327
|
+
const activeTextColor = getSelectionNotionSpanAttribute(editor, "color");
|
|
328
|
+
const activeBackgroundColor = getSelectionNotionSpanAttribute(
|
|
329
|
+
editor,
|
|
330
|
+
"bgColor",
|
|
331
|
+
);
|
|
332
|
+
void colorRevision;
|
|
333
|
+
|
|
334
|
+
const renderColorChoice = (
|
|
335
|
+
attribute: ColorAttribute,
|
|
336
|
+
value: string | null,
|
|
337
|
+
) => {
|
|
338
|
+
const sectionLabel = t(
|
|
339
|
+
attribute === "color" ? "editor.textColor" : "editor.backgroundColor",
|
|
340
|
+
);
|
|
341
|
+
const colorName = value?.replace(/_bg$/, "") as ColorName | undefined;
|
|
342
|
+
const choiceLabel = colorName
|
|
343
|
+
? t(`editor.color.${colorName}`)
|
|
344
|
+
: t("editor.defaultColor");
|
|
345
|
+
const activeValue =
|
|
346
|
+
attribute === "color" ? activeTextColor : activeBackgroundColor;
|
|
347
|
+
const isActive = activeValue !== "mixed" && activeValue === value;
|
|
348
|
+
|
|
349
|
+
return (
|
|
350
|
+
<button
|
|
351
|
+
key={`${attribute}-${value ?? "default"}`}
|
|
352
|
+
type="button"
|
|
353
|
+
role="menuitemradio"
|
|
354
|
+
aria-checked={isActive}
|
|
355
|
+
aria-label={`${sectionLabel}: ${choiceLabel}`}
|
|
356
|
+
onPointerDown={(event) => {
|
|
357
|
+
event.preventDefault();
|
|
358
|
+
event.stopPropagation();
|
|
359
|
+
applyColor(attribute, value);
|
|
360
|
+
}}
|
|
361
|
+
onClick={(event) => {
|
|
362
|
+
if (event.detail === 0) applyColor(attribute, value);
|
|
363
|
+
}}
|
|
364
|
+
className={cn(
|
|
365
|
+
"relative flex size-8 items-center justify-center rounded-md border border-border bg-background text-sm font-semibold hover:bg-accent focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring",
|
|
366
|
+
isActive && "ring-2 ring-foreground",
|
|
367
|
+
)}
|
|
368
|
+
>
|
|
369
|
+
{attribute === "color" ? (
|
|
370
|
+
<span className={colorName ? `notion-block-color--${colorName}` : ""}>
|
|
371
|
+
A
|
|
372
|
+
</span>
|
|
373
|
+
) : (
|
|
374
|
+
<span
|
|
375
|
+
className={cn(
|
|
376
|
+
"size-5 rounded border border-border",
|
|
377
|
+
colorName && `notion-block-bg--${colorName}`,
|
|
378
|
+
)}
|
|
379
|
+
/>
|
|
380
|
+
)}
|
|
381
|
+
{isActive ? (
|
|
382
|
+
<IconCheck
|
|
383
|
+
aria-hidden="true"
|
|
384
|
+
className="absolute -end-1 -top-1 rounded-full bg-foreground p-0.5 text-background"
|
|
385
|
+
size={12}
|
|
386
|
+
strokeWidth={3}
|
|
387
|
+
/>
|
|
388
|
+
) : null}
|
|
389
|
+
</button>
|
|
390
|
+
);
|
|
391
|
+
};
|
|
392
|
+
|
|
202
393
|
const openLinkInput = useCallback(() => {
|
|
203
394
|
setLinkUrl(editor.getAttributes("link").href || "");
|
|
204
395
|
setShowLinkInput(true);
|
|
@@ -318,6 +509,15 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
318
509
|
};
|
|
319
510
|
|
|
320
511
|
const items = [
|
|
512
|
+
{ type: "text-style" as const },
|
|
513
|
+
...(selectionHasColorableText(
|
|
514
|
+
editor.state,
|
|
515
|
+
editor.state.selection.from,
|
|
516
|
+
editor.state.selection.to,
|
|
517
|
+
)
|
|
518
|
+
? [{ type: "color" as const }]
|
|
519
|
+
: []),
|
|
520
|
+
{ type: "divider" as const },
|
|
321
521
|
{
|
|
322
522
|
icon: IconBold,
|
|
323
523
|
title: t("editor.bold"),
|
|
@@ -343,8 +543,6 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
343
543
|
isActive: () => editor.isActive("code"),
|
|
344
544
|
},
|
|
345
545
|
{ type: "divider" as const },
|
|
346
|
-
{ type: "text-style" as const },
|
|
347
|
-
{ type: "divider" as const },
|
|
348
546
|
{
|
|
349
547
|
icon: IconLink,
|
|
350
548
|
title: t("editor.link"),
|
|
@@ -529,6 +727,103 @@ export function BubbleToolbar({ editor, onComment }: BubbleToolbarProps) {
|
|
|
529
727
|
</Popover>
|
|
530
728
|
);
|
|
531
729
|
}
|
|
730
|
+
if ("type" in item && item.type === "color") {
|
|
731
|
+
return (
|
|
732
|
+
<Popover
|
|
733
|
+
key="color"
|
|
734
|
+
open={colorOpen}
|
|
735
|
+
onOpenChange={(open) => {
|
|
736
|
+
if (open) {
|
|
737
|
+
colorApplied.current = false;
|
|
738
|
+
restoreEditorFocusOnClose.current = false;
|
|
739
|
+
const { from, to } = editor.state.selection;
|
|
740
|
+
if (from !== to) colorSelection.current = { from, to };
|
|
741
|
+
}
|
|
742
|
+
setColorOpen(open);
|
|
743
|
+
}}
|
|
744
|
+
>
|
|
745
|
+
<PopoverTrigger asChild>
|
|
746
|
+
<button
|
|
747
|
+
type="button"
|
|
748
|
+
aria-label={t("editor.color.label")}
|
|
749
|
+
className={cn(
|
|
750
|
+
"flex size-8 items-center justify-center rounded text-sm font-semibold text-popover-foreground/85 hover:bg-accent hover:text-accent-foreground",
|
|
751
|
+
colorOpen && "bg-accent text-accent-foreground",
|
|
752
|
+
)}
|
|
753
|
+
>
|
|
754
|
+
A
|
|
755
|
+
</button>
|
|
756
|
+
</PopoverTrigger>
|
|
757
|
+
<PopoverContent
|
|
758
|
+
portalled={false}
|
|
759
|
+
align="start"
|
|
760
|
+
sideOffset={24}
|
|
761
|
+
className="w-52 p-2"
|
|
762
|
+
onEscapeKeyDown={() => {
|
|
763
|
+
restoreEditorFocusOnClose.current = true;
|
|
764
|
+
window.setTimeout(() => editor.commands.focus(), 0);
|
|
765
|
+
}}
|
|
766
|
+
onCloseAutoFocus={(event) => {
|
|
767
|
+
if (
|
|
768
|
+
colorApplied.current ||
|
|
769
|
+
restoreEditorFocusOnClose.current
|
|
770
|
+
) {
|
|
771
|
+
event.preventDefault();
|
|
772
|
+
}
|
|
773
|
+
if (restoreEditorFocusOnClose.current) {
|
|
774
|
+
editor.commands.focus();
|
|
775
|
+
}
|
|
776
|
+
colorApplied.current = false;
|
|
777
|
+
restoreEditorFocusOnClose.current = false;
|
|
778
|
+
}}
|
|
779
|
+
>
|
|
780
|
+
{recentColor ? (
|
|
781
|
+
<div className="mb-2">
|
|
782
|
+
<div className="mb-1 text-xs font-medium text-muted-foreground">
|
|
783
|
+
{t("editor.color.recentlyUsed")}
|
|
784
|
+
</div>
|
|
785
|
+
<div role="menu">
|
|
786
|
+
{renderColorChoice(
|
|
787
|
+
recentColor.attribute,
|
|
788
|
+
recentColor.value,
|
|
789
|
+
)}
|
|
790
|
+
</div>
|
|
791
|
+
</div>
|
|
792
|
+
) : null}
|
|
793
|
+
<div className="mb-2">
|
|
794
|
+
<div className="mb-1 text-xs font-medium text-muted-foreground">
|
|
795
|
+
{t("editor.textColor")}
|
|
796
|
+
</div>
|
|
797
|
+
<div
|
|
798
|
+
role="menu"
|
|
799
|
+
aria-label={t("editor.textColor")}
|
|
800
|
+
className="grid grid-cols-5 gap-1"
|
|
801
|
+
>
|
|
802
|
+
{renderColorChoice("color", null)}
|
|
803
|
+
{COLOR_NAMES.map((name) =>
|
|
804
|
+
renderColorChoice("color", name),
|
|
805
|
+
)}
|
|
806
|
+
</div>
|
|
807
|
+
</div>
|
|
808
|
+
<div>
|
|
809
|
+
<div className="mb-1 text-xs font-medium text-muted-foreground">
|
|
810
|
+
{t("editor.backgroundColor")}
|
|
811
|
+
</div>
|
|
812
|
+
<div
|
|
813
|
+
role="menu"
|
|
814
|
+
aria-label={t("editor.backgroundColor")}
|
|
815
|
+
className="grid grid-cols-5 gap-1"
|
|
816
|
+
>
|
|
817
|
+
{renderColorChoice("bgColor", null)}
|
|
818
|
+
{COLOR_NAMES.map((name) =>
|
|
819
|
+
renderColorChoice("bgColor", `${name}_bg`),
|
|
820
|
+
)}
|
|
821
|
+
</div>
|
|
822
|
+
</div>
|
|
823
|
+
</PopoverContent>
|
|
824
|
+
</Popover>
|
|
825
|
+
);
|
|
826
|
+
}
|
|
532
827
|
const {
|
|
533
828
|
icon: Icon,
|
|
534
829
|
title,
|
|
@@ -76,6 +76,7 @@ import {
|
|
|
76
76
|
LocalMdxComponentNode,
|
|
77
77
|
} from "./extensions/LocalMdxComponentNode";
|
|
78
78
|
import {
|
|
79
|
+
CompatibleCode,
|
|
79
80
|
createNotionEditorExtensions,
|
|
80
81
|
focusMostRecentEmptyToggleSummary,
|
|
81
82
|
type NotionPageLink,
|
|
@@ -1645,6 +1646,7 @@ export function createVisualEditorExtensions({
|
|
|
1645
1646
|
},
|
|
1646
1647
|
starterKit: {
|
|
1647
1648
|
blockquote: false,
|
|
1649
|
+
code: false,
|
|
1648
1650
|
paragraph: false,
|
|
1649
1651
|
heading: { levels: [1, 2, 3, 4, 5, 6] },
|
|
1650
1652
|
horizontalRule: {},
|
|
@@ -1653,6 +1655,7 @@ export function createVisualEditorExtensions({
|
|
|
1653
1655
|
collab:
|
|
1654
1656
|
ydoc || localAwareness ? { ydoc, awareness: localAwareness, user } : null,
|
|
1655
1657
|
extraExtensions: [
|
|
1658
|
+
CompatibleCode,
|
|
1656
1659
|
EmptyLineParagraph,
|
|
1657
1660
|
NotionBlockquote,
|
|
1658
1661
|
CodeBlock,
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import { findTrailingPlainInlineMath } from "@shared/inline-math";
|
|
2
|
+
import { NFM_COLORS } from "@shared/nfm";
|
|
2
3
|
import {
|
|
3
4
|
escapeHtml,
|
|
4
5
|
indentMarkdown,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
IconFileText,
|
|
13
14
|
} from "@tabler/icons-react";
|
|
14
15
|
import { InputRule, type Editor } from "@tiptap/core";
|
|
16
|
+
import { Code } from "@tiptap/extension-code";
|
|
15
17
|
import type { Fragment, Node as ProseMirrorNode } from "@tiptap/pm/model";
|
|
16
18
|
import { Selection } from "@tiptap/pm/state";
|
|
17
19
|
import {
|
|
@@ -745,12 +747,19 @@ export const NotionSpanMark = Mark.create({
|
|
|
745
747
|
renderHTML({ HTMLAttributes }) {
|
|
746
748
|
const attrs = parseAttrsJson(HTMLAttributes.attrsJson as string);
|
|
747
749
|
const style: string[] = [];
|
|
750
|
+
const classes: string[] = [];
|
|
748
751
|
|
|
749
|
-
if (
|
|
750
|
-
|
|
752
|
+
if (
|
|
753
|
+
NFM_COLORS.has(HTMLAttributes.color) &&
|
|
754
|
+
!HTMLAttributes.color.endsWith("_bg")
|
|
755
|
+
) {
|
|
756
|
+
classes.push(`notion-block-color--${HTMLAttributes.color}`);
|
|
751
757
|
}
|
|
752
|
-
if (
|
|
753
|
-
|
|
758
|
+
if (
|
|
759
|
+
NFM_COLORS.has(HTMLAttributes.bgColor) &&
|
|
760
|
+
HTMLAttributes.bgColor.endsWith("_bg")
|
|
761
|
+
) {
|
|
762
|
+
classes.push(`notion-block-bg--${HTMLAttributes.bgColor.slice(0, -3)}`);
|
|
754
763
|
}
|
|
755
764
|
if (HTMLAttributes.underline === "true") {
|
|
756
765
|
style.push("text-decoration: underline");
|
|
@@ -764,6 +773,7 @@ export const NotionSpanMark = Mark.create({
|
|
|
764
773
|
bg_color: HTMLAttributes.bgColor || undefined,
|
|
765
774
|
underline: HTMLAttributes.underline || undefined,
|
|
766
775
|
href: HTMLAttributes.href || undefined,
|
|
776
|
+
class: classes.length ? classes.join(" ") : undefined,
|
|
767
777
|
style: style.length ? style.join("; ") : undefined,
|
|
768
778
|
}),
|
|
769
779
|
0,
|
|
@@ -787,6 +797,10 @@ export const NotionSpanMark = Mark.create({
|
|
|
787
797
|
},
|
|
788
798
|
});
|
|
789
799
|
|
|
800
|
+
export const CompatibleCode = Code.extend({
|
|
801
|
+
excludes: "",
|
|
802
|
+
});
|
|
803
|
+
|
|
790
804
|
export const NotionToggle = Node.create({
|
|
791
805
|
name: "notionToggle",
|
|
792
806
|
priority: 1000,
|