create-nextblock 0.2.46 → 0.2.47

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 (25) hide show
  1. package/package.json +1 -1
  2. package/templates/nextblock-template/app/cms/dashboard/actions.ts +98 -0
  3. package/templates/nextblock-template/app/cms/dashboard/page.tsx +76 -153
  4. package/templates/nextblock-template/app/cms/media/components/MediaEditForm.tsx +16 -11
  5. package/templates/nextblock-template/app/cms/media/components/MediaUploadForm.tsx +23 -12
  6. package/templates/nextblock-template/app/cms/navigation/components/DeleteNavItemButton.tsx +4 -0
  7. package/templates/nextblock-template/app/cms/navigation/components/NavigationItemForm.tsx +30 -6
  8. package/templates/nextblock-template/app/cms/pages/components/PageForm.tsx +17 -11
  9. package/templates/nextblock-template/app/cms/pages/page.tsx +6 -3
  10. package/templates/nextblock-template/app/cms/posts/components/PostForm.tsx +18 -12
  11. package/templates/nextblock-template/app/cms/posts/page.tsx +8 -5
  12. package/templates/nextblock-template/app/cms/revisions/RevisionHistoryButton.tsx +18 -5
  13. package/templates/nextblock-template/app/cms/settings/copyright/components/CopyrightForm.tsx +20 -4
  14. package/templates/nextblock-template/app/cms/settings/extra-translations/page.tsx +33 -7
  15. package/templates/nextblock-template/app/cms/settings/languages/components/DeleteLanguageButton.tsx +3 -3
  16. package/templates/nextblock-template/app/cms/settings/languages/components/LanguageForm.tsx +41 -13
  17. package/templates/nextblock-template/app/cms/settings/languages/page.tsx +15 -13
  18. package/templates/nextblock-template/app/cms/settings/logos/actions.ts +2 -3
  19. package/templates/nextblock-template/app/cms/settings/logos/components/DeleteLogoButton.tsx +50 -0
  20. package/templates/nextblock-template/app/cms/settings/logos/components/LogoForm.tsx +14 -2
  21. package/templates/nextblock-template/app/cms/settings/logos/page.tsx +3 -6
  22. package/templates/nextblock-template/app/cms/users/components/UserForm.tsx +33 -13
  23. package/templates/nextblock-template/hooks/use-hotkeys.ts +27 -0
  24. package/templates/nextblock-template/next-env.d.ts +1 -1
  25. package/templates/nextblock-template/package.json +1 -1
@@ -17,8 +17,9 @@ import {
17
17
  DropdownMenuTrigger,
18
18
  DropdownMenuSeparator,
19
19
  } from '@nextblock-cms/ui'
20
- import { deleteLogo, getLogos } from './actions'
20
+ import { getLogos } from './actions'
21
21
  import MediaImage from '@/app/cms/media/components/MediaImage'
22
+ import DeleteLogoButton from './components/DeleteLogoButton'
22
23
 
23
24
  const R2_BASE_URL = process.env.NEXT_PUBLIC_R2_BASE_URL || ''
24
25
 
