create-nextblock 0.2.26 → 0.2.29

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.
@@ -177,19 +177,22 @@ async function runSetupWizard(projectDir, projectName) {
177
177
  const projectPath = resolve(projectDir);
178
178
  process.chdir(projectPath);
179
179
 
180
- clack.intro('🚀 Welcome to the NextBlock setup wizard!');
181
-
182
- const supabaseDir = resolve(projectPath, 'supabase');
183
- await fs.ensureDir(supabaseDir);
184
- await resetSupabaseProjectRef(projectPath);
185
-
186
- clack.note(
187
- 'Supabase Prerequisites:\n\nBefore proceeding, ensure you have a Supabase project ready.\n\nSupabase Cloud: Create a project at https://supabase.com/dashboard\n\nVercel Storage: If created via Vercel > Storage > Create Database, check your .env.local snippet on Vercel for the required keys.',
188
- );
189
-
190
- clack.note('Connecting to Supabase...');
191
- clack.note('I will now open your browser to log into Supabase.');
192
- await runSupabaseCli(['login'], { cwd: projectPath });
180
+ clack.intro('🚀 Welcome to the NextBlock setup wizard!');
181
+
182
+ const supabaseDir = resolve(projectPath, 'supabase');
183
+ await fs.ensureDir(supabaseDir);
184
+ await resetSupabaseProjectRef(projectPath);
185
+
186
+ clack.note(
187
+ "Before proceeding, ensure you have a Supabase project ready.\n\n" +
188
+ "1. Supabase Cloud: Create a project at https://supabase.com/dashboard\n" +
189
+ "2. Vercel Storage: If created via Vercel > Storage, check your .env.local snippet on Vercel for keys.",
190
+ "Supabase Prerequisites"
191
+ );
192
+
193
+ clack.note('Connecting to Supabase...');
194
+ clack.note('I will now open your browser to log into Supabase.');
195
+ await runSupabaseCli(['login'], { cwd: projectPath });
193
196
 
194
197
  clack.note('Now, please select your NextBlock project when prompted.');
195
198
  await runSupabaseCli(['link'], { cwd: projectPath });
@@ -230,27 +233,27 @@ async function runSetupWizard(projectDir, projectName) {
230
233
  const siteUrl = siteUrlPrompt.trim();
231
234
 
232
235
  clack.note('Please go to your Supabase project dashboard to get the following secrets.');
233
- const supabaseKeys = await clack.group(
234
- {
235
- dbPassword: () =>
236
- clack.password({
237
- message:
238
- 'What is your Database Password? (Supabase: Database > Database Settings > Reset database password | Vercel: POSTGRES_PASSWORD)',
239
- validate: (val) => (!val ? 'Password is required' : undefined),
240
- }),
241
- anonKey: () =>
242
- clack.password({
243
- message:
244
- 'What is your Project API Key (anon key)? (Supabase: Project Settings > API Keys > Project Legacy API Keys | Vercel: SUPABASE_ANON_KEY)',
245
- validate: (val) => (!val ? 'Anon Key is required' : undefined),
246
- }),
247
- serviceKey: () =>
248
- clack.password({
249
- message:
250
- 'What is your Service Role Key (service_role key)? (Supabase: Project Settings > API Keys > Project Legacy API Keys | Vercel: SUPABASE_SERVICE_ROLE_KEY)',
251
- validate: (val) => (!val ? 'Service Role Key is required' : undefined),
252
- }),
253
- },
236
+ const supabaseKeys = await clack.group(
237
+ {
238
+ dbPassword: () =>
239
+ clack.password({
240
+ message:
241
+ 'What is your Database Password? (Supabase: Database > Database Settings > Reset database password | Vercel: POSTGRES_PASSWORD)',
242
+ validate: (val) => (!val ? 'Password is required' : undefined),
243
+ }),
244
+ anonKey: () =>
245
+ clack.password({
246
+ message:
247
+ 'What is your Project API Key (anon key)? (Supabase: Project Settings > API Keys > Project Legacy API Keys | Vercel: SUPABASE_ANON_KEY)',
248
+ validate: (val) => (!val ? 'Anon Key is required' : undefined),
249
+ }),
250
+ serviceKey: () =>
251
+ clack.password({
252
+ message:
253
+ 'What is your Service Role Key (service_role key)? (Supabase: Project Settings > API Keys > Project Legacy API Keys | Vercel: SUPABASE_SERVICE_ROLE_KEY)',
254
+ validate: (val) => (!val ? 'Service Role Key is required' : undefined),
255
+ }),
256
+ },
254
257
  { onCancel: () => handleWizardCancel('Setup cancelled.') },
255
258
  );
256
259
 
@@ -338,15 +341,15 @@ async function runSetupWizard(projectDir, projectName) {
338
341
  }
339
342
  }
340
343
 
341
- clack.note(
342
- 'Optional Cloudflare R2 Setup:\nHave your Account ID, API token (Access + Secret), bucket name, and public bucket URL handy if you want media storage ready now.',
343
- );
344
- const setupR2 = await clack.confirm({
345
- message: 'Do you want to set up Cloudflare R2 for media storage now? (Optional > populate .env keys)',
346
- });
347
- if (clack.isCancel(setupR2)) {
348
- handleWizardCancel('Setup cancelled.');
349
- }
344
+ clack.note(
345
+ 'Optional Cloudflare R2 Setup:\nHave your Account ID, API token (Access + Secret), bucket name, and public bucket URL handy if you want media storage ready now.',
346
+ );
347
+ const setupR2 = await clack.confirm({
348
+ message: 'Do you want to set up Cloudflare R2 for media storage now? (Optional > populate .env keys)',
349
+ });
350
+ if (clack.isCancel(setupR2)) {
351
+ handleWizardCancel('Setup cancelled.');
352
+ }
350
353
 
351
354
  let r2Values = {
352
355
  publicBaseUrl: '',
@@ -360,34 +363,34 @@ async function runSetupWizard(projectDir, projectName) {
360
363
  clack.note('I will open your browser to the R2 dashboard.\nYou need to create a bucket and an R2 API Token.');
361
364
  await open('https://dash.cloudflare.com/?to=/:account/r2', { wait: false });
362
365
 
363
- const r2Keys = await clack.group(
364
- {
365
- accountId: () =>
366
- clack.text({
367
- message: 'R2: Paste your Cloudflare Account ID (Overview > Account Details - Bottom right):',
368
- validate: (val) => (!val ? 'Account ID is required' : undefined),
369
- }),
370
- bucketName: () =>
366
+ const r2Keys = await clack.group(
367
+ {
368
+ accountId: () =>
369
+ clack.text({
370
+ message: 'R2: Paste your Cloudflare Account ID (Overview > Account Details - Bottom right):',
371
+ validate: (val) => (!val ? 'Account ID is required' : undefined),
372
+ }),
373
+ bucketName: () =>
371
374
  clack.text({
372
375
  message: 'R2: Paste your Bucket Name:',
373
376
  validate: (val) => (!val ? 'Bucket name is required' : undefined),
374
377
  }),
375
- accessKey: () =>
376
- clack.password({
377
- message: 'R2: Paste your Access Key ID (create API tokens):',
378
- validate: (val) => (!val ? 'Access Key ID is required' : undefined),
379
- }),
378
+ accessKey: () =>
379
+ clack.password({
380
+ message: 'R2: Paste your Access Key ID (create API tokens):',
381
+ validate: (val) => (!val ? 'Access Key ID is required' : undefined),
382
+ }),
380
383
  secretKey: () =>
381
384
  clack.password({
382
385
  message: 'R2: Paste your Secret Access Key:',
383
386
  validate: (val) => (!val ? 'Secret Access Key is required' : undefined),
384
387
  }),
385
- publicBaseUrl: () =>
386
- clack.text({
387
- message:
388
- 'R2: Public Base URL (Bucket > Settings > Public Development URL-Enable: e.g., https://pub-xxx.r2.dev)',
389
- validate: (val) => (!val ? 'Public base URL is required' : undefined),
390
- }),
388
+ publicBaseUrl: () =>
389
+ clack.text({
390
+ message:
391
+ 'R2: Public Base URL (Bucket > Settings > Public Development URL-Enable: e.g., https://pub-xxx.r2.dev)',
392
+ validate: (val) => (!val ? 'Public base URL is required' : undefined),
393
+ }),
391
394
  },
392
395
  { onCancel: () => handleWizardCancel('Setup cancelled.') },
393
396
  );
@@ -417,10 +420,10 @@ async function runSetupWizard(projectDir, projectName) {
417
420
  clack.note('Cloudflare R2 placeholders added to .env. Configure them later when ready.');
418
421
  }
419
422
 
420
- clack.note(
421
- 'Optional SMTP Setup:\nProvide the host, port, credentials, and from details for your email provider (e.g., Resend, Postmark) to send transactional emails immediately.',
422
- );
423
- const setupSMTP = await clack.confirm({
423
+ clack.note(
424
+ 'Optional SMTP Setup:\nProvide the host, port, credentials, and from details for your email provider (e.g., Resend, Postmark) to send transactional emails immediately.',
425
+ );
426
+ const setupSMTP = await clack.confirm({
424
427
  message: 'Do you want to set up an SMTP server for emails now? (Optional)',
425
428
  });
426
429
  if (clack.isCancel(setupSMTP)) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-nextblock",
3
- "version": "0.2.26",
3
+ "version": "0.2.29",
4
4
  "description": "",
5
5
  "main": "index.js",
6
6
  "bin": {
@@ -1,8 +1,9 @@
1
- # Next.js 15 & Supabase - Ultra-Fast CMS Template
1
+ # Next.js 16 & Supabase - Ultra-Fast CMS Template
2
2
 
3
- This project is a starter template for building an ultra-fast, localized, block-based Content Management System (CMS) using Next.js 15 (App Router), Supabase for the backend (PostgreSQL, Auth, Storage via R2), Tailwind CSS for styling, and shadcn/ui for components.
3
+ This project is a starter template for building an ultra-fast, localized, block-based Content Management System (CMS) using Next.js 16 (App Router), Supabase for the backend (PostgreSQL, Auth, Storage via R2), Tailwind CSS for styling, and shadcn/ui for components.
4
4
 
5
5
  It features:
6
+
6
7
  - Role-Based Access Control (Admin, Writer, User)
7
8
  - Internationalization (i18n) with client-side language switching on single URLs
8
9
  - Block-based content editor for Pages and Posts
@@ -12,156 +13,84 @@ It features:
12
13
 
13
14
  ## Features Implemented (Phases 1-6)
14
15
 
15
- * **Authentication & Authorization (Phase 1):** User roles (ADMIN, WRITER, USER), profiles table linked to `auth.users`, Row Level Security (RLS) on tables, Next.js middleware for route protection, and client-side auth context.
16
- * **Internationalization (Phase 2):** `languages` table in Supabase, client-side language switching using `LanguageContext` without URL path changes (e.g., `/about-us` serves content based on selected language), and auto-creation of localized placeholder content.
17
- * **CMS Schema & Core CRUD (Phase 3):** Database tables for `pages`, `posts`, `media`, `blocks`, `navigation_items`. CRUD UIs and server actions for managing Pages, Posts, Navigation Items, Users (role changes), and Languages.
18
- * **Block-Based Content Builder (Phase 4):** Dynamic block system for Pages (and Posts), UI for adding, editing (basic forms), deleting, and drag-and-drop reordering of content blocks.
19
- * **Rich Text & Media (Phase 5):** Tiptap rich text editor integrated into "Text" blocks, image insertion from Media Library into Tiptap, and media uploads to Cloudflare R2 with a Media Library UI (upload, view, delete, edit metadata).
20
- * **SSG & Revalidation (Phase 6):** Static generation of public pages/posts (default language), client-side content fetching for language changes, `generateStaticParams`, `generateMetadata`, and on-demand revalidation via Supabase Database Webhooks calling a Next.js API route.
16
+ - **Authentication & Authorization (Phase 1):** User roles (ADMIN, WRITER, USER), profiles table linked to `auth.users`, Row Level Security (RLS) on tables, Next.js middleware for route protection, and client-side auth context.
17
+ - **Internationalization (Phase 2):** `languages` table in Supabase, client-side language switching using `LanguageContext` without URL path changes (e.g., `/about-us` serves content based on selected language), and auto-creation of localized placeholder content.
18
+ - **CMS Schema & Core CRUD (Phase 3):** Database tables for `pages`, `posts`, `media`, `blocks`, `navigation_items`. CRUD UIs and server actions for managing Pages, Posts, Navigation Items, Users (role changes), and Languages.
19
+ - **Block-Based Content Builder (Phase 4):** Dynamic block system for Pages (and Posts), UI for adding, editing (basic forms), deleting, and drag-and-drop reordering of content blocks.
20
+ - **Rich Text & Media (Phase 5):** Tiptap rich text editor integrated into "Text" blocks, image insertion from Media Library into Tiptap, and media uploads to Cloudflare R2 with a Media Library UI (upload, view, delete, edit metadata).
21
+ - **SSG & Revalidation (Phase 6):** Static generation of public pages/posts (default language), client-side content fetching for language changes, `generateStaticParams`, `generateMetadata`, and on-demand revalidation via Supabase Database Webhooks calling a Next.js API route.
22
+
23
+ ## 🚀 Getting Started
24
+
25
+ The fastest way to start a new project is with our interactive setup wizard.
26
+
27
+ ```bash
28
+ npm create nextblock@latest
29
+ ```
30
+
31
+ This command will:
21
32
 
22
- ## Clone and Run Locally
33
+ 1. Scaffold a new NextBlock project.
34
+ 2. Guide you through Supabase and Cloudflare R2 configuration.
35
+ 3. Set up your local environment variables automatically.
23
36
 
24
- 1. **Create a Supabase Project:**
25
- * Go to the [Supabase dashboard](https://database.new) and create a new project.
37
+ ### Manual Setup
38
+
39
+ If you are contributing to the core repo or prefer manual setup:
40
+
41
+ 1. **Clone the repo:**
26
42
 
27
- 2. **Clone This Repository:**
28
43
  ```bash
29
- git clone <your-repository-url> your-cms-app
30
- cd your-cms-app
44
+ git clone https://github.com/Webman-Dev/nextblock-monorepo.git
45
+ cd nextblock-monorepo
31
46
  ```
32
47
 
33
- 3. **Install Dependencies:**
48
+ 2. **Install dependencies:**
49
+
34
50
  ```bash
35
51
  npm install
36
- # or
37
- yarn install
38
- # or
39
- pnpm install
40
52
  ```
41
53
 
42
- 4. **Set Up Environment Variables:**
43
- * Rename `.env.example` to `.env.local`.
44
- * Update the following variables in `.env.local` with your Supabase project details and other configurations:
45
-
46
- ```env
47
- # Supabase Project Connection (from your Supabase project's API settings)
48
- NEXT_PUBLIC_SUPABASE_URL=[https://your-project-ref.supabase.co](https://your-project-ref.supabase.co)
49
- NEXT_PUBLIC_SUPABASE_ANON_KEY=your-public-anon-key
50
- SUPABASE_SERVICE_ROLE_KEY=your-service-role-key # Found in API settings, needed for admin actions like deleting users
51
- SUPABASE_PROJECT_ID=your-supabase-project-id # Used by the Supabase CLI (e.g., in supabase/config.toml)
52
-
53
- # Cloudflare R2 Storage (from your Cloudflare R2 bucket settings & API token)
54
- NEXT_PUBLIC_R2_BASE_URL=[https://your-r2-public-url.r2.dev/your-bucket-name](https://your-r2-public-url.r2.dev/your-bucket-name) # Or your custom domain for R2
55
- R2_ACCOUNT_ID=your_cloudflare_account_id
56
- R2_ACCESS_KEY_ID=your_r2_access_key_id
57
- R2_SECRET_ACCESS_KEY=your_r2_secret_access_key
58
- R2_BUCKET_NAME=your_r2_bucket_name
59
- R2_S3_ENDPOINT=https://<R2_ACCOUNT_ID>.r2.cloudflarestorage.com # e.g., [https://abcdef12345.r2.cloudflarestorage.com](https://abcdef12345.r2.cloudflarestorage.com)
60
- R2_REGION=auto # Typically 'auto' for R2
61
-
62
- # Next.js Site Configuration
63
- NEXT_PUBLIC_SITE_URL=http://localhost:3000 # For local dev; update for production (e.g., [https://www.yourdomain.com](https://www.yourdomain.com))
64
- REVALIDATE_SECRET_TOKEN=generate_a_strong_random_string_here # Used to secure the on-demand revalidation API endpoint
65
- ```
66
- * `NEXT_PUBLIC_SUPABASE_URL` and `NEXT_PUBLIC_SUPABASE_ANON_KEY` can be found in your Supabase project's API settings.
67
- * `SUPABASE_SERVICE_ROLE_KEY` is also in API settings (typically hidden by default, click "Reveal").
68
- * Generate a strong, unique string for `REVALIDATE_SECRET_TOKEN`.
69
-
70
- 5. **Apply Supabase Migrations:**
71
- * Ensure you have the Supabase CLI installed and are logged in (`supabase login`).
72
- * Link your local project to your Supabase project:
73
- ```bash
74
- supabase link --project-ref your-project-ref
75
- ```
76
- * Apply all database migrations:
77
- ```bash
78
- supabase db push
79
- ```
80
- Alternatively, if you prefer to run migrations individually (e.g., for a fresh setup or to ensure order):
81
- ```bash
82
- supabase migration up
83
- ```
84
- * This will create all necessary tables (`profiles`, `languages`, `pages`, `posts`, `media`, `blocks`, `navigation_items`), roles, RLS policies, and helper functions.
85
-
86
- 6. **Configure Supabase Database Webhooks for On-Demand Revalidation:**
87
- Since this project avoids using Supabase Edge Functions (and their Docker dependency) for revalidation, you need to manually set up Database Webhooks to call your Next.js API endpoint directly.
88
-
89
- * Go to your Supabase Project Dashboard -> Database -> Webhooks.
90
- * Click "Create a new webhook".
91
-
92
- * **For the `pages` Table:**
93
- * **Name:** `Next.js Revalidate Pages` (or similar)
94
- * **Table:** Select `pages` (from the `public` schema).
95
- * **Events:** Check `INSERT`, `UPDATE`, `DELETE`.
96
- * **Webhook Type:** `HTTP Request`
97
- * **HTTP URL:** Your Next.js application's revalidation API endpoint.
98
- * For local development (if using a tunneling service like ngrok to expose localhost): `http://your-ngrok-url.ngrok.io/api/revalidate`
99
- * For production (e.g., Vercel): `https://your-app-name.vercel.app/api/revalidate`
100
- * **HTTP Method:** `POST`
101
- * **HTTP Headers:**
102
- * Click "Add header".
103
- * Header name: `x-revalidate-secret`
104
- * Header value: The same `REVALIDATE_SECRET_TOKEN` you set in your `.env.local`.
105
- * Click "Add header" again.
106
- * Header name: `Content-Type`
107
- * Header value: `application/json`
108
- * Click "Create webhook".
109
-
110
- * **For the `posts` Table:**
111
- * Create another webhook with similar settings:
112
- * **Name:** `Next.js Revalidate Posts`
113
- * **Table:** `posts`
114
- * **Events:** `INSERT`, `UPDATE`, `DELETE`.
115
- * **HTTP URL:** Same as above.
116
- * **HTTP Method:** `POST`
117
- * **HTTP Headers:**
118
- * `x-revalidate-secret`: Your `REVALIDATE_SECRET_TOKEN`
119
- * `Content-Type`: `application/json`
120
- * Click "Create webhook".
121
-
122
- 7. **Run the Next.js Development Server:**
54
+ 3. **Setup Environment:**
55
+ Copy `.env.exemple` to `apps/nextblock/.env.local` and fill in your Supabase/R2 credentials.
56
+
57
+ 4. **Run the Dev Server:**
58
+
123
59
  ```bash
124
- npm run dev
125
- # or
126
- yarn dev
127
- # or
128
- pnpm dev
60
+ nx serve nextblock
129
61
  ```
130
- The application should now be running on [http://localhost:3000](http://localhost:3000/).
131
62
 
132
- 8. **Initial Admin User Setup:**
133
- * Sign up for a new user account through the application's sign-up page.
134
- * After signing up and verifying the email, you'll need to manually update this user's role to `ADMIN` in the Supabase `profiles` table. You can do this via the Supabase Studio (Table Editor -> `profiles` table).
135
- * Find your user's row (by their ID, which matches `auth.users.id`).
136
- * Change the `role` column value from `USER` to `ADMIN`.
63
+ 5. **Initial Admin User Setup:**
64
+ - Sign up for a new user account through the application's sign-up page.
65
+ - After signing up and verifying the email, you'll need to manually update this user's role to `ADMIN` in the Supabase `profiles` table.
137
66
 
138
- 9. **Shadcn/UI Styling (Optional):**
139
- * This template comes with the default shadcn/ui style initialized. If you want to customize the theme or use a different base color, you can delete `components.json` and re-initialize shadcn/ui following their [official documentation](https://ui.shadcn.com/docs/installation/next).
67
+ 6. **Shadcn/UI Styling (Optional):**
68
+ - This template comes with the default shadcn/ui style initialized. If you want to customize the theme or use a different base color, you can delete `components.json` and re-initialize shadcn/ui following their [official documentation](https://ui.shadcn.com/docs/installation/next).
140
69
 
141
70
  ## Project Structure Highlights
142
71
 
143
- * `app/`: Next.js App Router.
144
- * `app/(auth-pages)/`: Routes for sign-in, sign-up, etc.
145
- * `app/cms/`: CMS admin panel routes and layouts.
146
- * `app/cms/[entity]/`: CRUD pages for different content types (pages, posts, media, users, navigation, languages).
147
- * `app/cms/blocks/`: Components and actions related to the block editor.
148
- * `app/[slug]/`: Dynamic route for public "Pages".
149
- * `app/article/[slug]/`: Dynamic route for public "Articles".
150
- * `app/api/`: API routes (e.g., for revalidation, R2 pre-signed URLs).
151
- * `components/`: Shared UI components (shadcn/ui based).
152
- * `components/ui/`: shadcn/ui components.
153
- * `context/`: React Context providers (e.g., `AuthContext`, `LanguageContext`).
154
- * `lib/`: Utility functions and configurations.
155
- * `lib/cloudflare/`: Client for Cloudflare R2.
156
- * `utils/supabase/`: Supabase client setup, types, and middleware helpers.
157
- * `supabase/migrations/`: SQL database migrations.
72
+ - `app/`: Next.js App Router.
73
+ - `app/(auth-pages)/`: Routes for sign-in, sign-up, etc.
74
+ - `app/cms/`: CMS admin panel routes and layouts.
75
+ - `app/cms/[entity]/`: CRUD pages for different content types (pages, posts, media, users, navigation, languages).
76
+ - `app/cms/blocks/`: Components and actions related to the block editor.
77
+ - `app/[slug]/`: Dynamic route for public "Pages".
78
+ - `app/article/[slug]/`: Dynamic route for public "Articles".
79
+ - `app/api/`: API routes (e.g., for revalidation, R2 pre-signed URLs).
80
+ - `components/`: Shared UI components (shadcn/ui based).
81
+ - `components/ui/`: shadcn/ui components.
82
+ - `context/`: React Context providers (e.g., `AuthContext`, `LanguageContext`).
83
+ - `lib/`: Utility functions and configurations.
84
+ - `lib/cloudflare/`: Client for Cloudflare R2.
85
+ - `utils/supabase/`: Supabase client setup, types, and middleware helpers.
86
+ - `supabase/migrations/`: SQL database migrations.
158
87
 
159
88
  ## Documentation
160
89
 
161
90
  For a deeper understanding of the CMS's internal workings, please refer to the detailed documentation:
162
91
 
163
- * **[CMS Application Overview](./docs/cms-application-overview.md):** A high-level guide to the Next.js application structure, core modules, and key functionalities.
164
- * **[Block Editor Architecture](./docs/cms-architecture-overview.md):** A technical deep-dive into the architecture of the block-based content editor.
92
+ - **[CMS Application Overview](./docs/cms-application-overview.md):** A high-level guide to the Next.js application structure, core modules, and key functionalities.
93
+ - **[Block Editor Architecture](./docs/cms-architecture-overview.md):** A technical deep-dive into the architecture of the block-based content editor.
165
94
 
166
95
  ## Deployment
167
96
 
@@ -170,7 +99,7 @@ This project is optimized for deployment on [Vercel](https://vercel.com/).
170
99
  1. Push your code to a GitHub/GitLab/Bitbucket repository.
171
100
  2. Import the project into Vercel.
172
101
  3. **Configure Environment Variables in Vercel:**
173
- * Add all the environment variables from your `.env.local` file to your Vercel project settings (Project Settings -> Environment Variables). This includes Supabase keys, R2 keys, `NEXT_PUBLIC_SITE_URL` (set to your production domain), and `REVALIDATE_SECRET_TOKEN`.
102
+ - Add all the environment variables from your `.env.local` file to your Vercel project settings (Project Settings -> Environment Variables). This includes Supabase keys, R2 keys, `NEXT_PUBLIC_SITE_URL` (set to your production domain), and `REVALIDATE_SECRET_TOKEN`.
174
103
  4. Vercel will automatically build and deploy your Next.js application.
175
104
  5. Ensure your Supabase Database Webhooks are pointing to your production Next.js API endpoint for revalidation.
176
105
 
@@ -179,7 +108,8 @@ This project is optimized for deployment on [Vercel](https://vercel.com/).
179
108
  This project includes a simple script to backup your Supabase PostgreSQL database.
180
109
 
181
110
  **Requirements:**
182
- * You must have the PostgreSQL command-line tools (`pg_dump`) installed and available in your system's PATH.
111
+
112
+ - You must have the PostgreSQL command-line tools (`pg_dump`) installed and available in your system's PATH.
183
113
 
184
114
  **Usage:**
185
115
  To create a backup, run the following command from your project root:
@@ -189,6 +119,7 @@ npm run db:backup
189
119
  ```
190
120
 
191
121
  This command will generate a timestamped SQL dump file and save it to the `backup/` directory.
122
+
192
123
  ## Feedback and Issues
193
124
 
194
125
  Please file feedback and issues on the GitHub repository for this project.
@@ -1,6 +1,6 @@
1
- import '@nextblock-cms/ui/styles/globals.css';
2
- import '@nextblock-cms/editor/styles/editor.css';
3
- // app/layout.tsx
1
+ import '@nextblock-cms/ui/styles/globals.css';
2
+ import '@nextblock-cms/editor/styles/editor.css';
3
+ // app/layout.tsx
4
4
  import { EnvVarWarning } from "@/components/env-var-warning";
5
5
  import { ThemeSwitcher } from '@/components/theme-switcher';
6
6
  import type { Metadata } from 'next';
@@ -13,8 +13,8 @@ import { getActiveLanguagesServerSide } from '@nextblock-cms/db/server';
13
13
  import { getNavigationMenu } from '@/app/cms/navigation/actions';
14
14
  import { getActiveLogo } from '@/app/cms/settings/logos/actions';
15
15
  import { getCopyrightSettings } from '@/app/cms/settings/copyright/actions';
16
- import { getTranslations } from '@/app/cms/settings/extra-translations/actions';
17
- import type { Database } from '@nextblock-cms/db';
16
+ import { getTranslations } from '@/app/cms/settings/extra-translations/actions';
17
+ import type { Database } from '@nextblock-cms/db';
18
18
  import { headers, cookies } from 'next/headers';
19
19
 
20
20
  const defaultUrl = process.env.VERCEL_URL
@@ -49,7 +49,7 @@ async function loadLayoutData() {
49
49
  ] = await Promise.all([
50
50
  supabase.auth.getUser(),
51
51
  getActiveLanguagesServerSide().catch(() => []),
52
- getCopyrightSettings().catch(() => ({ en: '© {year} Nextblock CMS. All rights reserved.' })),
52
+ getCopyrightSettings().catch(() => ({ en: '© {year} Nextblock CMS. All rights reserved.' })),
53
53
  getTranslations().catch(() => []),
54
54
  ]);
55
55
 
@@ -65,8 +65,8 @@ async function loadLayoutData() {
65
65
  }
66
66
 
67
67
  const copyrightSettings = copyrightSettingsResult as Record<string, string>;
68
- const fallbackTemplate =
69
- copyrightSettings['en'] ?? '© {year} Nextblock CMS. All rights reserved.';
68
+ const fallbackTemplate =
69
+ copyrightSettings['en'] ?? '© {year} Nextblock CMS. All rights reserved.';
70
70
  const templateForLocale =
71
71
  copyrightSettings[serverDeterminedLocale] ?? fallbackTemplate;
72
72
  const copyrightText = templateForLocale.replace('{year}', new Date().getFullYear().toString());
@@ -78,11 +78,11 @@ async function loadLayoutData() {
78
78
 
79
79
  const headerNavItems: NavigationItem[] = await getNavigationMenu('HEADER', serverDeterminedLocale).catch(() => []);
80
80
  const footerNavItems: NavigationItem[] = await getNavigationMenu('FOOTER', serverDeterminedLocale).catch(() => []);
81
- const logo = await getActiveLogo().catch(() => null);
81
+ const logo = await getActiveLogo().catch(() => null);
82
82
 
83
83
  const role = profile?.role ?? null;
84
84
  const canAccessCms = role === 'ADMIN' || role === 'WRITER';
85
- const siteTitle = logo?.site_title ?? 'Nextblock';
85
+ const siteTitle = logo?.site_title ?? 'Nextblock';
86
86
 
87
87
  return {
88
88
  user,
@@ -102,11 +102,22 @@ async function loadLayoutData() {
102
102
  };
103
103
  }
104
104
 
105
- export const metadata: Metadata = {
106
- metadataBase: new URL(defaultUrl),
107
- title: 'Nextblock CMS',
108
- description: 'Nextblock CMS pairs a visual block editor with a blazing-fast Next.js + Supabase architecture.',
109
- };
105
+ export const metadata: Metadata = {
106
+ metadataBase: new URL(defaultUrl),
107
+ title: 'Nextblock CMS',
108
+ description: 'Nextblock CMS pairs a visual block editor with a blazing-fast Next.js + Supabase architecture.',
109
+ icons: {
110
+ icon: [
111
+ { url: '/favicon/favicon.ico' },
112
+ { url: '/favicon/favicon-16x16.png', sizes: '16x16', type: 'image/png' },
113
+ { url: '/favicon/favicon-32x32.png', sizes: '32x32', type: 'image/png' },
114
+ ],
115
+ apple: [
116
+ { url: '/favicon/apple-touch-icon.png' },
117
+ ],
118
+ },
119
+ manifest: '/favicon/site.webmanifest',
120
+ };
110
121
 
111
122
  export default async function RootLayout({
112
123
  children,
@@ -1,5 +1,4 @@
1
1
  import nx from '@nx/eslint-plugin';
2
- import baseConfig from '../../eslint.config.mjs';
3
2
  import nextPlugin from '@next/eslint-plugin-next';
4
3
 
5
4
  const nextRules = {
@@ -8,7 +7,6 @@ const nextRules = {
8
7
  };
9
8
 
10
9
  const config = [
11
- ...baseConfig,
12
10
  ...nx.configs['flat/react-typescript'],
13
11
  {
14
12
  ignores: ['.next/**/*', '**/next-env.d.ts', 'apps/nextblock/next-env.d.ts'],
@@ -1,6 +1,6 @@
1
1
  /// <reference types="next" />
2
2
  /// <reference types="next/image-types/global" />
3
- import "./.next/types/routes.d.ts";
3
+ import "./.next/dev/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.5",
3
+ "version": "0.2.7",
4
4
  "private": true,
5
5
  "scripts": {
6
6
  "dev": "next dev",
@@ -0,0 +1 @@
1
+ {"name":"","short_name":"","icons":[{"src":"/android-chrome-192x192.png","sizes":"192x192","type":"image/png"},{"src":"/android-chrome-512x512.png","sizes":"512x512","type":"image/png"}],"theme_color":"#ffffff","background_color":"#ffffff","display":"standalone"}