create-nextblock 0.2.76 → 0.2.77
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/package.json
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
"use client"
|
|
3
3
|
|
|
4
4
|
import React, { type ReactNode, useEffect } from "react"
|
|
5
|
-
import { useAuth } from "
|
|
5
|
+
import { useAuth } from "../../context/AuthContext"
|
|
6
6
|
import { useRouter, usePathname } from "next/navigation" // Import usePathname
|
|
7
7
|
import Link from "next/link"
|
|
8
8
|
import {
|
|
@@ -12,7 +12,7 @@ import {
|
|
|
12
12
|
import { Button } from "@nextblock-cms/ui"
|
|
13
13
|
import { Avatar, AvatarFallback, AvatarImage } from "@nextblock-cms/ui"
|
|
14
14
|
import { cn } from "@nextblock-cms/utils"
|
|
15
|
-
import { signOutAction } from "
|
|
15
|
+
import { signOutAction } from "../actions";
|
|
16
16
|
import Image from "next/image";
|
|
17
17
|
import { FeedbackModal } from "./components/FeedbackModal";
|
|
18
18
|
|
|
@@ -36,9 +36,10 @@ type NavItemProps = {
|
|
|
36
36
|
writerOnly?: boolean
|
|
37
37
|
isAdmin?: boolean
|
|
38
38
|
isWriter?: boolean
|
|
39
|
+
onClick?: () => void
|
|
39
40
|
}
|
|
40
41
|
|
|
41
|
-
const NavItem = ({ href, icon: Icon, children, isActive, adminOnly, writerOnly, isAdmin, isWriter }: NavItemProps) => {
|
|
42
|
+
const NavItem = ({ href, icon: Icon, children, isActive, adminOnly, writerOnly, isAdmin, isWriter, onClick }: NavItemProps) => {
|
|
42
43
|
if (adminOnly && !isAdmin) return null
|
|
43
44
|
if (writerOnly && !isWriter && !isAdmin) return null
|
|
44
45
|
|
|
@@ -46,6 +47,7 @@ const NavItem = ({ href, icon: Icon, children, isActive, adminOnly, writerOnly,
|
|
|
46
47
|
<li>
|
|
47
48
|
<Link
|
|
48
49
|
href={href}
|
|
50
|
+
onClick={onClick}
|
|
49
51
|
className={cn(
|
|
50
52
|
"flex items-center gap-3 px-3 py-2 rounded-lg text-sm font-medium transition-all",
|
|
51
53
|
isActive
|
|
@@ -139,6 +141,12 @@ export default function CmsClientLayout({ children }: { children: ReactNode }) {
|
|
|
139
141
|
return () => window.removeEventListener('resize', handleResize);
|
|
140
142
|
}, []);
|
|
141
143
|
|
|
144
|
+
const closeSidebarOnMobile = () => {
|
|
145
|
+
if (window.innerWidth < 768) {
|
|
146
|
+
setCmsSidebarOpen(false);
|
|
147
|
+
}
|
|
148
|
+
};
|
|
149
|
+
|
|
142
150
|
|
|
143
151
|
// With server-side auth data, isLoading is initially false.
|
|
144
152
|
// We show a spinner only if something client-side sets it to true (e.g., during logout).
|
|
@@ -230,16 +238,16 @@ export default function CmsClientLayout({ children }: { children: ReactNode }) {
|
|
|
230
238
|
|
|
231
239
|
<nav className="px-3 py-4 flex-1 overflow-y-auto">
|
|
232
240
|
<ul className="space-y-1.5">
|
|
233
|
-
<NavItem href="/cms/dashboard" icon={LayoutDashboard} isActive={pathname === "/cms/dashboard"} isAdmin={isAdmin} isWriter={isWriter}>
|
|
241
|
+
<NavItem href="/cms/dashboard" icon={LayoutDashboard} isActive={pathname === "/cms/dashboard"} isAdmin={isAdmin} isWriter={isWriter} onClick={closeSidebarOnMobile}>
|
|
234
242
|
Dashboard
|
|
235
243
|
</NavItem>
|
|
236
|
-
<NavItem href="/cms/pages" icon={FileText} isActive={pathname.startsWith("/cms/pages")} writerOnly isAdmin={isAdmin} isWriter={isWriter}>
|
|
244
|
+
<NavItem href="/cms/pages" icon={FileText} isActive={pathname.startsWith("/cms/pages")} writerOnly isAdmin={isAdmin} isWriter={isWriter} onClick={closeSidebarOnMobile}>
|
|
237
245
|
Pages
|
|
238
246
|
</NavItem>
|
|
239
|
-
<NavItem href="/cms/posts" icon={PenTool} isActive={pathname.startsWith("/cms/posts")} writerOnly isAdmin={isAdmin} isWriter={isWriter}>
|
|
247
|
+
<NavItem href="/cms/posts" icon={PenTool} isActive={pathname.startsWith("/cms/posts")} writerOnly isAdmin={isAdmin} isWriter={isWriter} onClick={closeSidebarOnMobile}>
|
|
240
248
|
Posts
|
|
241
249
|
</NavItem>
|
|
242
|
-
<NavItem href="/cms/media" icon={ImageIconLucide} isActive={pathname.startsWith("/cms/media")} writerOnly isAdmin={isAdmin} isWriter={isWriter}>
|
|
250
|
+
<NavItem href="/cms/media" icon={ImageIconLucide} isActive={pathname.startsWith("/cms/media")} writerOnly isAdmin={isAdmin} isWriter={isWriter} onClick={closeSidebarOnMobile}>
|
|
243
251
|
Media
|
|
244
252
|
</NavItem>
|
|
245
253
|
|
|
@@ -250,10 +258,10 @@ export default function CmsClientLayout({ children }: { children: ReactNode }) {
|
|
|
250
258
|
Administration
|
|
251
259
|
</p>
|
|
252
260
|
</div>
|
|
253
|
-
<NavItem href="/cms/navigation" icon={ListTree} isActive={pathname.startsWith("/cms/navigation")} adminOnly isAdmin={isAdmin}>
|
|
261
|
+
<NavItem href="/cms/navigation" icon={ListTree} isActive={pathname.startsWith("/cms/navigation")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
254
262
|
Navigation
|
|
255
263
|
</NavItem>
|
|
256
|
-
<NavItem href="/cms/users" icon={Users} isActive={pathname.startsWith("/cms/users")} adminOnly isAdmin={isAdmin}>
|
|
264
|
+
<NavItem href="/cms/users" icon={Users} isActive={pathname.startsWith("/cms/users")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
257
265
|
Manage Users
|
|
258
266
|
</NavItem>
|
|
259
267
|
<CollapsibleNavItem
|
|
@@ -263,16 +271,16 @@ export default function CmsClientLayout({ children }: { children: ReactNode }) {
|
|
|
263
271
|
adminOnly
|
|
264
272
|
isAdmin={isAdmin}
|
|
265
273
|
>
|
|
266
|
-
<NavItem href="/cms/settings/languages" icon={LanguagesIconLucide} isActive={pathname.startsWith("/cms/settings/languages")} adminOnly isAdmin={isAdmin}>
|
|
274
|
+
<NavItem href="/cms/settings/languages" icon={LanguagesIconLucide} isActive={pathname.startsWith("/cms/settings/languages")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
267
275
|
Languages
|
|
268
276
|
</NavItem>
|
|
269
|
-
<NavItem href="/cms/settings/logos" icon={ImageIconLucide} isActive={pathname.startsWith("/cms/settings/logos")} adminOnly isAdmin={isAdmin}>
|
|
277
|
+
<NavItem href="/cms/settings/logos" icon={ImageIconLucide} isActive={pathname.startsWith("/cms/settings/logos")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
270
278
|
Logos
|
|
271
279
|
</NavItem>
|
|
272
|
-
<NavItem href="/cms/settings/copyright" icon={CopyrightIcon} isActive={pathname.startsWith("/cms/settings/copyright")} adminOnly isAdmin={isAdmin}>
|
|
280
|
+
<NavItem href="/cms/settings/copyright" icon={CopyrightIcon} isActive={pathname.startsWith("/cms/settings/copyright")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
273
281
|
Copyright
|
|
274
282
|
</NavItem>
|
|
275
|
-
<NavItem href="/cms/settings/extra-translations" icon={MessageSquare} isActive={pathname.startsWith("/cms/settings/extra-translations")} adminOnly isAdmin={isAdmin}>
|
|
283
|
+
<NavItem href="/cms/settings/extra-translations" icon={MessageSquare} isActive={pathname.startsWith("/cms/settings/extra-translations")} adminOnly isAdmin={isAdmin} onClick={closeSidebarOnMobile}>
|
|
276
284
|
Extra Translations
|
|
277
285
|
</NavItem>
|
|
278
286
|
</CollapsibleNavItem>
|
|
@@ -5,6 +5,8 @@ import { createClient } from "@nextblock-cms/db/server";
|
|
|
5
5
|
import { revalidatePath } from "next/cache";
|
|
6
6
|
import type { Database } from "@nextblock-cms/db";
|
|
7
7
|
import { encodedRedirect } from "@nextblock-cms/utils/server";
|
|
8
|
+
import { DeleteObjectCommand, DeleteObjectsCommand, CopyObjectCommand, ListObjectsV2Command, HeadObjectCommand } from "@aws-sdk/client-s3";
|
|
9
|
+
import { getS3Client } from "@nextblock-cms/utils/server";
|
|
8
10
|
|
|
9
11
|
type Media = Database['public']['Tables']['media']['Row'];
|
|
10
12
|
|
|
@@ -201,8 +203,6 @@ export async function deleteMediaItem(mediaId: string, objectKey: string) {
|
|
|
201
203
|
return encodedRedirect("error", "/cms/media", "Forbidden: Insufficient permissions.");
|
|
202
204
|
}
|
|
203
205
|
|
|
204
|
-
const { DeleteObjectCommand } = await import("@aws-sdk/client-s3");
|
|
205
|
-
const { getS3Client } = await import("@nextblock-cms/utils/server");
|
|
206
206
|
const s3Client = await getS3Client();
|
|
207
207
|
const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME;
|
|
208
208
|
|
|
@@ -255,8 +255,6 @@ export async function deleteMultipleMediaItems(items: Array<{ id: string; object
|
|
|
255
255
|
return { error: "No items selected for deletion." };
|
|
256
256
|
}
|
|
257
257
|
|
|
258
|
-
const { DeleteObjectsCommand } = await import("@aws-sdk/client-s3"); // Use DeleteObjects for batch
|
|
259
|
-
const { getS3Client } = await import("@nextblock-cms/utils/server");
|
|
260
258
|
const s3Client = await getS3Client();
|
|
261
259
|
const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME;
|
|
262
260
|
|
|
@@ -345,8 +343,6 @@ export async function moveMultipleMediaItems(
|
|
|
345
343
|
};
|
|
346
344
|
const folder = sanitizeFolder(destinationFolder);
|
|
347
345
|
|
|
348
|
-
const { CopyObjectCommand, DeleteObjectCommand, ListObjectsV2Command, HeadObjectCommand } = await import("@aws-sdk/client-s3");
|
|
349
|
-
const { getS3Client } = await import("@nextblock-cms/utils/server");
|
|
350
346
|
const s3Client = await getS3Client();
|
|
351
347
|
const R2_BUCKET_NAME = process.env.R2_BUCKET_NAME;
|
|
352
348
|
const R2_PUBLIC_URL_BASE = process.env.NEXT_PUBLIC_R2_BASE_URL || '';
|
|
@@ -348,26 +348,31 @@ export default function ResponsiveNav({
|
|
|
348
348
|
{/* Menu Content (this part slides with the container above) */}
|
|
349
349
|
<div className="fixed top-16 left-0 h-[calc(100vh-4rem)] w-full max-w-sm bg-background text-foreground shadow-xl p-5 z-50 flex flex-col">
|
|
350
350
|
<nav className="flex-grow flex flex-col space-y-1 overflow-y-auto pt-6">
|
|
351
|
-
|
|
352
|
-
|
|
353
|
-
|
|
354
|
-
|
|
355
|
-
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-gray-100 dark:hover:bg-gray-700"
|
|
356
|
-
onClick={() => {
|
|
357
|
-
toggleMobileMenu();
|
|
358
|
-
}}
|
|
359
|
-
>
|
|
360
|
-
{editPathDetails.label}
|
|
361
|
-
</Link>
|
|
362
|
-
)}
|
|
351
|
+
<div className="space-y-1">
|
|
352
|
+
{renderMobileNavItems(hierarchicalNavItems)}
|
|
353
|
+
</div>
|
|
354
|
+
|
|
363
355
|
{canAccessCms && (
|
|
364
|
-
<
|
|
365
|
-
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
356
|
+
<div className="mt-auto space-y-1 border-t border-gray-200 dark:border-gray-800">
|
|
357
|
+
{editPathDetails && (
|
|
358
|
+
<Link
|
|
359
|
+
href={editPathDetails.href}
|
|
360
|
+
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-gray-100 dark:hover:bg-gray-700"
|
|
361
|
+
onClick={() => {
|
|
362
|
+
toggleMobileMenu();
|
|
363
|
+
}}
|
|
364
|
+
>
|
|
365
|
+
{editPathDetails.label}
|
|
366
|
+
</Link>
|
|
367
|
+
)}
|
|
368
|
+
<Link
|
|
369
|
+
href={cmsDashboardLinkHref}
|
|
370
|
+
className="block px-3 py-2 rounded-md text-base font-medium text-foreground hover:bg-gray-100 dark:hover:bg-gray-700"
|
|
371
|
+
onClick={toggleMobileMenu}
|
|
372
|
+
>
|
|
373
|
+
{t('cms_dashboard')}
|
|
374
|
+
</Link>
|
|
375
|
+
</div>
|
|
371
376
|
)}
|
|
372
377
|
</nav>
|
|
373
378
|
|