@agent-native/core 0.177.0-nightly-20260906034133 → 0.177.0
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/CHANGELOG.md +13 -0
- package/corpus/templates/calendar/CHANGELOG.md +20 -0
- package/corpus/templates/clips/CHANGELOG.md +7 -0
- package/corpus/templates/clips/server/plugins/db.ts +10 -2
- package/corpus/templates/content/CHANGELOG.md +6 -0
- package/corpus/templates/design/CHANGELOG.md +16 -0
- package/corpus/templates/design/app/components/design/EditPanel.tsx +8 -1
- package/corpus/templates/design/app/components/design/MultiScreenCanvas.tsx +12 -20
- package/corpus/templates/design/app/components/design/multi-screen/board-surface-html.ts +23 -22
- package/corpus/templates/design/app/pages/DesignEditor.tsx +43 -6
- package/corpus/templates/design/app/pages/Index.tsx +10 -3
- package/corpus/templates/design/app/pages/Templates.tsx +1 -18
- package/corpus/templates/design/app/pages/design-editor/canvas-primitive-insert.ts +25 -11
- package/corpus/templates/design/app/pages/design-editor/canvas-primitives.ts +8 -18
- package/corpus/templates/design/app/pages/design-editor/commands/create-primitive.ts +4 -0
- package/corpus/templates/design/changelog/2026-09-04-board-text-is-readable-on-a-light-canvas.md +6 -0
- package/corpus/templates/design/changelog/2026-09-04-designs-grid-fills-its-last-row.md +6 -0
- package/corpus/templates/design/changelog/2026-09-04-no-design-system-now-sticks-when-you-choose-it.md +6 -0
- package/corpus/templates/design/changelog/2026-09-04-the-canvas-keeps-its-colour-when-you-draw-on-it.md +6 -0
- package/corpus/templates/design/changelog/2026-09-04-the-design-system-picker-stays-after-a-template-fil.md +6 -0
- package/corpus/templates/dispatch/CHANGELOG.md +6 -0
- package/corpus/templates/factory/CHANGELOG.md +18 -0
- package/corpus/templates/mail/CHANGELOG.md +11 -0
- package/dist/automation/index.d.ts +1 -1
- package/dist/chat-threads/schema.d.ts +4 -4
- package/dist/chat-threads/schema.js +5 -5
- package/dist/collab/routes.d.ts +1 -1
- package/dist/collab/struct-routes.d.ts +1 -1
- package/dist/email-catalog/log.js +2 -0
- package/dist/email-catalog/schema.d.ts +1 -1
- package/dist/email-catalog/schema.js +2 -2
- package/dist/file-upload/actions/upload-image.d.ts +2 -2
- package/dist/observability/routes.d.ts +4 -4
- package/dist/org/migrations.js +36 -8
- package/dist/org/schema.d.ts +8 -8
- package/dist/org/schema.js +13 -9
- package/dist/progress/routes.d.ts +1 -1
- package/dist/secrets/routes.d.ts +6 -6
- package/dist/secrets/schema.d.ts +2 -2
- package/dist/secrets/schema.js +3 -3
- package/dist/server/identity-sso-migrations.js +24 -4
- package/package.json +3 -3
- package/corpus/templates/clips/data/clips-transactional-emails/config.json +0 -3
package/corpus/README.md
CHANGED
|
@@ -3,6 +3,19 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Analytics are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-04
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- The agent now answers data questions with explicit confidence instead of a dead end, and uses existing dashboards first
|
|
11
|
+
|
|
12
|
+
## 2026-09-03
|
|
13
|
+
|
|
14
|
+
### Fixed
|
|
15
|
+
|
|
16
|
+
- Analytics autosaves now skip unchanged edits, keeping history focused on real changes.
|
|
17
|
+
- Saved Analytics panels recover when chart fields are nested in their config
|
|
18
|
+
|
|
6
19
|
## 2026-09-01
|
|
7
20
|
|
|
8
21
|
### Added
|
|
@@ -3,10 +3,30 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Calendar are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-05
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- Calendar booking pages show the docs hero wave background
|
|
11
|
+
|
|
12
|
+
## 2026-09-04
|
|
13
|
+
|
|
14
|
+
### Improved
|
|
15
|
+
|
|
16
|
+
- Generated booking-link OG images now use the shared branded background.
|
|
17
|
+
|
|
18
|
+
### Fixed
|
|
19
|
+
|
|
20
|
+
- Calendar controls now add the right source, shared events use their calendar colors, and color changes appear immediately.
|
|
21
|
+
- Calendar sidebar remains toggleable while agent chat is open.
|
|
22
|
+
- Read-only calendar events keep their date and time controls disabled
|
|
23
|
+
|
|
6
24
|
## 2026-09-03
|
|
7
25
|
|
|
8
26
|
### Improved
|
|
9
27
|
|
|
28
|
+
- Calendar makes all-day event creation discoverable from the visible all-day row
|
|
29
|
+
- Shared Google calendars now appear automatically with instant visibility controls and local display colors.
|
|
10
30
|
- Calendar now supports reliable batch event updates and booking cancellations.
|
|
11
31
|
- The agent now asks for your approval before it deletes events in bulk, emails your guests about a cancellation or change, or moves an event to another calendar.
|
|
12
32
|
|
|
@@ -3,6 +3,13 @@
|
|
|
3
3
|
All notable user-facing changes to Clips are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-04
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Clips desktop shows its real version again in About and Get Info, and nightly builds resume.
|
|
11
|
+
- Meeting notes now stop within about 15 seconds of a Zoom, Teams, or Meet call ending, even while music or a video keeps playing afterward.
|
|
12
|
+
|
|
6
13
|
## 2026-09-01
|
|
7
14
|
|
|
8
15
|
### Improved
|
|
@@ -1090,7 +1090,7 @@ export const migrations = runMigrations(
|
|
|
1090
1090
|
sql: `CREATE TABLE IF NOT EXISTS clips_backfill_leases (
|
|
1091
1091
|
lease_key TEXT PRIMARY KEY,
|
|
1092
1092
|
holder TEXT NOT NULL,
|
|
1093
|
-
expires_at
|
|
1093
|
+
expires_at BIGINT NOT NULL
|
|
1094
1094
|
)`,
|
|
1095
1095
|
},
|
|
1096
1096
|
{
|
|
@@ -1135,7 +1135,7 @@ export const migrations = runMigrations(
|
|
|
1135
1135
|
sql: `CREATE TABLE IF NOT EXISTS clips_backfill_leases (
|
|
1136
1136
|
lease_key TEXT PRIMARY KEY,
|
|
1137
1137
|
holder TEXT NOT NULL,
|
|
1138
|
-
expires_at
|
|
1138
|
+
expires_at BIGINT NOT NULL
|
|
1139
1139
|
)`,
|
|
1140
1140
|
},
|
|
1141
1141
|
{
|
|
@@ -1210,6 +1210,14 @@ export const migrations = runMigrations(
|
|
|
1210
1210
|
// pass a reason — absent stays distinguishable from every named cause.
|
|
1211
1211
|
sql: `ALTER TABLE clips_meetings ADD COLUMN IF NOT EXISTS end_reason TEXT`,
|
|
1212
1212
|
},
|
|
1213
|
+
{
|
|
1214
|
+
version: 70,
|
|
1215
|
+
name: "clips-backfill-leases-expires-at-bigint",
|
|
1216
|
+
sql: `
|
|
1217
|
+
-- guard:allow-destructive-ddl — widen legacy int4 timestamp storage to preserve Date.now() values
|
|
1218
|
+
ALTER TABLE clips_backfill_leases ALTER COLUMN expires_at TYPE BIGINT
|
|
1219
|
+
`,
|
|
1220
|
+
},
|
|
1213
1221
|
],
|
|
1214
1222
|
{ table: "clips_migrations" },
|
|
1215
1223
|
);
|
|
@@ -3,6 +3,12 @@
|
|
|
3
3
|
All notable user-facing changes to Agent-Native Content are documented here. Open it any
|
|
4
4
|
time from the command menu (Cmd+K → "What's new").
|
|
5
5
|
|
|
6
|
+
## 2026-09-03
|
|
7
|
+
|
|
8
|
+
### Fixed
|
|
9
|
+
|
|
10
|
+
- Database records can be added even when older rows use legacy positions.
|
|
11
|
+
|
|
6
12
|
## 2026-08-28
|
|
7
13
|
|
|
8
14
|
### Fixed
|
|
@@ -3,10 +3,26 @@
|
|
|
3
3
|
All notable user-facing changes to Design are documented here. Open it any time
|
|
4
4
|
from the command menu (Cmd+K → "What's new") or from Settings.
|
|
5
5
|
|
|
6
|
+
## 2026-09-04
|
|
7
|
+
|
|
8
|
+
### Improved
|
|
9
|
+
|
|
10
|
+
- The designs list now fills every row instead of leaving a single card stranded on the last one, and the card actions menu is readable in light mode.
|
|
11
|
+
- The design system picker stays in the editor chat after a template fills the design, so later prompts can still target a specific system.
|
|
12
|
+
|
|
13
|
+
### Fixed
|
|
14
|
+
|
|
15
|
+
- Text drawn straight onto the canvas now takes a colour you can read against it, instead of always being white.
|
|
16
|
+
- Design editor links now keep agent tools available.
|
|
17
|
+
- Choosing "No design system" now clears the design's system instead of snapping back to your default.
|
|
18
|
+
- Drawing the first shape on the board no longer flips the canvas to a different colour, and the Canvas swatch shows the colour it is painted with instead of "NONE".
|
|
19
|
+
|
|
6
20
|
## 2026-09-02
|
|
7
21
|
|
|
8
22
|
### Fixed
|
|
9
23
|
|
|
24
|
+
- Fill and Stroke in the inspector now paint a pen path, line, polygon, or star itself rather than tinting its selection bounding box.
|
|
25
|
+
- A closed pen path now takes the same fill and no stroke a drawn rectangle takes, instead of a black outline you had to hide.
|
|
10
26
|
- Edit with AI now opens a focused editing prompt for selected elements in multi-screen view and reliably returns generated options without misclassifying an active request as superseded.
|
|
11
27
|
- A greeting or question as the first message in a new design no longer ends with a false "couldn't confirm that a Design artifact was saved" reply.
|
|
12
28
|
|
|
@@ -263,6 +263,9 @@ interface EditPanelProps {
|
|
|
263
263
|
*/
|
|
264
264
|
/** Design-level canvas background — the surround, not a screen's document. */
|
|
265
265
|
canvasBackground?: string | null;
|
|
266
|
+
/** What the canvas is actually painted with when nothing is stored, so the
|
|
267
|
+
* swatch reads as a colour rather than as an absent value. */
|
|
268
|
+
canvasBackgroundFallback?: string | null;
|
|
266
269
|
onCanvasBackgroundChange?: (value: string, meta?: StyleChangeMeta) => void;
|
|
267
270
|
onScreenGeometryChange?: (
|
|
268
271
|
screenId: string,
|
|
@@ -1429,6 +1432,7 @@ function PageProperties({
|
|
|
1429
1432
|
onStyleChange,
|
|
1430
1433
|
onStylesChange,
|
|
1431
1434
|
canvasBackground,
|
|
1435
|
+
canvasBackgroundFallback,
|
|
1432
1436
|
onCanvasBackgroundChange,
|
|
1433
1437
|
}: {
|
|
1434
1438
|
scope: "canvas" | "document";
|
|
@@ -1436,6 +1440,7 @@ function PageProperties({
|
|
|
1436
1440
|
onStyleChange: StyleChangeHandler;
|
|
1437
1441
|
onStylesChange?: StylesChangeHandler;
|
|
1438
1442
|
canvasBackground?: string | null;
|
|
1443
|
+
canvasBackgroundFallback?: string | null;
|
|
1439
1444
|
onCanvasBackgroundChange?: (value: string, meta?: StyleChangeMeta) => void;
|
|
1440
1445
|
}) {
|
|
1441
1446
|
const t = useT();
|
|
@@ -1462,7 +1467,7 @@ function PageProperties({
|
|
|
1462
1467
|
<PanelSection title={t("editPanel.sections.canvas")}>
|
|
1463
1468
|
<ColorInput
|
|
1464
1469
|
label={t("editPanel.labels.background")}
|
|
1465
|
-
value={canvasBackground ?? ""}
|
|
1470
|
+
value={canvasBackground ?? canvasBackgroundFallback ?? ""}
|
|
1466
1471
|
// meta carries phase: "preview" while dragging vs "commit" on
|
|
1467
1472
|
// release. Dropping it persists every tick and the picker jumps.
|
|
1468
1473
|
onChange={(value, meta) => onCanvasBackgroundChange(value, meta)}
|
|
@@ -1775,6 +1780,7 @@ export const EditPanel = memo(function EditPanel({
|
|
|
1775
1780
|
selectedScreenLayoutGrid,
|
|
1776
1781
|
onLayoutGridChange,
|
|
1777
1782
|
canvasBackground,
|
|
1783
|
+
canvasBackgroundFallback,
|
|
1778
1784
|
onCanvasBackgroundChange,
|
|
1779
1785
|
onScreenGeometryChange,
|
|
1780
1786
|
pageStyles = {},
|
|
@@ -2356,6 +2362,7 @@ export const EditPanel = memo(function EditPanel({
|
|
|
2356
2362
|
onStyleChange={onStyleChange}
|
|
2357
2363
|
onStylesChange={onStylesChange}
|
|
2358
2364
|
canvasBackground={canvasBackground}
|
|
2365
|
+
canvasBackgroundFallback={canvasBackgroundFallback}
|
|
2359
2366
|
onCanvasBackgroundChange={onCanvasBackgroundChange}
|
|
2360
2367
|
/>
|
|
2361
2368
|
) : null}
|
|
@@ -147,6 +147,10 @@ import { type ElementInfo, type PortableStyleSnapshot } from "./types";
|
|
|
147
147
|
* resizable frame inside an infinite, pannable surface.
|
|
148
148
|
*/
|
|
149
149
|
const SCREEN_WIDTH = OVERVIEW_FRAME_WIDTH;
|
|
150
|
+
/** The board layers sit inside the canvas container, which redefines this var
|
|
151
|
+
* when the design stores a colour — so reading it live is what keeps every
|
|
152
|
+
* board layer the same colour as the canvas around it. */
|
|
153
|
+
const CANVAS_BACKGROUND_VAR = "var(--design-editor-canvas-bg)";
|
|
150
154
|
const SCREEN_HEIGHT = 640;
|
|
151
155
|
const SCREEN_CARD_HEIGHT = SCREEN_HEIGHT + 26;
|
|
152
156
|
const SCREEN_GAP = 56;
|
|
@@ -226,7 +230,6 @@ function hasScreenChildLayers(content: string): boolean {
|
|
|
226
230
|
|
|
227
231
|
import {
|
|
228
232
|
getBoardContentKey,
|
|
229
|
-
resolveBoardSurfaceBackground,
|
|
230
233
|
getBoardContentLayerSignature,
|
|
231
234
|
getBoardSurfaceContentBounds,
|
|
232
235
|
getBoardSurfaceRenderContent,
|
|
@@ -685,19 +688,6 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
685
688
|
height: surfaceSize.height / scale,
|
|
686
689
|
};
|
|
687
690
|
}, [canvasZoom, pan.x, pan.y, surfaceSize.height, surfaceSize.width]);
|
|
688
|
-
// The board iframe cannot read the host's CSS vars. Prefer the live
|
|
689
|
-
// design canvas colour; the theme var is only the unset fallback.
|
|
690
|
-
const boardSurfaceBackground = useMemo(() => {
|
|
691
|
-
const themed =
|
|
692
|
-
typeof window === "undefined"
|
|
693
|
-
? ""
|
|
694
|
-
: window
|
|
695
|
-
.getComputedStyle(document.documentElement)
|
|
696
|
-
.getPropertyValue("--design-editor-canvas-bg")
|
|
697
|
-
.trim();
|
|
698
|
-
return resolveBoardSurfaceBackground(canvasBackground, themed);
|
|
699
|
-
}, [canvasBackground, resolvedTheme]);
|
|
700
|
-
|
|
701
691
|
const boardSurfaceRenderGeometry = useMemo(() => {
|
|
702
692
|
if (!boardFrameGeometry) return undefined;
|
|
703
693
|
const focusGeometry = boardSurfaceFocusPoint
|
|
@@ -746,16 +736,16 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
746
736
|
return null;
|
|
747
737
|
}
|
|
748
738
|
return getBoardSurfaceStaticPreviewContent({
|
|
739
|
+
darkScheme: resolvedTheme === "dark",
|
|
749
740
|
html: boardSurfaceHtml,
|
|
750
741
|
logicalGeometry: boardFrameGeometry,
|
|
751
742
|
viewport: boardStaticPreviewViewport,
|
|
752
|
-
background: boardSurfaceBackground,
|
|
753
743
|
});
|
|
754
744
|
}, [
|
|
755
745
|
boardSurfaceHtml,
|
|
756
746
|
boardFrameGeometry,
|
|
757
747
|
boardStaticPreviewViewport,
|
|
758
|
-
|
|
748
|
+
resolvedTheme,
|
|
759
749
|
]);
|
|
760
750
|
const showBoardStaticPreview = Boolean(
|
|
761
751
|
boardFrameGeometry &&
|
|
@@ -8547,7 +8537,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
8547
8537
|
pointerEvents: "none",
|
|
8548
8538
|
transform: `scale(${boardFrameGeometry.width / boardStaticPreviewViewport.width}, ${boardFrameGeometry.height / boardStaticPreviewViewport.height})`,
|
|
8549
8539
|
transformOrigin: "top left",
|
|
8550
|
-
background:
|
|
8540
|
+
background: CANVAS_BACKGROUND_VAR,
|
|
8551
8541
|
}}
|
|
8552
8542
|
/>
|
|
8553
8543
|
</div>
|
|
@@ -8572,8 +8562,10 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
8572
8562
|
});
|
|
8573
8563
|
const boardLayerSignature =
|
|
8574
8564
|
getBoardContentLayerSignature(boardFileContent);
|
|
8575
|
-
const boardRenderContent =
|
|
8576
|
-
|
|
8565
|
+
const boardRenderContent = getBoardSurfaceRenderContent(
|
|
8566
|
+
boardFileContent,
|
|
8567
|
+
resolvedTheme === "dark",
|
|
8568
|
+
);
|
|
8577
8569
|
return (
|
|
8578
8570
|
// Overflow-hidden wrapper so the board iframe never bleeds outside
|
|
8579
8571
|
// its declared logical surface. z-index 0 keeps it below screen
|
|
@@ -8593,7 +8585,7 @@ export const MultiScreenCanvas = memo(function MultiScreenCanvas({
|
|
|
8593
8585
|
// board document. Inside the document it would be part of
|
|
8594
8586
|
// the srcdoc, so every colour-picker tick would rebuild the
|
|
8595
8587
|
// iframe; out here it is a CSS change and updates instantly.
|
|
8596
|
-
background:
|
|
8588
|
+
background: CANVAS_BACKGROUND_VAR,
|
|
8597
8589
|
}}
|
|
8598
8590
|
>
|
|
8599
8591
|
<DesignCanvas
|
|
@@ -9,19 +9,15 @@ export function hasBoardSurfaceContent(html: string | undefined) {
|
|
|
9
9
|
return content.replace(/<!--[\s\S]*?-->/g, "").trim().length > 0;
|
|
10
10
|
}
|
|
11
11
|
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
return (
|
|
21
|
-
canvasBackground?.trim() ||
|
|
22
|
-
themedFallback?.trim() ||
|
|
23
|
-
BOARD_SURFACE_BACKGROUND
|
|
24
|
-
);
|
|
12
|
+
/**
|
|
13
|
+
* `color-scheme` is load-bearing, not cosmetic. Chrome paints an opaque base
|
|
14
|
+
* behind a frame whose scheme disagrees with its embedder, and that base sits
|
|
15
|
+
* between this transparent document and the canvas colour on the host layer —
|
|
16
|
+
* white in a dark editor. Matching the editor is what keeps the frame see-through.
|
|
17
|
+
*/
|
|
18
|
+
function boardSurfaceRenderStyle(darkScheme: boolean) {
|
|
19
|
+
const scheme = darkScheme ? "html{color-scheme:dark!important;}" : "";
|
|
20
|
+
return `<style data-agent-native-board-surface-render>${scheme}html,body{background:transparent!important;background-color:transparent!important;background-image:none!important;}body{margin:0!important;position:relative;overflow:visible;}body>:not([data-agent-native-node-id]):not(style):not(script),body>[data-agent-native-node-id]:not([data-an-primitive]):not([data-agent-native-preserve-styles="true"]):has([data-agent-native-node-id]),body>[data-agent-native-node-id="body"],body>[data-agent-native-node-id="Body"],body>[data-agent-native-layer-name="body"],body>[data-agent-native-layer-name="Body"],body>[data-agent-native-layer-name="<body>"]{background:transparent!important;background-color:transparent!important;background-image:none!important;box-shadow:none!important;}[data-agent-native-board-backdrop-candidate="true"]{display:none!important;pointer-events:none!important;}</style>`;
|
|
25
21
|
}
|
|
26
22
|
|
|
27
23
|
const BOARD_SURFACE_BACKDROP_MIN_EDGE_PX = 2400;
|
|
@@ -267,12 +263,19 @@ function getCurrentLayerParentNodeId(
|
|
|
267
263
|
return "body";
|
|
268
264
|
}
|
|
269
265
|
|
|
270
|
-
export function getBoardSurfaceRenderContent(html: string) {
|
|
266
|
+
export function getBoardSurfaceRenderContent(html: string, darkScheme = false) {
|
|
271
267
|
if (!html) return html;
|
|
272
|
-
const
|
|
273
|
-
|
|
274
|
-
|
|
268
|
+
const markedHtml = markAccidentalBoardBackdropCandidates(html);
|
|
269
|
+
const BOARD_SURFACE_RENDER_STYLE = boardSurfaceRenderStyle(darkScheme);
|
|
270
|
+
if (markedHtml.includes(BOARD_SURFACE_RENDER_STYLE)) {
|
|
271
|
+
return markedHtml;
|
|
275
272
|
}
|
|
273
|
+
// A block from the other scheme is stale, not already-rendered: leaving it
|
|
274
|
+
// would pin the frame to the theme it was first rendered under.
|
|
275
|
+
const renderHtml = markedHtml.replace(
|
|
276
|
+
/<style data-agent-native-board-surface-render>[\s\S]*?<\/style>/i, // i18n-ignore render-style matcher, not visible UI copy
|
|
277
|
+
"",
|
|
278
|
+
);
|
|
276
279
|
if (/<\/head>/i.test(html)) {
|
|
277
280
|
return renderHtml.replace(
|
|
278
281
|
/<\/head>/i,
|
|
@@ -321,24 +324,22 @@ function stripExecutableStaticPreviewContent(html: string) {
|
|
|
321
324
|
* logical board paintable without allocating or scrolling a 131k iframe.
|
|
322
325
|
*/
|
|
323
326
|
export function getBoardSurfaceStaticPreviewContent(args: {
|
|
324
|
-
|
|
325
|
-
background?: string;
|
|
327
|
+
darkScheme?: boolean;
|
|
326
328
|
html: string;
|
|
327
329
|
logicalGeometry: FrameGeometry;
|
|
328
330
|
viewport: { width: number; height: number };
|
|
329
331
|
}) {
|
|
330
332
|
const renderHtml = stripExecutableStaticPreviewContent(
|
|
331
|
-
getBoardSurfaceRenderContent(args.html),
|
|
333
|
+
getBoardSurfaceRenderContent(args.html, args.darkScheme),
|
|
332
334
|
);
|
|
333
335
|
const width = Math.max(1, args.logicalGeometry.width);
|
|
334
336
|
const height = Math.max(1, args.logicalGeometry.height);
|
|
335
337
|
const viewportWidth = Math.max(1, args.viewport.width);
|
|
336
338
|
const viewportHeight = Math.max(1, args.viewport.height);
|
|
337
|
-
const background = args.background?.trim() || BOARD_SURFACE_BACKGROUND;
|
|
338
339
|
const scale = Math.min(viewportWidth / width, viewportHeight / height);
|
|
339
340
|
const offsetX = -args.logicalGeometry.x;
|
|
340
341
|
const offsetY = -args.logicalGeometry.y;
|
|
341
|
-
const style = `<style data-agent-native-board-static-preview>*,*::before,*::after{animation:none!important;animation-delay:0s!important;transition:none!important;caret-color:transparent!important;}html{width:${viewportWidth}px!important;height:${viewportHeight}px!important;overflow:hidden!important;}html,body{background
|
|
342
|
+
const style = `<style data-agent-native-board-static-preview>*,*::before,*::after{animation:none!important;animation-delay:0s!important;transition:none!important;caret-color:transparent!important;}html{width:${viewportWidth}px!important;height:${viewportHeight}px!important;overflow:hidden!important;}html,body{background:transparent!important;background-color:transparent!important;background-image:none!important;}body{margin:0!important;width:${width}px!important;height:${height}px!important;overflow:visible!important;transform:scale(${scale})!important;transform-origin:0 0!important;}body>[data-agent-native-node-id]{translate:${offsetX}px ${offsetY}px!important;}</style>`;
|
|
342
343
|
if (/<\/head\s*>/i.test(renderHtml)) {
|
|
343
344
|
return injectDocumentMarkup(renderHtml, style, { target: "head" });
|
|
344
345
|
}
|
|
@@ -165,6 +165,7 @@ import {
|
|
|
165
165
|
IconMessageCircle,
|
|
166
166
|
} from "@tabler/icons-react";
|
|
167
167
|
import { useQueryClient } from "@tanstack/react-query";
|
|
168
|
+
import { useTheme } from "next-themes";
|
|
168
169
|
import {
|
|
169
170
|
useState,
|
|
170
171
|
useEffect,
|
|
@@ -5629,6 +5630,10 @@ function DesignEditor() {
|
|
|
5629
5630
|
// layer (see beginRename in LayersPanel.tsx).
|
|
5630
5631
|
const layersPanelRef = useRef<LayersPanelHandle | null>(null);
|
|
5631
5632
|
const canvasContainerRef = useRef<HTMLDivElement>(null);
|
|
5633
|
+
/** Read by primitive creation, which runs far above where the colour is
|
|
5634
|
+
* derived. */
|
|
5635
|
+
const canvasBackgroundRef = useRef<string | null>(null);
|
|
5636
|
+
const { resolvedTheme } = useTheme();
|
|
5632
5637
|
const activeEditorDragRef = useRef(false);
|
|
5633
5638
|
|
|
5634
5639
|
// Live handle to the active DesignCanvas preview iframe. DesignCanvas owns the
|
|
@@ -8080,6 +8085,7 @@ function DesignEditor() {
|
|
|
8080
8085
|
activeFile,
|
|
8081
8086
|
applyLocalContentUpdate,
|
|
8082
8087
|
boardFileId,
|
|
8088
|
+
canvasBackground: canvasBackgroundRef.current,
|
|
8083
8089
|
canEditDesign,
|
|
8084
8090
|
collabContentFileIdRef,
|
|
8085
8091
|
collabContentRef,
|
|
@@ -15778,7 +15784,7 @@ function DesignEditor() {
|
|
|
15778
15784
|
})),
|
|
15779
15785
|
[firstRunTemplatesQuery.data?.templates],
|
|
15780
15786
|
);
|
|
15781
|
-
const
|
|
15787
|
+
const designSystemOptions = useMemo(
|
|
15782
15788
|
() => designSystemPickerOptions(designSystems),
|
|
15783
15789
|
[designSystems],
|
|
15784
15790
|
);
|
|
@@ -15790,6 +15796,10 @@ function DesignEditor() {
|
|
|
15790
15796
|
// first screen row exists.
|
|
15791
15797
|
const [chatMessageCount, setChatMessageCount] = useState(0);
|
|
15792
15798
|
const showFirstRunStart = designIsEmpty && chatMessageCount === 0;
|
|
15799
|
+
// The picked system is stored on the design and read by every later
|
|
15800
|
+
// generation, so it outlives the starting-point row a template retires.
|
|
15801
|
+
const showComposerDesignSystem =
|
|
15802
|
+
designSystemsLoading || designSystemOptions.length > 0;
|
|
15793
15803
|
const applyTemplate = useActionMutation("create-design-from-template");
|
|
15794
15804
|
const handleFirstRunTemplate = useCallback(
|
|
15795
15805
|
async (templateId: string) => {
|
|
@@ -15820,9 +15830,11 @@ function DesignEditor() {
|
|
|
15820
15830
|
selectedPromptDesignSystemId,
|
|
15821
15831
|
],
|
|
15822
15832
|
);
|
|
15823
|
-
const
|
|
15833
|
+
const handleComposerDesignSystem = useCallback(
|
|
15824
15834
|
(designSystemId: string | null) => {
|
|
15825
|
-
|
|
15835
|
+
// null is the user picking "No design system"; only undefined means
|
|
15836
|
+
// nothing has been chosen yet, which re-resolves the default.
|
|
15837
|
+
setPromptDesignSystemId(designSystemId);
|
|
15826
15838
|
persistPromptDesignSystem(designSystemId);
|
|
15827
15839
|
},
|
|
15828
15840
|
[persistPromptDesignSystem],
|
|
@@ -16334,6 +16346,29 @@ function DesignEditor() {
|
|
|
16334
16346
|
string | null
|
|
16335
16347
|
>(null);
|
|
16336
16348
|
const canvasBackground = canvasBackgroundDraft ?? persistedCanvasBackground;
|
|
16349
|
+
/** The inspector must show a colour, not "none", for a canvas the user has
|
|
16350
|
+
* not set — and the only honest source for that is what the container is
|
|
16351
|
+
* currently painted with, which follows the editor theme. */
|
|
16352
|
+
const [themedCanvasBackground, setThemedCanvasBackground] = useState<
|
|
16353
|
+
string | null
|
|
16354
|
+
>(null);
|
|
16355
|
+
canvasBackgroundRef.current = canvasBackground ?? themedCanvasBackground;
|
|
16356
|
+
useEffect(() => {
|
|
16357
|
+
if (canvasBackground) return;
|
|
16358
|
+
// A throwaway element, not the raw token: the token is space-separated
|
|
16359
|
+
// HSL, which the colour parser rejects. After a frame, because next-themes
|
|
16360
|
+
// sets the `dark` class in an ancestor effect React runs after this one.
|
|
16361
|
+
const frame = requestAnimationFrame(() => {
|
|
16362
|
+
const probe = document.createElement("span");
|
|
16363
|
+
probe.style.cssText =
|
|
16364
|
+
"position:absolute;visibility:hidden;background-color:var(--design-editor-canvas-bg)";
|
|
16365
|
+
document.body.append(probe);
|
|
16366
|
+
const painted = window.getComputedStyle(probe).backgroundColor;
|
|
16367
|
+
probe.remove();
|
|
16368
|
+
setThemedCanvasBackground(painted || null);
|
|
16369
|
+
});
|
|
16370
|
+
return () => cancelAnimationFrame(frame);
|
|
16371
|
+
}, [canvasBackground, resolvedTheme]);
|
|
16337
16372
|
const handleCanvasBackgroundChange = useCallback(
|
|
16338
16373
|
(value: string, meta?: { phase?: "preview" | "commit" }) => {
|
|
16339
16374
|
if (!id || !canEditDesignRef.current) return;
|
|
@@ -19760,6 +19795,7 @@ function DesignEditor() {
|
|
|
19760
19795
|
selectedScreenLayoutGrid,
|
|
19761
19796
|
onLayoutGridChange: canEditDesign ? handleLayoutGridChange : undefined,
|
|
19762
19797
|
canvasBackground,
|
|
19798
|
+
canvasBackgroundFallback: themedCanvasBackground,
|
|
19763
19799
|
onCanvasBackgroundChange: canEditDesign
|
|
19764
19800
|
? handleCanvasBackgroundChange
|
|
19765
19801
|
: undefined,
|
|
@@ -20016,13 +20052,13 @@ function DesignEditor() {
|
|
|
20016
20052
|
}
|
|
20017
20053
|
composerSlot={
|
|
20018
20054
|
<>
|
|
20019
|
-
{
|
|
20055
|
+
{showComposerDesignSystem ? (
|
|
20020
20056
|
<div data-design-system-picker className="px-3 pb-2">
|
|
20021
20057
|
<DesignSystemPickerControl
|
|
20022
|
-
designSystems={
|
|
20058
|
+
designSystems={designSystemOptions}
|
|
20023
20059
|
loading={designSystemsLoading}
|
|
20024
20060
|
selectedId={selectedPromptDesignSystemId ?? null}
|
|
20025
|
-
onChange={
|
|
20061
|
+
onChange={handleComposerDesignSystem}
|
|
20026
20062
|
/>
|
|
20027
20063
|
</div>
|
|
20028
20064
|
) : null}
|
|
@@ -20523,6 +20559,7 @@ function DesignEditor() {
|
|
|
20523
20559
|
BreakpointDeviceControl — see rightSidebarActions. */}
|
|
20524
20560
|
<div
|
|
20525
20561
|
ref={canvasContainerRef}
|
|
20562
|
+
data-design-canvas-container
|
|
20526
20563
|
className="relative min-w-0 flex-1 overflow-hidden bg-[var(--design-editor-canvas-bg)]"
|
|
20527
20564
|
// Overrides the themed canvas colour rather than a background
|
|
20528
20565
|
// shorthand, so every descendant reading the var follows.
|
|
@@ -112,7 +112,9 @@ interface DesignListResult {
|
|
|
112
112
|
designs: Design[];
|
|
113
113
|
}
|
|
114
114
|
|
|
115
|
-
|
|
115
|
+
// The New Design card shares the grid, so a full page is pageSize + 1 tiles;
|
|
116
|
+
// 12 is what divides evenly into every breakpoint's column count.
|
|
117
|
+
const DESIGN_PAGE_SIZE = 11;
|
|
116
118
|
|
|
117
119
|
export default function Index() {
|
|
118
120
|
const t = useT();
|
|
@@ -1201,9 +1203,14 @@ export default function Index() {
|
|
|
1201
1203
|
aria-label={t("home.actionsForDesign", {
|
|
1202
1204
|
title: design.title,
|
|
1203
1205
|
})}
|
|
1204
|
-
|
|
1206
|
+
// A scrim over the user's thumbnail, which is
|
|
1207
|
+
// their content: a theme-following chip vanishes
|
|
1208
|
+
// on a thumbnail that happens to match it.
|
|
1209
|
+
// guard:allow-raw-color — scrim over user content
|
|
1210
|
+
className="h-7 w-7 bg-black/60 hover:bg-black/75 cursor-pointer"
|
|
1205
1211
|
>
|
|
1206
|
-
|
|
1212
|
+
{/* guard:allow-raw-color — scrim over user content */}
|
|
1213
|
+
<IconDots className="w-3.5 h-3.5 text-white" />
|
|
1207
1214
|
</Button>
|
|
1208
1215
|
</DropdownMenuTrigger>
|
|
1209
1216
|
<DropdownMenuContent align="end">
|
|
@@ -319,15 +319,6 @@ export default function Templates() {
|
|
|
319
319
|
</div>
|
|
320
320
|
) : null}
|
|
321
321
|
<main className="mx-auto w-full max-w-[1480px] px-4 py-6 sm:px-6 sm:py-10">
|
|
322
|
-
<div className="mb-8 max-w-2xl">
|
|
323
|
-
<h1 className="text-lg font-semibold text-foreground">
|
|
324
|
-
{t("templatesPage.title")}
|
|
325
|
-
</h1>
|
|
326
|
-
<p className="mt-1 text-sm leading-relaxed text-muted-foreground">
|
|
327
|
-
{t("templatesPage.description")}
|
|
328
|
-
</p>
|
|
329
|
-
</div>
|
|
330
|
-
|
|
331
322
|
{isLoading ? (
|
|
332
323
|
<TemplateGridSkeleton />
|
|
333
324
|
) : isError ? (
|
|
@@ -339,7 +330,6 @@ export default function Templates() {
|
|
|
339
330
|
<div className="flex flex-col gap-10">
|
|
340
331
|
<TemplateSection
|
|
341
332
|
title={t("templatesPage.yourTemplates")}
|
|
342
|
-
description={t("templatesPage.yourTemplatesDescription")}
|
|
343
333
|
templates={userTemplates}
|
|
344
334
|
linkedTemplateId={linkedTemplateId}
|
|
345
335
|
empty={t("templatesPage.yourTemplatesEmpty")}
|
|
@@ -428,7 +418,6 @@ export default function Templates() {
|
|
|
428
418
|
|
|
429
419
|
function TemplateSection({
|
|
430
420
|
title,
|
|
431
|
-
description,
|
|
432
421
|
templates,
|
|
433
422
|
linkedTemplateId,
|
|
434
423
|
empty,
|
|
@@ -436,7 +425,6 @@ function TemplateSection({
|
|
|
436
425
|
onDelete,
|
|
437
426
|
}: {
|
|
438
427
|
title: string;
|
|
439
|
-
description?: string;
|
|
440
428
|
templates: DesignTemplateSummary[];
|
|
441
429
|
linkedTemplateId?: string | null;
|
|
442
430
|
empty?: string;
|
|
@@ -446,12 +434,7 @@ function TemplateSection({
|
|
|
446
434
|
if (templates.length === 0 && !empty) return null;
|
|
447
435
|
return (
|
|
448
436
|
<section>
|
|
449
|
-
<
|
|
450
|
-
<h2 className="text-sm font-semibold text-foreground">{title}</h2>
|
|
451
|
-
{description ? (
|
|
452
|
-
<p className="mt-1 text-xs text-muted-foreground">{description}</p>
|
|
453
|
-
) : null}
|
|
454
|
-
</div>
|
|
437
|
+
<h2 className="mb-3 text-sm font-semibold text-foreground">{title}</h2>
|
|
455
438
|
{templates.length === 0 ? (
|
|
456
439
|
<div className="flex min-h-32 items-center justify-center rounded-xl border border-dashed bg-muted/20 px-6 text-center text-sm text-muted-foreground">
|
|
457
440
|
{empty}
|
|
@@ -15,6 +15,7 @@ import {
|
|
|
15
15
|
import {
|
|
16
16
|
BOARD_TEXT_AUTO_COLOR_MARKER,
|
|
17
17
|
destinationBackgroundLightness,
|
|
18
|
+
resolveDestinationBackgroundLightnessOrNull,
|
|
18
19
|
} from "./cross-screen-text-color";
|
|
19
20
|
import { escapeHtmlAttributeValue, escapeHtmlText } from "./dom-utils";
|
|
20
21
|
import { isStandaloneHttpUrl } from "./editor-state";
|
|
@@ -281,7 +282,13 @@ function deepestFrameContaining(
|
|
|
281
282
|
export function appendCanvasPrimitiveToHtml(
|
|
282
283
|
content: string,
|
|
283
284
|
primitive: CanvasPrimitiveInsert,
|
|
284
|
-
options?: {
|
|
285
|
+
options?: {
|
|
286
|
+
preserveNegativePosition?: boolean;
|
|
287
|
+
isBoardTarget?: boolean;
|
|
288
|
+
/** The canvas colour behind the board. The board document is transparent
|
|
289
|
+
* by design, so its surface can only be measured from the host. */
|
|
290
|
+
boardBackground?: string | null;
|
|
291
|
+
},
|
|
285
292
|
): string | null {
|
|
286
293
|
if (typeof window === "undefined") return null;
|
|
287
294
|
// A live/localhost screen stores its route URL here, not a document.
|
|
@@ -520,18 +527,25 @@ export function appendCanvasPrimitiveToHtml(
|
|
|
520
527
|
element.style.alignItems = "flex-start";
|
|
521
528
|
}
|
|
522
529
|
// "currentColor" inherits the unstyled document's black body text, so
|
|
523
|
-
// it is invisible on any dark surface
|
|
524
|
-
//
|
|
525
|
-
//
|
|
526
|
-
//
|
|
527
|
-
|
|
528
|
-
|
|
529
|
-
|
|
530
|
-
|
|
530
|
+
// it is invisible on any dark surface. The board renderer forces its own
|
|
531
|
+
// document transparent, so a colour on that body is never painted and
|
|
532
|
+
// measuring it would judge a surface nobody sees — a frame inside the
|
|
533
|
+
// board still can be. The canvas behind it arrives from the host.
|
|
534
|
+
const boardSurfaceIsLight =
|
|
535
|
+
options?.isBoardTarget === true
|
|
536
|
+
? resolveDestinationBackgroundLightnessOrNull([
|
|
537
|
+
{ color: options.boardBackground ?? null },
|
|
538
|
+
])
|
|
539
|
+
: null;
|
|
540
|
+
const measuredIsLight =
|
|
541
|
+
options?.isBoardTarget === true && hostOrBody === doc.body
|
|
542
|
+
? null
|
|
543
|
+
: destinationBackgroundLightness(hostOrBody);
|
|
544
|
+
const surfaceIsLight = measuredIsLight ?? boardSurfaceIsLight;
|
|
531
545
|
const autoTextNeedsLightFill =
|
|
532
|
-
|
|
546
|
+
surfaceIsLight === null
|
|
533
547
|
? options?.isBoardTarget === true
|
|
534
|
-
: !
|
|
548
|
+
: !surfaceIsLight;
|
|
535
549
|
const resolvedTextColor =
|
|
536
550
|
primitive.fill ?? defaultCanvasTextColor(autoTextNeedsLightFill);
|
|
537
551
|
element.style.color = resolvedTextColor;
|