@wervt/nuxt 0.2.15 → 0.3.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/README.md +2 -1
- package/dist/dev.d.ts +5 -0
- package/dist/dev.js +23 -3
- package/dist/module.js +50 -7
- package/dist/provision.d.ts +5 -1
- package/dist/provision.js +12 -1
- package/dist/route-tools.js +44 -0
- package/dist/runtime/app/useShape.d.ts +32 -11
- package/dist/runtime/app/useShape.js +104 -42
- package/dist/runtime/email/components.d.ts +71 -10
- package/dist/runtime/email/components.js +445 -98
- package/dist/runtime/email/render.js +4 -0
- package/dist/runtime/server/index.d.ts +5 -3
- package/dist/runtime/server/index.js +4 -3
- package/dist/runtime/server/mcp.js +2 -6
- package/dist/runtime/server/seed.d.ts +18 -0
- package/dist/runtime/server/seed.js +27 -0
- package/dist/runtime/server/shape.d.ts +12 -5
- package/dist/runtime/server/shape.js +3 -1
- package/dist/runtime/server/tool-handlers.d.ts +5 -0
- package/dist/runtime/server/tool-handlers.js +37 -13
- package/dist/runtime/server/tools.d.ts +36 -0
- package/dist/runtime/server/tools.js +53 -1
- package/dist/runtime/server/validate.d.ts +1 -0
- package/dist/runtime/server/validate.js +1 -1
- package/dist/runtime/shared/shape.d.ts +18 -0
- package/dist/runtime/shared/shape.js +16 -0
- package/dist/seed.js +52 -0
- package/dist/shapes.js +70 -0
- package/package.json +1 -1
|
@@ -5,21 +5,58 @@ const SUBJECT_KEY = Symbol("wervt-email-subject");
|
|
|
5
5
|
const emailTheme = {
|
|
6
6
|
page: "#fafafa",
|
|
7
7
|
card: "#ffffff",
|
|
8
|
-
border: "#
|
|
9
|
-
|
|
8
|
+
border: "#e5e5e5",
|
|
9
|
+
rule: "#d4d4d4",
|
|
10
|
+
text: "#262626",
|
|
10
11
|
highlighted: "#0a0a0a",
|
|
11
12
|
muted: "#666666",
|
|
12
13
|
dimmed: "#8f8f8f",
|
|
13
|
-
|
|
14
|
+
accent: "#2f5bff",
|
|
15
|
+
accentSoft: "#eef2ff",
|
|
16
|
+
accentBorder: "#d6defe",
|
|
17
|
+
band: "#0a0b0f",
|
|
18
|
+
bandText: "#d4d7de",
|
|
19
|
+
bandDimmed: "#6b7080",
|
|
20
|
+
button: "#2f5bff",
|
|
14
21
|
buttonText: "#ffffff",
|
|
15
|
-
codeBackground: "#
|
|
16
|
-
radius: "
|
|
22
|
+
codeBackground: "#f6f8ff",
|
|
23
|
+
radius: "8px",
|
|
17
24
|
font: "Poppins, -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif",
|
|
18
|
-
mono: "'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace"
|
|
25
|
+
mono: "'Geist Mono', ui-monospace, SFMono-Regular, Menlo, Consolas, monospace",
|
|
26
|
+
/** Where the logo images live. PNG, because Gmail and Outlook don't show SVG. */
|
|
27
|
+
assets: "https://wervt.app/email",
|
|
28
|
+
site: "https://wervt.app",
|
|
29
|
+
docs: "https://wervt.app/getting-started/introduction"
|
|
19
30
|
};
|
|
20
31
|
const t = emailTheme;
|
|
32
|
+
const darkStyles = `
|
|
33
|
+
:root { color-scheme: light dark; supported-color-schemes: light dark; }
|
|
34
|
+
@media (prefers-color-scheme: dark) {
|
|
35
|
+
.wv-page { background: #0a0a0a !important; }
|
|
36
|
+
.wv-card { background: #111113 !important; }
|
|
37
|
+
.wv-foot { background: #0a0a0a !important; }
|
|
38
|
+
.wv-frame { border-color: #262626 !important; }
|
|
39
|
+
.wv-line { background: #262626 !important; }
|
|
40
|
+
.wv-mark { background: #6b6b6b !important; }
|
|
41
|
+
.wv-sep { color: #404040 !important; }
|
|
42
|
+
.wv-text { color: #e5e5e5 !important; }
|
|
43
|
+
.wv-strong { color: #fafafa !important; }
|
|
44
|
+
.wv-muted { color: #a1a1a1 !important; }
|
|
45
|
+
.wv-accent { color: #7c9bff !important; }
|
|
46
|
+
.wv-code { background: #151a2e !important; border-color: #26304f !important; color: #fafafa !important; }
|
|
47
|
+
}
|
|
48
|
+
[data-ogsc] .wv-text { color: #e5e5e5 !important; }
|
|
49
|
+
[data-ogsc] .wv-strong { color: #fafafa !important; }
|
|
50
|
+
[data-ogsc] .wv-muted { color: #a1a1a1 !important; }
|
|
51
|
+
@media only screen and (max-width: 480px) {
|
|
52
|
+
.wv-pad { padding-left: 24px !important; padding-right: 24px !important; }
|
|
53
|
+
.wv-hero { font-size: 22px !important; line-height: 30px !important; }
|
|
54
|
+
.wv-codetext { font-size: 28px !important; letter-spacing: 6px !important; }
|
|
55
|
+
}
|
|
56
|
+
`;
|
|
21
57
|
/**
|
|
22
|
-
* The whole email: document, preheader,
|
|
58
|
+
* The whole email: document, preheader, header with the logo, body and footer. Put it at the
|
|
59
|
+
* root of every template.
|
|
23
60
|
*
|
|
24
61
|
* ```vue
|
|
25
62
|
* <WervtEmail subject="Your code" app="kontor"> … </WervtEmail>
|
|
@@ -33,7 +70,7 @@ const WervtEmail = defineComponent({
|
|
|
33
70
|
type: String,
|
|
34
71
|
required: true
|
|
35
72
|
},
|
|
36
|
-
/**
|
|
73
|
+
/** The app that sends the mail, shown in the header and the footer. */
|
|
37
74
|
app: {
|
|
38
75
|
type: String,
|
|
39
76
|
default: "wervt"
|
|
@@ -43,10 +80,15 @@ const WervtEmail = defineComponent({
|
|
|
43
80
|
type: String,
|
|
44
81
|
default: ""
|
|
45
82
|
},
|
|
46
|
-
/** Replaces the footer
|
|
83
|
+
/** Replaces the footer's "Sent by <app> via wervt" line. */
|
|
47
84
|
footer: {
|
|
48
85
|
type: String,
|
|
49
86
|
default: ""
|
|
87
|
+
},
|
|
88
|
+
/** Why the recipient got this mail, shown small in the footer. */
|
|
89
|
+
reason: {
|
|
90
|
+
type: String,
|
|
91
|
+
default: ""
|
|
50
92
|
}
|
|
51
93
|
},
|
|
52
94
|
setup(props, { slots }) {
|
|
@@ -59,22 +101,26 @@ const WervtEmail = defineComponent({
|
|
|
59
101
|
}),
|
|
60
102
|
h("meta", {
|
|
61
103
|
name: "color-scheme",
|
|
62
|
-
content: "light"
|
|
104
|
+
content: "light dark"
|
|
63
105
|
}),
|
|
64
106
|
h("meta", {
|
|
65
107
|
name: "supported-color-schemes",
|
|
66
|
-
content: "light"
|
|
108
|
+
content: "light dark"
|
|
67
109
|
}),
|
|
68
110
|
h("title", props.subject),
|
|
69
111
|
h("link", {
|
|
70
112
|
rel: "stylesheet",
|
|
71
|
-
href: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&display=swap"
|
|
72
|
-
})
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
113
|
+
href: "https://fonts.googleapis.com/css2?family=Poppins:wght@400;500;600&family=Geist+Mono:wght@400;500;600&display=swap"
|
|
114
|
+
}),
|
|
115
|
+
h("style", { innerHTML: darkStyles })
|
|
116
|
+
]), h("body", {
|
|
117
|
+
class: "wv-page",
|
|
118
|
+
style: {
|
|
119
|
+
margin: 0,
|
|
120
|
+
padding: 0,
|
|
121
|
+
background: t.page
|
|
122
|
+
}
|
|
123
|
+
}, [props.preview ? h("div", {
|
|
78
124
|
class: "wervt-preheader",
|
|
79
125
|
style: {
|
|
80
126
|
display: "none",
|
|
@@ -88,75 +134,333 @@ const WervtEmail = defineComponent({
|
|
|
88
134
|
}
|
|
89
135
|
}, props.preview) : null, table({
|
|
90
136
|
width: "100%",
|
|
137
|
+
class: "wv-page",
|
|
91
138
|
style: { background: t.page }
|
|
92
139
|
}, [h("tr", [h("td", {
|
|
93
140
|
align: "center",
|
|
94
|
-
style: { padding: "
|
|
141
|
+
style: { padding: "0 12px" }
|
|
95
142
|
}, table({
|
|
96
143
|
width: "100%",
|
|
97
|
-
style: { maxWidth: "
|
|
144
|
+
style: { maxWidth: "600px" }
|
|
98
145
|
}, [
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
146
|
+
stub(),
|
|
147
|
+
rule(true, none, {
|
|
148
|
+
color: t.band,
|
|
149
|
+
image: `url('${t.assets}/header.png') right top / 600px 100px no-repeat`
|
|
150
|
+
}),
|
|
151
|
+
framed(header(props.app), { padding: 0 }),
|
|
152
|
+
framed(accentLine(), { padding: 0 }),
|
|
153
|
+
framed(slots.default?.(), {
|
|
154
|
+
class: "wv-card wv-pad",
|
|
107
155
|
background: t.card,
|
|
108
|
-
|
|
109
|
-
borderRadius: t.radius,
|
|
110
|
-
padding: "32px",
|
|
156
|
+
padding: "36px 40px 20px",
|
|
111
157
|
fontFamily: t.font,
|
|
112
158
|
color: t.text
|
|
113
|
-
}
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
}
|
|
159
|
+
}),
|
|
160
|
+
rule(true, {
|
|
161
|
+
color: t.card,
|
|
162
|
+
class: "wv-card"
|
|
163
|
+
}, {
|
|
164
|
+
color: t.page,
|
|
165
|
+
class: "wv-foot"
|
|
166
|
+
}),
|
|
167
|
+
framed(footer(props), {
|
|
168
|
+
class: "wv-foot wv-pad",
|
|
169
|
+
background: t.page,
|
|
170
|
+
padding: "24px 40px 28px"
|
|
171
|
+
}),
|
|
172
|
+
rule(false, {
|
|
173
|
+
color: t.page,
|
|
174
|
+
class: "wv-foot"
|
|
175
|
+
}, none),
|
|
176
|
+
stub()
|
|
121
177
|
]))])])])]);
|
|
122
178
|
}
|
|
123
179
|
});
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
180
|
+
/** The dark band on top: the lockup over the dot grid, the sending app on the right. */
|
|
181
|
+
function header(app) {
|
|
182
|
+
return table({
|
|
183
|
+
width: "100%",
|
|
184
|
+
bgcolor: t.band,
|
|
185
|
+
background: `${t.assets}/header.png`,
|
|
186
|
+
style: { background: `${t.band} url('${t.assets}/header.png') right -4px / 600px 100px no-repeat` }
|
|
187
|
+
}, [h("tr", [h("td", {
|
|
188
|
+
class: "wv-pad wervt-skip-text",
|
|
189
|
+
style: {
|
|
190
|
+
padding: "30px 40px",
|
|
191
|
+
verticalAlign: "middle"
|
|
192
|
+
}
|
|
193
|
+
}, h("a", {
|
|
194
|
+
href: t.site,
|
|
195
|
+
style: {
|
|
196
|
+
textDecoration: "none",
|
|
197
|
+
color: "#fafafa"
|
|
198
|
+
}
|
|
199
|
+
}, h("img", {
|
|
200
|
+
src: `${t.assets}/lockup-on-dark.png`,
|
|
201
|
+
width: 116,
|
|
202
|
+
height: 32,
|
|
203
|
+
alt: "wervt",
|
|
204
|
+
style: {
|
|
205
|
+
display: "block",
|
|
206
|
+
width: "116px",
|
|
207
|
+
height: "32px",
|
|
208
|
+
border: 0,
|
|
209
|
+
outline: "none",
|
|
129
210
|
fontFamily: t.font,
|
|
130
|
-
fontSize: "
|
|
131
|
-
lineHeight: "
|
|
211
|
+
fontSize: "24px",
|
|
212
|
+
lineHeight: "32px",
|
|
132
213
|
fontWeight: 600,
|
|
133
|
-
|
|
134
|
-
|
|
214
|
+
letterSpacing: "-0.5px",
|
|
215
|
+
color: "#fafafa"
|
|
216
|
+
}
|
|
217
|
+
}))), app === "wervt" ? null : h("td", {
|
|
218
|
+
class: "wv-pad wervt-skip-text",
|
|
219
|
+
align: "right",
|
|
220
|
+
style: {
|
|
221
|
+
padding: "30px 40px",
|
|
222
|
+
verticalAlign: "middle"
|
|
223
|
+
}
|
|
224
|
+
}, table({ align: "right" }, [h("tr", [h("td", { style: {
|
|
225
|
+
border: "1px solid #2a2e38",
|
|
226
|
+
borderRadius: "999px",
|
|
227
|
+
background: "#12141b",
|
|
228
|
+
padding: "5px 12px",
|
|
229
|
+
fontFamily: t.mono,
|
|
230
|
+
fontSize: "12px",
|
|
231
|
+
lineHeight: "16px",
|
|
232
|
+
color: t.bandText,
|
|
233
|
+
whiteSpace: "nowrap"
|
|
234
|
+
} }, [h("span", { style: { color: "#5885ff" } }, "●"), `\u00A0\u00A0${app}`])])]))])]);
|
|
235
|
+
}
|
|
236
|
+
/** The landing page's headline gradient, as a hairline under the header. */
|
|
237
|
+
function accentLine() {
|
|
238
|
+
return table({ width: "100%" }, [h("tr", [h("td", {
|
|
239
|
+
height: 2,
|
|
240
|
+
bgcolor: t.accent,
|
|
241
|
+
style: {
|
|
242
|
+
height: "2px",
|
|
243
|
+
fontSize: 0,
|
|
244
|
+
lineHeight: 0,
|
|
245
|
+
background: `${t.accent} linear-gradient(90deg, #60a5fa, ${t.accent} 45%, #a78bfa)`
|
|
246
|
+
}
|
|
247
|
+
})])]);
|
|
248
|
+
}
|
|
249
|
+
function footer(props) {
|
|
250
|
+
const sentBy = props.footer || (props.app === "wervt" ? "Sent by wervt" : `Sent by ${props.app} via wervt`);
|
|
251
|
+
const small = {
|
|
252
|
+
fontFamily: t.font,
|
|
253
|
+
fontSize: "12px",
|
|
254
|
+
lineHeight: "18px"
|
|
255
|
+
};
|
|
256
|
+
const link = {
|
|
257
|
+
color: t.muted,
|
|
258
|
+
textDecoration: "none"
|
|
259
|
+
};
|
|
260
|
+
return table({ width: "100%" }, [h("tr", [h("td", {
|
|
261
|
+
width: 40,
|
|
262
|
+
style: {
|
|
263
|
+
width: "40px",
|
|
264
|
+
verticalAlign: "top",
|
|
265
|
+
paddingTop: "2px"
|
|
266
|
+
}
|
|
267
|
+
}, h("img", {
|
|
268
|
+
src: `${t.assets}/mark-tile.png`,
|
|
269
|
+
width: 28,
|
|
270
|
+
height: 28,
|
|
271
|
+
alt: "",
|
|
272
|
+
style: {
|
|
273
|
+
display: "block",
|
|
274
|
+
width: "28px",
|
|
275
|
+
height: "28px",
|
|
276
|
+
border: 0,
|
|
277
|
+
borderRadius: "7px"
|
|
278
|
+
}
|
|
279
|
+
})), h("td", { style: { verticalAlign: "top" } }, [
|
|
280
|
+
h("p", {
|
|
281
|
+
class: "wv-strong",
|
|
282
|
+
style: {
|
|
283
|
+
...small,
|
|
284
|
+
margin: 0,
|
|
285
|
+
fontSize: "13px",
|
|
286
|
+
fontWeight: 500,
|
|
287
|
+
color: t.highlighted
|
|
288
|
+
}
|
|
289
|
+
}, sentBy),
|
|
290
|
+
props.reason ? h("p", {
|
|
291
|
+
class: "wv-muted",
|
|
292
|
+
style: {
|
|
293
|
+
...small,
|
|
294
|
+
margin: "4px 0 0",
|
|
295
|
+
color: t.muted
|
|
296
|
+
}
|
|
297
|
+
}, props.reason) : null,
|
|
298
|
+
h("p", {
|
|
299
|
+
class: "wv-muted",
|
|
300
|
+
style: {
|
|
301
|
+
...small,
|
|
302
|
+
margin: "10px 0 0",
|
|
303
|
+
fontFamily: t.mono,
|
|
304
|
+
fontSize: "11px",
|
|
305
|
+
color: t.dimmed
|
|
306
|
+
}
|
|
307
|
+
}, [
|
|
308
|
+
h("a", {
|
|
309
|
+
href: t.site,
|
|
310
|
+
class: "wv-muted",
|
|
311
|
+
style: link
|
|
312
|
+
}, "wervt.app"),
|
|
313
|
+
separator(),
|
|
314
|
+
h("a", {
|
|
315
|
+
href: t.docs,
|
|
316
|
+
class: "wv-muted",
|
|
317
|
+
style: link
|
|
318
|
+
}, "Docs")
|
|
319
|
+
])
|
|
320
|
+
])])]);
|
|
321
|
+
}
|
|
322
|
+
function separator() {
|
|
323
|
+
return h("span", {
|
|
324
|
+
class: "wv-sep",
|
|
325
|
+
style: { color: t.rule }
|
|
326
|
+
}, "\xA0\xA0/\xA0\xA0");
|
|
327
|
+
}
|
|
328
|
+
/** A row inside the frame: the hairlines run down both sides, like the landing page's sections. */
|
|
329
|
+
function framed(children, style) {
|
|
330
|
+
const { class: className, ...rest } = style;
|
|
331
|
+
return h("tr", [h("td", { style: { padding: "0 4px" } }, table({ width: "100%" }, [h("tr", [h("td", {
|
|
332
|
+
class: ["wv-frame", className],
|
|
333
|
+
style: {
|
|
334
|
+
borderLeft: `1px solid ${t.border}`,
|
|
335
|
+
borderRight: `1px solid ${t.border}`,
|
|
336
|
+
...rest
|
|
337
|
+
}
|
|
338
|
+
}, children)])]))]);
|
|
339
|
+
}
|
|
340
|
+
/** The frame's sides fading out above and below, so it reads as part of a larger sheet. */
|
|
341
|
+
function stub() {
|
|
342
|
+
return framed(h("div", { style: {
|
|
343
|
+
height: "28px",
|
|
344
|
+
lineHeight: "28px",
|
|
345
|
+
fontSize: 0
|
|
346
|
+
} }, "\xA0"), { padding: 0 });
|
|
347
|
+
}
|
|
348
|
+
const none = { color: "transparent" };
|
|
349
|
+
/**
|
|
350
|
+
* A horizontal rule across the frame, drawn as a 9px-high grid so the "+" marks can sit where it
|
|
351
|
+
* crosses the sides. `above` and `below` paint the frame's inside around the line, so the
|
|
352
|
+
* sections it separates start right at the line instead of 4px off.
|
|
353
|
+
*/
|
|
354
|
+
function rule(crosshairs, above, below) {
|
|
355
|
+
const mark = {
|
|
356
|
+
color: t.dimmed,
|
|
357
|
+
class: "wv-mark"
|
|
358
|
+
};
|
|
359
|
+
const line = {
|
|
360
|
+
color: t.border,
|
|
361
|
+
class: "wv-line"
|
|
362
|
+
};
|
|
363
|
+
const side = crosshairs ? mark : line;
|
|
364
|
+
const cell = (fill, width, height, colspan) => h("td", {
|
|
365
|
+
width,
|
|
366
|
+
height,
|
|
367
|
+
colspan,
|
|
368
|
+
bgcolor: fill === none ? void 0 : fill.color,
|
|
369
|
+
class: fill.class,
|
|
370
|
+
style: {
|
|
371
|
+
width: width === void 0 ? void 0 : `${width}px`,
|
|
372
|
+
height: `${height}px`,
|
|
373
|
+
fontSize: 0,
|
|
374
|
+
lineHeight: 0,
|
|
375
|
+
background: fill.image ? `${fill.color} ${fill.image}` : fill.color
|
|
376
|
+
}
|
|
377
|
+
});
|
|
378
|
+
const row = (fill, height) => h("tr", [
|
|
379
|
+
cell(none, 4, height),
|
|
380
|
+
cell(side, 1, height),
|
|
381
|
+
cell(fill, void 0, height, 3),
|
|
382
|
+
cell(side, 1, height),
|
|
383
|
+
cell(none, 4, height)
|
|
384
|
+
]);
|
|
385
|
+
const arm = crosshairs ? mark : line;
|
|
386
|
+
const crossing = h("tr", [
|
|
387
|
+
cell(crosshairs ? mark : none, 4, 1),
|
|
388
|
+
cell(side, 1, 1),
|
|
389
|
+
cell(arm, 4, 1),
|
|
390
|
+
cell(line, void 0, 1),
|
|
391
|
+
cell(arm, 4, 1),
|
|
392
|
+
cell(side, 1, 1),
|
|
393
|
+
cell(crosshairs ? mark : none, 4, 1)
|
|
394
|
+
]);
|
|
395
|
+
return h("tr", [h("td", table({ width: "100%" }, [
|
|
396
|
+
row(above, 4),
|
|
397
|
+
crossing,
|
|
398
|
+
row(below, 4)
|
|
399
|
+
]))]);
|
|
400
|
+
}
|
|
401
|
+
const EmailHeading = defineComponent({
|
|
402
|
+
name: "EmailHeading",
|
|
403
|
+
props: {
|
|
404
|
+
/** A short label above the heading, in the landing page's mono eyebrow style. */
|
|
405
|
+
eyebrow: {
|
|
406
|
+
type: String,
|
|
407
|
+
default: ""
|
|
408
|
+
} },
|
|
409
|
+
setup(props, { slots }) {
|
|
410
|
+
return () => [props.eyebrow ? h("p", {
|
|
411
|
+
class: "wv-accent",
|
|
412
|
+
style: {
|
|
413
|
+
margin: "0 0 10px",
|
|
414
|
+
fontFamily: t.mono,
|
|
415
|
+
fontSize: "12px",
|
|
416
|
+
lineHeight: "16px",
|
|
417
|
+
letterSpacing: "0.5px",
|
|
418
|
+
textTransform: "uppercase",
|
|
419
|
+
color: t.accent
|
|
420
|
+
}
|
|
421
|
+
}, props.eyebrow) : null, h("h1", {
|
|
422
|
+
class: "wv-strong wv-hero",
|
|
423
|
+
style: {
|
|
424
|
+
margin: "0 0 16px",
|
|
425
|
+
fontFamily: t.font,
|
|
426
|
+
fontSize: "26px",
|
|
427
|
+
lineHeight: "34px",
|
|
428
|
+
fontWeight: 600,
|
|
429
|
+
letterSpacing: "-0.6px",
|
|
430
|
+
color: t.highlighted
|
|
431
|
+
}
|
|
432
|
+
}, slots.default?.())];
|
|
135
433
|
}
|
|
136
434
|
});
|
|
137
435
|
const EmailText = defineComponent({
|
|
138
436
|
name: "EmailText",
|
|
139
437
|
setup(_, { slots }) {
|
|
140
|
-
return () => h("p", {
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
438
|
+
return () => h("p", {
|
|
439
|
+
class: "wv-text",
|
|
440
|
+
style: {
|
|
441
|
+
margin: "0 0 16px",
|
|
442
|
+
fontFamily: t.font,
|
|
443
|
+
fontSize: "15px",
|
|
444
|
+
lineHeight: "24px",
|
|
445
|
+
color: t.text
|
|
446
|
+
}
|
|
447
|
+
}, slots.default?.());
|
|
147
448
|
}
|
|
148
449
|
});
|
|
149
450
|
/** Secondary text: hints, "ignore this if …". */
|
|
150
451
|
const EmailMuted = defineComponent({
|
|
151
452
|
name: "EmailMuted",
|
|
152
453
|
setup(_, { slots }) {
|
|
153
|
-
return () => h("p", {
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
454
|
+
return () => h("p", {
|
|
455
|
+
class: "wv-muted",
|
|
456
|
+
style: {
|
|
457
|
+
margin: "0 0 16px",
|
|
458
|
+
fontFamily: t.font,
|
|
459
|
+
fontSize: "13px",
|
|
460
|
+
lineHeight: "20px",
|
|
461
|
+
color: t.muted
|
|
462
|
+
}
|
|
463
|
+
}, slots.default?.());
|
|
160
464
|
}
|
|
161
465
|
});
|
|
162
466
|
const EmailLink = defineComponent({
|
|
@@ -168,8 +472,9 @@ const EmailLink = defineComponent({
|
|
|
168
472
|
setup(props, { slots }) {
|
|
169
473
|
return () => h("a", {
|
|
170
474
|
href: props.href,
|
|
475
|
+
class: "wv-accent",
|
|
171
476
|
style: {
|
|
172
|
-
color: t.
|
|
477
|
+
color: t.accent,
|
|
173
478
|
textDecoration: "underline"
|
|
174
479
|
}
|
|
175
480
|
}, slots.default?.() ?? props.href);
|
|
@@ -178,64 +483,106 @@ const EmailLink = defineComponent({
|
|
|
178
483
|
/** A call to action. Bulletproof: a table cell carries the background, so Outlook shows it too. */
|
|
179
484
|
const EmailButton = defineComponent({
|
|
180
485
|
name: "EmailButton",
|
|
181
|
-
props: {
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
486
|
+
props: {
|
|
487
|
+
href: {
|
|
488
|
+
type: String,
|
|
489
|
+
required: true
|
|
490
|
+
},
|
|
491
|
+
/** `primary` is the landing page's blue; `neutral` the dashboard's black. */
|
|
492
|
+
color: {
|
|
493
|
+
type: String,
|
|
494
|
+
default: "primary"
|
|
495
|
+
}
|
|
496
|
+
},
|
|
185
497
|
setup(props, { slots }) {
|
|
186
|
-
return () =>
|
|
187
|
-
background: t.button
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
498
|
+
return () => {
|
|
499
|
+
const background = props.color === "neutral" ? "#171717" : t.button;
|
|
500
|
+
return table({ style: { margin: "8px 0 24px" } }, [h("tr", [h("td", {
|
|
501
|
+
bgcolor: background,
|
|
502
|
+
style: {
|
|
503
|
+
background,
|
|
504
|
+
borderRadius: t.radius
|
|
505
|
+
}
|
|
506
|
+
}, h("a", {
|
|
507
|
+
href: props.href,
|
|
508
|
+
style: {
|
|
509
|
+
display: "inline-block",
|
|
510
|
+
padding: "12px 22px",
|
|
511
|
+
border: `1px solid ${background}`,
|
|
512
|
+
fontFamily: t.font,
|
|
513
|
+
fontSize: "14px",
|
|
514
|
+
fontWeight: 500,
|
|
515
|
+
lineHeight: "20px",
|
|
516
|
+
color: t.buttonText,
|
|
517
|
+
textDecoration: "none",
|
|
518
|
+
borderRadius: t.radius
|
|
519
|
+
}
|
|
520
|
+
}, [slots.default?.(), h("span", { class: "wervt-skip-text" }, "\xA0\xA0→")]))])]);
|
|
521
|
+
};
|
|
203
522
|
}
|
|
204
523
|
});
|
|
205
524
|
/** A one-time code, large and spaced so it reads (and copies) easily. */
|
|
206
525
|
const EmailCode = defineComponent({
|
|
207
526
|
name: "EmailCode",
|
|
208
|
-
props: {
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
527
|
+
props: {
|
|
528
|
+
code: {
|
|
529
|
+
type: String,
|
|
530
|
+
required: true
|
|
531
|
+
},
|
|
532
|
+
/** A small line under the code, e.g. when it expires. */
|
|
533
|
+
caption: {
|
|
534
|
+
type: String,
|
|
535
|
+
default: ""
|
|
536
|
+
}
|
|
537
|
+
},
|
|
212
538
|
setup(props) {
|
|
213
539
|
return () => table({
|
|
214
540
|
width: "100%",
|
|
215
541
|
style: { margin: "8px 0 24px" }
|
|
216
542
|
}, [h("tr", [h("td", {
|
|
217
543
|
align: "center",
|
|
544
|
+
bgcolor: t.codeBackground,
|
|
545
|
+
class: "wv-code",
|
|
218
546
|
style: {
|
|
219
547
|
background: t.codeBackground,
|
|
220
|
-
|
|
221
|
-
|
|
548
|
+
border: `1px solid ${t.accentBorder}`,
|
|
549
|
+
borderRadius: "10px",
|
|
550
|
+
padding: props.caption ? "22px 16px 16px" : "22px 16px"
|
|
551
|
+
}
|
|
552
|
+
}, [h("div", {
|
|
553
|
+
class: "wv-strong wv-codetext",
|
|
554
|
+
style: {
|
|
222
555
|
fontFamily: t.mono,
|
|
223
|
-
fontSize: "
|
|
556
|
+
fontSize: "36px",
|
|
557
|
+
lineHeight: "44px",
|
|
224
558
|
fontWeight: 600,
|
|
225
|
-
letterSpacing: "
|
|
559
|
+
letterSpacing: "10px",
|
|
560
|
+
paddingLeft: "10px",
|
|
226
561
|
color: t.highlighted
|
|
227
562
|
}
|
|
228
|
-
}, props.code)
|
|
563
|
+
}, props.code), props.caption ? h("div", {
|
|
564
|
+
class: "wv-muted",
|
|
565
|
+
style: {
|
|
566
|
+
marginTop: "8px",
|
|
567
|
+
fontFamily: t.mono,
|
|
568
|
+
fontSize: "12px",
|
|
569
|
+
lineHeight: "16px",
|
|
570
|
+
color: t.muted
|
|
571
|
+
}
|
|
572
|
+
}, props.caption) : null])])]);
|
|
229
573
|
}
|
|
230
574
|
});
|
|
231
575
|
const EmailDivider = defineComponent({
|
|
232
576
|
name: "EmailDivider",
|
|
233
577
|
setup() {
|
|
234
|
-
return () => h("hr", {
|
|
235
|
-
|
|
236
|
-
|
|
237
|
-
|
|
238
|
-
|
|
578
|
+
return () => h("hr", {
|
|
579
|
+
class: "wv-frame",
|
|
580
|
+
style: {
|
|
581
|
+
border: "none",
|
|
582
|
+
borderTop: `1px solid ${t.border}`,
|
|
583
|
+
margin: "24px 0"
|
|
584
|
+
}
|
|
585
|
+
});
|
|
239
586
|
}
|
|
240
587
|
});
|
|
241
588
|
function table(attrs, children) {
|
|
@@ -4,9 +4,11 @@ import { useDb } from "./db.js";
|
|
|
4
4
|
import { createEvlogError, log, useLogger } from "./logger.js";
|
|
5
5
|
import { SendMailOptions, sendMail } from "./mail.js";
|
|
6
6
|
import { McpTokenContext } from "./mcp-auth.js";
|
|
7
|
-
import {
|
|
7
|
+
import { seedTable } from "./seed.js";
|
|
8
|
+
import { ShapeResponse } from "../shared/shape.js";
|
|
9
|
+
import { ShapeOptions, ShapeRow, proxyShape } from "./shape.js";
|
|
8
10
|
import { Task, TaskEvent, TaskResult, defineTask } from "./tasks.js";
|
|
9
11
|
import { SafeResult, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, vh } from "./validate.js";
|
|
10
|
-
import { Tool, defineTool } from "./tools.js";
|
|
12
|
+
import { Tool, ToolRoute, defineTool, defineToolRoute } from "./tools.js";
|
|
11
13
|
import { useWervtUser } from "./user.js";
|
|
12
|
-
export { type EmailProps, type McpTokenContext, type RenderedEmail, type SafeResult, type SendMailOptions, type ShapeOptions, type Task, type TaskEvent, type TaskResult, type Tool, type WervtUser, createEvlogError, defineTask, defineTool, log, proxyShape, renderEmail, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtUser, vh };
|
|
14
|
+
export { type EmailProps, type McpTokenContext, type RenderedEmail, type SafeResult, type SendMailOptions, type ShapeOptions, type ShapeResponse, type ShapeRow, type Task, type TaskEvent, type TaskResult, type Tool, type ToolRoute, type WervtUser, createEvlogError, defineTask, defineTool, defineToolRoute, log, proxyShape, renderEmail, seedTable, sendMail, useDb, useLogger, useSafeValidatedBody, useSafeValidatedParams, useSafeValidatedQuery, useValidatedBody, useValidatedParams, useValidatedQuery, useWervtUser, vh };
|