@dyrected/admin 2.4.0 → 2.4.2
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/App.d.ts +1 -0
- package/dist/admin.css +2 -0
- package/dist/components/auth/auth-gate.d.ts +13 -0
- package/dist/components/error-boundary.d.ts +16 -0
- package/dist/components/forms/field-renderer.d.ts +22 -0
- package/dist/components/forms/fields/block-builder.d.ts +9 -0
- package/dist/components/forms/fields/date-picker.d.ts +8 -0
- package/dist/components/forms/fields/json-editor.d.ts +8 -0
- package/dist/components/forms/fields/media-picker.d.ts +12 -0
- package/dist/components/forms/fields/multi-select.d.ts +19 -0
- package/dist/components/forms/fields/radio-field.d.ts +8 -0
- package/dist/components/forms/fields/relationship-picker.d.ts +10 -0
- package/dist/components/forms/fields/rich-text-editor.d.ts +9 -0
- package/dist/components/forms/fields/select-field.d.ts +8 -0
- package/dist/components/forms/fields/switch-field.d.ts +6 -0
- package/dist/components/forms/fields/text-area-field.d.ts +8 -0
- package/dist/components/forms/fields/text-field.d.ts +8 -0
- package/dist/components/forms/form-engine.d.ts +14 -0
- package/dist/components/forms/form-field-renderer.d.ts +20 -0
- package/dist/components/forms/utils.d.ts +11 -0
- package/dist/components/layout/admin-shell.d.ts +5 -0
- package/dist/components/layout/branding-provider.d.ts +4 -0
- package/dist/components/live-preview/LivePreviewPane.d.ts +7 -0
- package/dist/components/media/focal-point-picker.d.ts +12 -0
- package/dist/components/media/media-card.d.ts +8 -0
- package/dist/components/media/media-grid.d.ts +8 -0
- package/dist/components/media/media-library-dialog.d.ts +11 -0
- package/dist/components/ui/aspect-ratio.d.ts +3 -0
- package/dist/components/ui/badge.d.ts +9 -0
- package/dist/components/ui/button.d.ts +11 -0
- package/dist/components/ui/calendar.d.ts +8 -0
- package/dist/components/ui/card.d.ts +8 -0
- package/dist/components/ui/checkbox.d.ts +4 -0
- package/dist/components/ui/command.d.ts +80 -0
- package/dist/components/ui/data-table.d.ts +14 -0
- package/dist/components/ui/dialog.d.ts +19 -0
- package/dist/components/ui/dropdown-menu.d.ts +27 -0
- package/dist/components/ui/form.d.ts +23 -0
- package/dist/components/ui/input.d.ts +3 -0
- package/dist/components/ui/label.d.ts +5 -0
- package/dist/components/ui/page-header.d.ts +10 -0
- package/dist/components/ui/pagination.d.ts +11 -0
- package/dist/components/ui/popover.d.ts +6 -0
- package/dist/components/ui/progress.d.ts +4 -0
- package/dist/components/ui/radio-group.d.ts +5 -0
- package/dist/components/ui/render-cell.d.ts +8 -0
- package/dist/components/ui/scroll-area.d.ts +5 -0
- package/dist/components/ui/select.d.ts +13 -0
- package/dist/components/ui/separator.d.ts +4 -0
- package/dist/components/ui/sheet.d.ts +25 -0
- package/dist/components/ui/sidebar.d.ts +65 -0
- package/dist/components/ui/skeleton.d.ts +2 -0
- package/dist/components/ui/sonner.d.ts +4 -0
- package/dist/components/ui/switch.d.ts +4 -0
- package/dist/components/ui/table.d.ts +10 -0
- package/dist/components/ui/tabs.d.ts +7 -0
- package/dist/components/ui/textarea.d.ts +3 -0
- package/dist/components/ui/toggle.d.ts +12 -0
- package/dist/components/ui/tooltip.d.ts +7 -0
- package/dist/hooks/use-mobile.d.ts +1 -0
- package/dist/hooks/use-preferences.d.ts +6 -0
- package/dist/index.d.ts +38 -0
- package/dist/index.mjs +69091 -0
- package/dist/lib/utils.d.ts +3 -0
- package/dist/main.d.ts +0 -0
- package/dist/pages/auth/first-user-page.d.ts +4 -0
- package/dist/pages/auth/login-page.d.ts +4 -0
- package/dist/pages/collections/edit-page.d.ts +1 -0
- package/dist/pages/collections/list-page.d.ts +5 -0
- package/dist/pages/dashboard/dashboard.d.ts +1 -0
- package/dist/pages/globals/editor-page.d.ts +1 -0
- package/dist/pages/media/media-page.d.ts +4 -0
- package/dist/pages/setup/setup-prompt.d.ts +6 -0
- package/dist/providers/dyrected-provider.d.ts +29 -0
- package/dist/providers/query-provider.d.ts +3 -0
- package/package.json +6 -3
- package/CHANGELOG.md +0 -153
- package/components.json +0 -17
- package/eslint.config.js +0 -22
- package/index.html +0 -13
- package/postcss.config.js +0 -6
- package/scripts/prefix-tailwind-precision.py +0 -98
- package/scripts/prefix-tailwind.py +0 -67
- package/src/App.css +0 -184
- package/src/App.tsx +0 -25
- package/src/assets/dyrected.svg +0 -155
- package/src/assets/hero.png +0 -0
- package/src/assets/react.svg +0 -1
- package/src/assets/vite.svg +0 -1
- package/src/components/auth/auth-gate.tsx +0 -64
- package/src/components/error-boundary.tsx +0 -45
- package/src/components/forms/field-renderer.tsx +0 -111
- package/src/components/forms/fields/block-builder.tsx +0 -213
- package/src/components/forms/fields/date-picker.tsx +0 -60
- package/src/components/forms/fields/json-editor.tsx +0 -62
- package/src/components/forms/fields/media-picker.tsx +0 -286
- package/src/components/forms/fields/multi-select.tsx +0 -145
- package/src/components/forms/fields/radio-field.tsx +0 -51
- package/src/components/forms/fields/relationship-picker.tsx +0 -143
- package/src/components/forms/fields/rich-text-editor.tsx +0 -224
- package/src/components/forms/fields/select-field.tsx +0 -35
- package/src/components/forms/fields/switch-field.tsx +0 -16
- package/src/components/forms/fields/text-area-field.tsx +0 -15
- package/src/components/forms/fields/text-field.tsx +0 -24
- package/src/components/forms/form-engine.tsx +0 -87
- package/src/components/forms/form-field-renderer.tsx +0 -269
- package/src/components/forms/utils.ts +0 -97
- package/src/components/layout/admin-shell.tsx +0 -479
- package/src/components/layout/branding-provider.tsx +0 -112
- package/src/components/live-preview/LivePreviewPane.tsx +0 -128
- package/src/components/media/focal-point-picker.tsx +0 -66
- package/src/components/media/media-card.tsx +0 -44
- package/src/components/media/media-grid.tsx +0 -32
- package/src/components/media/media-library-dialog.tsx +0 -465
- package/src/components/ui/aspect-ratio.tsx +0 -7
- package/src/components/ui/badge.tsx +0 -36
- package/src/components/ui/button.tsx +0 -56
- package/src/components/ui/calendar.tsx +0 -214
- package/src/components/ui/card.tsx +0 -79
- package/src/components/ui/checkbox.tsx +0 -28
- package/src/components/ui/command.tsx +0 -151
- package/src/components/ui/data-table.tsx +0 -219
- package/src/components/ui/dialog.tsx +0 -122
- package/src/components/ui/dropdown-menu.tsx +0 -200
- package/src/components/ui/form.tsx +0 -178
- package/src/components/ui/input.tsx +0 -24
- package/src/components/ui/label.tsx +0 -24
- package/src/components/ui/page-header.tsx +0 -30
- package/src/components/ui/pagination.tsx +0 -57
- package/src/components/ui/popover.tsx +0 -29
- package/src/components/ui/progress.tsx +0 -26
- package/src/components/ui/radio-group.tsx +0 -42
- package/src/components/ui/render-cell.tsx +0 -110
- package/src/components/ui/scroll-area.tsx +0 -46
- package/src/components/ui/select.tsx +0 -160
- package/src/components/ui/separator.tsx +0 -29
- package/src/components/ui/sheet.tsx +0 -140
- package/src/components/ui/sidebar.tsx +0 -771
- package/src/components/ui/skeleton.tsx +0 -15
- package/src/components/ui/sonner.tsx +0 -27
- package/src/components/ui/switch.tsx +0 -27
- package/src/components/ui/table.tsx +0 -117
- package/src/components/ui/tabs.tsx +0 -53
- package/src/components/ui/textarea.tsx +0 -22
- package/src/components/ui/toggle.tsx +0 -43
- package/src/components/ui/tooltip.tsx +0 -28
- package/src/hooks/use-mobile.tsx +0 -19
- package/src/hooks/use-preferences.ts +0 -56
- package/src/index.css +0 -111
- package/src/index.tsx +0 -198
- package/src/lib/utils.ts +0 -36
- package/src/main.tsx +0 -10
- package/src/pages/auth/first-user-page.tsx +0 -115
- package/src/pages/auth/login-page.tsx +0 -91
- package/src/pages/collections/edit-page.tsx +0 -280
- package/src/pages/collections/list-page.tsx +0 -343
- package/src/pages/dashboard/dashboard.tsx +0 -150
- package/src/pages/globals/editor-page.tsx +0 -122
- package/src/pages/media/media-page.tsx +0 -564
- package/src/pages/setup/setup-prompt.tsx +0 -181
- package/src/providers/dyrected-provider.tsx +0 -122
- package/src/providers/query-provider.tsx +0 -19
- package/src/types/jexl.d.ts +0 -11
- package/tailwind.config.ts +0 -103
- package/tsconfig.app.json +0 -28
- package/tsconfig.json +0 -12
- package/tsconfig.node.json +0 -25
- package/vite.config.ts +0 -39
- /package/{public → dist}/favicon.svg +0 -0
- /package/{public → dist}/icons.svg +0 -0
package/src/index.tsx
DELETED
|
@@ -1,198 +0,0 @@
|
|
|
1
|
-
/** @jsxImportSource react */
|
|
2
|
-
import "./index.css";
|
|
3
|
-
import React, { useEffect, useState, StrictMode } from "react";
|
|
4
|
-
import { createRoot } from "react-dom/client";
|
|
5
|
-
import {
|
|
6
|
-
HashRouter,
|
|
7
|
-
MemoryRouter,
|
|
8
|
-
Routes,
|
|
9
|
-
Route,
|
|
10
|
-
useParams,
|
|
11
|
-
useLocation,
|
|
12
|
-
} from "react-router-dom";
|
|
13
|
-
import { useQuery } from "@tanstack/react-query";
|
|
14
|
-
import { DyrectedProvider, useDyrected } from "./providers/dyrected-provider";
|
|
15
|
-
import { QueryProvider } from "./providers/query-provider";
|
|
16
|
-
import { AdminShell } from "./components/layout/admin-shell";
|
|
17
|
-
import { Dashboard } from "./pages/dashboard/dashboard";
|
|
18
|
-
import { CollectionListPage } from "./pages/collections/list-page";
|
|
19
|
-
import { EditEntryPage } from "./pages/collections/edit-page";
|
|
20
|
-
import { MediaPage } from "./pages/media/media-page";
|
|
21
|
-
import { GlobalEditorPage } from "./pages/globals/editor-page";
|
|
22
|
-
import { SetupPromptUI } from "./pages/setup/setup-prompt";
|
|
23
|
-
import { ErrorBoundary } from "./components/error-boundary";
|
|
24
|
-
import { AuthGate } from "./components/auth/auth-gate";
|
|
25
|
-
import { Toaster } from "./components/ui/sonner";
|
|
26
|
-
|
|
27
|
-
// ─── Route that resolves collection → list or media page ─────────────────────
|
|
28
|
-
|
|
29
|
-
function CollectionRoute() {
|
|
30
|
-
const { slug } = useParams();
|
|
31
|
-
const { client } = useDyrected();
|
|
32
|
-
|
|
33
|
-
const { data: schemas } = useQuery({
|
|
34
|
-
queryKey: ["schemas"],
|
|
35
|
-
queryFn: () => client?.getSchemas() || Promise.resolve({ collections: [], globals: [] }),
|
|
36
|
-
enabled: !!client,
|
|
37
|
-
});
|
|
38
|
-
|
|
39
|
-
const schema = schemas?.collections.find((c: any) => c.slug === slug);
|
|
40
|
-
|
|
41
|
-
if (schema?.admin?.hidden) {
|
|
42
|
-
return <div>404: Not Found</div>;
|
|
43
|
-
}
|
|
44
|
-
|
|
45
|
-
if (schema?.upload) {
|
|
46
|
-
return <MediaPage collectionSlug={slug!} schema={schema} />;
|
|
47
|
-
}
|
|
48
|
-
|
|
49
|
-
return <CollectionListPage slug={slug!} />;
|
|
50
|
-
}
|
|
51
|
-
|
|
52
|
-
// ─── Setup page — reads config from context ───────────────────────────────────
|
|
53
|
-
|
|
54
|
-
function SetupPage() {
|
|
55
|
-
const { config } = useDyrected();
|
|
56
|
-
return <SetupPromptUI config={config} />;
|
|
57
|
-
}
|
|
58
|
-
|
|
59
|
-
// ─── Navigation sync — notifies host on every internal route change ───────────
|
|
60
|
-
|
|
61
|
-
interface NavigationSyncProps {
|
|
62
|
-
onNavigate?: (path: string) => void;
|
|
63
|
-
}
|
|
64
|
-
|
|
65
|
-
function NavigationSync({ onNavigate }: NavigationSyncProps) {
|
|
66
|
-
const location = useLocation();
|
|
67
|
-
|
|
68
|
-
useEffect(() => {
|
|
69
|
-
onNavigate?.(location.pathname + location.search);
|
|
70
|
-
}, [location, onNavigate]);
|
|
71
|
-
|
|
72
|
-
return null;
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
// ─── Route tree (shared between embedded and standalone) ──────────────────────
|
|
76
|
-
|
|
77
|
-
function AdminRoutes({ onNavigate, isEmbedded = false }: { onNavigate?: (path: string) => void, isEmbedded?: boolean }) {
|
|
78
|
-
return (
|
|
79
|
-
<AuthGate>
|
|
80
|
-
<AdminShell isEmbedded={isEmbedded}>
|
|
81
|
-
<NavigationSync onNavigate={onNavigate} />
|
|
82
|
-
<Routes>
|
|
83
|
-
<Route path="/" element={<Dashboard />} />
|
|
84
|
-
<Route path="/collections/:slug" element={<CollectionRoute />} />
|
|
85
|
-
<Route path="/collections/:slug/new" element={<EditEntryPage />} />
|
|
86
|
-
<Route path="/collections/:slug/edit/:id" element={<EditEntryPage />} />
|
|
87
|
-
<Route path="/globals/:slug" element={<GlobalEditorPage />} />
|
|
88
|
-
<Route path="/setup" element={<SetupPage />} />
|
|
89
|
-
</Routes>
|
|
90
|
-
</AdminShell>
|
|
91
|
-
</AuthGate>
|
|
92
|
-
);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
// ─── Public types ─────────────────────────────────────────────────────────────
|
|
96
|
-
|
|
97
|
-
export interface AdminUIProps {
|
|
98
|
-
apiKey?: string;
|
|
99
|
-
baseUrl?: string;
|
|
100
|
-
siteId?: string;
|
|
101
|
-
/**
|
|
102
|
-
* The base path where the admin is mounted in the host app.
|
|
103
|
-
* Defaults to "/admin". Used by BrowserRouter so internal links
|
|
104
|
-
* are relative to this prefix.
|
|
105
|
-
*
|
|
106
|
-
* Example — Next.js catch-all page at `app/admin/[[...path]]/page.tsx`:
|
|
107
|
-
* <AdminUI basename="/admin" ... />
|
|
108
|
-
*/
|
|
109
|
-
basename?: string;
|
|
110
|
-
/**
|
|
111
|
-
* Called whenever the internal admin route changes.
|
|
112
|
-
* Use this to sync the host router (e.g. Next.js router.push / Nuxt navigateTo)
|
|
113
|
-
* so browser history works correctly when embedded.
|
|
114
|
-
*
|
|
115
|
-
* Example (Nuxt):
|
|
116
|
-
* <AdminUI onNavigate={(path) => navigateTo('/admin' + path)} ... />
|
|
117
|
-
*/
|
|
118
|
-
onNavigate?: (path: string) => void;
|
|
119
|
-
isEmbedded?: boolean
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
// ─── Embedded component (BrowserRouter — real URL + history) ─────────────────
|
|
123
|
-
|
|
124
|
-
export function AdminUI({
|
|
125
|
-
apiKey,
|
|
126
|
-
baseUrl = "/dyrected",
|
|
127
|
-
siteId,
|
|
128
|
-
onNavigate,
|
|
129
|
-
isEmbedded
|
|
130
|
-
}: AdminUIProps) {
|
|
131
|
-
const [mounted, setMounted] = useState(false);
|
|
132
|
-
useEffect(() => setMounted(true), []);
|
|
133
|
-
|
|
134
|
-
if (!mounted) {
|
|
135
|
-
return (
|
|
136
|
-
<div className="dy-flex-1 dy-flex dy-items-center dy-justify-center dy-p-12 dy-bg-muted/5 dy-animate-pulse">
|
|
137
|
-
<div className="dy-text-muted-foreground/40 dy-text-sm dy-font-medium">Loading Dashboard...</div>
|
|
138
|
-
</div>
|
|
139
|
-
);
|
|
140
|
-
}
|
|
141
|
-
|
|
142
|
-
return (
|
|
143
|
-
<div className="dy-admin-ui dy-h-full">
|
|
144
|
-
<ErrorBoundary>
|
|
145
|
-
<DyrectedProvider apiKey={apiKey} baseUrl={baseUrl} siteId={siteId}>
|
|
146
|
-
<QueryProvider>
|
|
147
|
-
<HashRouter>
|
|
148
|
-
<AdminRoutes onNavigate={onNavigate} isEmbedded={isEmbedded} />
|
|
149
|
-
</HashRouter>
|
|
150
|
-
</QueryProvider>
|
|
151
|
-
<Toaster position="top-right" expand={true} richColors />
|
|
152
|
-
</DyrectedProvider>
|
|
153
|
-
</ErrorBoundary>
|
|
154
|
-
</div>
|
|
155
|
-
);
|
|
156
|
-
}
|
|
157
|
-
|
|
158
|
-
/**
|
|
159
|
-
* Renders the Admin UI into a DOM element.
|
|
160
|
-
* Useful for non-React frameworks like Nuxt, Svelte, or Vanilla JS.
|
|
161
|
-
*/
|
|
162
|
-
export function renderAdminUI(container: HTMLElement, props: AdminUIProps) {
|
|
163
|
-
const root = createRoot(container);
|
|
164
|
-
root.render(
|
|
165
|
-
React.createElement(StrictMode, null,
|
|
166
|
-
React.createElement(AdminUI, props)
|
|
167
|
-
)
|
|
168
|
-
);
|
|
169
|
-
return () => root.unmount();
|
|
170
|
-
}
|
|
171
|
-
|
|
172
|
-
// ─── Standalone component (MemoryRouter — for iframe / self-hosted mode) ──────
|
|
173
|
-
|
|
174
|
-
export interface AdminStandaloneProps {
|
|
175
|
-
apiKey: string;
|
|
176
|
-
baseUrl: string;
|
|
177
|
-
siteId?: string;
|
|
178
|
-
}
|
|
179
|
-
|
|
180
|
-
export function AdminStandalone({ apiKey, baseUrl, siteId }: AdminStandaloneProps) {
|
|
181
|
-
return (
|
|
182
|
-
<div className="dy-admin-ui dy-h-full">
|
|
183
|
-
<DyrectedProvider apiKey={apiKey} baseUrl={baseUrl} siteId={siteId}>
|
|
184
|
-
<QueryProvider>
|
|
185
|
-
<MemoryRouter>
|
|
186
|
-
<AdminRoutes />
|
|
187
|
-
</MemoryRouter>
|
|
188
|
-
</QueryProvider>
|
|
189
|
-
<Toaster position="top-right" expand={true} richColors />
|
|
190
|
-
</DyrectedProvider>
|
|
191
|
-
</div>
|
|
192
|
-
);
|
|
193
|
-
}
|
|
194
|
-
|
|
195
|
-
// ─── Re-exports for external use ──────────────────────────────────────────────
|
|
196
|
-
|
|
197
|
-
export { SetupPromptUI } from "./pages/setup/setup-prompt";
|
|
198
|
-
export type { SetupPromptProps } from "./pages/setup/setup-prompt";
|
package/src/lib/utils.ts
DELETED
|
@@ -1,36 +0,0 @@
|
|
|
1
|
-
import { clsx, type ClassValue } from "clsx"
|
|
2
|
-
import { extendTailwindMerge } from "tailwind-merge"
|
|
3
|
-
|
|
4
|
-
const customTwMerge = extendTailwindMerge({
|
|
5
|
-
prefix: "dy-",
|
|
6
|
-
})
|
|
7
|
-
|
|
8
|
-
export function cn(...inputs: ClassValue[]) {
|
|
9
|
-
return customTwMerge(clsx(inputs))
|
|
10
|
-
}
|
|
11
|
-
|
|
12
|
-
export function getMediaUrl(val: string | any, baseUrl: string) {
|
|
13
|
-
if (!val) return "";
|
|
14
|
-
|
|
15
|
-
// Handle object with direct URL
|
|
16
|
-
if (typeof val === 'object' && (val.url || val.filename)) {
|
|
17
|
-
const url = val.url || val.filename;
|
|
18
|
-
if (url.startsWith('http')) return url;
|
|
19
|
-
if (url.startsWith('/')) return `${baseUrl}${url}`;
|
|
20
|
-
// If it's just a filename in the object, use proxy
|
|
21
|
-
return `${baseUrl}/media/${val.filename || val.url}`;
|
|
22
|
-
}
|
|
23
|
-
|
|
24
|
-
const valueStr = typeof val === 'string' ? val : val.id || val.filename || val.url;
|
|
25
|
-
if (!valueStr) return "";
|
|
26
|
-
|
|
27
|
-
if (valueStr.startsWith('http')) return valueStr;
|
|
28
|
-
|
|
29
|
-
// Check if it's a relative path starting with /
|
|
30
|
-
if (valueStr.startsWith('/')) {
|
|
31
|
-
return `${baseUrl}${valueStr}`;
|
|
32
|
-
}
|
|
33
|
-
|
|
34
|
-
// Default fallback to proxy endpoint
|
|
35
|
-
return `${baseUrl}/media/${valueStr}`;
|
|
36
|
-
}
|
package/src/main.tsx
DELETED
|
@@ -1,115 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { useDyrected } from "../../providers/dyrected-provider";
|
|
3
|
-
import { Button } from "../../components/ui/button";
|
|
4
|
-
import { Input } from "../../components/ui/input";
|
|
5
|
-
import { Label } from "../../components/ui/label";
|
|
6
|
-
import { toast } from "sonner";
|
|
7
|
-
|
|
8
|
-
export function FirstUserPage({
|
|
9
|
-
collectionSlug,
|
|
10
|
-
onComplete
|
|
11
|
-
}: {
|
|
12
|
-
collectionSlug: string;
|
|
13
|
-
onComplete: (data: any) => void
|
|
14
|
-
}) {
|
|
15
|
-
const { client } = useDyrected();
|
|
16
|
-
const [email, setEmail] = useState("");
|
|
17
|
-
const [password, setPassword] = useState("");
|
|
18
|
-
const [confirmPassword, setConfirmPassword] = useState("");
|
|
19
|
-
const [error, setError] = useState("");
|
|
20
|
-
const [loading, setLoading] = useState(false);
|
|
21
|
-
|
|
22
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
23
|
-
e.preventDefault();
|
|
24
|
-
setError("");
|
|
25
|
-
|
|
26
|
-
if (password !== confirmPassword) {
|
|
27
|
-
setError("Passwords do not match");
|
|
28
|
-
return;
|
|
29
|
-
}
|
|
30
|
-
|
|
31
|
-
setLoading(true);
|
|
32
|
-
|
|
33
|
-
try {
|
|
34
|
-
const data = await client!.collection(collectionSlug).registerFirstUser({
|
|
35
|
-
email,
|
|
36
|
-
password,
|
|
37
|
-
});
|
|
38
|
-
toast.success("Admin account created successfully");
|
|
39
|
-
onComplete(data);
|
|
40
|
-
} catch (err: any) {
|
|
41
|
-
const message = err.message || "Failed to create initial user";
|
|
42
|
-
setError(message);
|
|
43
|
-
toast.error(message);
|
|
44
|
-
} finally {
|
|
45
|
-
setLoading(false);
|
|
46
|
-
}
|
|
47
|
-
};
|
|
48
|
-
|
|
49
|
-
return (
|
|
50
|
-
<div className="dy-flex dy-min-h-screen dy-items-center dy-justify-center dy-bg-background dy-px-4">
|
|
51
|
-
<div className="dy-w-full dy-max-w-sm dy-space-y-8">
|
|
52
|
-
<div className="dy-space-y-2 dy-text-center">
|
|
53
|
-
<div className="dy-mx-auto dy-h-12 dy-w-12 dy-rounded-full dy-bg-primary/5 dy-flex dy-items-center dy-justify-center dy-mb-4">
|
|
54
|
-
<div className="dy-h-6 dy-w-6 dy-rounded-full dy-border-2 dy-border-primary dy-border-t-transparent dy-animate-pulse" />
|
|
55
|
-
</div>
|
|
56
|
-
<h1 className="dy-text-2xl dy-font-semibold dy-tracking-tight">Setup Admin Account</h1>
|
|
57
|
-
<p className="dy-text-sm dy-text-muted-foreground">Create the first administrative user to get started</p>
|
|
58
|
-
</div>
|
|
59
|
-
|
|
60
|
-
<form onSubmit={handleSubmit} className="dy-space-y-4">
|
|
61
|
-
<div className="dy-space-y-2">
|
|
62
|
-
<Label htmlFor="email">Admin Email</Label>
|
|
63
|
-
<Input
|
|
64
|
-
id="email"
|
|
65
|
-
type="email"
|
|
66
|
-
placeholder="admin@example.com"
|
|
67
|
-
value={email}
|
|
68
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
69
|
-
required
|
|
70
|
-
className="dy-bg-transparent"
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
<div className="dy-space-y-2">
|
|
74
|
-
<Label htmlFor="password">Password</Label>
|
|
75
|
-
<Input
|
|
76
|
-
id="password"
|
|
77
|
-
type="password"
|
|
78
|
-
value={password}
|
|
79
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
80
|
-
required
|
|
81
|
-
className="dy-bg-transparent"
|
|
82
|
-
/>
|
|
83
|
-
</div>
|
|
84
|
-
<div className="dy-space-y-2">
|
|
85
|
-
<Label htmlFor="confirm-password">Confirm Password</Label>
|
|
86
|
-
<Input
|
|
87
|
-
id="confirm-password"
|
|
88
|
-
type="password"
|
|
89
|
-
value={confirmPassword}
|
|
90
|
-
onChange={(e) => setConfirmPassword(e.target.value)}
|
|
91
|
-
required
|
|
92
|
-
className="dy-bg-transparent"
|
|
93
|
-
/>
|
|
94
|
-
</div>
|
|
95
|
-
|
|
96
|
-
{error && (
|
|
97
|
-
<div className="dy-text-xs dy-text-destructive dy-font-medium dy-bg-destructive/10 dy-p-3 dy-rounded-md">
|
|
98
|
-
{error}
|
|
99
|
-
</div>
|
|
100
|
-
)}
|
|
101
|
-
|
|
102
|
-
<Button type="submit" className="dy-w-full" disabled={loading}>
|
|
103
|
-
{loading ? "Creating account..." : "Create Admin Account"}
|
|
104
|
-
</Button>
|
|
105
|
-
</form>
|
|
106
|
-
|
|
107
|
-
<div className="dy-pt-4 dy-border-t dy-text-center dy-space-y-2">
|
|
108
|
-
<p className="dy-text-[10px] dy-text-muted-foreground dy-uppercase dy-tracking-widest">
|
|
109
|
-
Dyrected CMS · Initial Setup
|
|
110
|
-
</p>
|
|
111
|
-
</div>
|
|
112
|
-
</div>
|
|
113
|
-
</div>
|
|
114
|
-
);
|
|
115
|
-
}
|
|
@@ -1,91 +0,0 @@
|
|
|
1
|
-
import React, { useState } from "react";
|
|
2
|
-
import { useDyrected } from "../../providers/dyrected-provider";
|
|
3
|
-
import { Button } from "../../components/ui/button";
|
|
4
|
-
import { Input } from "../../components/ui/input";
|
|
5
|
-
import { Label } from "../../components/ui/label";
|
|
6
|
-
import { toast } from "sonner";
|
|
7
|
-
|
|
8
|
-
export function LoginPage({
|
|
9
|
-
collectionSlug,
|
|
10
|
-
onLogin
|
|
11
|
-
}: {
|
|
12
|
-
collectionSlug: string;
|
|
13
|
-
onLogin: (data: any) => void
|
|
14
|
-
}) {
|
|
15
|
-
const { client } = useDyrected();
|
|
16
|
-
const [email, setEmail] = useState("");
|
|
17
|
-
const [password, setPassword] = useState("");
|
|
18
|
-
const [error, setError] = useState("");
|
|
19
|
-
const [loading, setLoading] = useState(false);
|
|
20
|
-
|
|
21
|
-
const handleSubmit = async (e: React.FormEvent) => {
|
|
22
|
-
e.preventDefault();
|
|
23
|
-
setError("");
|
|
24
|
-
setLoading(true);
|
|
25
|
-
|
|
26
|
-
try {
|
|
27
|
-
const data = await client!.collection(collectionSlug).login(email, password);
|
|
28
|
-
toast.success("Welcome back!");
|
|
29
|
-
onLogin(data);
|
|
30
|
-
} catch (err: any) {
|
|
31
|
-
const message = err.message || "Invalid email or password";
|
|
32
|
-
setError(message);
|
|
33
|
-
toast.error(message);
|
|
34
|
-
} finally {
|
|
35
|
-
setLoading(false);
|
|
36
|
-
}
|
|
37
|
-
};
|
|
38
|
-
|
|
39
|
-
return (
|
|
40
|
-
<div className="dy-flex dy-min-h-screen dy-items-center dy-justify-center dy-bg-background dy-px-4">
|
|
41
|
-
<div className="dy-w-full dy-max-w-sm dy-space-y-8">
|
|
42
|
-
<div className="dy-space-y-2 dy-text-center">
|
|
43
|
-
<h1 className="dy-text-2xl dy-font-semibold dy-tracking-tight">Welcome back</h1>
|
|
44
|
-
<p className="dy-text-sm dy-text-muted-foreground">Enter your credentials to access the dashboard</p>
|
|
45
|
-
</div>
|
|
46
|
-
|
|
47
|
-
<form onSubmit={handleSubmit} className="dy-space-y-4">
|
|
48
|
-
<div className="dy-space-y-2">
|
|
49
|
-
<Label htmlFor="email">Email</Label>
|
|
50
|
-
<Input
|
|
51
|
-
id="email"
|
|
52
|
-
type="email"
|
|
53
|
-
placeholder="name@example.com"
|
|
54
|
-
value={email}
|
|
55
|
-
onChange={(e) => setEmail(e.target.value)}
|
|
56
|
-
required
|
|
57
|
-
className="dy-bg-transparent"
|
|
58
|
-
/>
|
|
59
|
-
</div>
|
|
60
|
-
<div className="dy-space-y-2">
|
|
61
|
-
<div className="dy-flex dy-items-center dy-justify-between">
|
|
62
|
-
<Label htmlFor="password">Password</Label>
|
|
63
|
-
</div>
|
|
64
|
-
<Input
|
|
65
|
-
id="password"
|
|
66
|
-
type="password"
|
|
67
|
-
value={password}
|
|
68
|
-
onChange={(e) => setPassword(e.target.value)}
|
|
69
|
-
required
|
|
70
|
-
className="dy-bg-transparent"
|
|
71
|
-
/>
|
|
72
|
-
</div>
|
|
73
|
-
|
|
74
|
-
{error && (
|
|
75
|
-
<div className="dy-text-xs dy-text-destructive dy-font-medium dy-bg-destructive/10 dy-p-3 dy-rounded-md">
|
|
76
|
-
{error}
|
|
77
|
-
</div>
|
|
78
|
-
)}
|
|
79
|
-
|
|
80
|
-
<Button type="submit" className="dy-w-full" disabled={loading}>
|
|
81
|
-
{loading ? "Signing in..." : "Sign In"}
|
|
82
|
-
</Button>
|
|
83
|
-
</form>
|
|
84
|
-
|
|
85
|
-
<p className="dy-text-center dy-text-xs dy-text-muted-foreground dy-uppercase dy-tracking-widest">
|
|
86
|
-
Dyrected CMS
|
|
87
|
-
</p>
|
|
88
|
-
</div>
|
|
89
|
-
</div>
|
|
90
|
-
);
|
|
91
|
-
}
|