@agent-native/core-corpus 0.216.0 → 0.217.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/.agents/skills/session-replay/SKILL.md +61 -1
- package/corpus/templates/analytics/AGENTS.md +1 -1
- package/corpus/templates/analytics/CHANGELOG.md +1 -0
- package/corpus/templates/analytics/actions/get-session-replay-summary.ts +9 -65
- package/corpus/templates/analytics/actions/list-event-catalog.ts +1 -1
- package/corpus/templates/analytics/actions/list-session-outputs.ts +40 -0
- package/corpus/templates/analytics/actions/list-session-recordings.ts +17 -4
- package/corpus/templates/analytics/actions/view-screen.ts +29 -3
- package/corpus/templates/analytics/app/i18n/en-US.ts +27 -0
- package/corpus/templates/analytics/app/pages/sessions/EventCatalogPage.tsx +18 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionDetailPage.tsx +3 -1
- package/corpus/templates/analytics/app/pages/sessions/SessionOutputs.tsx +197 -0
- package/corpus/templates/analytics/app/pages/sessions/SessionsTriagePage.tsx +114 -4
- package/corpus/templates/analytics/changelog/2026-10-15-sessions-can-find-people-who-made-a-slides-deck-but-didn-t-p.md +6 -0
- package/corpus/templates/analytics/changelog/2026-10-16-the-activation-funnel-counts-visitors-who-decline-analytics-.md +6 -0
- package/corpus/templates/analytics/server/db/schema.ts +67 -0
- package/corpus/templates/analytics/server/lib/canonical-first-party-dashboard-repair.ts +9 -0
- package/corpus/templates/analytics/server/lib/first-party-analytics.ts +28 -22
- package/corpus/templates/analytics/server/lib/first-party-metric-catalog.ts +36 -1
- package/corpus/templates/analytics/server/lib/output-outcomes.ts +712 -0
- package/corpus/templates/analytics/server/lib/replay-origins.ts +33 -0
- package/corpus/templates/analytics/server/lib/session-event-index.ts +20 -0
- package/corpus/templates/analytics/server/lib/session-performance.ts +6 -40
- package/corpus/templates/analytics/server/lib/session-recording-associations.ts +30 -1
- package/corpus/templates/analytics/server/lib/session-replay-triage.ts +99 -0
- package/corpus/templates/analytics/server/lib/session-replay.ts +45 -31
- package/corpus/templates/analytics/server/lib/sessions-triage-lab.ts +8 -2
- package/corpus/templates/analytics/server/plugins/db.ts +46 -0
- package/corpus/templates/analytics/shared/output-use.ts +205 -0
- package/corpus/templates/analytics/shared/session-events.ts +6 -0
- package/corpus/templates/calendar/CHANGELOG.md +6 -0
- package/corpus/templates/calendar/actions/create-event.ts +2 -4
- package/corpus/templates/calendar/actions/update-event.ts +35 -6
- package/corpus/templates/calendar/changelog/2026-10-21-solo-events-avoid-notification-approval.md +6 -0
- package/corpus/templates/community/qr/package.json +1 -1
- package/corpus/templates/content/.agents/skills/document-editing/references/databases.md +6 -3
- package/corpus/templates/content/CHANGELOG.md +8 -0
- package/corpus/templates/content/actions/_browser-document-save-attempt.ts +23 -1
- package/corpus/templates/content/actions/_builder-cms-blob-custody.ts +467 -0
- package/corpus/templates/content/actions/_builder-cms-execution-lease.ts +17 -0
- package/corpus/templates/content/actions/_builder-cms-intent-lookup.ts +5 -0
- package/corpus/templates/content/actions/_builder-cms-read-client.ts +881 -21
- package/corpus/templates/content/actions/_builder-cms-write-adapter.ts +28 -2
- package/corpus/templates/content/actions/_builder-cms-write-client.ts +109 -11
- package/corpus/templates/content/actions/_builder-docs-client.ts +1 -0
- package/corpus/templates/content/actions/_builder-private-blob.test-fixture.ts +90 -0
- package/corpus/templates/content/actions/_builder-source-execution-guard.ts +48 -0
- package/corpus/templates/content/actions/_content-save-outcomes.ts +5 -0
- package/corpus/templates/content/actions/_database-source-utils.ts +290 -8
- package/corpus/templates/content/actions/_database-utils.ts +93 -7
- package/corpus/templates/content/actions/_database-view-setup.ts +21 -2
- package/corpus/templates/content/actions/_delete-content-space.ts +8 -1
- package/corpus/templates/content/actions/_github-source-freshness.ts +30 -4
- package/corpus/templates/content/actions/add-content-database-source-field-property.ts +23 -6
- package/corpus/templates/content/actions/cancel-prepared-builder-source-update.ts +110 -26
- package/corpus/templates/content/actions/change-content-database-source-role.ts +51 -7
- package/corpus/templates/content/actions/delete-document.ts +41 -3
- package/corpus/templates/content/actions/disconnect-content-database-source.ts +68 -2
- package/corpus/templates/content/actions/disconnect-local-folder-source.ts +33 -2
- package/corpus/templates/content/actions/execute-builder-source-execution.ts +900 -140
- package/corpus/templates/content/actions/get-document.ts +2 -0
- package/corpus/templates/content/actions/permanently-delete-document.ts +6 -0
- package/corpus/templates/content/actions/prepare-builder-source-execution.ts +155 -13
- package/corpus/templates/content/actions/prepare-builder-source-review.ts +299 -73
- package/corpus/templates/content/actions/set-live-body-switch.ts +45 -0
- package/corpus/templates/content/actions/update-document.ts +139 -20
- package/corpus/templates/content/actions/validate-builder-source-execution.ts +135 -26
- package/corpus/templates/content/app/components/editor/database/DatabaseView.tsx +23 -0
- package/corpus/templates/content/app/components/editor/database/GitHubSourceStatusLine.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database/ListItemLayout.tsx +32 -8
- package/corpus/templates/content/app/components/editor/database/ListItemRow.tsx +27 -2
- package/corpus/templates/content/app/components/editor/database-sources/BuilderSourceReviewDialog.tsx +1 -0
- package/corpus/templates/content/app/hooks/use-content-database.ts +40 -2
- package/corpus/templates/content/app/hooks/use-documents.ts +14 -0
- package/corpus/templates/content/app/i18n-data.ts +1 -0
- package/corpus/templates/content/changelog/2026-10-17-builder-content-avoids-retrying-a-write-when-builder-accepte.md +6 -0
- package/corpus/templates/content/changelog/2026-10-18-link-a-new-collection-to-a-github-folder-from-its-sources.md +1 -1
- package/corpus/templates/content/changelog/2026-10-20-builder-content-sync-keeps-read-and-write-status-accurate-wh.md +6 -0
- package/corpus/templates/content/changelog/2026-10-21-list-rows-can-show-each-pages-first-lines.md +6 -0
- package/corpus/templates/content/changelog/2026-10-22-a-collection-linked-to-a-big-github-folder-fills-faster-and-p.md +6 -0
- package/corpus/templates/content/docs/product/capabilities/content.source.adapters.md +29 -0
- package/corpus/templates/content/parity/matrix.md +42 -42
- package/corpus/templates/content/parity/matrix.ts +3 -1
- package/corpus/templates/content/server/db/schema.ts +20 -0
- package/corpus/templates/content/server/lib/content-trash-purge.ts +15 -1
- package/corpus/templates/content/server/lib/live-body-writer.ts +138 -26
- package/corpus/templates/content/server/live-copy/binding.ts +31 -0
- package/corpus/templates/content/server/live-copy/bounded-task.d.ts +6 -0
- package/corpus/templates/content/server/live-copy/exec-db.ts +1 -0
- package/corpus/templates/content/server/live-copy/holds.ts +59 -0
- package/corpus/templates/content/server/live-copy/persist.ts +656 -0
- package/corpus/templates/content/server/live-copy/switch.ts +136 -0
- package/corpus/templates/content/server/live-copy/task-names.ts +4 -0
- package/corpus/templates/content/server/live-copy/tasks.ts +183 -0
- package/corpus/templates/content/server/live-copy/write-cause.ts +85 -0
- package/corpus/templates/content/server/live-copy/write.ts +85 -0
- package/corpus/templates/content/server/plugins/builder-private-payload-cleanup.ts +22 -0
- package/corpus/templates/content/server/plugins/collab.ts +3 -0
- package/corpus/templates/content/server/plugins/db.ts +28 -0
- package/corpus/templates/content/shared/api.ts +30 -1
- package/corpus/templates/content/shared/database-item-layout.ts +54 -22
- package/corpus/templates/content/shared/document-intent-merge.ts +16 -9
- package/corpus/templates/content/shared/og-description.ts +258 -36
- package/corpus/templates/design/.agents/skills/design-templates/SKILL.md +5 -1
- package/corpus/templates/design/.generated/bridge/shader-runtime.generated.ts +25 -4
- package/corpus/templates/design/CHANGELOG.md +2 -0
- package/corpus/templates/design/actions/get-getting-started.ts +53 -0
- package/corpus/templates/design/app/components/design/DesignCanvas.tsx +10 -0
- package/corpus/templates/design/app/components/design/bridge/native-shader-runtime.bridge.ts +132 -79
- package/corpus/templates/design/app/components/design/bridge/native-source-provider.ts +268 -130
- package/corpus/templates/design/app/components/design/bridge/native-worker-scene-host.ts +122 -42
- package/corpus/templates/design/app/components/design/bridge/shader-runtime.bridge.ts +41 -4
- package/corpus/templates/design/app/components/design/design-canvas/text-content-change-result.ts +46 -12
- package/corpus/templates/design/app/components/home/DesignHomeLibrary.tsx +15 -8
- package/corpus/templates/design/app/components/layout/GettingStarted.tsx +50 -0
- package/corpus/templates/design/app/components/layout/Sidebar.tsx +3 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateGrid.tsx +163 -0
- package/corpus/templates/design/app/components/templates/DesignTemplateLibrary.tsx +65 -78
- package/corpus/templates/design/app/components/templates/TemplatePreview.tsx +6 -2
- package/corpus/templates/design/app/global.css +6 -0
- package/corpus/templates/design/app/i18n/en-US.ts +17 -0
- package/corpus/templates/design/app/lib/canvas-load-outcome.ts +147 -0
- package/corpus/templates/design/app/lib/canvas-outcome-tracking.ts +531 -0
- package/corpus/templates/design/app/lib/canvas-style-kind.ts +50 -0
- package/corpus/templates/design/app/pages/Index.tsx +10 -3
- package/corpus/templates/design/app/pages/design-editor/commands/commit-visual-styles.ts +86 -29
- package/corpus/templates/design/app/pages/design-editor/commands/save-file-content.ts +38 -3
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-core.ts +9 -0
- package/corpus/templates/design/app/pages/design-editor/domains/use-editor-files-and-saving.ts +2 -0
- package/corpus/templates/design/changelog/2026-10-21-a-getting-started-checklist-at-the-bottom-of-the-sidebar-tra.md +6 -0
- package/corpus/templates/design/changelog/2026-10-21-templates-now-open-a-read-only-preview-from-the-card-and-the.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-collapsed-shader-layers-no-longer-interrupt-other-shaders-on.md +6 -0
- package/corpus/templates/design/changelog/2026-10-22-shader-fills-keep-rendering-when-other-screen-content-cannot.md +6 -0
- package/corpus/templates/design/scripts/design-export-validation/export-baseline.json +24 -0
- package/corpus/templates/design/server/lib/getting-started.ts +267 -0
- package/corpus/templates/design/server/plugins/getting-started.ts +5 -0
- package/corpus/templates/design/shared/design-template-presets/analytics-dashboard.ts +127 -0
- package/corpus/templates/design/shared/design-template-presets/design-studio.ts +98 -0
- package/corpus/templates/design/shared/design-template-presets/messaging-app.ts +101 -0
- package/corpus/templates/design/shared/design-template-presets/project-tasks.ts +120 -0
- package/corpus/templates/design/shared/design-template-presets.ts +8 -0
- package/corpus/templates/forms/server/plugins/agent-chat.ts +1 -1
- package/corpus/templates/slides/CHANGELOG.md +6 -0
- package/corpus/templates/slides/actions/delete-deck.ts +7 -0
- package/corpus/templates/slides/changelog/2026-10-21-connected-deck-deletion-requires-approval.md +6 -0
- package/corpus/templates/slides/scripts/edit-fidelity/client-action.ts +61 -0
- package/corpus/templates/slides/scripts/edit-fidelity/run.ts +10 -0
- package/package.json +1 -1
|
@@ -0,0 +1,267 @@
|
|
|
1
|
+
import { getDbExec } from "@agent-native/core/db";
|
|
2
|
+
import { isFeatureFlagEnabled } from "@agent-native/core/feature-flags";
|
|
3
|
+
import {
|
|
4
|
+
registerOnboardingStep,
|
|
5
|
+
type OnboardingResolveContext,
|
|
6
|
+
type OnboardingStep,
|
|
7
|
+
} from "@agent-native/core/onboarding";
|
|
8
|
+
import { isMissingOrganizationTableError } from "@agent-native/core/org";
|
|
9
|
+
import { accessFilter } from "@agent-native/core/sharing";
|
|
10
|
+
import { and, eq, inArray, notInArray, sql, type AnyColumn } from "drizzle-orm";
|
|
11
|
+
|
|
12
|
+
import { DESIGN_SYSTEM_WORKFLOWS } from "../../shared/design-flags.js";
|
|
13
|
+
import { PRODUCTION_DESIGN_SYSTEM_TEMPLATES } from "../../shared/design-system-templates.js";
|
|
14
|
+
import { getDb, schema } from "../db/index.js";
|
|
15
|
+
|
|
16
|
+
export const GETTING_STARTED_CHECKLIST = "getting-started";
|
|
17
|
+
|
|
18
|
+
type Ctx = OnboardingResolveContext | undefined;
|
|
19
|
+
|
|
20
|
+
function ownerEmailOf(ctx: Ctx): string | null {
|
|
21
|
+
return ctx?.userEmail?.trim().toLowerCase() || null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
function ownedBy(column: AnyColumn, email: string) {
|
|
25
|
+
return sql`lower(trim(${column})) = ${email}`;
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
/** The user has created at least one design of their own. */
|
|
29
|
+
export async function hasOwnDesign(ctx: Ctx): Promise<boolean> {
|
|
30
|
+
const email = ownerEmailOf(ctx);
|
|
31
|
+
if (!email) return false;
|
|
32
|
+
const rows = await getDb()
|
|
33
|
+
.select({ id: schema.designs.id })
|
|
34
|
+
.from(schema.designs)
|
|
35
|
+
.where(
|
|
36
|
+
and(
|
|
37
|
+
accessFilter(schema.designs, schema.designShares),
|
|
38
|
+
ownedBy(schema.designs.ownerEmail, email),
|
|
39
|
+
),
|
|
40
|
+
)
|
|
41
|
+
.limit(1);
|
|
42
|
+
return rows.length > 0;
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* A design system that is not an untouched copy of a built-in template.
|
|
47
|
+
* `create-design-system` stores a template copy's `data` as the exact JSON of
|
|
48
|
+
* the template snapshot, so any edit or custom system counts as the user's
|
|
49
|
+
* brand while a one-click copy does not.
|
|
50
|
+
*/
|
|
51
|
+
export async function hasOwnBrand(ctx: Ctx): Promise<boolean> {
|
|
52
|
+
const email = ownerEmailOf(ctx);
|
|
53
|
+
if (!email) return false;
|
|
54
|
+
const rows = await getDb()
|
|
55
|
+
.select({ id: schema.designSystems.id })
|
|
56
|
+
.from(schema.designSystems)
|
|
57
|
+
.where(
|
|
58
|
+
and(
|
|
59
|
+
accessFilter(schema.designSystems, schema.designSystemShares),
|
|
60
|
+
ownedBy(schema.designSystems.ownerEmail, email),
|
|
61
|
+
notInArray(
|
|
62
|
+
schema.designSystems.data,
|
|
63
|
+
PRODUCTION_DESIGN_SYSTEM_TEMPLATES.map((template) =>
|
|
64
|
+
JSON.stringify(template.data),
|
|
65
|
+
),
|
|
66
|
+
),
|
|
67
|
+
),
|
|
68
|
+
)
|
|
69
|
+
.limit(1);
|
|
70
|
+
return rows.length > 0;
|
|
71
|
+
}
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* `create-design-system` refuses to run while the design-system workflows flag
|
|
75
|
+
* is off, so the step would be impossible to finish. A user who already has a
|
|
76
|
+
* brand keeps the step either way.
|
|
77
|
+
*/
|
|
78
|
+
export async function canAddBrand(ctx: Ctx): Promise<boolean> {
|
|
79
|
+
const enabled = await isFeatureFlagEnabled(DESIGN_SYSTEM_WORKFLOWS, {
|
|
80
|
+
userEmail: ctx?.userEmail,
|
|
81
|
+
orgId: ctx?.orgId ?? undefined,
|
|
82
|
+
});
|
|
83
|
+
return enabled || (await hasOwnBrand(ctx));
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* The user connected a running app (a localhost connection) to Design, so
|
|
88
|
+
* designs can start from its real screens and data. Design has no other
|
|
89
|
+
* per-user data-source row; a connection that errored does not count.
|
|
90
|
+
*/
|
|
91
|
+
export async function hasConnectedDataSource(ctx: Ctx): Promise<boolean> {
|
|
92
|
+
const email = ownerEmailOf(ctx);
|
|
93
|
+
if (!email) return false;
|
|
94
|
+
const rows = await getDb()
|
|
95
|
+
.select({ id: schema.designLocalhostConnections.id })
|
|
96
|
+
.from(schema.designLocalhostConnections)
|
|
97
|
+
.where(
|
|
98
|
+
and(
|
|
99
|
+
ownedBy(schema.designLocalhostConnections.ownerEmail, email),
|
|
100
|
+
inArray(schema.designLocalhostConnections.status, [
|
|
101
|
+
"connected",
|
|
102
|
+
"manual",
|
|
103
|
+
]),
|
|
104
|
+
),
|
|
105
|
+
)
|
|
106
|
+
.limit(1);
|
|
107
|
+
return rows.length > 0;
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
/**
|
|
111
|
+
* Something the user shared on purpose. New designs in an organization start
|
|
112
|
+
* with `org` visibility, so only an explicit grant to someone else or a public
|
|
113
|
+
* link counts.
|
|
114
|
+
*/
|
|
115
|
+
export async function hasSharedDesign(ctx: Ctx): Promise<boolean> {
|
|
116
|
+
const email = ownerEmailOf(ctx);
|
|
117
|
+
if (!email) return false;
|
|
118
|
+
const db = getDb();
|
|
119
|
+
const ownDesign = and(
|
|
120
|
+
accessFilter(schema.designs, schema.designShares),
|
|
121
|
+
ownedBy(schema.designs.ownerEmail, email),
|
|
122
|
+
);
|
|
123
|
+
const [grants, publicDesigns] = await Promise.all([
|
|
124
|
+
db
|
|
125
|
+
.select({ id: schema.designShares.id })
|
|
126
|
+
.from(schema.designShares)
|
|
127
|
+
.innerJoin(
|
|
128
|
+
schema.designs,
|
|
129
|
+
eq(schema.designs.id, schema.designShares.resourceId),
|
|
130
|
+
)
|
|
131
|
+
.where(
|
|
132
|
+
and(
|
|
133
|
+
ownDesign,
|
|
134
|
+
sql`not (${schema.designShares.principalType} = 'user' and lower(trim(${schema.designShares.principalId})) = ${email})`,
|
|
135
|
+
),
|
|
136
|
+
)
|
|
137
|
+
.limit(1),
|
|
138
|
+
db
|
|
139
|
+
.select({ id: schema.designs.id })
|
|
140
|
+
.from(schema.designs)
|
|
141
|
+
.where(and(ownDesign, eq(schema.designs.visibility, "public")))
|
|
142
|
+
.limit(1),
|
|
143
|
+
]);
|
|
144
|
+
return grants.length > 0 || publicDesigns.length > 0;
|
|
145
|
+
}
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* The organization has someone besides the caller, or an invitation waiting.
|
|
149
|
+
* No active organization (or no organization tables at all) means no teammate
|
|
150
|
+
* can exist yet; any other read failure rejects so it is not reported as "no".
|
|
151
|
+
*/
|
|
152
|
+
export async function hasInvitedTeammate(ctx: Ctx): Promise<boolean> {
|
|
153
|
+
const orgId = ctx?.orgId;
|
|
154
|
+
if (!orgId) return false;
|
|
155
|
+
try {
|
|
156
|
+
const db = getDbExec();
|
|
157
|
+
const members = await db.execute({
|
|
158
|
+
sql: `SELECT 1 FROM org_members
|
|
159
|
+
WHERE org_id = ? AND federation_removal_pending_at IS NULL
|
|
160
|
+
LIMIT 2`,
|
|
161
|
+
args: [orgId],
|
|
162
|
+
});
|
|
163
|
+
if (members.rows.length > 1) return true;
|
|
164
|
+
const invitations = await db.execute({
|
|
165
|
+
sql: `SELECT 1 FROM org_invitations
|
|
166
|
+
WHERE org_id = ? AND status = 'pending'
|
|
167
|
+
LIMIT 1`,
|
|
168
|
+
args: [orgId],
|
|
169
|
+
});
|
|
170
|
+
return invitations.rows.length > 0;
|
|
171
|
+
} catch (error) {
|
|
172
|
+
if (isMissingOrganizationTableError(error)) return false;
|
|
173
|
+
throw error;
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
/** The user saved a design as a template of their own. */
|
|
178
|
+
export async function hasSavedTemplate(ctx: Ctx): Promise<boolean> {
|
|
179
|
+
const email = ownerEmailOf(ctx);
|
|
180
|
+
if (!email) return false;
|
|
181
|
+
const rows = await getDb()
|
|
182
|
+
.select({ id: schema.designTemplates.id })
|
|
183
|
+
.from(schema.designTemplates)
|
|
184
|
+
.where(
|
|
185
|
+
and(
|
|
186
|
+
accessFilter(schema.designTemplates, schema.designTemplateShares),
|
|
187
|
+
ownedBy(schema.designTemplates.ownerEmail, email),
|
|
188
|
+
),
|
|
189
|
+
)
|
|
190
|
+
.limit(1);
|
|
191
|
+
return rows.length > 0;
|
|
192
|
+
}
|
|
193
|
+
|
|
194
|
+
type GettingStartedStep = Pick<
|
|
195
|
+
OnboardingStep,
|
|
196
|
+
| "id"
|
|
197
|
+
| "order"
|
|
198
|
+
| "title"
|
|
199
|
+
| "description"
|
|
200
|
+
| "href"
|
|
201
|
+
| "isAvailable"
|
|
202
|
+
| "isComplete"
|
|
203
|
+
>;
|
|
204
|
+
|
|
205
|
+
export const GETTING_STARTED_STEPS: GettingStartedStep[] = [
|
|
206
|
+
{
|
|
207
|
+
id: "create-design",
|
|
208
|
+
order: 10,
|
|
209
|
+
title: "Create your first design",
|
|
210
|
+
description: "Describe what you want and let the agent build it.",
|
|
211
|
+
href: "/home",
|
|
212
|
+
isComplete: hasOwnDesign,
|
|
213
|
+
},
|
|
214
|
+
{
|
|
215
|
+
id: "add-brand",
|
|
216
|
+
order: 20,
|
|
217
|
+
title: "Add your brand",
|
|
218
|
+
description: "Set up a design system with your colors, type, and logo.",
|
|
219
|
+
href: "/design-systems/setup",
|
|
220
|
+
isAvailable: canAddBrand,
|
|
221
|
+
isComplete: hasOwnBrand,
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
id: "use-real-data",
|
|
225
|
+
order: 30,
|
|
226
|
+
title: "Use your real data",
|
|
227
|
+
description: "Connect a running app so designs start from real screens.",
|
|
228
|
+
href: "/settings/integrations",
|
|
229
|
+
isComplete: hasConnectedDataSource,
|
|
230
|
+
},
|
|
231
|
+
{
|
|
232
|
+
id: "share-feedback",
|
|
233
|
+
order: 40,
|
|
234
|
+
title: "Share for feedback",
|
|
235
|
+
description: "Share a design with someone or publish a link.",
|
|
236
|
+
href: "/home",
|
|
237
|
+
isComplete: hasSharedDesign,
|
|
238
|
+
},
|
|
239
|
+
{
|
|
240
|
+
id: "invite-teammate",
|
|
241
|
+
order: 50,
|
|
242
|
+
title: "Invite a teammate",
|
|
243
|
+
description: "Add someone to your organization.",
|
|
244
|
+
href: "/settings/organization",
|
|
245
|
+
isComplete: hasInvitedTeammate,
|
|
246
|
+
},
|
|
247
|
+
{
|
|
248
|
+
id: "save-template",
|
|
249
|
+
order: 60,
|
|
250
|
+
title: "Save a design as a template",
|
|
251
|
+
description: "Turn a finished design into something your team can reuse.",
|
|
252
|
+
href: "/home",
|
|
253
|
+
isComplete: hasSavedTemplate,
|
|
254
|
+
},
|
|
255
|
+
];
|
|
256
|
+
|
|
257
|
+
/** Safe to call from every entry point that reads the checklist; a repeat replaces the same ids. */
|
|
258
|
+
export function registerGettingStartedSteps(): void {
|
|
259
|
+
for (const step of GETTING_STARTED_STEPS) {
|
|
260
|
+
registerOnboardingStep({
|
|
261
|
+
...step,
|
|
262
|
+
checklist: GETTING_STARTED_CHECKLIST,
|
|
263
|
+
required: false,
|
|
264
|
+
methods: [],
|
|
265
|
+
});
|
|
266
|
+
}
|
|
267
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
import type { DesignTemplatePreset } from "../design-template-presets.js";
|
|
2
|
+
import { presetDocument } from "./doc.js";
|
|
3
|
+
|
|
4
|
+
const C = {
|
|
5
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
6
|
+
canvas: "#EEF1F8",
|
|
7
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
8
|
+
paper: "#FFFFFF",
|
|
9
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
10
|
+
ink: "#1C2033",
|
|
11
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
12
|
+
muted: "#6B7190",
|
|
13
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
14
|
+
line: "#E3E7F2",
|
|
15
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
16
|
+
indigo: "#6F6BE8",
|
|
17
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
18
|
+
lilac: "#C9C6FA",
|
|
19
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
20
|
+
sky: "#CFE3FF",
|
|
21
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
22
|
+
teal: "#2FB5A8",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const bars = [
|
|
26
|
+
["Direct", 92],
|
|
27
|
+
["Search", 78],
|
|
28
|
+
["Referral", 61],
|
|
29
|
+
["Social", 47],
|
|
30
|
+
["Email", 34],
|
|
31
|
+
]
|
|
32
|
+
.map(
|
|
33
|
+
([label, value]) =>
|
|
34
|
+
`<li><span>${label}</span><i style="width:${Number(value) * 4.4}px"></i><b>${value}%</b></li>`,
|
|
35
|
+
)
|
|
36
|
+
.join("");
|
|
37
|
+
|
|
38
|
+
export const analyticsDashboard: DesignTemplatePreset = {
|
|
39
|
+
id: "preset-analytics-dashboard",
|
|
40
|
+
title: "Analytics dashboard",
|
|
41
|
+
description: "Track KPIs and metrics in one place.",
|
|
42
|
+
category: "other",
|
|
43
|
+
width: 1440,
|
|
44
|
+
height: 900,
|
|
45
|
+
filename: "analytics-dashboard.html",
|
|
46
|
+
content: presetDocument({
|
|
47
|
+
title: "Lumen — Analytics dashboard",
|
|
48
|
+
width: 1440,
|
|
49
|
+
height: 900,
|
|
50
|
+
fonts: "family=Inter:wght@400;500;600;700",
|
|
51
|
+
palette: {
|
|
52
|
+
canvas: C.canvas,
|
|
53
|
+
paper: C.paper,
|
|
54
|
+
ink: C.ink,
|
|
55
|
+
muted: C.muted,
|
|
56
|
+
line: C.line,
|
|
57
|
+
indigo: C.indigo,
|
|
58
|
+
lilac: C.lilac,
|
|
59
|
+
sky: C.sky,
|
|
60
|
+
teal: C.teal,
|
|
61
|
+
},
|
|
62
|
+
css: `
|
|
63
|
+
.artboard { color:var(--ink); font-family:'Inter', sans-serif; }
|
|
64
|
+
.sidebar { position:absolute; left:0; top:0; bottom:0; width:240px; z-index:1; padding:84px 20px 24px; background:var(--paper); border-right:1px solid var(--line); }
|
|
65
|
+
.sidebar li { display:flex; align-items:center; gap:12px; height:42px; padding:0 14px; border-radius:10px; color:var(--muted); font-size:15px; font-weight:500; }
|
|
66
|
+
.sidebar li::before { content:""; width:16px; height:16px; border-radius:5px; background:var(--line); }
|
|
67
|
+
.sidebar li.active { background:var(--canvas); color:var(--ink); }
|
|
68
|
+
.sidebar li.active::before { background:var(--indigo); }
|
|
69
|
+
.head { position:absolute; left:288px; right:48px; top:36px; z-index:1; display:flex; justify-content:space-between; align-items:center; }
|
|
70
|
+
.head h1 { font-size:30px; font-weight:700; letter-spacing:-.02em; }
|
|
71
|
+
.range { padding:10px 16px; border:1px solid var(--line); border-radius:999px; background:var(--paper); color:var(--muted); font-size:14px; font-weight:500; }
|
|
72
|
+
.stats { position:absolute; left:288px; right:48px; top:116px; z-index:1; display:grid; grid-template-columns:repeat(4,1fr); gap:20px; }
|
|
73
|
+
.stat { padding:22px 24px; border-radius:16px; background:var(--paper); border:1px solid var(--line); }
|
|
74
|
+
.stat small { display:block; color:var(--muted); font-size:14px; font-weight:400; }
|
|
75
|
+
.stat strong { display:block; margin-top:10px; font-size:36px; font-weight:700; letter-spacing:-.03em; }
|
|
76
|
+
.stat em { display:block; margin-top:6px; color:var(--teal); font-size:13px; font-style:normal; font-weight:600; }
|
|
77
|
+
.stat.hot { background:var(--indigo); border-color:var(--indigo); color:var(--paper); }
|
|
78
|
+
.stat.hot small, .stat.hot em { color:var(--lilac); }
|
|
79
|
+
.card { position:absolute; z-index:1; padding:26px 28px; border-radius:16px; background:var(--paper); border:1px solid var(--line); }
|
|
80
|
+
.card h2 { font-size:18px; font-weight:600; letter-spacing:-.01em; }
|
|
81
|
+
.revenue { left:288px; top:300px; width:520px; height:552px; }
|
|
82
|
+
.revenue ul { margin-top:28px; display:grid; gap:22px; }
|
|
83
|
+
.revenue li { display:grid; grid-template-columns:84px auto 1fr; align-items:center; gap:14px; font-size:14px; font-weight:500; color:var(--muted); }
|
|
84
|
+
.revenue i { display:block; height:22px; border-radius:6px; background:linear-gradient(90deg, var(--indigo), var(--lilac)); }
|
|
85
|
+
.revenue b { color:var(--ink); font-weight:600; text-align:right; }
|
|
86
|
+
.engagement { left:832px; top:300px; right:48px; height:552px; }
|
|
87
|
+
.engagement svg { position:absolute; left:28px; right:28px; bottom:84px; width:calc(100% - 56px); height:300px; }
|
|
88
|
+
.engagement .axis { position:absolute; left:28px; right:28px; bottom:40px; display:flex; justify-content:space-between; color:var(--muted); font-size:13px; font-weight:500; }
|
|
89
|
+
.pill { position:absolute; right:28px; top:24px; padding:6px 12px; border-radius:999px; background:var(--sky); color:var(--indigo); font-size:13px; font-weight:600; }
|
|
90
|
+
`,
|
|
91
|
+
body: `
|
|
92
|
+
<div style="position:absolute;inset:0;background:${C.canvas}" data-agent-native-node-id="template-background" data-agent-native-layer-name="Background" data-agent-native-locked="true"></div>
|
|
93
|
+
<aside class="sidebar" data-agent-native-node-id="sidebar" data-agent-native-layer-name="Sidebar">
|
|
94
|
+
<ul>
|
|
95
|
+
<li class="active">Overview</li><li>Audience</li><li>Revenue</li><li>Campaigns</li><li>Reports</li><li>Settings</li>
|
|
96
|
+
</ul>
|
|
97
|
+
</aside>
|
|
98
|
+
<div style="position:absolute;left:24px;top:28px;z-index:2;display:flex;align-items:center;gap:10px;color:${C.ink};font:700 20px/1 'Inter',sans-serif;letter-spacing:-.02em" data-agent-native-node-id="template-logo" data-agent-native-layer-name="Logo" data-agent-native-locked="true">
|
|
99
|
+
<svg width="28" height="28" viewBox="0 0 28 28" aria-hidden="true"><rect width="28" height="28" rx="8" fill="${C.indigo}"/><circle cx="14" cy="14" r="5" fill="${C.paper}"/></svg>
|
|
100
|
+
<span>Lumen</span>
|
|
101
|
+
</div>
|
|
102
|
+
<header class="head" data-agent-native-node-id="header" data-agent-native-layer-name="Header">
|
|
103
|
+
<h1>Overview</h1>
|
|
104
|
+
<span class="range">Last 30 days</span>
|
|
105
|
+
</header>
|
|
106
|
+
<section class="stats" data-agent-native-node-id="stats" data-agent-native-layer-name="Stats">
|
|
107
|
+
<div class="stat"><small>Total users</small><strong>1.2M</strong><em>+8.2% vs last month</em></div>
|
|
108
|
+
<div class="stat"><small>Conversion rate</small><strong>4.8%</strong><em>+0.6 pts</em></div>
|
|
109
|
+
<div class="stat hot"><small>New sign-ups</small><strong>25,000</strong><em>+12.4% vs last month</em></div>
|
|
110
|
+
<div class="stat"><small>Avg. session</small><strong>6m 12s</strong><em>+14s</em></div>
|
|
111
|
+
</section>
|
|
112
|
+
<section class="card revenue" data-agent-native-node-id="revenue" data-agent-native-layer-name="Revenue by channel">
|
|
113
|
+
<h2>Revenue by channel</h2>
|
|
114
|
+
<ul>${bars}</ul>
|
|
115
|
+
</section>
|
|
116
|
+
<section class="card engagement" data-agent-native-node-id="engagement" data-agent-native-layer-name="User engagement">
|
|
117
|
+
<h2>User engagement over time</h2>
|
|
118
|
+
<span class="pill">+18% this quarter</span>
|
|
119
|
+
<svg viewBox="0 0 520 300" preserveAspectRatio="none" aria-hidden="true">
|
|
120
|
+
<path d="M0 240 C60 220 90 150 150 170 S250 250 310 150 S420 60 520 40 L520 300 L0 300 Z" fill="${C.sky}" opacity=".7"/>
|
|
121
|
+
<path d="M0 240 C60 220 90 150 150 170 S250 250 310 150 S420 60 520 40" fill="none" stroke="${C.indigo}" stroke-width="4" stroke-linecap="round"/>
|
|
122
|
+
<path d="M0 270 C80 250 120 230 190 235 S330 200 390 190 S470 170 520 150" fill="none" stroke="${C.teal}" stroke-width="3" stroke-linecap="round" stroke-dasharray="2 8"/>
|
|
123
|
+
</svg>
|
|
124
|
+
<div class="axis"><span>Jan</span><span>Feb</span><span>Mar</span><span>Apr</span><span>May</span><span>Jun</span></div>
|
|
125
|
+
</section>`,
|
|
126
|
+
}),
|
|
127
|
+
};
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
import type { DesignTemplatePreset } from "../design-template-presets.js";
|
|
2
|
+
import { presetDocument } from "./doc.js";
|
|
3
|
+
|
|
4
|
+
const C = {
|
|
5
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
6
|
+
canvas: "#ECE8EF",
|
|
7
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
8
|
+
paper: "#FFFFFF",
|
|
9
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
10
|
+
ink: "#241F31",
|
|
11
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
12
|
+
muted: "#7A748A",
|
|
13
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
14
|
+
line: "#DAD4E2",
|
|
15
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
16
|
+
pink: "#E8447A",
|
|
17
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
18
|
+
violet: "#7A5CF0",
|
|
19
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
20
|
+
teal: "#27B5A6",
|
|
21
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
22
|
+
amber: "#F2A33A",
|
|
23
|
+
};
|
|
24
|
+
|
|
25
|
+
const swatches = [C.pink, C.violet, C.teal, C.amber, C.ink, C.line]
|
|
26
|
+
.map((color) => `<i style="background:${color}"></i>`)
|
|
27
|
+
.join("");
|
|
28
|
+
|
|
29
|
+
export const designStudio: DesignTemplatePreset = {
|
|
30
|
+
id: "preset-design-studio",
|
|
31
|
+
title: "Design studio",
|
|
32
|
+
description: "Create and explore visual ideas.",
|
|
33
|
+
category: "other",
|
|
34
|
+
width: 1440,
|
|
35
|
+
height: 900,
|
|
36
|
+
filename: "design-studio.html",
|
|
37
|
+
content: presetDocument({
|
|
38
|
+
title: "Atelier — Design studio",
|
|
39
|
+
width: 1440,
|
|
40
|
+
height: 900,
|
|
41
|
+
fonts: "family=Space+Grotesk:wght@400;500;700",
|
|
42
|
+
palette: {
|
|
43
|
+
canvas: C.canvas,
|
|
44
|
+
paper: C.paper,
|
|
45
|
+
ink: C.ink,
|
|
46
|
+
muted: C.muted,
|
|
47
|
+
line: C.line,
|
|
48
|
+
pink: C.pink,
|
|
49
|
+
violet: C.violet,
|
|
50
|
+
teal: C.teal,
|
|
51
|
+
amber: C.amber,
|
|
52
|
+
},
|
|
53
|
+
css: `
|
|
54
|
+
.artboard { color:var(--ink); font-family:'Space Grotesk', sans-serif; }
|
|
55
|
+
.toolbar { position:absolute; left:24px; top:96px; z-index:1; display:grid; gap:12px; padding:12px; border-radius:18px; background:var(--paper); border:1px solid var(--line); }
|
|
56
|
+
.toolbar i { display:block; width:44px; height:44px; border-radius:12px; background:var(--canvas); }
|
|
57
|
+
.toolbar i:first-child { background:var(--pink); }
|
|
58
|
+
.menubar { position:absolute; left:96px; right:24px; top:24px; z-index:1; display:flex; align-items:center; gap:28px; height:48px; padding:0 24px; border-radius:14px; background:var(--paper); border:1px solid var(--line); color:var(--muted); font-size:15px; font-weight:500; }
|
|
59
|
+
.menubar b { margin-left:auto; padding:8px 16px; border-radius:999px; background:var(--ink); color:var(--paper); font-size:14px; font-weight:700; }
|
|
60
|
+
.stage { position:absolute; left:96px; top:96px; right:376px; bottom:24px; z-index:1; border-radius:24px; background:var(--paper); border:1px solid var(--line); overflow:hidden; }
|
|
61
|
+
.shape { position:absolute; }
|
|
62
|
+
.tri { left:210px; top:150px; width:0; height:0; border-left:200px solid transparent; border-right:200px solid transparent; border-bottom:350px solid var(--pink); }
|
|
63
|
+
.blob { left:450px; top:130px; width:340px; height:300px; border-radius:58% 42% 55% 45% / 48% 58% 42% 52%; background:var(--violet); opacity:.82; }
|
|
64
|
+
.circle { left:380px; top:360px; width:240px; height:240px; border-radius:50%; background:var(--teal); opacity:.78; }
|
|
65
|
+
.square { left:640px; top:380px; width:210px; height:210px; border-radius:36px; background:var(--amber); transform:rotate(12deg); opacity:.9; }
|
|
66
|
+
.panel { position:absolute; right:24px; top:96px; bottom:24px; width:328px; z-index:1; padding:26px; border-radius:24px; background:var(--paper); border:1px solid var(--line); }
|
|
67
|
+
.panel h2 { color:var(--muted); font-size:12px; font-weight:700; letter-spacing:.12em; text-transform:uppercase; }
|
|
68
|
+
.swatches { display:grid; grid-template-columns:repeat(3,1fr); gap:12px; margin-top:16px; }
|
|
69
|
+
.swatches i { display:block; aspect-ratio:1; border-radius:50%; }
|
|
70
|
+
.sliders { display:grid; gap:26px; margin-top:34px; }
|
|
71
|
+
.sliders p { display:flex; justify-content:space-between; color:var(--muted); font-size:14px; font-weight:400; }
|
|
72
|
+
.sliders em { font-style:normal; }
|
|
73
|
+
.sliders > div > span { display:block; height:6px; margin-top:12px; border-radius:3px; background:var(--line); }
|
|
74
|
+
.sliders > div > span b { display:block; height:100%; border-radius:3px; background:var(--violet); }
|
|
75
|
+
`,
|
|
76
|
+
body: `
|
|
77
|
+
<div style="position:absolute;inset:0;background:${C.canvas}" data-agent-native-node-id="template-background" data-agent-native-layer-name="Background" data-agent-native-locked="true"></div>
|
|
78
|
+
<div style="position:absolute;left:24px;top:30px;z-index:2;display:flex;align-items:center;gap:8px;color:${C.ink};font:700 22px/1 'Space Grotesk',sans-serif;letter-spacing:-.03em" data-agent-native-node-id="template-logo" data-agent-native-layer-name="Logo" data-agent-native-locked="true">
|
|
79
|
+
<svg width="30" height="30" viewBox="0 0 30 30" aria-hidden="true"><rect width="30" height="30" rx="9" fill="${C.ink}"/><path d="M15 7l8 15H7z" fill="${C.pink}"/></svg>
|
|
80
|
+
</div>
|
|
81
|
+
<header class="menubar" data-agent-native-node-id="menubar" data-agent-native-layer-name="Menu bar">
|
|
82
|
+
<span>File</span><span>Edit</span><span>View</span><span>Arrange</span><b>Share</b>
|
|
83
|
+
</header>
|
|
84
|
+
<nav class="toolbar" data-agent-native-node-id="toolbar" data-agent-native-layer-name="Toolbar"><i></i><i></i><i></i><i></i><i></i></nav>
|
|
85
|
+
<section class="stage" data-agent-native-node-id="stage" data-agent-native-layer-name="Canvas">
|
|
86
|
+
<div class="shape tri"></div><div class="shape blob"></div><div class="shape circle"></div><div class="shape square"></div>
|
|
87
|
+
</section>
|
|
88
|
+
<aside class="panel" data-agent-native-node-id="inspector" data-agent-native-layer-name="Inspector">
|
|
89
|
+
<h2>Palette</h2>
|
|
90
|
+
<div class="swatches">${swatches}</div>
|
|
91
|
+
<div class="sliders">
|
|
92
|
+
<div><p><em>Opacity</em><em>82%</em></p><span><b style="width:82%"></b></span></div>
|
|
93
|
+
<div><p><em>Blur</em><em>24</em></p><span><b style="width:36%"></b></span></div>
|
|
94
|
+
<div><p><em>Rotation</em><em>12°</em></p><span><b style="width:14%"></b></span></div>
|
|
95
|
+
</div>
|
|
96
|
+
</aside>`,
|
|
97
|
+
}),
|
|
98
|
+
};
|
|
@@ -0,0 +1,101 @@
|
|
|
1
|
+
import type { DesignTemplatePreset } from "../design-template-presets.js";
|
|
2
|
+
import { presetDocument } from "./doc.js";
|
|
3
|
+
|
|
4
|
+
const C = {
|
|
5
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
6
|
+
canvas: "#EDEFE4",
|
|
7
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
8
|
+
paper: "#FFFFFF",
|
|
9
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
10
|
+
ink: "#1F2A24",
|
|
11
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
12
|
+
muted: "#6F7A73",
|
|
13
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
14
|
+
line: "#DDE2D5",
|
|
15
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
16
|
+
green: "#79B98B",
|
|
17
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
18
|
+
greenDeep: "#2F7D4B",
|
|
19
|
+
// guard:allow-raw-color — authored template palette, not app chrome.
|
|
20
|
+
bubble: "#F7F8F2",
|
|
21
|
+
};
|
|
22
|
+
|
|
23
|
+
const people = [
|
|
24
|
+
["Anna", "Are we still on for 3?", "A"],
|
|
25
|
+
["Ben", "Sent the latest draft", "B"],
|
|
26
|
+
["Chloe", "Thanks, that works!", "C"],
|
|
27
|
+
["Dev team", "Release notes are live", "D"],
|
|
28
|
+
["Elena", "Can you review this?", "E"],
|
|
29
|
+
]
|
|
30
|
+
.map(
|
|
31
|
+
([name, preview, initial], index) =>
|
|
32
|
+
`<li${index === 1 ? ' class="active"' : ""}><span class="avatar">${initial}</span><div><b>${name}</b><small>${preview}</small></div></li>`,
|
|
33
|
+
)
|
|
34
|
+
.join("");
|
|
35
|
+
|
|
36
|
+
export const messagingApp: DesignTemplatePreset = {
|
|
37
|
+
id: "preset-messaging-app",
|
|
38
|
+
title: "Messaging app",
|
|
39
|
+
description: "Build a fast, modern chat experience.",
|
|
40
|
+
category: "other",
|
|
41
|
+
width: 1440,
|
|
42
|
+
height: 900,
|
|
43
|
+
filename: "messaging-app.html",
|
|
44
|
+
content: presetDocument({
|
|
45
|
+
title: "Relay — Messaging app",
|
|
46
|
+
width: 1440,
|
|
47
|
+
height: 900,
|
|
48
|
+
fonts: "family=DM+Sans:wght@400;500;700",
|
|
49
|
+
palette: {
|
|
50
|
+
canvas: C.canvas,
|
|
51
|
+
paper: C.paper,
|
|
52
|
+
ink: C.ink,
|
|
53
|
+
muted: C.muted,
|
|
54
|
+
line: C.line,
|
|
55
|
+
green: C.green,
|
|
56
|
+
deep: C.greenDeep,
|
|
57
|
+
bubble: C.bubble,
|
|
58
|
+
},
|
|
59
|
+
css: `
|
|
60
|
+
.artboard { color:var(--ink); font-family:'DM Sans', sans-serif; }
|
|
61
|
+
.inbox { position:absolute; left:0; top:0; bottom:0; width:360px; z-index:1; padding:88px 16px 24px; background:var(--paper); border-right:1px solid var(--line); }
|
|
62
|
+
.inbox li { display:flex; align-items:center; gap:14px; padding:14px; border-radius:14px; }
|
|
63
|
+
.inbox li.active { background:var(--canvas); }
|
|
64
|
+
.avatar { display:grid; place-items:center; flex:none; width:44px; height:44px; border-radius:50%; background:var(--green); color:var(--paper); font-size:17px; font-weight:700; }
|
|
65
|
+
.inbox b { display:block; font-size:16px; font-weight:700; }
|
|
66
|
+
.inbox small { display:block; margin-top:3px; color:var(--muted); font-size:14px; }
|
|
67
|
+
.thread-head { position:absolute; left:360px; right:0; top:0; z-index:1; display:flex; align-items:center; gap:14px; height:84px; padding:0 40px; border-bottom:1px solid var(--line); background:color-mix(in srgb, var(--paper) 80%, transparent); }
|
|
68
|
+
.thread-head b { font-size:18px; font-weight:700; }
|
|
69
|
+
.thread-head small { display:block; color:var(--deep); font-size:13px; font-weight:500; }
|
|
70
|
+
.thread { position:absolute; left:360px; right:0; top:84px; bottom:112px; z-index:1; display:flex; flex-direction:column; justify-content:flex-start; gap:16px; padding:48px 64px 0; }
|
|
71
|
+
.msg { max-width:520px; padding:16px 20px; border-radius:20px; font-size:18px; line-height:1.4; background:var(--bubble); border:1px solid var(--line); }
|
|
72
|
+
.msg.me { align-self:flex-end; background:var(--green); border-color:var(--green); color:var(--paper); border-bottom-right-radius:6px; }
|
|
73
|
+
.msg.them { border-bottom-left-radius:6px; }
|
|
74
|
+
.composer { position:absolute; left:424px; right:64px; bottom:32px; z-index:1; display:flex; align-items:center; justify-content:space-between; height:64px; padding:0 12px 0 28px; border-radius:999px; background:var(--paper); border:1px solid var(--line); color:var(--muted); font-size:17px; }
|
|
75
|
+
.send { display:grid; place-items:center; width:44px; height:44px; border-radius:50%; background:var(--deep); }
|
|
76
|
+
`,
|
|
77
|
+
body: `
|
|
78
|
+
<div style="position:absolute;inset:0;background:${C.canvas}" data-agent-native-node-id="template-background" data-agent-native-layer-name="Background" data-agent-native-locked="true"></div>
|
|
79
|
+
<aside class="inbox" data-agent-native-node-id="inbox" data-agent-native-layer-name="Inbox">
|
|
80
|
+
<ul>${people}</ul>
|
|
81
|
+
</aside>
|
|
82
|
+
<div style="position:absolute;left:24px;top:28px;z-index:2;display:flex;align-items:center;gap:10px;color:${C.ink};font:700 22px/1 'DM Sans',sans-serif;letter-spacing:-.02em" data-agent-native-node-id="template-logo" data-agent-native-layer-name="Logo" data-agent-native-locked="true">
|
|
83
|
+
<svg width="28" height="28" viewBox="0 0 28 28" aria-hidden="true"><rect width="28" height="28" rx="14" fill="${C.greenDeep}"/><path d="M8 13h12M8 17h7" stroke="${C.paper}" stroke-width="2.4" stroke-linecap="round"/></svg>
|
|
84
|
+
<span>Relay</span>
|
|
85
|
+
</div>
|
|
86
|
+
<header class="thread-head" data-agent-native-node-id="thread-header" data-agent-native-layer-name="Thread header">
|
|
87
|
+
<span class="avatar">B</span>
|
|
88
|
+
<div><b>Ben</b><small>Online</small></div>
|
|
89
|
+
</header>
|
|
90
|
+
<section class="thread" data-agent-native-node-id="thread" data-agent-native-layer-name="Conversation">
|
|
91
|
+
<p class="msg them">Hey, how are you?</p>
|
|
92
|
+
<p class="msg me">I'm good, thanks! Just got it.</p>
|
|
93
|
+
<p class="msg them">Did you get my email?</p>
|
|
94
|
+
<p class="msg me">Reading it now, looks promising!</p>
|
|
95
|
+
</section>
|
|
96
|
+
<div class="composer" data-agent-native-node-id="composer" data-agent-native-layer-name="Composer">
|
|
97
|
+
<span>Type a message</span>
|
|
98
|
+
<span class="send"><svg width="20" height="20" viewBox="0 0 20 20" aria-hidden="true"><path d="M3 10h13M11 5l5 5-5 5" fill="none" stroke="${C.paper}" stroke-width="2.2" stroke-linecap="round" stroke-linejoin="round"/></svg></span>
|
|
99
|
+
</div>`,
|
|
100
|
+
}),
|
|
101
|
+
};
|