create-nextblock 0.0.1
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/bin/create-nextblock.js +997 -0
- package/package.json +25 -0
- package/scripts/sync-template.js +284 -0
- package/templates/nextblock-template/.env.example +37 -0
- package/templates/nextblock-template/.swcrc +30 -0
- package/templates/nextblock-template/README.md +194 -0
- package/templates/nextblock-template/app/(auth-pages)/forgot-password/page.tsx +57 -0
- package/templates/nextblock-template/app/(auth-pages)/layout.tsx +9 -0
- package/templates/nextblock-template/app/(auth-pages)/post-sign-in/page.tsx +28 -0
- package/templates/nextblock-template/app/(auth-pages)/sign-in/page.tsx +67 -0
- package/templates/nextblock-template/app/(auth-pages)/sign-up/page.tsx +70 -0
- package/templates/nextblock-template/app/ToasterProvider.tsx +17 -0
- package/templates/nextblock-template/app/[slug]/PageClientContent.tsx +147 -0
- package/templates/nextblock-template/app/[slug]/page.tsx +145 -0
- package/templates/nextblock-template/app/[slug]/page.utils.ts +183 -0
- package/templates/nextblock-template/app/actions/email.ts +31 -0
- package/templates/nextblock-template/app/actions/formActions.ts +65 -0
- package/templates/nextblock-template/app/actions/languageActions.ts +130 -0
- package/templates/nextblock-template/app/actions/postActions.ts +80 -0
- package/templates/nextblock-template/app/actions.ts +146 -0
- package/templates/nextblock-template/app/api/process-image/route.ts +210 -0
- package/templates/nextblock-template/app/api/revalidate/route.ts +86 -0
- package/templates/nextblock-template/app/api/revalidate-log/route.ts +23 -0
- package/templates/nextblock-template/app/api/upload/presigned-url/route.ts +106 -0
- package/templates/nextblock-template/app/api/upload/proxy/route.ts +84 -0
- package/templates/nextblock-template/app/auth/callback/route.ts +58 -0
- package/templates/nextblock-template/app/blog/[slug]/PostClientContent.tsx +169 -0
- package/templates/nextblock-template/app/blog/[slug]/page.tsx +177 -0
- package/templates/nextblock-template/app/blog/[slug]/page.utils.ts +136 -0
- package/templates/nextblock-template/app/blog/page.tsx +77 -0
- package/templates/nextblock-template/app/cms/CmsClientLayout.tsx +321 -0
- package/templates/nextblock-template/app/cms/blocks/actions.ts +434 -0
- package/templates/nextblock-template/app/cms/blocks/components/BackgroundSelector.tsx +348 -0
- package/templates/nextblock-template/app/cms/blocks/components/BlockEditorArea.tsx +567 -0
- package/templates/nextblock-template/app/cms/blocks/components/BlockEditorModal.tsx +98 -0
- package/templates/nextblock-template/app/cms/blocks/components/BlockTypeCard.tsx +58 -0
- package/templates/nextblock-template/app/cms/blocks/components/BlockTypeSelector.tsx +62 -0
- package/templates/nextblock-template/app/cms/blocks/components/ColumnEditor.tsx +276 -0
- package/templates/nextblock-template/app/cms/blocks/components/DeleteBlockButtonClient.tsx +47 -0
- package/templates/nextblock-template/app/cms/blocks/components/EditableBlock.tsx +182 -0
- package/templates/nextblock-template/app/cms/blocks/components/MediaLibraryModal.tsx +120 -0
- package/templates/nextblock-template/app/cms/blocks/components/SectionConfigPanel.tsx +133 -0
- package/templates/nextblock-template/app/cms/blocks/components/SortableBlockItem.tsx +46 -0
- package/templates/nextblock-template/app/cms/blocks/editors/ButtonBlockEditor.tsx +85 -0
- package/templates/nextblock-template/app/cms/blocks/editors/FormBlockEditor.tsx +182 -0
- package/templates/nextblock-template/app/cms/blocks/editors/HeadingBlockEditor.tsx +111 -0
- package/templates/nextblock-template/app/cms/blocks/editors/ImageBlockEditor.tsx +150 -0
- package/templates/nextblock-template/app/cms/blocks/editors/PostsGridBlockEditor.tsx +79 -0
- package/templates/nextblock-template/app/cms/blocks/editors/SectionBlockEditor.tsx +337 -0
- package/templates/nextblock-template/app/cms/blocks/editors/TextBlockEditor.tsx +81 -0
- package/templates/nextblock-template/app/cms/blocks/editors/VideoEmbedBlockEditor.tsx +64 -0
- package/templates/nextblock-template/app/cms/components/ConfirmationModal.tsx +51 -0
- package/templates/nextblock-template/app/cms/components/ContentLanguageSwitcher.tsx +145 -0
- package/templates/nextblock-template/app/cms/components/CopyContentFromLanguage.tsx +203 -0
- package/templates/nextblock-template/app/cms/components/LanguageFilterSelect.tsx +69 -0
- package/templates/nextblock-template/app/cms/dashboard/page.tsx +247 -0
- package/templates/nextblock-template/app/cms/layout.tsx +10 -0
- package/templates/nextblock-template/app/cms/media/UploadFolderContext.tsx +22 -0
- package/templates/nextblock-template/app/cms/media/[id]/edit/page.tsx +80 -0
- package/templates/nextblock-template/app/cms/media/actions.ts +577 -0
- package/templates/nextblock-template/app/cms/media/components/DeleteMediaButtonClient.tsx +53 -0
- package/templates/nextblock-template/app/cms/media/components/FolderNavigator.tsx +273 -0
- package/templates/nextblock-template/app/cms/media/components/FolderTree.tsx +122 -0
- package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +157 -0
- package/templates/nextblock-template/app/cms/media/components/MediaGridClient.tsx +275 -0
- package/templates/nextblock-template/app/cms/media/components/MediaImage.tsx +70 -0
- package/templates/nextblock-template/app/cms/media/components/MediaPickerDialog.tsx +195 -0
- package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +362 -0
- package/templates/nextblock-template/app/cms/media/page.tsx +120 -0
- package/templates/nextblock-template/app/cms/navigation/[id]/edit/page.tsx +101 -0
- package/templates/nextblock-template/app/cms/navigation/actions.ts +358 -0
- package/templates/nextblock-template/app/cms/navigation/components/DeleteNavItemButton.tsx +52 -0
- package/templates/nextblock-template/app/cms/navigation/components/NavigationItemForm.tsx +248 -0
- package/templates/nextblock-template/app/cms/navigation/components/NavigationLanguageSwitcher.tsx +132 -0
- package/templates/nextblock-template/app/cms/navigation/components/NavigationMenuDnd.tsx +701 -0
- package/templates/nextblock-template/app/cms/navigation/components/SortableNavItem.tsx +98 -0
- package/templates/nextblock-template/app/cms/navigation/new/page.tsx +26 -0
- package/templates/nextblock-template/app/cms/navigation/page.tsx +102 -0
- package/templates/nextblock-template/app/cms/navigation/utils.ts +51 -0
- package/templates/nextblock-template/app/cms/pages/[id]/edit/EditPageClient.tsx +121 -0
- package/templates/nextblock-template/app/cms/pages/[id]/edit/page.tsx +79 -0
- package/templates/nextblock-template/app/cms/pages/actions.ts +241 -0
- package/templates/nextblock-template/app/cms/pages/components/DeletePageButtonClient.tsx +47 -0
- package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +253 -0
- package/templates/nextblock-template/app/cms/pages/new/page.tsx +52 -0
- package/templates/nextblock-template/app/cms/pages/page.tsx +232 -0
- package/templates/nextblock-template/app/cms/posts/[id]/edit/page.tsx +183 -0
- package/templates/nextblock-template/app/cms/posts/actions.ts +309 -0
- package/templates/nextblock-template/app/cms/posts/components/DeletePostButtonClient.tsx +55 -0
- package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +419 -0
- package/templates/nextblock-template/app/cms/posts/new/page.tsx +21 -0
- package/templates/nextblock-template/app/cms/posts/page.tsx +192 -0
- package/templates/nextblock-template/app/cms/revisions/JsonDiffView.tsx +86 -0
- package/templates/nextblock-template/app/cms/revisions/RevisionHistoryButton.tsx +201 -0
- package/templates/nextblock-template/app/cms/revisions/actions.ts +84 -0
- package/templates/nextblock-template/app/cms/revisions/service.ts +344 -0
- package/templates/nextblock-template/app/cms/revisions/utils.ts +127 -0
- package/templates/nextblock-template/app/cms/settings/copyright/actions.ts +68 -0
- package/templates/nextblock-template/app/cms/settings/copyright/components/CopyrightForm.tsx +78 -0
- package/templates/nextblock-template/app/cms/settings/copyright/page.tsx +32 -0
- package/templates/nextblock-template/app/cms/settings/extra-translations/actions.ts +117 -0
- package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +216 -0
- package/templates/nextblock-template/app/cms/settings/languages/[id]/edit/page.tsx +77 -0
- package/templates/nextblock-template/app/cms/settings/languages/actions.ts +261 -0
- package/templates/nextblock-template/app/cms/settings/languages/components/DeleteLanguageButton.tsx +76 -0
- package/templates/nextblock-template/app/cms/settings/languages/components/LanguageForm.tsx +167 -0
- package/templates/nextblock-template/app/cms/settings/languages/new/page.tsx +34 -0
- package/templates/nextblock-template/app/cms/settings/languages/page.tsx +156 -0
- package/templates/nextblock-template/app/cms/settings/logos/[id]/edit/page.tsx +19 -0
- package/templates/nextblock-template/app/cms/settings/logos/actions.ts +114 -0
- package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +177 -0
- package/templates/nextblock-template/app/cms/settings/logos/new/page.tsx +11 -0
- package/templates/nextblock-template/app/cms/settings/logos/page.tsx +118 -0
- package/templates/nextblock-template/app/cms/settings/logos/types.ts +8 -0
- package/templates/nextblock-template/app/cms/users/[id]/edit/page.tsx +91 -0
- package/templates/nextblock-template/app/cms/users/actions.ts +156 -0
- package/templates/nextblock-template/app/cms/users/components/DeleteUserButton.tsx +71 -0
- package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +138 -0
- package/templates/nextblock-template/app/cms/users/page.tsx +183 -0
- package/templates/nextblock-template/app/favicon.ico +0 -0
- package/templates/nextblock-template/app/globals.css +401 -0
- package/templates/nextblock-template/app/layout.tsx +191 -0
- package/templates/nextblock-template/app/lib/sitemap-utils.ts +68 -0
- package/templates/nextblock-template/app/page.tsx +109 -0
- package/templates/nextblock-template/app/providers.tsx +43 -0
- package/templates/nextblock-template/app/robots.txt/route.ts +19 -0
- package/templates/nextblock-template/app/sitemap.xml/route.ts +63 -0
- package/templates/nextblock-template/app/unauthorized/page.tsx +27 -0
- package/templates/nextblock-template/backup/backup_2025-06-19.sql +8057 -0
- package/templates/nextblock-template/backup/backup_2025-06-20.sql +8159 -0
- package/templates/nextblock-template/backup/backup_2025-07-08.sql +8411 -0
- package/templates/nextblock-template/backup/backup_2025-07-09.sql +8442 -0
- package/templates/nextblock-template/backup/backup_2025-07-10.sql +8442 -0
- package/templates/nextblock-template/backup/backup_2025-10-01.sql +8803 -0
- package/templates/nextblock-template/backup/backup_2025-10-02.sql +9749 -0
- package/templates/nextblock-template/components/BlockRenderer.tsx +119 -0
- package/templates/nextblock-template/components/FooterNavigation.tsx +33 -0
- package/templates/nextblock-template/components/Header.tsx +42 -0
- package/templates/nextblock-template/components/HtmlScriptExecutor.tsx +47 -0
- package/templates/nextblock-template/components/LanguageSwitcher.tsx +103 -0
- package/templates/nextblock-template/components/ResponsiveNav.tsx +372 -0
- package/templates/nextblock-template/components/blocks/PostCardSkeleton.tsx +17 -0
- package/templates/nextblock-template/components/blocks/PostsGridBlock.tsx +93 -0
- package/templates/nextblock-template/components/blocks/PostsGridClient.tsx +180 -0
- package/templates/nextblock-template/components/blocks/renderers/ButtonBlockRenderer.tsx +92 -0
- package/templates/nextblock-template/components/blocks/renderers/ClientTextBlockRenderer.tsx +69 -0
- package/templates/nextblock-template/components/blocks/renderers/FormBlockRenderer.tsx +98 -0
- package/templates/nextblock-template/components/blocks/renderers/HeadingBlockRenderer.tsx +41 -0
- package/templates/nextblock-template/components/blocks/renderers/HeroBlockRenderer.tsx +240 -0
- package/templates/nextblock-template/components/blocks/renderers/ImageBlockRenderer.tsx +79 -0
- package/templates/nextblock-template/components/blocks/renderers/PostsGridBlockRenderer.tsx +33 -0
- package/templates/nextblock-template/components/blocks/renderers/SectionBlockRenderer.tsx +189 -0
- package/templates/nextblock-template/components/blocks/renderers/TextBlockRenderer.tsx +31 -0
- package/templates/nextblock-template/components/blocks/renderers/VideoEmbedBlockRenderer.tsx +59 -0
- package/templates/nextblock-template/components/blocks/renderers/inline/AlertWidgetRenderer.tsx +51 -0
- package/templates/nextblock-template/components/blocks/renderers/inline/CtaWidgetRenderer.tsx +40 -0
- package/templates/nextblock-template/components/blocks/types.ts +8 -0
- package/templates/nextblock-template/components/env-var-warning.tsx +33 -0
- package/templates/nextblock-template/components/form-message.tsx +26 -0
- package/templates/nextblock-template/components/header-auth.tsx +71 -0
- package/templates/nextblock-template/components/submit-button.tsx +23 -0
- package/templates/nextblock-template/components/theme-switcher.tsx +78 -0
- package/templates/nextblock-template/context/AuthContext.tsx +138 -0
- package/templates/nextblock-template/context/CurrentContentContext.tsx +42 -0
- package/templates/nextblock-template/context/LanguageContext.tsx +206 -0
- package/templates/nextblock-template/docs/cms-application-overview.md +56 -0
- package/templates/nextblock-template/docs/cms-architecture-overview.md +73 -0
- package/templates/nextblock-template/docs/files-structure.md +426 -0
- package/templates/nextblock-template/docs/tiptap-bundle-optimization-summary.md +174 -0
- package/templates/nextblock-template/eslint.config.mjs +28 -0
- package/templates/nextblock-template/index.d.ts +5 -0
- package/templates/nextblock-template/lib/blocks/README.md +670 -0
- package/templates/nextblock-template/lib/blocks/blockRegistry.ts +1001 -0
- package/templates/nextblock-template/lib/ui/ColorPicker.ts +1 -0
- package/templates/nextblock-template/lib/ui/ConfirmationDialog.ts +1 -0
- package/templates/nextblock-template/lib/ui/CustomSelectWithInput.ts +1 -0
- package/templates/nextblock-template/lib/ui/Skeleton.ts +1 -0
- package/templates/nextblock-template/lib/ui/avatar.ts +1 -0
- package/templates/nextblock-template/lib/ui/badge.ts +1 -0
- package/templates/nextblock-template/lib/ui/button.ts +1 -0
- package/templates/nextblock-template/lib/ui/card.ts +1 -0
- package/templates/nextblock-template/lib/ui/checkbox.ts +1 -0
- package/templates/nextblock-template/lib/ui/dialog.ts +1 -0
- package/templates/nextblock-template/lib/ui/dropdown-menu.ts +1 -0
- package/templates/nextblock-template/lib/ui/input.ts +1 -0
- package/templates/nextblock-template/lib/ui/label.ts +1 -0
- package/templates/nextblock-template/lib/ui/popover.ts +1 -0
- package/templates/nextblock-template/lib/ui/progress.ts +1 -0
- package/templates/nextblock-template/lib/ui/select.ts +1 -0
- package/templates/nextblock-template/lib/ui/separator.ts +1 -0
- package/templates/nextblock-template/lib/ui/table.ts +1 -0
- package/templates/nextblock-template/lib/ui/textarea.ts +1 -0
- package/templates/nextblock-template/lib/ui/tooltip.ts +1 -0
- package/templates/nextblock-template/lib/ui/ui.ts +1 -0
- package/templates/nextblock-template/middleware.ts +206 -0
- package/templates/nextblock-template/next-env.d.ts +6 -0
- package/templates/nextblock-template/next.config.js +99 -0
- package/templates/nextblock-template/package.json +52 -0
- package/templates/nextblock-template/postcss.config.js +6 -0
- package/templates/nextblock-template/project.json +7 -0
- package/templates/nextblock-template/public/.gitkeep +0 -0
- package/templates/nextblock-template/scripts/backfill-image-meta.ts +149 -0
- package/templates/nextblock-template/scripts/backup.js +53 -0
- package/templates/nextblock-template/scripts/test-bundle-optimization.js +114 -0
- package/templates/nextblock-template/tailwind.config.ts +19 -0
- package/templates/nextblock-template/tsconfig.json +62 -0
|
@@ -0,0 +1,247 @@
|
|
|
1
|
+
import { Card, CardContent, CardDescription, CardHeader, CardTitle } from "@nextblock-cms/ui"
|
|
2
|
+
import { Calendar, FileText, PenTool, Users, ArrowUpRight, ArrowDownRight, Eye } from "lucide-react"
|
|
3
|
+
|
|
4
|
+
export default function CmsDashboardPage() {
|
|
5
|
+
return (
|
|
6
|
+
<div className="w-full space-y-6">
|
|
7
|
+
<div>
|
|
8
|
+
<h2 className="text-xl font-bold mb-2">Welcome to the CMS Dashboard</h2>
|
|
9
|
+
<p className="text-muted-foreground">Manage your content and monitor site performance from one place.</p>
|
|
10
|
+
</div>
|
|
11
|
+
|
|
12
|
+
{/* Stats overview */}
|
|
13
|
+
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-4 gap-4">
|
|
14
|
+
<Card>
|
|
15
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
16
|
+
<CardTitle className="text-sm font-medium">Total Pages</CardTitle>
|
|
17
|
+
<FileText className="h-4 w-4 text-muted-foreground" />
|
|
18
|
+
</CardHeader>
|
|
19
|
+
<CardContent>
|
|
20
|
+
<div className="text-2xl font-bold">24</div>
|
|
21
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
22
|
+
<span className="text-emerald-500 font-medium inline-flex items-center">
|
|
23
|
+
<ArrowUpRight className="h-3 w-3 mr-1" />
|
|
24
|
+
12%
|
|
25
|
+
</span>{" "}
|
|
26
|
+
from last month
|
|
27
|
+
</p>
|
|
28
|
+
</CardContent>
|
|
29
|
+
</Card>
|
|
30
|
+
|
|
31
|
+
<Card>
|
|
32
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
33
|
+
<CardTitle className="text-sm font-medium">Total Posts</CardTitle>
|
|
34
|
+
<PenTool className="h-4 w-4 text-muted-foreground" />
|
|
35
|
+
</CardHeader>
|
|
36
|
+
<CardContent>
|
|
37
|
+
<div className="text-2xl font-bold">142</div>
|
|
38
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
39
|
+
<span className="text-emerald-500 font-medium inline-flex items-center">
|
|
40
|
+
<ArrowUpRight className="h-3 w-3 mr-1" />
|
|
41
|
+
8%
|
|
42
|
+
</span>{" "}
|
|
43
|
+
from last month
|
|
44
|
+
</p>
|
|
45
|
+
</CardContent>
|
|
46
|
+
</Card>
|
|
47
|
+
|
|
48
|
+
<Card>
|
|
49
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
50
|
+
<CardTitle className="text-sm font-medium">Page Views</CardTitle>
|
|
51
|
+
<Eye className="h-4 w-4 text-muted-foreground" />
|
|
52
|
+
</CardHeader>
|
|
53
|
+
<CardContent>
|
|
54
|
+
<div className="text-2xl font-bold">8,623</div>
|
|
55
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
56
|
+
<span className="text-emerald-500 font-medium inline-flex items-center">
|
|
57
|
+
<ArrowUpRight className="h-3 w-3 mr-1" />
|
|
58
|
+
24%
|
|
59
|
+
</span>{" "}
|
|
60
|
+
from last month
|
|
61
|
+
</p>
|
|
62
|
+
</CardContent>
|
|
63
|
+
</Card>
|
|
64
|
+
|
|
65
|
+
<Card>
|
|
66
|
+
<CardHeader className="flex flex-row items-center justify-between pb-2">
|
|
67
|
+
<CardTitle className="text-sm font-medium">Active Users</CardTitle>
|
|
68
|
+
<Users className="h-4 w-4 text-muted-foreground" />
|
|
69
|
+
</CardHeader>
|
|
70
|
+
<CardContent>
|
|
71
|
+
<div className="text-2xl font-bold">573</div>
|
|
72
|
+
<p className="text-xs text-muted-foreground mt-1">
|
|
73
|
+
<span className="text-red-500 font-medium inline-flex items-center">
|
|
74
|
+
<ArrowDownRight className="h-3 w-3 mr-1" />
|
|
75
|
+
3%
|
|
76
|
+
</span>{" "}
|
|
77
|
+
from last month
|
|
78
|
+
</p>
|
|
79
|
+
</CardContent>
|
|
80
|
+
</Card>
|
|
81
|
+
</div>
|
|
82
|
+
|
|
83
|
+
{/* Recent activity and analytics */}
|
|
84
|
+
<div className="grid grid-cols-1 lg:grid-cols-2 gap-6">
|
|
85
|
+
<Card className="col-span-1">
|
|
86
|
+
<CardHeader>
|
|
87
|
+
<CardTitle>Recent Content</CardTitle>
|
|
88
|
+
<CardDescription>Latest content updates across your site</CardDescription>
|
|
89
|
+
</CardHeader>
|
|
90
|
+
<CardContent>
|
|
91
|
+
<div className="space-y-4">
|
|
92
|
+
{recentContent.map((item, index) => (
|
|
93
|
+
<div key={index} className="flex items-start gap-4 pb-4 border-b last:border-0 last:pb-0">
|
|
94
|
+
<div
|
|
95
|
+
className={`w-8 h-8 rounded-full flex items-center justify-center ${item.type === "page" ? "bg-blue-100 text-blue-600" : "bg-amber-100 text-amber-600"} dark:bg-opacity-20`}
|
|
96
|
+
>
|
|
97
|
+
{item.type === "page" ? <FileText className="h-4 w-4" /> : <PenTool className="h-4 w-4" />}
|
|
98
|
+
</div>
|
|
99
|
+
<div className="flex-1">
|
|
100
|
+
<h4 className="text-sm font-medium">{item.title}</h4>
|
|
101
|
+
<div className="flex items-center gap-2 mt-1">
|
|
102
|
+
<p className="text-xs text-muted-foreground">{item.author}</p>
|
|
103
|
+
<span className="text-xs text-muted-foreground">•</span>
|
|
104
|
+
<p className="text-xs text-muted-foreground">{item.date}</p>
|
|
105
|
+
</div>
|
|
106
|
+
</div>
|
|
107
|
+
<div className="flex items-center">
|
|
108
|
+
<span
|
|
109
|
+
className={`text-xs px-2 py-1 rounded-full ${item.status === "Published" ? "bg-emerald-100 text-emerald-700" : "bg-amber-100 text-amber-700"} dark:bg-opacity-20`}
|
|
110
|
+
>
|
|
111
|
+
{item.status}
|
|
112
|
+
</span>
|
|
113
|
+
</div>
|
|
114
|
+
</div>
|
|
115
|
+
))}
|
|
116
|
+
</div>
|
|
117
|
+
</CardContent>
|
|
118
|
+
</Card>
|
|
119
|
+
|
|
120
|
+
<Card className="col-span-1">
|
|
121
|
+
<CardHeader>
|
|
122
|
+
<CardTitle>Upcoming Schedule</CardTitle>
|
|
123
|
+
<CardDescription>Content scheduled for publication</CardDescription>
|
|
124
|
+
</CardHeader>
|
|
125
|
+
<CardContent>
|
|
126
|
+
<div className="space-y-4">
|
|
127
|
+
{scheduledContent.map((item, index) => (
|
|
128
|
+
<div key={index} className="flex items-start gap-4 pb-4 border-b last:border-0 last:pb-0">
|
|
129
|
+
<div className="w-10 h-10 rounded bg-slate-100 dark:bg-slate-800 flex flex-col items-center justify-center text-center">
|
|
130
|
+
<span className="text-xs font-medium">{item.month}</span>
|
|
131
|
+
<span className="text-sm font-bold">{item.day}</span>
|
|
132
|
+
</div>
|
|
133
|
+
<div className="flex-1">
|
|
134
|
+
<h4 className="text-sm font-medium">{item.title}</h4>
|
|
135
|
+
<div className="flex items-center gap-2 mt-1">
|
|
136
|
+
<Calendar className="h-3 w-3 text-muted-foreground" />
|
|
137
|
+
<p className="text-xs text-muted-foreground">{item.time}</p>
|
|
138
|
+
</div>
|
|
139
|
+
</div>
|
|
140
|
+
<div className="flex items-center">
|
|
141
|
+
<span className="text-xs px-2 py-1 rounded-full bg-slate-100 text-slate-700 dark:bg-slate-800 dark:text-slate-300">
|
|
142
|
+
{item.type}
|
|
143
|
+
</span>
|
|
144
|
+
</div>
|
|
145
|
+
</div>
|
|
146
|
+
))}
|
|
147
|
+
</div>
|
|
148
|
+
</CardContent>
|
|
149
|
+
</Card>
|
|
150
|
+
</div>
|
|
151
|
+
|
|
152
|
+
{/* Analytics chart */}
|
|
153
|
+
<Card>
|
|
154
|
+
<CardHeader>
|
|
155
|
+
<CardTitle>Traffic Overview</CardTitle>
|
|
156
|
+
<CardDescription>Page views over the last 30 days</CardDescription>
|
|
157
|
+
</CardHeader>
|
|
158
|
+
<CardContent>
|
|
159
|
+
<div className="h-[200px] flex items-end gap-2">
|
|
160
|
+
{analyticsData.map((item, index) => (
|
|
161
|
+
<div key={index} className="flex-1 flex flex-col items-center">
|
|
162
|
+
<div
|
|
163
|
+
className="w-full bg-primary/10 dark:bg-primary/20 rounded-sm"
|
|
164
|
+
style={{ height: `${item.value}%` }}
|
|
165
|
+
></div>
|
|
166
|
+
<span className="text-xs text-muted-foreground mt-2">{item.label}</span>
|
|
167
|
+
</div>
|
|
168
|
+
))}
|
|
169
|
+
</div>
|
|
170
|
+
</CardContent>
|
|
171
|
+
</Card>
|
|
172
|
+
</div>
|
|
173
|
+
)
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
// Sample data
|
|
177
|
+
const recentContent = [
|
|
178
|
+
{
|
|
179
|
+
title: "Homepage Redesign",
|
|
180
|
+
type: "page",
|
|
181
|
+
author: "John Smith",
|
|
182
|
+
date: "Today, 2:30 PM",
|
|
183
|
+
status: "Published",
|
|
184
|
+
},
|
|
185
|
+
{
|
|
186
|
+
title: "New Product Launch",
|
|
187
|
+
type: "post",
|
|
188
|
+
author: "Sarah Johnson",
|
|
189
|
+
date: "Yesterday, 10:15 AM",
|
|
190
|
+
status: "Published",
|
|
191
|
+
},
|
|
192
|
+
{
|
|
193
|
+
title: "Q2 Marketing Strategy",
|
|
194
|
+
type: "post",
|
|
195
|
+
author: "Michael Brown",
|
|
196
|
+
date: "May 12, 2023",
|
|
197
|
+
status: "Draft",
|
|
198
|
+
},
|
|
199
|
+
{
|
|
200
|
+
title: "About Us Page",
|
|
201
|
+
type: "page",
|
|
202
|
+
author: "John Smith",
|
|
203
|
+
date: "May 10, 2023",
|
|
204
|
+
status: "Published",
|
|
205
|
+
},
|
|
206
|
+
]
|
|
207
|
+
|
|
208
|
+
const scheduledContent = [
|
|
209
|
+
{
|
|
210
|
+
title: "Summer Sale Announcement",
|
|
211
|
+
month: "May",
|
|
212
|
+
day: "20",
|
|
213
|
+
time: "9:00 AM",
|
|
214
|
+
type: "Post",
|
|
215
|
+
},
|
|
216
|
+
{
|
|
217
|
+
title: "New Feature Release",
|
|
218
|
+
month: "May",
|
|
219
|
+
day: "22",
|
|
220
|
+
time: "12:00 PM",
|
|
221
|
+
type: "Page",
|
|
222
|
+
},
|
|
223
|
+
{
|
|
224
|
+
title: "Customer Testimonials",
|
|
225
|
+
month: "May",
|
|
226
|
+
day: "25",
|
|
227
|
+
time: "3:30 PM",
|
|
228
|
+
type: "Post",
|
|
229
|
+
},
|
|
230
|
+
{
|
|
231
|
+
title: "Team Page Update",
|
|
232
|
+
month: "May",
|
|
233
|
+
day: "28",
|
|
234
|
+
time: "10:00 AM",
|
|
235
|
+
type: "Page",
|
|
236
|
+
},
|
|
237
|
+
]
|
|
238
|
+
|
|
239
|
+
const analyticsData = [
|
|
240
|
+
{ label: "1", value: 20 },
|
|
241
|
+
{ label: "5", value: 40 },
|
|
242
|
+
{ label: "10", value: 35 },
|
|
243
|
+
{ label: "15", value: 50 },
|
|
244
|
+
{ label: "20", value: 30 },
|
|
245
|
+
{ label: "25", value: 80 },
|
|
246
|
+
{ label: "30", value: 60 },
|
|
247
|
+
]
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
"use client";
|
|
2
|
+
|
|
3
|
+
import React, { createContext, useContext } from "react";
|
|
4
|
+
|
|
5
|
+
type UploadFolderContextValue = {
|
|
6
|
+
defaultFolder?: string | null;
|
|
7
|
+
};
|
|
8
|
+
|
|
9
|
+
const UploadFolderContext = createContext<UploadFolderContextValue>({ defaultFolder: undefined });
|
|
10
|
+
|
|
11
|
+
export function UploadFolderProvider({ defaultFolder, children }: { defaultFolder?: string; children: React.ReactNode }) {
|
|
12
|
+
return (
|
|
13
|
+
<UploadFolderContext.Provider value={{ defaultFolder }}>
|
|
14
|
+
{children}
|
|
15
|
+
</UploadFolderContext.Provider>
|
|
16
|
+
);
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
export function useUploadFolder() {
|
|
20
|
+
return useContext(UploadFolderContext);
|
|
21
|
+
}
|
|
22
|
+
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
// app/cms/media/[id]/edit/page.tsx
|
|
2
|
+
import React from "react";
|
|
3
|
+
import { createClient } from "@nextblock-cms/db/server";
|
|
4
|
+
import MediaEditForm from "../../components/MediaEditForm"; // Adjusted path
|
|
5
|
+
import { updateMediaItem } from "../../actions"; // Server action for updating
|
|
6
|
+
import type { Database } from "@nextblock-cms/db";
|
|
7
|
+
import { notFound, redirect } from "next/navigation";
|
|
8
|
+
|
|
9
|
+
type Media = Database['public']['Tables']['media']['Row'];
|
|
10
|
+
import { ArrowLeft } from "lucide-react";
|
|
11
|
+
import Link from "next/link";
|
|
12
|
+
import { Button } from "@nextblock-cms/ui";
|
|
13
|
+
|
|
14
|
+
async function getMediaData(id: string): Promise<Media | null> {
|
|
15
|
+
const supabase = createClient();
|
|
16
|
+
// Validate if ID is a UUID, otherwise Supabase might error
|
|
17
|
+
// For simplicity, we assume it's a valid UUID format if it reaches here.
|
|
18
|
+
const { data, error } = await supabase
|
|
19
|
+
.from("media")
|
|
20
|
+
.select("*")
|
|
21
|
+
.eq("id", id)
|
|
22
|
+
.single();
|
|
23
|
+
|
|
24
|
+
if (error) {
|
|
25
|
+
console.error("Error fetching media for edit:", error);
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
return data;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export default async function EditMediaPage(props: { params: Promise<{ id: string }> }) {
|
|
32
|
+
const params = await props.params;
|
|
33
|
+
const mediaId = params.id;
|
|
34
|
+
if (!mediaId) { // Basic check, UUID validation could be added
|
|
35
|
+
return notFound();
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// Verify admin/writer role before even fetching (optional, RLS on media table should also protect)
|
|
39
|
+
const supabase = createClient();
|
|
40
|
+
const { data: { user } } = await supabase.auth.getUser();
|
|
41
|
+
if (!user) return redirect("/sign-in?redirect=/cms/media");
|
|
42
|
+
|
|
43
|
+
const { data: profile } = await supabase.from("profiles").select("role").eq("id", user.id).single();
|
|
44
|
+
if (!profile || !["ADMIN", "WRITER"].includes(profile.role)) {
|
|
45
|
+
return <div className="p-6">Access Denied. You do not have permission to edit media.</div>;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
const mediaItem = await getMediaData(mediaId);
|
|
49
|
+
|
|
50
|
+
if (!mediaItem) {
|
|
51
|
+
return notFound();
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
// Bind the mediaId to the updateMediaItem server action
|
|
55
|
+
// Wrap to accept FormData as expected by MediaEditForm
|
|
56
|
+
const updateMediaFormAction = async (formData: FormData) => {
|
|
57
|
+
"use server";
|
|
58
|
+
const description = formData.get("description") as string | undefined;
|
|
59
|
+
const file_name = formData.get("file_name") as string | undefined;
|
|
60
|
+
// Return data instead of redirect to avoid NEXT_REDIRECT noise during dev
|
|
61
|
+
return await updateMediaItem(mediaItem.id, { description, file_name }, true);
|
|
62
|
+
};
|
|
63
|
+
|
|
64
|
+
return (
|
|
65
|
+
<div className="w-full">
|
|
66
|
+
<div className="mb-6 flex items-center gap-3">
|
|
67
|
+
<Button variant="outline" size="icon" asChild>
|
|
68
|
+
<Link href="/cms/media">
|
|
69
|
+
<ArrowLeft className="h-4 w-4" />
|
|
70
|
+
</Link>
|
|
71
|
+
</Button>
|
|
72
|
+
<h1 className="text-2xl font-semibold">Edit Media: {mediaItem.file_name}</h1>
|
|
73
|
+
</div>
|
|
74
|
+
<MediaEditForm
|
|
75
|
+
mediaItem={mediaItem}
|
|
76
|
+
formAction={updateMediaFormAction}
|
|
77
|
+
/>
|
|
78
|
+
</div>
|
|
79
|
+
);
|
|
80
|
+
}
|