@autono/open-pages 0.1.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.
Files changed (110) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +108 -0
  3. package/bin.js +2 -0
  4. package/dist/build-TP72kiw7.js +35 -0
  5. package/dist/cli/bin.d.ts +1 -0
  6. package/dist/cli/bin.js +100 -0
  7. package/dist/config-C9or4m4J.d.ts +23 -0
  8. package/dist/config-L0IbktJ0.js +3135 -0
  9. package/dist/design-C13iz9_4.js +35 -0
  10. package/dist/dev-I2IyEh5W.js +97 -0
  11. package/dist/export-B-kBRWB1.js +4 -0
  12. package/dist/export-ic28osQP.js +131 -0
  13. package/dist/index.d.ts +56 -0
  14. package/dist/index.js +3 -0
  15. package/dist/locale/index.d.ts +24 -0
  16. package/dist/locale/index.js +881 -0
  17. package/dist/open-pages-plugin-D_DN_zjh.js +632 -0
  18. package/dist/preview-BrDuvgAN.js +21 -0
  19. package/dist/sync-Be_hxSOF.js +139 -0
  20. package/dist/sync-lKEXyPOh.js +3 -0
  21. package/dist/types-C5NCdDT-.d.ts +219 -0
  22. package/dist/update-CV62NhBT.js +37 -0
  23. package/dist/update-package-Cxt57pz7.js +152 -0
  24. package/dist/version-B6AiiGvT.js +26 -0
  25. package/dist/version-CeffgdfZ.js +3 -0
  26. package/dist/vite/index.d.ts +14 -0
  27. package/dist/vite/index.js +7 -0
  28. package/env.d.ts +59 -0
  29. package/package.json +106 -0
  30. package/skills/apply-comments/SKILL.md +86 -0
  31. package/skills/create-page/SKILL.md +92 -0
  32. package/skills/create-theme/SKILL.md +223 -0
  33. package/skills/current-page/SKILL.md +106 -0
  34. package/skills/page-authoring/SKILL.md +148 -0
  35. package/skills/page-authoring/references/assets-and-fonts.md +85 -0
  36. package/skills/page-authoring/references/html-pages.md +65 -0
  37. package/skills/page-authoring/references/interactivity.md +77 -0
  38. package/skills/page-authoring/references/layout-and-responsive.md +71 -0
  39. package/skills/page-authoring/references/typography-and-color.md +60 -0
  40. package/src/app/app.tsx +45 -0
  41. package/src/app/components/asset-view.tsx +1665 -0
  42. package/src/app/components/command/command-menu.tsx +227 -0
  43. package/src/app/components/command/command.tsx +142 -0
  44. package/src/app/components/command/home-command-menu.tsx +96 -0
  45. package/src/app/components/icon-tooltip.tsx +34 -0
  46. package/src/app/components/language-toggle.tsx +46 -0
  47. package/src/app/components/sidebar/folder-item.tsx +269 -0
  48. package/src/app/components/sidebar/icon-picker.tsx +61 -0
  49. package/src/app/components/sidebar/sidebar-footer.tsx +139 -0
  50. package/src/app/components/sidebar/sidebar.tsx +302 -0
  51. package/src/app/components/theme-toggle.tsx +66 -0
  52. package/src/app/components/themes/theme-detail.tsx +226 -0
  53. package/src/app/components/themes/themes-gallery.tsx +104 -0
  54. package/src/app/components/ui/badge.tsx +48 -0
  55. package/src/app/components/ui/button.tsx +93 -0
  56. package/src/app/components/ui/card.tsx +92 -0
  57. package/src/app/components/ui/context-menu.tsx +247 -0
  58. package/src/app/components/ui/dialog.tsx +155 -0
  59. package/src/app/components/ui/dropdown-menu.tsx +267 -0
  60. package/src/app/components/ui/input.tsx +25 -0
  61. package/src/app/components/ui/label.tsx +21 -0
  62. package/src/app/components/ui/popover.tsx +82 -0
  63. package/src/app/components/ui/progress.tsx +33 -0
  64. package/src/app/components/ui/scroll-area.tsx +53 -0
  65. package/src/app/components/ui/select.tsx +195 -0
  66. package/src/app/components/ui/separator.tsx +26 -0
  67. package/src/app/components/ui/slider.tsx +68 -0
  68. package/src/app/components/ui/sonner.tsx +48 -0
  69. package/src/app/components/ui/tabs.tsx +79 -0
  70. package/src/app/components/ui/textarea.tsx +22 -0
  71. package/src/app/components/ui/toggle-group.tsx +84 -0
  72. package/src/app/components/ui/toggle.tsx +45 -0
  73. package/src/app/components/ui/tooltip.tsx +75 -0
  74. package/src/app/favicon.ico +0 -0
  75. package/src/app/frame/inspect.ts +140 -0
  76. package/src/app/frame/main.tsx +91 -0
  77. package/src/app/frame.html +12 -0
  78. package/src/app/index.html +13 -0
  79. package/src/app/lib/asset-filter.test.ts +176 -0
  80. package/src/app/lib/asset-filter.ts +80 -0
  81. package/src/app/lib/assets.ts +257 -0
  82. package/src/app/lib/design.ts +58 -0
  83. package/src/app/lib/folders.ts +239 -0
  84. package/src/app/lib/frame.ts +38 -0
  85. package/src/app/lib/locale-store.ts +67 -0
  86. package/src/app/lib/page-thumb.tsx +46 -0
  87. package/src/app/lib/pages.ts +28 -0
  88. package/src/app/lib/sdk.ts +43 -0
  89. package/src/app/lib/themes.ts +22 -0
  90. package/src/app/lib/use-locale.ts +8 -0
  91. package/src/app/lib/use-page-module.ts +48 -0
  92. package/src/app/lib/use-page-titles.ts +29 -0
  93. package/src/app/lib/use-restart-server.ts +78 -0
  94. package/src/app/lib/utils.test.ts +25 -0
  95. package/src/app/lib/utils.ts +6 -0
  96. package/src/app/main.tsx +14 -0
  97. package/src/app/routes/assets.tsx +9 -0
  98. package/src/app/routes/home-shell.tsx +252 -0
  99. package/src/app/routes/home.tsx +846 -0
  100. package/src/app/routes/page.tsx +329 -0
  101. package/src/app/routes/themes.tsx +34 -0
  102. package/src/app/styles.css +405 -0
  103. package/src/app/virtual.d.ts +53 -0
  104. package/src/locale/en.ts +218 -0
  105. package/src/locale/format.ts +12 -0
  106. package/src/locale/index.ts +6 -0
  107. package/src/locale/ja.ts +221 -0
  108. package/src/locale/types.ts +215 -0
  109. package/src/locale/zh-cn.ts +218 -0
  110. package/src/locale/zh-tw.ts +218 -0
