create-berna-stencil 2.0.5 → 2.0.7

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.
@@ -41,26 +41,26 @@
41
41
 
42
42
  <div id="content-welcome" class="tab-content active">
43
43
  <div class="grid" style="display: flex; gap: 1rem; flex-wrap: wrap;">
44
- <a href="https://bernastencil.com" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
44
+ <a href="https://github.com/rhaastrake/berna-stencil" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
45
45
  <svg class="card-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
46
- <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
47
- <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
46
+ <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
48
47
  </svg>
49
- <h3>Documentation</h3>
50
- <p>Everything you need to get started, from setup to advanced topics and customizations</p>
51
- <span class="card-link">Go to documentation
48
+ <h3>Github repository</h3>
49
+ <p>Community-driven. Contributions, issues and PRs are welcome.</p>
50
+ <span class="card-link">Open the repository
52
51
  <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" style="margin-left:4px;">
53
52
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
54
53
  </svg>
55
54
  </span>
56
55
  </a>
57
- <a href="https://github.com/rhaastrake/berna-stencil" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
56
+ <a href="https://github.com/Rhaastrake/Berna-Stencil/tree/main/docs" class="card" target="_blank" rel="noopener noreferrer" style="flex: 1; min-width: 250px;">
58
57
  <svg class="card-icon" xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round" aria-hidden="true">
59
- <path d="M9 19c-5 1.5-5-2.5-7-3m14 6v-3.87a3.37 3.37 0 0 0-.94-2.61c3.14-.35 6.44-1.54 6.44-7A5.44 5.44 0 0 0 20 4.77 5.07 5.07 0 0 0 19.91 1S18.73.65 16 2.48a13.38 13.38 0 0 0-7 0C6.27.65 5.09 1 5.09 1A5.07 5.07 0 0 0 5 4.77a5.44 5.44 0 0 0-1.5 3.78c0 5.42 3.3 6.61 6.44 7A3.37 3.37 0 0 0 9 18.13V22"></path>
58
+ <path d="M2 3h6a4 4 0 0 1 4 4v14a3 3 0 0 0-3-3H2z"></path>
59
+ <path d="M22 3h-6a4 4 0 0 0-4 4v14a3 3 0 0 1 3-3h7z"></path>
60
60
  </svg>
61
- <h3>Github repository</h3>
62
- <p>Community-driven. Contributions, issues and PRs are welcome.</p>
63
- <span class="card-link">Open the repository
61
+ <h3>Documentation</h3>
62
+ <p>Everything you need to get started, from setup to advanced topics and customizations</p>
63
+ <span class="card-link">Go to documentation
64
64
  <svg width="16" height="16" xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 24 24" stroke="currentColor" stroke-width="2" style="margin-left:4px;">
65
65
  <path stroke-linecap="round" stroke-linejoin="round" d="M14 5l7 7m0 0l-7 7m7-7H3"></path>
66
66
  </svg>
