@autono/open-pages 0.7.0 → 0.9.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/dist/{build-CCoxDxL-.js → build-Cpod-K9R.js} +9 -4
- package/dist/cli/bin.js +7 -7
- package/dist/{config-D_U_aCQz.js → config-CYLBzMMb.js} +1077 -18
- package/dist/{config-p-TWNXbv.d.ts → config-IkwICvOe.d.ts} +2 -1
- package/dist/{dev-CTrB263u.js → dev-B7x-G-wk.js} +1 -1
- package/dist/{export-enKL9R7x.js → export-BxMksWEc.js} +74 -12
- package/dist/index.d.ts +23 -3
- package/dist/locale/index.d.ts +1 -1
- package/dist/locale/index.js +96 -0
- package/dist/{preview-Dmzyd1cf.js → preview-CMv1lGOC.js} +1 -1
- package/dist/{types-DDdUFUIS.d.ts → types-B-9WXL93.d.ts} +24 -0
- package/dist/vite/index.d.ts +1 -1
- package/dist/vite/index.js +1 -1
- package/package.json +1 -1
- package/skills/apply-comments/SKILL.md +6 -3
- package/skills/create-email/SKILL.md +166 -0
- package/skills/create-page/SKILL.md +5 -1
- package/skills/create-theme/SKILL.md +33 -7
- package/skills/create-theme/references/email-theme-from-css.mjs +185 -0
- package/skills/create-theme/references/email-theme.md +48 -0
- package/skills/current-page/SKILL.md +3 -3
- package/skills/page-authoring/SKILL.md +3 -0
- package/skills/web-design-guidelines/SKILL.md +41 -0
- package/src/app/app.tsx +4 -0
- package/src/app/components/command/home-command-menu.tsx +19 -2
- package/src/app/components/selection-note.tsx +71 -0
- package/src/app/components/sidebar/folder-item.tsx +9 -2
- package/src/app/components/sidebar/sidebar.tsx +10 -0
- package/src/app/frame/email-inspect.ts +17 -0
- package/src/app/lib/emails.ts +17 -0
- package/src/app/lib/frame.ts +15 -4
- package/src/app/lib/page-thumb.tsx +11 -3
- package/src/app/lib/sdk.ts +22 -0
- package/src/app/routes/email.tsx +424 -0
- package/src/app/routes/emails.tsx +94 -0
- package/src/app/routes/home-shell.tsx +21 -2
- package/src/app/routes/page.tsx +21 -57
- package/src/app/virtual.d.ts +10 -0
- package/src/locale/en.ts +25 -0
- package/src/locale/ja.ts +25 -0
- package/src/locale/types.ts +24 -0
- package/src/locale/zh-cn.ts +25 -0
- package/src/locale/zh-tw.ts +25 -0
- package/workspace/components.json +3 -1
- package/workspace/styles/globals.css +8 -2
- package/dist/open-pages-plugin-C8cFhMB9.js +0 -662
- package/dist/version-DZrXLoAD.js +0 -42
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { Mail } from 'lucide-react';
|
|
2
|
+
import { Link } from 'react-router-dom';
|
|
3
|
+
import { format, useLocale } from '~/lib/use-locale';
|
|
4
|
+
import { SystemViewIcon } from '../components/sidebar/folder-item';
|
|
5
|
+
import { emailCreatedAt, emailIds, emailMeta } from '../lib/emails';
|
|
6
|
+
import { PageThumb } from '../lib/page-thumb';
|
|
7
|
+
|
|
8
|
+
// Emails lay out at 600px; a slightly wider thumb viewport keeps the body
|
|
9
|
+
// margins visible so the card reads as an email, not a cropped page.
|
|
10
|
+
const EMAIL_THUMB_VIEWPORT = 760;
|
|
11
|
+
|
|
12
|
+
export function EmailsGalleryPage() {
|
|
13
|
+
const t = useLocale();
|
|
14
|
+
const sorted = emailIds
|
|
15
|
+
.slice()
|
|
16
|
+
.sort((a, b) => (emailCreatedAt[b] ?? 0) - (emailCreatedAt[a] ?? 0));
|
|
17
|
+
|
|
18
|
+
return (
|
|
19
|
+
<>
|
|
20
|
+
<header className="mb-6 md:mb-8">
|
|
21
|
+
<div className="flex flex-wrap items-center gap-2.5">
|
|
22
|
+
<SystemViewIcon kind="emails" className="text-muted-foreground" />
|
|
23
|
+
<h1 className="font-heading text-[19px] font-semibold leading-none tracking-[-0.015em] md:text-[21px]">
|
|
24
|
+
{t.emails.title}
|
|
25
|
+
</h1>
|
|
26
|
+
<span className="folio ml-0.5">{emailIds.length.toString().padStart(2, '0')}</span>
|
|
27
|
+
</div>
|
|
28
|
+
</header>
|
|
29
|
+
|
|
30
|
+
{sorted.length === 0 ? (
|
|
31
|
+
<EmptyState />
|
|
32
|
+
) : (
|
|
33
|
+
<ul className="grid grid-cols-[repeat(auto-fill,minmax(240px,1fr))] gap-x-6 gap-y-9 md:grid-cols-[repeat(auto-fill,minmax(300px,1fr))]">
|
|
34
|
+
{sorted.map((id, i) => {
|
|
35
|
+
const info = emailMeta[id];
|
|
36
|
+
const title = info?.title ?? id;
|
|
37
|
+
return (
|
|
38
|
+
<li
|
|
39
|
+
key={id}
|
|
40
|
+
className="rise-in"
|
|
41
|
+
style={{ animationDelay: `${Math.min(i, 11) * 30}ms` }}
|
|
42
|
+
>
|
|
43
|
+
<Link
|
|
44
|
+
to={`/e/${id}`}
|
|
45
|
+
aria-label={format(t.emails.openEmailAria, { name: title })}
|
|
46
|
+
className="group block rounded-[6px] outline-none focus-visible:ring-2 focus-visible:ring-ring/40 focus-visible:ring-offset-2 focus-visible:ring-offset-background"
|
|
47
|
+
>
|
|
48
|
+
<div className="relative aspect-[4/3] overflow-hidden rounded-[6px] border border-hairline bg-card shadow-edge ring-1 ring-foreground/[0.04] group-hover:shadow-floating group-hover:ring-foreground/20 motion-safe:transition-[box-shadow,--tw-ring-color,scale] motion-safe:duration-200 group-active:scale-[0.99]">
|
|
49
|
+
<div className="h-full w-full motion-safe:transition-transform motion-safe:duration-300 motion-safe:group-hover:scale-[1.03]">
|
|
50
|
+
<PageThumb
|
|
51
|
+
source={{ emailId: id }}
|
|
52
|
+
title={title}
|
|
53
|
+
viewport={EMAIL_THUMB_VIEWPORT}
|
|
54
|
+
/>
|
|
55
|
+
</div>
|
|
56
|
+
</div>
|
|
57
|
+
<div className="mt-3 min-w-0">
|
|
58
|
+
<h3 className="truncate font-heading text-[14px] font-medium tracking-tight">
|
|
59
|
+
{title}
|
|
60
|
+
</h3>
|
|
61
|
+
<p className="mt-0.5 truncate text-[12.5px] text-muted-foreground">
|
|
62
|
+
{info?.subject ?? t.emails.noSubject}
|
|
63
|
+
</p>
|
|
64
|
+
</div>
|
|
65
|
+
</Link>
|
|
66
|
+
</li>
|
|
67
|
+
);
|
|
68
|
+
})}
|
|
69
|
+
</ul>
|
|
70
|
+
)}
|
|
71
|
+
</>
|
|
72
|
+
);
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function EmptyState() {
|
|
76
|
+
const t = useLocale();
|
|
77
|
+
return (
|
|
78
|
+
<div className="rounded-[8px] border border-dashed border-border px-8 py-20">
|
|
79
|
+
<div className="mx-auto flex max-w-md flex-col items-center text-center">
|
|
80
|
+
<Mail className="size-5 text-muted-foreground/60" aria-hidden />
|
|
81
|
+
<p className="mt-4 font-heading text-[14px] font-semibold tracking-tight">
|
|
82
|
+
{t.emails.noEmailsTitle}
|
|
83
|
+
</p>
|
|
84
|
+
<p className="mt-1.5 text-[13px] leading-relaxed text-muted-foreground">
|
|
85
|
+
{t.emails.noEmailsHintPrefix}
|
|
86
|
+
<code className="rounded-[4px] bg-muted px-1.5 py-0.5 font-mono text-[11.5px] text-foreground">
|
|
87
|
+
/create-email
|
|
88
|
+
</code>
|
|
89
|
+
{t.emails.noEmailsHintSuffix}
|
|
90
|
+
</p>
|
|
91
|
+
</div>
|
|
92
|
+
</div>
|
|
93
|
+
);
|
|
94
|
+
}
|
|
@@ -18,7 +18,14 @@ import { cn } from '~/lib/utils';
|
|
|
18
18
|
import { CommandMenuTrigger } from '../components/command/command-menu';
|
|
19
19
|
import { HomeCommandMenu } from '../components/command/home-command-menu';
|
|
20
20
|
import { SystemViewIcon } from '../components/sidebar/folder-item';
|
|
21
|
-
import {
|
|
21
|
+
import {
|
|
22
|
+
ALL_DOCS_ID,
|
|
23
|
+
ASSETS_ID,
|
|
24
|
+
EMAILS_ID,
|
|
25
|
+
Sidebar,
|
|
26
|
+
THEMES_ID,
|
|
27
|
+
} from '../components/sidebar/sidebar';
|
|
28
|
+
import { emailIds } from '../lib/emails';
|
|
22
29
|
import { pageIds } from '../lib/pages';
|
|
23
30
|
import type { FoldersManifest } from '../lib/sdk';
|
|
24
31
|
import { themes as themeRegistry } from '../lib/themes';
|
|
@@ -28,7 +35,7 @@ export type HomeOutletContext = {
|
|
|
28
35
|
loading: boolean;
|
|
29
36
|
draftDocs: string[];
|
|
30
37
|
docsByFolder: Record<string, string[]>;
|
|
31
|
-
/** Selected view id: ALL_DOCS_ID, DRAFT_ID, a folder id, THEMES_ID, or
|
|
38
|
+
/** Selected view id: ALL_DOCS_ID, DRAFT_ID, a folder id, THEMES_ID, ASSETS_ID, or EMAILS_ID. */
|
|
32
39
|
selectedId: string;
|
|
33
40
|
selectFolder: (id: string) => void;
|
|
34
41
|
reportTitle: (pageId: string, title: string) => void;
|
|
@@ -42,6 +49,7 @@ export type HomeOutletContext = {
|
|
|
42
49
|
function pathToSelectedId(pathname: string, search: URLSearchParams): string {
|
|
43
50
|
if (pathname === '/themes' || pathname.startsWith('/themes/')) return THEMES_ID;
|
|
44
51
|
if (pathname === '/assets') return ASSETS_ID;
|
|
52
|
+
if (pathname === '/emails') return EMAILS_ID;
|
|
45
53
|
return search.get('f') ?? ALL_DOCS_ID;
|
|
46
54
|
}
|
|
47
55
|
|
|
@@ -81,6 +89,7 @@ export function HomeShell() {
|
|
|
81
89
|
(id: string) => {
|
|
82
90
|
if (id === THEMES_ID) navigate('/themes', { replace: true });
|
|
83
91
|
else if (id === ASSETS_ID) navigate('/assets', { replace: true });
|
|
92
|
+
else if (id === EMAILS_ID) navigate('/emails', { replace: true });
|
|
84
93
|
else if (id === ALL_DOCS_ID) navigate('/', { replace: true });
|
|
85
94
|
else navigate(`/?f=${encodeURIComponent(id)}`, { replace: true });
|
|
86
95
|
},
|
|
@@ -151,6 +160,7 @@ export function HomeShell() {
|
|
|
151
160
|
allCount={pageIds.length}
|
|
152
161
|
themesCount={themeRegistry.length}
|
|
153
162
|
assetsCount={globalAssets.length}
|
|
163
|
+
emailsCount={emailIds.length}
|
|
154
164
|
selectedId={selectedId}
|
|
155
165
|
onSelect={selectFolder}
|
|
156
166
|
onCreate={(name, icon) => create(name, icon)}
|
|
@@ -215,6 +225,7 @@ export function HomeShell() {
|
|
|
215
225
|
className={cn(
|
|
216
226
|
selectedId !== THEMES_ID &&
|
|
217
227
|
selectedId !== ASSETS_ID &&
|
|
228
|
+
selectedId !== EMAILS_ID &&
|
|
218
229
|
'bg-muted text-foreground',
|
|
219
230
|
)}
|
|
220
231
|
>
|
|
@@ -232,6 +243,14 @@ export function HomeShell() {
|
|
|
232
243
|
{themeRegistry.length.toString().padStart(2, '0')}
|
|
233
244
|
</span>
|
|
234
245
|
</DropdownMenuItem>
|
|
246
|
+
<DropdownMenuItem
|
|
247
|
+
onClick={() => selectFolder(EMAILS_ID)}
|
|
248
|
+
className={cn(selectedId === EMAILS_ID && 'bg-muted text-foreground')}
|
|
249
|
+
>
|
|
250
|
+
<SystemViewIcon kind="emails" className="text-muted-foreground" />
|
|
251
|
+
<span className="flex-1 truncate">{t.home.emails}</span>
|
|
252
|
+
<span className="folio">{emailIds.length.toString().padStart(2, '0')}</span>
|
|
253
|
+
</DropdownMenuItem>
|
|
235
254
|
{import.meta.env.DEV && (
|
|
236
255
|
<DropdownMenuItem
|
|
237
256
|
onClick={() => selectFolder(ASSETS_ID)}
|
package/src/app/routes/page.tsx
CHANGED
|
@@ -4,17 +4,16 @@ import {
|
|
|
4
4
|
Crosshair,
|
|
5
5
|
ExternalLink,
|
|
6
6
|
Loader2,
|
|
7
|
-
MessageSquarePlus,
|
|
8
7
|
Monitor,
|
|
9
8
|
RotateCw,
|
|
10
9
|
Smartphone,
|
|
11
10
|
Tablet,
|
|
12
|
-
X,
|
|
13
11
|
} from 'lucide-react';
|
|
14
12
|
import { useCallback, useEffect, useMemo, useRef, useState } from 'react';
|
|
15
13
|
import { useNavigate, useParams } from 'react-router-dom';
|
|
16
14
|
import { toast } from 'sonner';
|
|
17
|
-
import {
|
|
15
|
+
import { type Selection, SelectionNote } from '~/components/selection-note';
|
|
16
|
+
import { Button, buttonVariants } from '~/components/ui/button';
|
|
18
17
|
import { readLastHomeLocation } from '~/lib/last-home-location';
|
|
19
18
|
import { cn } from '~/lib/utils';
|
|
20
19
|
import { type FrameMessage, frameUrl, isFrameMessage, type WorkspaceMessage } from '../lib/frame';
|
|
@@ -44,8 +43,6 @@ function readViewportPref(): Viewport {
|
|
|
44
43
|
|
|
45
44
|
const VIEWPORT_ICONS = { desktop: Monitor, tablet: Tablet, mobile: Smartphone } as const;
|
|
46
45
|
|
|
47
|
-
type Selection = { loc: string; tag: string; text: string };
|
|
48
|
-
|
|
49
46
|
export function PageView() {
|
|
50
47
|
const { pageId = '' } = useParams();
|
|
51
48
|
const known = pageIds.includes(pageId);
|
|
@@ -253,17 +250,22 @@ export function PageView() {
|
|
|
253
250
|
Inspect
|
|
254
251
|
</Button>
|
|
255
252
|
)}
|
|
256
|
-
<
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
260
|
-
render={<a href={src} target="_blank" rel="noreferrer" />}
|
|
253
|
+
<a
|
|
254
|
+
href={known ? src : undefined}
|
|
255
|
+
target="_blank"
|
|
256
|
+
rel="noreferrer"
|
|
261
257
|
aria-label="Open page in a new tab"
|
|
258
|
+
aria-disabled={!known || undefined}
|
|
259
|
+
tabIndex={known ? undefined : -1}
|
|
262
260
|
title="Open the page by itself in a new tab"
|
|
261
|
+
className={cn(
|
|
262
|
+
buttonVariants({ variant: 'outline', size: 'sm' }),
|
|
263
|
+
!known && 'pointer-events-none opacity-50',
|
|
264
|
+
)}
|
|
263
265
|
>
|
|
264
266
|
<ExternalLink className="size-4" />
|
|
265
267
|
Open
|
|
266
|
-
</
|
|
268
|
+
</a>
|
|
267
269
|
</div>
|
|
268
270
|
</header>
|
|
269
271
|
)}
|
|
@@ -291,52 +293,14 @@ export function PageView() {
|
|
|
291
293
|
)}
|
|
292
294
|
|
|
293
295
|
{selection && (
|
|
294
|
-
<
|
|
295
|
-
|
|
296
|
-
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
<Button
|
|
303
|
-
variant="ghost"
|
|
304
|
-
size="icon"
|
|
305
|
-
className="ml-auto size-6"
|
|
306
|
-
aria-label="Clear selection"
|
|
307
|
-
onClick={() => setSelection(null)}
|
|
308
|
-
>
|
|
309
|
-
<X className="size-3.5" />
|
|
310
|
-
</Button>
|
|
311
|
-
</div>
|
|
312
|
-
{selection.text && (
|
|
313
|
-
<p className="mt-1.5 line-clamp-2 text-xs text-muted-foreground">
|
|
314
|
-
“{selection.text}”
|
|
315
|
-
</p>
|
|
316
|
-
)}
|
|
317
|
-
<textarea
|
|
318
|
-
value={note}
|
|
319
|
-
onChange={(e) => setNote(e.target.value)}
|
|
320
|
-
placeholder="Leave a note for your agent — e.g. “make this bold”"
|
|
321
|
-
rows={2}
|
|
322
|
-
className="mt-2 w-full resize-none rounded-md border bg-transparent px-2 py-1.5 text-sm outline-none focus:ring-1 focus:ring-ring"
|
|
323
|
-
/>
|
|
324
|
-
<div className="mt-2 flex justify-end gap-2">
|
|
325
|
-
<Button
|
|
326
|
-
size="sm"
|
|
327
|
-
onClick={submitComment}
|
|
328
|
-
disabled={!note.trim() || savingNote}
|
|
329
|
-
aria-label="Save comment"
|
|
330
|
-
>
|
|
331
|
-
{savingNote ? (
|
|
332
|
-
<Loader2 className="size-3.5 animate-spin" />
|
|
333
|
-
) : (
|
|
334
|
-
<MessageSquarePlus className="size-3.5" />
|
|
335
|
-
)}
|
|
336
|
-
Comment
|
|
337
|
-
</Button>
|
|
338
|
-
</div>
|
|
339
|
-
</div>
|
|
296
|
+
<SelectionNote
|
|
297
|
+
selection={selection}
|
|
298
|
+
note={note}
|
|
299
|
+
saving={savingNote}
|
|
300
|
+
onNoteChange={setNote}
|
|
301
|
+
onSubmit={submitComment}
|
|
302
|
+
onClear={() => setSelection(null)}
|
|
303
|
+
/>
|
|
340
304
|
)}
|
|
341
305
|
</main>
|
|
342
306
|
</div>
|
package/src/app/virtual.d.ts
CHANGED
|
@@ -7,6 +7,15 @@ declare module 'virtual:open-pages/pages' {
|
|
|
7
7
|
export function loadPage(id: string): Promise<PageModule>;
|
|
8
8
|
}
|
|
9
9
|
|
|
10
|
+
declare module 'virtual:open-pages/emails' {
|
|
11
|
+
export const emailIds: string[];
|
|
12
|
+
export const emailMeta: Record<
|
|
13
|
+
string,
|
|
14
|
+
{ title: string; subject: string | null; description: string | null }
|
|
15
|
+
>;
|
|
16
|
+
export const emailCreatedAt: Record<string, number>;
|
|
17
|
+
}
|
|
18
|
+
|
|
10
19
|
declare module 'virtual:open-pages/pages.css' {}
|
|
11
20
|
|
|
12
21
|
declare module 'virtual:open-pages/config' {
|
|
@@ -15,6 +24,7 @@ declare module 'virtual:open-pages/config' {
|
|
|
15
24
|
const config: {
|
|
16
25
|
base?: string;
|
|
17
26
|
pagesDir?: string;
|
|
27
|
+
emailsDir?: string;
|
|
18
28
|
port?: number;
|
|
19
29
|
locale?: Locale;
|
|
20
30
|
version: string;
|
package/src/locale/en.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const en: Locale = {
|
|
|
23
23
|
duplicate: 'Duplicate',
|
|
24
24
|
themes: 'Themes',
|
|
25
25
|
assets: 'Assets',
|
|
26
|
+
emails: 'Emails',
|
|
26
27
|
folders: 'Folders',
|
|
27
28
|
pages: 'Pages',
|
|
28
29
|
menu: 'Menu',
|
|
@@ -193,6 +194,7 @@ export const en: Locale = {
|
|
|
193
194
|
placeholder: 'Search pages or run a command…',
|
|
194
195
|
empty: 'No results.',
|
|
195
196
|
groupDocs: 'Pages',
|
|
197
|
+
groupEmails: 'Emails',
|
|
196
198
|
groupFolders: 'Folders',
|
|
197
199
|
groupNavigation: 'Go to',
|
|
198
200
|
groupAppearance: 'Appearance',
|
|
@@ -211,6 +213,29 @@ export const en: Locale = {
|
|
|
211
213
|
system: 'System',
|
|
212
214
|
},
|
|
213
215
|
|
|
216
|
+
emails: {
|
|
217
|
+
title: 'Emails',
|
|
218
|
+
noEmailsTitle: 'No emails yet',
|
|
219
|
+
noEmailsHintPrefix: 'Run ',
|
|
220
|
+
noEmailsHintSuffix: ' in your agent to scaffold one under emails/.',
|
|
221
|
+
subjectLabel: 'Subject',
|
|
222
|
+
noSubject: 'No subject set',
|
|
223
|
+
openEmailAria: 'Open email {name}',
|
|
224
|
+
backToEmails: 'Back to emails',
|
|
225
|
+
viewHtml: 'HTML',
|
|
226
|
+
viewText: 'Text',
|
|
227
|
+
viewportDesktop: 'Desktop',
|
|
228
|
+
viewportMobile: 'Mobile',
|
|
229
|
+
copyHtml: 'Copy HTML',
|
|
230
|
+
copiedHtml: 'HTML copied',
|
|
231
|
+
copyHtmlFailed: 'Could not copy the HTML',
|
|
232
|
+
reload: 'Reload email',
|
|
233
|
+
openInTab: 'Open the rendered email by itself in a new tab',
|
|
234
|
+
notFound: 'Email not found: {id}',
|
|
235
|
+
unresolvedCount: '{count} classes did not compile',
|
|
236
|
+
unresolvedTitle:
|
|
237
|
+
'Tailwind utilities the email compiler could not inline (check components/email/email-theme.ts):',
|
|
238
|
+
},
|
|
214
239
|
themes: {
|
|
215
240
|
title: 'Themes',
|
|
216
241
|
noThemesTitle: 'No themes yet',
|
package/src/locale/ja.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const ja: Locale = {
|
|
|
23
23
|
duplicate: '複製',
|
|
24
24
|
themes: 'テーマ',
|
|
25
25
|
assets: 'アセット',
|
|
26
|
+
emails: 'メール',
|
|
26
27
|
folders: 'フォルダ',
|
|
27
28
|
pages: 'スライド',
|
|
28
29
|
menu: 'メニュー',
|
|
@@ -196,6 +197,7 @@ export const ja: Locale = {
|
|
|
196
197
|
placeholder: 'スライドを検索、またはコマンドを実行…',
|
|
197
198
|
empty: '結果がありません。',
|
|
198
199
|
groupDocs: 'スライド',
|
|
200
|
+
groupEmails: 'メール',
|
|
199
201
|
groupFolders: 'フォルダ',
|
|
200
202
|
groupNavigation: '移動',
|
|
201
203
|
groupAppearance: '外観',
|
|
@@ -214,6 +216,29 @@ export const ja: Locale = {
|
|
|
214
216
|
system: 'システム',
|
|
215
217
|
},
|
|
216
218
|
|
|
219
|
+
emails: {
|
|
220
|
+
title: 'メール',
|
|
221
|
+
noEmailsTitle: 'メールはまだありません',
|
|
222
|
+
noEmailsHintPrefix: 'エージェントで ',
|
|
223
|
+
noEmailsHintSuffix: ' を実行すると emails/ に作成されます。',
|
|
224
|
+
subjectLabel: '件名',
|
|
225
|
+
noSubject: '件名が未設定',
|
|
226
|
+
openEmailAria: 'メール {name} を開く',
|
|
227
|
+
backToEmails: 'メール一覧へ戻る',
|
|
228
|
+
viewHtml: 'HTML',
|
|
229
|
+
viewText: 'テキスト',
|
|
230
|
+
viewportDesktop: 'デスクトップ',
|
|
231
|
+
viewportMobile: 'モバイル',
|
|
232
|
+
copyHtml: 'HTML をコピー',
|
|
233
|
+
copiedHtml: 'HTML をコピーしました',
|
|
234
|
+
copyHtmlFailed: 'HTML をコピーできませんでした',
|
|
235
|
+
reload: 'メールを再読み込み',
|
|
236
|
+
openInTab: 'レンダリングされたメールを新しいタブで開く',
|
|
237
|
+
notFound: 'メールが見つかりません: {id}',
|
|
238
|
+
unresolvedCount: '{count} 個のクラスが変換されませんでした',
|
|
239
|
+
unresolvedTitle:
|
|
240
|
+
'メールコンパイラがインライン化できなかった Tailwind ユーティリティ (components/email/email-theme.ts を確認):',
|
|
241
|
+
},
|
|
217
242
|
themes: {
|
|
218
243
|
title: 'テーマ',
|
|
219
244
|
noThemesTitle: 'テーマがまだありません',
|
package/src/locale/types.ts
CHANGED
|
@@ -23,6 +23,7 @@ export type Locale = {
|
|
|
23
23
|
duplicate: string;
|
|
24
24
|
themes: string;
|
|
25
25
|
assets: string;
|
|
26
|
+
emails: string;
|
|
26
27
|
folders: string;
|
|
27
28
|
pages: string;
|
|
28
29
|
menu: string;
|
|
@@ -192,6 +193,7 @@ export type Locale = {
|
|
|
192
193
|
placeholder: string;
|
|
193
194
|
empty: string;
|
|
194
195
|
groupDocs: string;
|
|
196
|
+
groupEmails: string;
|
|
195
197
|
groupFolders: string;
|
|
196
198
|
groupNavigation: string;
|
|
197
199
|
groupAppearance: string;
|
|
@@ -210,6 +212,28 @@ export type Locale = {
|
|
|
210
212
|
system: string;
|
|
211
213
|
};
|
|
212
214
|
|
|
215
|
+
emails: {
|
|
216
|
+
title: string;
|
|
217
|
+
noEmailsTitle: string;
|
|
218
|
+
noEmailsHintPrefix: string;
|
|
219
|
+
noEmailsHintSuffix: string;
|
|
220
|
+
subjectLabel: string;
|
|
221
|
+
noSubject: string;
|
|
222
|
+
openEmailAria: string;
|
|
223
|
+
backToEmails: string;
|
|
224
|
+
viewHtml: string;
|
|
225
|
+
viewText: string;
|
|
226
|
+
viewportDesktop: string;
|
|
227
|
+
viewportMobile: string;
|
|
228
|
+
copyHtml: string;
|
|
229
|
+
copiedHtml: string;
|
|
230
|
+
copyHtmlFailed: string;
|
|
231
|
+
reload: string;
|
|
232
|
+
openInTab: string;
|
|
233
|
+
notFound: string;
|
|
234
|
+
unresolvedCount: string;
|
|
235
|
+
unresolvedTitle: string;
|
|
236
|
+
};
|
|
213
237
|
themes: {
|
|
214
238
|
title: string;
|
|
215
239
|
noThemesTitle: string;
|
package/src/locale/zh-cn.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const zhCN: Locale = {
|
|
|
23
23
|
duplicate: '复制',
|
|
24
24
|
themes: '主题',
|
|
25
25
|
assets: '素材',
|
|
26
|
+
emails: '邮件',
|
|
26
27
|
folders: '頁面夹',
|
|
27
28
|
pages: '幻灯片',
|
|
28
29
|
menu: '菜单',
|
|
@@ -193,6 +194,7 @@ export const zhCN: Locale = {
|
|
|
193
194
|
placeholder: '搜索幻灯片或执行命令…',
|
|
194
195
|
empty: '没有匹配的结果。',
|
|
195
196
|
groupDocs: '幻灯片',
|
|
197
|
+
groupEmails: '邮件',
|
|
196
198
|
groupFolders: '頁面夹',
|
|
197
199
|
groupNavigation: '前往',
|
|
198
200
|
groupAppearance: '外观',
|
|
@@ -211,6 +213,29 @@ export const zhCN: Locale = {
|
|
|
211
213
|
system: '系统',
|
|
212
214
|
},
|
|
213
215
|
|
|
216
|
+
emails: {
|
|
217
|
+
title: '邮件',
|
|
218
|
+
noEmailsTitle: '还没有邮件',
|
|
219
|
+
noEmailsHintPrefix: '在你的代理中运行 ',
|
|
220
|
+
noEmailsHintSuffix: ' 即可在 emails/ 下创建一封。',
|
|
221
|
+
subjectLabel: '主题',
|
|
222
|
+
noSubject: '未设置主题',
|
|
223
|
+
openEmailAria: '打开邮件 {name}',
|
|
224
|
+
backToEmails: '返回邮件列表',
|
|
225
|
+
viewHtml: 'HTML',
|
|
226
|
+
viewText: '纯文本',
|
|
227
|
+
viewportDesktop: '桌面',
|
|
228
|
+
viewportMobile: '移动端',
|
|
229
|
+
copyHtml: '复制 HTML',
|
|
230
|
+
copiedHtml: '已复制 HTML',
|
|
231
|
+
copyHtmlFailed: '无法复制 HTML',
|
|
232
|
+
reload: '重新加载邮件',
|
|
233
|
+
openInTab: '在新标签页中单独打开渲染后的邮件',
|
|
234
|
+
notFound: '找不到邮件: {id}',
|
|
235
|
+
unresolvedCount: '{count} 个类未能编译',
|
|
236
|
+
unresolvedTitle:
|
|
237
|
+
'邮件编译器无法内联的 Tailwind 工具类 (请检查 components/email/email-theme.ts):',
|
|
238
|
+
},
|
|
214
239
|
themes: {
|
|
215
240
|
title: '主题',
|
|
216
241
|
noThemesTitle: '尚无主题',
|
package/src/locale/zh-tw.ts
CHANGED
|
@@ -23,6 +23,7 @@ export const zhTW: Locale = {
|
|
|
23
23
|
duplicate: '複製',
|
|
24
24
|
themes: '主題',
|
|
25
25
|
assets: '素材',
|
|
26
|
+
emails: '郵件',
|
|
26
27
|
folders: '資料夾',
|
|
27
28
|
pages: '投影片',
|
|
28
29
|
menu: '選單',
|
|
@@ -193,6 +194,7 @@ export const zhTW: Locale = {
|
|
|
193
194
|
placeholder: '搜尋簡報或執行指令…',
|
|
194
195
|
empty: '沒有符合的結果。',
|
|
195
196
|
groupDocs: '簡報',
|
|
197
|
+
groupEmails: '郵件',
|
|
196
198
|
groupFolders: '資料夾',
|
|
197
199
|
groupNavigation: '前往',
|
|
198
200
|
groupAppearance: '外觀',
|
|
@@ -211,6 +213,29 @@ export const zhTW: Locale = {
|
|
|
211
213
|
system: '系統',
|
|
212
214
|
},
|
|
213
215
|
|
|
216
|
+
emails: {
|
|
217
|
+
title: '郵件',
|
|
218
|
+
noEmailsTitle: '還沒有郵件',
|
|
219
|
+
noEmailsHintPrefix: '在你的代理中執行 ',
|
|
220
|
+
noEmailsHintSuffix: ' 即可在 emails/ 下建立一封。',
|
|
221
|
+
subjectLabel: '主旨',
|
|
222
|
+
noSubject: '未設定主旨',
|
|
223
|
+
openEmailAria: '開啟郵件 {name}',
|
|
224
|
+
backToEmails: '返回郵件列表',
|
|
225
|
+
viewHtml: 'HTML',
|
|
226
|
+
viewText: '純文字',
|
|
227
|
+
viewportDesktop: '桌面',
|
|
228
|
+
viewportMobile: '行動裝置',
|
|
229
|
+
copyHtml: '複製 HTML',
|
|
230
|
+
copiedHtml: '已複製 HTML',
|
|
231
|
+
copyHtmlFailed: '無法複製 HTML',
|
|
232
|
+
reload: '重新載入郵件',
|
|
233
|
+
openInTab: '在新分頁中單獨開啟渲染後的郵件',
|
|
234
|
+
notFound: '找不到郵件: {id}',
|
|
235
|
+
unresolvedCount: '{count} 個類別未能編譯',
|
|
236
|
+
unresolvedTitle:
|
|
237
|
+
'郵件編譯器無法內聯的 Tailwind 工具類別 (請檢查 components/email/email-theme.ts):',
|
|
238
|
+
},
|
|
214
239
|
themes: {
|
|
215
240
|
title: '主題',
|
|
216
241
|
noThemesTitle: '尚無主題',
|
|
@@ -10,9 +10,15 @@
|
|
|
10
10
|
|
|
11
11
|
@custom-variant dark (&:is(.dark *));
|
|
12
12
|
|
|
13
|
-
|
|
14
|
-
|
|
13
|
+
/* Fonts are emitted as :root variables (not inlined) so a theme's own
|
|
14
|
+
:root block can swap them; inlined, Geist would be baked into every
|
|
15
|
+
font-* utility and themes could never change the typeface. */
|
|
16
|
+
@theme {
|
|
15
17
|
--font-sans: 'Geist Variable', sans-serif;
|
|
18
|
+
--font-heading: var(--font-sans);
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
@theme inline {
|
|
16
22
|
--color-sidebar-ring: var(--sidebar-ring);
|
|
17
23
|
--color-sidebar-border: var(--sidebar-border);
|
|
18
24
|
--color-sidebar-accent-foreground: var(--sidebar-accent-foreground);
|