@@ -0,0 +1,14 @@
1
+ import { ThemeProvider } from 'next-themes';
2
+ import { StrictMode } from 'react';
3
+ import { createRoot } from 'react-dom/client';
4
+ import { App } from './app';
5
+ import './styles.css';
6
+
7
+ // biome-ignore lint/style/noNonNullAssertion: #root is guaranteed by index.html
8
+ createRoot(document.getElementById('root')!).render(
9
+ <StrictMode>
10
+ <ThemeProvider attribute="class" defaultTheme="system" enableSystem disableTransitionOnChange>
11
+ <App />
12
+ </ThemeProvider>
13
+ </StrictMode>,
14
+ );
@@ -0,0 +1,9 @@
1
+ import { AssetView } from '../components/asset-view';
2
+
3
+ export function AssetsPage() {
4
+ return (
5
+ <div className="flex min-h-0 flex-1 flex-col">
6
+ <AssetView pageId={null} />
7
+ </div>
8
+ );
9
+ }
@@ -0,0 +1,252 @@
1
+ import { Menu } from 'lucide-react';
2
+ import { useCallback, useMemo, useState } from 'react';
3
+ import { Outlet, useLocation, useNavigate, useSearchParams } from 'react-router-dom';
4
+ import { toast } from 'sonner';
5
+ import { LanguageToggle } from '@/components/language-toggle';
6
+ import { ThemeToggle } from '@/components/theme-toggle';
7
+ import {
8
+ DropdownMenu,
9
+ DropdownMenuContent,
10
+ DropdownMenuItem,
11
+ DropdownMenuTrigger,
12
+ } from '@/components/ui/dropdown-menu';
13
+ import { useAssets } from '@/lib/assets';
14
+ import { useFolders } from '@/lib/folders';
15
+ import { format, useLocale } from '@/lib/use-locale';
16
+ import { cn } from '@/lib/utils';
17
+ import { CommandMenuTrigger } from '../components/command/command-menu';
18
+ import { HomeCommandMenu } from '../components/command/home-command-menu';
19
+ import { FolderIconChip } from '../components/sidebar/folder-item';
20
+ import { ALL_DOCS_ID, ASSETS_ID, Sidebar, THEMES_ID } from '../components/sidebar/sidebar';
21
+ import { pageIds } from '../lib/pages';
22
+ import type { FoldersManifest } from '../lib/sdk';
23
+ import { themes as themeRegistry } from '../lib/themes';
24
+
25
+ export type HomeOutletContext = {
26
+ manifest: FoldersManifest;
27
+ loading: boolean;
28
+ draftDocs: string[];
29
+ docsByFolder: Record<string, string[]>;
30
+ /** Selected view id: ALL_DOCS_ID, DRAFT_ID, a folder id, THEMES_ID, or ASSETS_ID. */
31
+ selectedId: string;
32
+ selectFolder: (id: string) => void;
33
+ reportTitle: (pageId: string, title: string) => void;
34
+ titleMap: Record<string, string>;
35
+ assign: (pageId: string, folderId: string | null) => Promise<void>;
36
+ renameDoc: (pageId: string, name: string) => Promise<void>;
37
+ duplicatePage: (pageId: string, newId?: string) => Promise<string>;
38
+ deletePage: (pageId: string) => Promise<void>;
39
+ };
40
+
41
+ function pathToSelectedId(pathname: string, search: URLSearchParams): string {
42
+ if (pathname === '/themes' || pathname.startsWith('/themes/')) return THEMES_ID;
43
+ if (pathname === '/assets') return ASSETS_ID;
44
+ return search.get('f') ?? ALL_DOCS_ID;
45
+ }
46
+
47
+ export function HomeShell() {
48
+ const {
49
+ manifest,
50
+ loading,
51
+ create,
52
+ update,
53
+ remove,
54
+ reorder,
55
+ assign,
56
+ renameDoc,
57
+ duplicatePage,
58
+ deletePage,
59
+ } = useFolders();
60
+ const navigate = useNavigate();
61
+ const location = useLocation();
62
+ const [searchParams] = useSearchParams();
63
+ const t = useLocale();
64
+
65
+ const selectedId = pathToSelectedId(location.pathname, searchParams);
66
+
67
+ const [commandOpen, setCommandOpen] = useState(false);
68
+ const openCommandMenu = useCallback(() => setCommandOpen(true), []);
69
+
70
+ const [titleMap, setTitleMap] = useState<Record<string, string>>({});
71
+ const reportTitle = useCallback((pageId: string, pageTitle: string) => {
72
+ setTitleMap((prev) => (prev[pageId] === pageTitle ? prev : { ...prev, [pageId]: pageTitle }));
73
+ }, []);
74
+
75
+ const selectFolder = useCallback(
76
+ (id: string) => {
77
+ if (id === THEMES_ID) navigate('/themes', { replace: true });
78
+ else if (id === ASSETS_ID) navigate('/assets', { replace: true });
79
+ else if (id === ALL_DOCS_ID) navigate('/', { replace: true });
80
+ else navigate(`/?f=${encodeURIComponent(id)}`, { replace: true });
81
+ },
82
+ [navigate],
83
+ );
84
+
85
+ const { assets: globalAssets } = useAssets('@global');
86
+ const isAssetsRoute = location.pathname === '/assets';
87
+
88
+ const { draftDocs, docsByFolder } = useMemo(() => {
89
+ const byFolder: Record<string, string[]> = {};
90
+ const draft: string[] = [];
91
+ const known = new Set(manifest.folders.map((f) => f.id));
92
+ for (const id of pageIds) {
93
+ const folderId = manifest.assignments[id];
94
+ if (folderId && known.has(folderId)) {
95
+ byFolder[folderId] ??= [];
96
+ byFolder[folderId].push(id);
97
+ } else {
98
+ draft.push(id);
99
+ }
100
+ }
101
+ return { draftDocs: draft, docsByFolder: byFolder };
102
+ }, [manifest]);
103
+
104
+ const countFor = (folderId: string | null) =>
105
+ folderId === null ? draftDocs.length : (docsByFolder[folderId]?.length ?? 0);
106
+
107
+ const moveDocWithToast = useCallback(
108
+ async (pageId: string, folderId: string | null) => {
109
+ if (manifest.assignments[pageId] === (folderId ?? undefined)) return;
110
+ const docName = titleMap[pageId] ?? pageId;
111
+ const folderName =
112
+ folderId === null
113
+ ? t.home.draft
114
+ : (manifest.folders.find((f) => f.id === folderId)?.name ?? folderId);
115
+ try {
116
+ await assign(pageId, folderId);
117
+ toast.success(format(t.home.toastDocMoved, { page: docName, folder: folderName }));
118
+ } catch {
119
+ toast.error(t.home.toastDocMoveFailed);
120
+ }
121
+ },
122
+ [assign, manifest, titleMap, t],
123
+ );
124
+
125
+ const ctx: HomeOutletContext = {
126
+ manifest,
127
+ loading,
128
+ draftDocs,
129
+ docsByFolder,
130
+ selectedId,
131
+ selectFolder,
132
+ reportTitle,
133
+ titleMap,
134
+ assign,
135
+ renameDoc,
136
+ duplicatePage,
137
+ deletePage,
138
+ };
139
+
140
+ return (
141
+ <div className="flex h-dvh overflow-hidden bg-background text-foreground">
142
+ <div className="hidden md:block">
143
+ <Sidebar
144
+ folders={manifest.folders}
145
+ countFor={countFor}
146
+ allCount={pageIds.length}
147
+ themesCount={themeRegistry.length}
148
+ assetsCount={globalAssets.length}
149
+ selectedId={selectedId}
150
+ onSelect={selectFolder}
151
+ onCreate={(name, icon) => create(name, icon)}
152
+ onRename={(id, name) => update(id, { name })}
153
+ onChangeIcon={(id, icon) => update(id, { icon })}
154
+ onDelete={async (id) => {
155
+ const name = manifest.folders.find((f) => f.id === id)?.name ?? id;
156
+ if (selectedId === id) selectFolder(ALL_DOCS_ID);
157
+ try {
158
+ await remove(id);
159
+ toast.success(format(t.home.toastFolderDeleted, { name }));
160
+ } catch {
161
+ toast.error(t.home.toastFolderDeleteFailed);
162
+ }
163
+ }}
164
+ onOpenCommandMenu={openCommandMenu}
165
+ onDropToFolder={(folderId, pageId) => moveDocWithToast(pageId, folderId)}
166
+ onDropToDraft={(pageId) => moveDocWithToast(pageId, null)}
167
+ onReorder={async (ids) => {
168
+ try {
169
+ await reorder(ids);
170
+ } catch {
171
+ toast.error(t.home.toastFolderReorderFailed);
172
+ }
173
+ }}
174
+ />
175
+ </div>
176
+
177
+ <div className="relative flex min-w-0 flex-1 flex-col overflow-y-auto bg-canvas">
178
+ <div className="flex items-center justify-between border-b border-hairline bg-sidebar px-4 py-3 md:hidden">
179
+ <h1 className="font-heading text-lg font-bold tracking-tight">{t.home.appTitle}</h1>
180
+ <div className="-mr-1.5 flex items-center gap-0.5">
181
+ <CommandMenuTrigger onClick={openCommandMenu} />
182
+ <LanguageToggle />
183
+ <ThemeToggle />
184
+ <DropdownMenu>
185
+ <DropdownMenuTrigger
186
+ render={
187
+ <button
188
+ type="button"
189
+ aria-label={t.home.menu}
190
+ className="flex size-8 items-center justify-center rounded-[6px] text-muted-foreground hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground"
191
+ >
192
+ <Menu className="size-4" />
193
+ </button>
194
+ }
195
+ />
196
+ <DropdownMenuContent align="end" className="min-w-[200px]">
197
+ <DropdownMenuItem
198
+ onClick={() => selectFolder(ALL_DOCS_ID)}
199
+ className={cn(
200
+ selectedId !== THEMES_ID &&
201
+ selectedId !== ASSETS_ID &&
202
+ 'bg-muted text-foreground',
203
+ )}
204
+ >
205
+ <FolderIconChip icon={{ type: 'emoji', value: '🎞️' }} />
206
+ <span className="flex-1 truncate">{t.home.pages}</span>
207
+ <span className="folio">{pageIds.length.toString().padStart(2, '0')}</span>
208
+ </DropdownMenuItem>
209
+ <DropdownMenuItem
210
+ onClick={() => selectFolder(THEMES_ID)}
211
+ className={cn(selectedId === THEMES_ID && 'bg-muted text-foreground')}
212
+ >
213
+ <FolderIconChip icon={{ type: 'emoji', value: '🎨' }} />
214
+ <span className="flex-1 truncate">{t.home.themes}</span>
215
+ <span className="folio">{themeRegistry.length.toString().padStart(2, '0')}</span>
216
+ </DropdownMenuItem>
217
+ {import.meta.env.DEV && (
218
+ <DropdownMenuItem
219
+ onClick={() => selectFolder(ASSETS_ID)}
220
+ className={cn(selectedId === ASSETS_ID && 'bg-muted text-foreground')}
221
+ >
222
+ <FolderIconChip icon={{ type: 'emoji', value: '🗂️' }} />
223
+ <span className="flex-1 truncate">{t.home.assets}</span>
224
+ <span className="folio">{globalAssets.length.toString().padStart(2, '0')}</span>
225
+ </DropdownMenuItem>
226
+ )}
227
+ </DropdownMenuContent>
228
+ </DropdownMenu>
229
+ </div>
230
+ </div>
231
+
232
+ <div
233
+ className={cn(
234
+ isAssetsRoute
235
+ ? 'flex min-h-0 flex-1 flex-col'
236
+ : 'mx-auto w-full max-w-[1180px] px-5 py-8 md:px-10 md:py-12',
237
+ )}
238
+ >
239
+ <Outlet context={ctx} />
240
+ </div>
241
+ </div>
242
+
243
+ <HomeCommandMenu
244
+ open={commandOpen}
245
+ onOpenChange={setCommandOpen}
246
+ folders={manifest.folders}
247
+ titleMap={titleMap}
248
+ onSelectView={selectFolder}
249
+ />
250
+ </div>
251
+ );
252
+ }