@@ -237,13 +237,13 @@ body {
237
237
  <h4>examplePage.js <small>(<code>src/frontend/js/pages/</code>)</small></h4>
238
238
  <pre><code class="language-js">import { showNotification } from '../modules/notification.js';
239
239
 
240
- import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
240
+ import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
241
241
 
242
- document.addEventListener("DOMContentLoaded", () => {
243
- initNormalizePhoneNumber();
244
- });
242
+ document.addEventListener("DOMContentLoaded", () => {
243
+ initNormalizePhoneNumber();
244
+ });
245
245
 
246
- showNotification("Page loaded", "success", 3000);</code></pre>
246
+ showNotification("Page loaded", "success", 3000);</code></pre>
247
247
 
248
248
  <h2>Modules</h2>
249
249
  <p>Modules live in <code>src/frontend/js/modules/</code>. Some must be called inside <code>DOMContentLoaded</code> as they interact with the DOM; others create elements dynamically and can be called anywhere.</p>
@@ -287,10 +287,11 @@ body {
287
287
  <p>Create a new <code>.js</code> file in <code>src/frontend/js/modules/</code>. You can organize them into subfolders freely.</p>
288
288
  <p>Use ESM syntax — esbuild handles the bundling:</p>
289
289
 
290
- <pre><code class="language-js">// _yourModule.js
291
- export function yourFunction() {
292
- // ...
293
- }</code></pre>
290
+ <h4>yourModule.js <small>(<code>src/frontend/js/modules/</code>)</small></h4>
291
+ <pre><code class="language-js">
292
+ export function yourFunction() {
293
+ // ...
294
+ }</code></pre>
294
295
 
295
296
  <p>Then import it in the pages that need it:</p>
296
297
 
@@ -324,7 +325,7 @@ body {
324
325
  </ol>
325
326
  <pre><code>&#123;% elif title == "myPage" %&#125;
326
327
  &#123;% include "_myPage.njk" %&#125;</code></pre>
327
- <p>See <a href="components.html">components.md</a> for details.</p>
328
+ <p>See <a href="#" class="nav-to-components">Components</a> for details.</p>
328
329
  <h3>URL and title</h3>
329
330
  <p>The URL is the kebab-case name (<code>/my-page/</code>). The <code>title</code> in the front matter is camelCase (<code>myPage</code>) and is used internally to load the correct CSS and JS files — <strong>do not change it</strong>.</p>
330
331
  <h3>SEO</h3>
@@ -403,17 +404,17 @@ body {
403
404
 
404
405
  <h3>site.json <small>(<code>src/frontend/data/</code>)</small></h3>
405
406
  <pre><code>"site_name": "Site name",
406
- "title": "Site title",
407
- "description": "Site description",
408
- "keywords": "keyword1, keyword2, keyword3",
409
- "domain": "yoursite.com",
410
- "url": "https://yoursite.com",
411
- "lang": "en",
412
- "author": "Name and surname",
413
- "data_bs_theme": "dark",
414
- "favicon": "/assets/brand/favicon.svg",
415
- "logo": "/assets/brand/logo.svg",
416
- ...</code></pre>
407
+ "title": "Site title",
408
+ "description": "Site description",
409
+ "keywords": "keyword1, keyword2, keyword3",
410
+ "domain": "yoursite.com",
411
+ "url": "https://yoursite.com",
412
+ "lang": "en",
413
+ "author": "Name and surname",
414
+ "data_bs_theme": "dark",
415
+ "favicon": "/assets/brand/favicon.svg",
416
+ "logo": "/assets/brand/logo.svg",
417
+ ...</code></pre>
417
418
 
418
419
  <h2>Per-page SEO and CDN</h2>
419
420
  <p>Each page entry is keyed by its camelCase <code>title</code> from the front matter:</p>
@@ -421,20 +422,20 @@ body {
421
422
 
422
423
  <h3>site.json <small>(<code>src/frontend/data/</code>)</small></h3>
423
424
  <pre><code>"pages": {
424
- ...
425
- "examplePage": {
426
- "seo": {
427
- "title": "Example Page",
428
- "description": "description"
429
- },
430
- "cdn": {
431
- // You can leave the [] empty
432
- "css": ["https://example1.com/lib.min.css", "https://example2.com/lib.min.css"],
433
- "js": ["https://example1.com/lib.min.js", "https://example2.com/lib.min.js"]
434
- }
435
- }
436
- ...
437
- }</code></pre>
425
+ ...
426
+ "examplePage": {
427
+ "seo": {
428
+ "title": "Example Page",
429
+ "description": "description"
430
+ },
431
+ "cdn": {
432
+ // You can leave the [] empty
433
+ "css": ["https://example1.com/lib.min.css", "https://example2.com/lib.min.css"],
434
+ "js": ["https://example1.com/lib.min.js", "https://example2.com/lib.min.js"]
435
+ }
436
+ }
437
+ ...
438
+ }</code></pre>
438
439
 
439
440
  <h2>AI & SEO bots</h2>
440
441
  <p><code>llms.txt</code> and <code>robots.txt</code> are generated automatically from <code>site.json</code> via their respective <code>.njk</code> files — no manual editing needed.</p>
@@ -454,20 +455,21 @@ body {
454
455
  <h3>Customizing llms.txt</h3>
455
456
  <p><code>src/llms.njk</code> ships with a base template — <strong>replace the placeholders with your own content</strong>:</p>
456
457
 
457
- <pre><code># Site name
458
+ <pre><code>{% raw %}# {{ site.site_name }}
458
459
 
459
- > Site description
460
+ > {{ site.description }}
460
461
 
461
- Built by Name and surnamehttps://yoursite.com
462
+ Built by {{ site.author }}{{ site.url }}
462
463
 
463
- ## Pages
464
+ ## Pages
464
465
 
465
- - https://yoursite.com: Homepage
466
+ - {{ site.url }}: Homepage
466
467
 
467
- ## Notes
468
+ ## Notes
468
469
 
469
- - Language: en
470
- - All content may be used for AI indexing unless otherwise stated</code></pre>
470
+ - Language: {{ site.lang }}
471
+ - All content may be used for AI indexing unless otherwise stated
472
+ {% endraw %}</code></pre>
471
473
 
472
474
  <blockquote>The more accurate and detailed your <code>llms.txt</code>, the better AI models will understand and reference your site.</blockquote>
473
475
 
@@ -494,52 +496,72 @@ body {
494
496
 
495
497
  <div id="content-backend" class="tab-content">
496
498
  <div class="markdown-body">
497
- <h2>Backend</h2>
498
- <p>The backend is a PHP REST API located in <code>src/backend/</code>, copied to the output directory automatically at build time.</p>
499
- <h3>Structure</h3>
500
- <pre><code>src/backend/
501
- ├── api/
502
- ├── public/ # Endpoints accessible without an API key
503
- └── protected/ # Endpoints requiring X-Api-Key header
504
- ├── database/
505
- ├── Database.php
506
- │ ├── models/
507
- └── migrations/
508
- ├── config.php # Your local config — never commit this
509
- └── config.example.php</code></pre>
510
- <h3>Configuration</h3>
511
- <p><code>config.php</code> works like a <code>.env</code> file — it holds secrets and environment settings that stay local and out of version control.</p>
512
- <p>Copy <code>config.example.php</code> to <code>config.php</code> and fill in your values:</p>
513
- <h4>config.php <small>(<code>src/backend/</code>)</small></h4>
514
- <pre><code>return [
515
- 'APP_ENV' => 'development', // or 'production'
516
- 'API_KEY' => 'your-default-key',
517
-
518
- 'ENDPOINT_KEYS' => [
519
- 'subfolder/example-protected' => 'specific-key',
520
- ],
521
-
522
- 'DB_HOST' => '127.0.0.1',
523
- 'DB_NAME' => 'example_db',
524
- 'DB_USER' => 'root',
525
- 'DB_PASS' => '',
499
+ <h2>Backend</h2>
500
+ <p>The backend is a PHP REST API located in <code>src/backend/</code>, copied to the output directory automatically at build time.</p>
501
+
502
+ <h3>Structure</h3>
503
+ <pre><code>src/backend/
504
+ ├── api/
505
+ ├── public/ # Endpoints accessible without an API key
506
+ │ └── protected/ # Endpoints requiring X-Api-Key header
507
+ ├── database/
508
+ │ ├── Database.php
509
+ ├── models/
510
+ │ └── migrations/
511
+ ├── config.php # Your local config — never commit this
512
+ └── config.example.php</code></pre>
513
+
514
+ <h3>Configuration</h3>
515
+ <p><code>config.php</code> works like a <code>.env</code> file — it holds secrets and environment settings that stay local and out of version control.</p>
516
+ <p>Copy <code>config.example.php</code> to <code>config.php</code> and fill in your values:</p>
517
+
518
+ <h4>config.php <small>(<code>src/backend/</code>)</small></h4>
519
+ <pre><code class="language-php">return [
520
+ // Default key for protected endpoints that don't have a specific key in ENDPOINT_KEYS
521
+ 'API_KEY' =&gt; 'default-key',
522
+
523
+ // If you want restrict access to protected endpoints to specific clients, you can define custom keys for each endpoint
524
+ // For subfolder endpoints, use the relative path ('subfolder/endpoint')
525
+ 'ENDPOINT_KEYS' =&gt; [
526
+ 'example-protected' =&gt; 'custom-key',
527
+ ],
528
+
529
+ 'DB_HOST' =&gt; '127.0.0.1',
530
+ 'DB_NAME' =&gt; 'example_db',
531
+ 'DB_USER' =&gt; 'root',
532
+ 'DB_PASS' =&gt; '',
526
533
  ];</code></pre>
527
- <p><code>API_KEY</code> is the fallback key for all protected endpoints. Use <code>ENDPOINT_KEYS</code> to assign a different key to a specific endpoint — for subfolder endpoints, use the relative path as the key.</p>
528
- <h3>How routing works</h3>
529
- <p>The file path inside <code>api/</code> maps directly to the URL. Extra URL segments become route parameters available as <code>$requestParams[]</code>.</p>
530
- <p>Every endpoint file has access to:</p>
531
- <table>
532
- <thead>
533
- <tr><th>Variable</th><th>Description</th></tr>
534
- </thead>
535
- <tbody>
536
- <tr><td><code>$method</code></td><td>HTTP method (<code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code>)</td></tr>
537
- <tr><td><code>$requestParams</code></td><td>Extra URL segments (e.g. <code>/api/posts/42</code> → <code>['42']</code>)</td></tr>
538
- </tbody>
539
- </table>
540
- <h3>Creating a public endpoint</h3>
541
- <p>Create a <code>.php</code> file anywhere inside <code>api/public/</code></p>
542
- <pre><code>&lt;?php
534
+
535
+ <p><code>API_KEY</code> is the fallback key for all protected endpoints. Use <code>ENDPOINT_KEYS</code> to assign a different key to a specific endpoint — for subfolder endpoints, use the relative path as the key.</p>
536
+
537
+ <h3>How routing works</h3>
538
+ <p>The file path inside <code>api/</code> maps directly to the URL. Extra URL segments become route parameters available as <code>$requestParams[]</code>.</p>
539
+ <p>Every endpoint file has access to:</p>
540
+
541
+ <table>
542
+ <thead>
543
+ <tr>
544
+ <th>Variable</th>
545
+ <th>Description</th>
546
+ </tr>
547
+ </thead>
548
+ <tbody>
549
+ <tr>
550
+ <td><code>$method</code></td>
551
+ <td>HTTP method (<code>GET</code>, <code>POST</code>, <code>PUT</code>, <code>PATCH</code>, <code>DELETE</code>)</td>
552
+ </tr>
553
+ <tr>
554
+ <td><code>$requestParams</code></td>
555
+ <td>Extra URL segments (e.g. <code>/api/posts/42</code> → <code>['42']</code>)</td>
556
+ </tr>
557
+ </tbody>
558
+ </table>
559
+
560
+ <h3>Creating a public endpoint</h3>
561
+ <p>Create a <code>.php</code> file anywhere inside <code>api/public/</code></p>
562
+
563
+ <h4>api/public/example.php</h4>
564
+ <pre><code class="language-php">&lt;?php
543
565
  declare(strict_types=1);
544
566
 
545
567
  require_once CORE_PATH . '/modules/Response.php';
@@ -550,11 +572,13 @@ if ($method !== 'GET') {
550
572
 
551
573
  $id = isset($requestParams[0]) ? (int)$requestParams[0] : null;
552
574
 
553
- Response::success(['id' => $id]);</code></pre>
554
- <p>Reachable at <code>/api/posts</code> or <code>/api/posts/42</code></p>
555
- <h3>Creating a protected endpoint</h3>
556
- <p>Create a <code>.php</code> file inside <code>api/protected/</code>. The API key check happens automatically before your file runs.</p>
557
- <pre><code>&lt;?php
575
+ Response::success(['id' =&gt; $id]);</code></pre>
576
+
577
+ <h3>Creating a protected endpoint</h3>
578
+ <p>Create a <code>.php</code> file inside <code>api/protected/</code>. The API key check happens automatically before your file runs.</p>
579
+
580
+ <h4>api/protected/example.php</h4>
581
+ <pre><code class="language-php">&lt;?php
558
582
  declare(strict_types=1);
559
583
 
560
584
  require_once CORE_PATH . '/modules/Response.php';
@@ -563,101 +587,40 @@ if ($method !== 'GET') {
563
587
  Response::error('Method not allowed', 405);
564
588
  }
565
589
 
566
- Response::success(['visits' => 1024]);</code></pre>
567
- <p>To assign a dedicated key, add it to <code>config.php</code>:</p>
568
- <pre><code>'ENDPOINT_KEYS' => [
569
- 'admin/stats' => 'secret-stats-key',
590
+ Response::success(['visits' =&gt; 1024]);</code></pre>
591
+
592
+ <p>To assign a dedicated key, add it to <code>config.php</code>:</p>
593
+ <pre><code class="language-php">'ENDPOINT_KEYS' =&gt; [
594
+ 'endpoint' =&gt; 'custom-key',
570
595
  ],</code></pre>
571
- <h3>The Response helper</h3>
572
- <pre><code>Response::success($data, $code); // default 200
596
+
597
+ <h3>The Response helper</h3>
598
+ <pre><code class="language-php">Response::success($data, $code); // default 200
573
599
  Response::error($message, $code, $details); // default 400
574
600
  Response::noContent(); // 204</code></pre>
575
- <h3>Handling multiple methods</h3>
576
- <pre><code>$id = isset($requestParams[0]) ? (int)$requestParams[0] : null;
577
- $input = json_decode(file_get_contents('php://input'), true) ?? [];
578
-
579
- switch ($method) {
580
- case 'GET':
581
- Response::success(['id' => $id]);
582
- break;
583
-
584
- case 'POST':
585
- if (empty($input['title'])) Response::error('Missing title', 400);
586
- Response::success(['message' => 'Created'], 201);
587
- break;
588
-
589
- case 'DELETE':
590
- if (!$id) Response::error('ID required', 400);
591
- Response::success(['message' => 'Deleted']);
592
- break;
593
-
594
- default:
595
- Response::error('Method not allowed', 405);
596
- }</code></pre>
597
- <h3>Using the database</h3>
598
- <h4>database/models/Post.php</h4>
599
- <pre><code>&lt;?php
600
- declare(strict_types=1);
601
-
602
- require_once __DIR__ . '/../Database.php';
603
-
604
- class Post {
605
- private PDO $db;
606
601
 
607
- public function __construct() {
608
- $this->db = Database::getInstance();
609
- }
610
-
611
- public function getAll(): array {
612
- return $this->db->query("SELECT * FROM posts")->fetchAll();
613
- }
614
-
615
- public function getById(int $id): ?array {
616
- $stmt = $this->db->prepare("SELECT * FROM posts WHERE id = :id");
617
- $stmt->execute(['id' => $id]);
618
- return $stmt->fetch() ?: null;
619
- }
620
-
621
- public function create(string $title): int {
622
- $stmt = $this->db->prepare("INSERT INTO posts (title) VALUES (:title)");
623
- $stmt->execute(['title' => htmlspecialchars(strip_tags(trim($title)))]);
624
- return (int)$this->db->lastInsertId();
625
- }
626
- }</code></pre>
627
- <p>Then use it inside an endpoint:</p>
628
- <pre><code>require_once __DIR__ . '/../../database/models/Post.php';
629
-
630
- $post = new Post();
631
- Response::success($post->getAll());</code></pre>
632
- <p>Migrations live in <code>database/migrations/</code> as plain SQL files — run them manually against your database.</p>
633
- <h3>Calling endpoints from the frontend</h3>
634
- <pre><code>// Public
635
- const res = await fetch('/api/posts/42');
636
-
637
- // Protected
638
- const res = await fetch('/api/admin/stats', {
639
- headers: { 'X-Api-Key': 'secret-stats-key' }
640
- });
641
-
642
- // POST
643
- const res = await fetch('/api/posts', {
644
- method: 'POST',
645
- headers: { 'Content-Type': 'application/json', 'X-Api-Key': 'your-key' },
646
- body: JSON.stringify({ title: 'Hello world' })
647
- });</code></pre>
648
- <h3>Pre-built endpoints</h3>
649
- <table>
650
- <thead>
651
- <tr><th>Route</th><th>Auth</th><th>Methods</th><th>Description</th></tr>
652
- </thead>
653
- <tbody>
654
- <tr><td><code>/api/example-public</code></td><td>No</td><td><code>GET</code></td><td>Smoke test for public routing</td></tr>
655
- <tr><td><code>/api/subfolder/example-protected</code></td><td>Yes</td><td><code>GET</code></td><td>Smoke test for protected routing</td></tr>
656
- <tr><td><code>/api/auth/register</code></td><td>No</td><td><code>POST</code></td><td>Register a new user</td></tr>
657
- <tr><td><code>/api/auth/login</code></td><td>No</td><td><code>POST</code></td><td>Login and retrieve user data</td></tr>
658
- <tr><td><code>/api/auth-system</code></td><td>Yes</td><td><code>GET POST PUT PATCH DELETE</code></td><td>Full CRUD on users</td></tr>
659
- </tbody>
660
- </table>
602
+ <h3>Pre-built endpoints</h3>
603
+ <table>
604
+ <thead>
605
+ <tr>
606
+ <th>Route</th>
607
+ <th>Method</th>
608
+ <th>Description</th>
609
+ </tr>
610
+ </thead>
611
+ <tbody>
612
+ <tr>
613
+ <td><code>/api/example-public</code></td>
614
+ <td><code>GET</code></td>
615
+ <td>Example endpoint that doesn't require any key</td>
616
+ </tr>
617
+ <tr>
618
+ <td><code>/api/example-protected</code></td>
619
+ <td><code>GET</code></td>
620
+ <td>Example endpoint that requires X-API-KEY</td>
621
+ </tr>
622
+ </tbody>
623
+ </table>
661
624
  </div>
662
625
  </div>
663
626
  </div>
@@ -1,11 +1,11 @@
1
- //==========================
1
+ //===========================
2
2
  // JAVASCRIPT MODULES IMPORTS
3
- //==========================
3
+ //===========================
4
4
 
5
5
  // Call anywhere
6
6
  import { showNotification } from '../modules/notification.js';
7
7
 
8
- // Uncomment to enable optional modules (call inside DOMContentLoaded)
8
+ // Uncomment of pre-existing modules
9
9
  // import { initTextAreaAutoExpand } from '../modules/forms/textAreaAutoExpand.js';
10
10
  // import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
11
11
 
@@ -14,6 +14,8 @@ import { showNotification } from '../modules/notification.js';
14
14
  //==========================
15
15
 
16
16
  document.addEventListener("DOMContentLoaded", () => {
17
+ // initTextAreaAutoExpand();
18
+ // initNormalizePhoneNumber();
17
19
  });
18
20
 
19
21
  showNotification("Example notification", "success", 3000);
@@ -1,11 +1,11 @@
1
- //==========================
1
+ //===========================
2
2
  // JAVASCRIPT MODULES IMPORTS
3
- //==========================
3
+ //===========================
4
4
 
5
5
  // Call anywhere
6
6
  import { showNotification } from '../modules/notification.js';
7
7
 
8
- // Uncomment to enable optional modules (call inside DOMContentLoaded)
8
+ // Uncomment of pre-existing modules
9
9
  // import { initTextAreaAutoExpand } from '../modules/forms/textAreaAutoExpand.js';
10
10
  // import { initNormalizePhoneNumber } from '../modules/forms/normalizePhoneNumber.js';
11
11
 
@@ -14,6 +14,8 @@ import { showNotification } from '../modules/notification.js';
14
14
  //==========================
15
15
 
16
16
  document.addEventListener("DOMContentLoaded", () => {
17
+ // initTextAreaAutoExpand();
18
+ // initNormalizePhoneNumber();
17
19
  });
18
20
 
19
21
  showNotification("Example notification", "success", 3000);
@@ -15,4 +15,4 @@ Built by {{ site.author }} — {{ site.url }}
15
15
  ## Notes
16
16
 
17
17
  - Language: {{ site.lang }}
18
- - All content may be used for AI indexing unless otherwise stated
18
+ - All content may be used for AI inde xing unless otherwise stated
@@ -5,12 +5,14 @@
5
5
  // Getting root rules from _root.scss
6
6
  @use 'root' as root;
7
7
 
8
+ // Frameworks imports
8
9
  @import "../modules/frameworks/bootstrap";
9
10
  // @import "../modules/frameworks/bulma";
10
11
  // @import "../modules/frameworks/foundation";
11
12
  // @import "../modules/frameworks/uikit";
12
13
 
13
14
 
15
+ // Modules imports
14
16
  @import "typography";
15
17
 
16
18
  @import "header";
@@ -21,6 +23,10 @@
21
23
 
22
24
  @import "buttons";
23
25
 
26
+ //==========================
27
+ // Global css rules for the entire site
28
+ //==========================
29
+
24
30
  *,
25
31
  *::before,
26
32
  *::after {
@@ -13,7 +13,7 @@
13
13
  @import "../modules/notification";
14
14
 
15
15
  //==========================
16
- // PAGE CUSTOM CSS RULES FOR PAGE: 404
16
+ // PAGE CUSTOM CSS RULES
17
17
  //==========================
18
18
 
19
19
  // Add any custom rule specific to this page below
@@ -13,7 +13,7 @@
13
13
  @import "../modules/notification";
14
14
 
15
15
  //==========================
16
- // PAGE CUSTOM CSS RULES FOR PAGE: homepage
16
+ // PAGE CUSTOM CSS RULES
17
17
  //==========================
18
18
 
19
19
  // Add any custom rule specific to this page below
@@ -1,67 +0,0 @@
1
- <?php
2
- declare(strict_types=1);
3
-
4
-
5
- // 2. Richiamo il tuo modulo Response e il Modello
6
- require_once CORE_PATH . '/modules/Response.php';
7
- require_once __DIR__ . '/../../database/models/User.php';
8
-
9
- //
10
- // Your protected endpoint logic here. You can access route parameters in $requestParams array
11
- //
12
-
13
- $user = new User();
14
- $id = isset($requestParams[0]) ? (int)$requestParams[0] : null;
15
- $input = json_decode(file_get_contents('php://input'), true) ?? [];
16
-
17
- try {
18
- switch ($method) {
19
- case 'GET':
20
- $data = $id ? $user->getById($id) : $user->getAll();
21
- if ($id && !$data) {
22
- Response::error('User not found', 404);
23
- }
24
- // Sostituito con Response::success()
25
- Response::success($data);
26
- break;
27
-
28
- case 'POST':
29
- if (empty($input['nickname']) || empty($input['email'])) {
30
- Response::error('Missing fields', 400);
31
- }
32
- if (!filter_var($input['email'], FILTER_VALIDATE_EMAIL)) {
33
- Response::error('Invalid email', 400);
34
- }
35
-
36
- $newId = $user->create($input['nickname'], $input['email']);
37
- http_response_code(201);
38
- Response::success(['message' => 'Created', 'id' => $newId]);
39
- break;
40
-
41
- case 'PUT':
42
- case 'PATCH':
43
- if (!$id) Response::error('ID required', 400);
44
- if (!$user->update($id, $input)) {
45
- Response::error('Not found or no changes', 404);
46
- }
47
- Response::success(['message' => 'Updated']);
48
- break;
49
-
50
- case 'DELETE':
51
- if (!$id) Response::error('ID required', 400);
52
- if (!$user->delete($id)) {
53
- Response::error('Not found', 404);
54
- }
55
- Response::success(['message' => 'Deleted']);
56
- break;
57
-
58
- default:
59
- Response::error('Method not allowed', 405);
60
- break;
61
- }
62
- } catch (PDOException $e) {
63
- if ($e->getCode() === '23000') {
64
- Response::error('Nickname or email already exists', 409);
65
- }
66
- Response::error('Database error', 500);
67
- }