@@ -99,11 +100,7 @@ export default async function CmsLogosListPage() {
99
100
  </Link>
100
101
  </DropdownMenuItem>
101
102
  <DropdownMenuSeparator />
102
- <form action={deleteLogo.bind(null, logo.id)}>
103
- <button type="submit" className="w-full text-left px-2 py-1.5 text-sm text-red-500">
104
- Delete
105
- </button>
106
- </form>
103
+ <DeleteLogoButton logoId={logo.id} />
107
104
  </DropdownMenuContent>
108
105
  </DropdownMenu>
109
106
  </TableCell>
@@ -1,9 +1,12 @@
1
1
  // app/cms/users/components/UserForm.tsx
2
2
  "use client";
3
3
 
4
- import { useEffect, useState, useTransition } from "react";
4
+ import { useEffect, useState, useTransition, useRef } from "react";
5
+ import { useHotkeys } from "@/hooks/use-hotkeys";
5
6
  import { useRouter, useSearchParams } from "next/navigation";
6
7
  import { Button } from "@nextblock-cms/ui";
8
+ import { Spinner, Alert, AlertDescription, Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@nextblock-cms/ui";
9
+ import { Info } from "lucide-react";
7
10
  import { Input } from "@nextblock-cms/ui";
8
11
  import { Label } from "@nextblock-cms/ui";
9
12
  import {
@@ -85,18 +88,15 @@ export default function UserForm({
85
88
 
86
89
  const userRoles: UserRole[] = ['USER', 'WRITER', 'ADMIN'];
87
90
 
91
+ const formRef = useRef<HTMLFormElement>(null);
92
+ useHotkeys('ctrl+s', () => formRef.current?.requestSubmit());
93
+
88
94
  return (
89
- <form onSubmit={handleSubmit} className="space-y-6">
95
+ <form ref={formRef} onSubmit={handleSubmit} className="space-y-6">
90
96
  {formMessage && (
91
- <div
92
- className={`p-3 rounded-md text-sm ${
93
- formMessage.type === 'success'
94
- ? 'bg-green-100 text-green-700 border border-green-200'
95
- : 'bg-red-100 text-red-700 border border-red-200'
96
- }`}
97
- >
98
- {formMessage.text}
99
- </div>
97
+ <Alert variant={formMessage.type === 'success' ? 'success' : 'destructive'}>
98
+ <AlertDescription>{formMessage.text}</AlertDescription>
99
+ </Alert>
100
100
  )}
101
101
  <div>
102
102
  <Label htmlFor="email">Email (Read-only)</Label>
@@ -114,7 +114,21 @@ export default function UserForm({
114
114
  </div>
115
115
 
116
116
  <div>
117
- <Label htmlFor="role">Role</Label>
117
+ <div className="flex items-center gap-2 mb-2">
118
+ <Label htmlFor="role">Role</Label>
119
+ <TooltipProvider>
120
+ <Tooltip>
121
+ <TooltipTrigger asChild>
122
+ <Info className="h-4 w-4 text-muted-foreground opacity-70 cursor-pointer" />
123
+ </TooltipTrigger>
124
+ <TooltipContent className="max-w-xs">
125
+ <p><strong>ADMIN:</strong> Full access to settings and content.</p>
126
+ <p><strong>WRITER:</strong> Can create/edit content, no settings access.</p>
127
+ <p><strong>USER:</strong> Read-only access.</p>
128
+ </TooltipContent>
129
+ </Tooltip>
130
+ </TooltipProvider>
131
+ </div>
118
132
  <Select name="role" value={role} onValueChange={(value) => setRole(value as UserRole)} required>
119
133
  <SelectTrigger className="mt-1"><SelectValue placeholder="Select role" /></SelectTrigger>
120
134
  <SelectContent>
@@ -130,7 +144,13 @@ export default function UserForm({
130
144
  Cancel
131
145
  </Button>
132
146
  <Button type="submit" disabled={isPending || authLoading}>
133
- {isPending ? "Saving..." : actionButtonText}
147
+ {isPending ? (
148
+ <>
149
+ <Spinner className="mr-2 h-4 w-4" /> Saving...
150
+ </>
151
+ ) : (
152
+ actionButtonText
153
+ )}
134
154
  </Button>
135
155
  </div>
136
156
  </form>
@@ -0,0 +1,27 @@
1
+ import { useEffect } from 'react';
2
+
3
+ /**
4
+ * Hook to handle keyboard shortcuts.
5
+ * Currently optimized for 'ctrl+s' / 'meta+s'.
6
+ *
7
+ * @param key The key combination to listen for (e.g. 'ctrl+s')
8
+ * @param callback The function to call when the key combination is pressed
9
+ * @param deps Dependencies array for the effect
10
+ */
11
+ export function useHotkeys(key: string, callback: (event: KeyboardEvent) => void, deps: any[] = []) {
12
+ useEffect(() => {
13
+ const handleKeyDown = (event: KeyboardEvent) => {
14
+ const isCtrl = event.ctrlKey || event.metaKey; // cmd on mac, ctrl on windows
15
+ const keyLower = event.key.toLowerCase();
16
+
17
+ // Check for ctrl+s / cmd+s
18
+ if ((key === 'ctrl+s' || key === 'meta+s') && isCtrl && keyLower === 's') {
19
+ event.preventDefault();
20
+ callback(event);
21
+ }
22
+ };
23
+
24
+ window.addEventListener('keydown', handleKeyDown);
25
+ return () => window.removeEventListener('keydown', handleKeyDown);
26
+ }, [key, ...deps]); // callback should be stable or included in deps if handled by caller
27
+ }
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/dev/types/routes.d.ts";
3
+ import "./.next/types/routes.d.ts";
4
4
 
5
5
  // NOTE: This file should not be edited
6
6
  // see https://nextjs.org/docs/app/api-reference/config/typescript for more information.
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@nextblock-cms/template",
3
- "version": "0.2.24",
3
+ "version": "0.2.25",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",