@yysng/astro-boilerplate 1.0.4 → 1.1.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/package.json CHANGED
@@ -1,15 +1,12 @@
1
1
  {
2
2
  "name": "@yysng/astro-boilerplate",
3
- "version": "1.0.4",
3
+ "version": "1.1.1",
4
4
  "description": "Astro + Sanity Boilerplate with AEO Layers 1–5",
5
5
  "type": "module",
6
6
  "exports": {
7
- "./components/*": "./src/components/*",
8
- "./layouts/*": "./src/layouts/*",
9
- "./config/*": "./src/config/*",
10
- "./utils/*": "./src/utils/*"
7
+ ".": "./src/index.js"
11
8
  },
12
- "main": "index.js",
9
+ "main": "./src/index.js",
13
10
  "files": [
14
11
  "src"
15
12
  ],
File without changes
File without changes
@@ -0,0 +1,8 @@
1
+ {
2
+ "title": "AI Updated Hero Title",
3
+ "subtitle": "Safely edited via boilerplate",
4
+ "cta": {
5
+ "label": "Continue",
6
+ "href": "/continue"
7
+ }
8
+ }
File without changes
@@ -0,0 +1,16 @@
1
+ import fs from "fs/promises";
2
+ import { CONTENT_REGISTRY } from "./registry.js";
3
+
4
+ export async function loadContent(key) {
5
+ const entry = CONTENT_REGISTRY[key];
6
+
7
+ if (!entry) {
8
+ throw new Error(`Unknown content key: ${key}`);
9
+ }
10
+
11
+ const fileUrl = new URL(`../${entry.file}`, import.meta.url);
12
+ const raw = await fs.readFile(fileUrl, "utf-8");
13
+ const data = JSON.parse(raw);
14
+
15
+ return data;
16
+ }
@@ -0,0 +1,20 @@
1
+ export const CONTENT_REGISTRY = {
2
+ hero: {
3
+ file: "content/hero.json",
4
+ section: "HeroSection",
5
+ __test_flag: "FROM_BOILERPLATE"
6
+ }
7
+ ,
8
+ about: {
9
+ file: "content/about.json",
10
+ section: "AboutSection"
11
+ },
12
+ cta: {
13
+ file: "content/cta.json",
14
+ section: "CTASection"
15
+ },
16
+ testimonials: {
17
+ file: "content/testimonials.json",
18
+ section: "TertimonialSection"
19
+ }
20
+ };
@@ -0,0 +1,28 @@
1
+ export const schemas = {
2
+ hero: {
3
+ required: ["title", "subtitle"],
4
+ validate(data) {
5
+ if (typeof data.title !== "string") {
6
+ throw new Error("Hero.title must be a string");
7
+ }
8
+
9
+ if (typeof data.subtitle !== "string") {
10
+ throw new Error("Hero.subtitle must be a string");
11
+ }
12
+
13
+ if (data.cta) {
14
+ if (typeof data.cta !== "object") {
15
+ throw new Error("Hero.cta must be an object");
16
+ }
17
+
18
+ if (typeof data.cta.label !== "string") {
19
+ throw new Error("Hero.cta.label must be a string");
20
+ }
21
+
22
+ if (typeof data.cta.href !== "string") {
23
+ throw new Error("Hero.cta.href must be a string");
24
+ }
25
+ }
26
+ }
27
+ }
28
+ };
@@ -0,0 +1,27 @@
1
+ import fs from "fs/promises";
2
+ import { CONTENT_REGISTRY } from "./registry.js";
3
+ import { schemas } from "./schemas.js";
4
+
5
+ export async function updateContent(key, data) {
6
+ const entry = CONTENT_REGISTRY[key];
7
+
8
+ if (!entry) {
9
+ throw new Error(`Unknown content key: ${key}`);
10
+ }
11
+
12
+ // 🔒 Schema validation
13
+ const schema = schemas[key];
14
+ if (!schema) {
15
+ throw new Error(`No schema defined for content key: ${key}`);
16
+ }
17
+
18
+ schema.validate(data);
19
+
20
+ const fileUrl = new URL(`../${entry.file}`, import.meta.url);
21
+
22
+ await fs.writeFile(
23
+ fileUrl,
24
+ JSON.stringify(data, null, 2),
25
+ "utf-8"
26
+ );
27
+ }
package/src/index.js ADDED
@@ -0,0 +1,5 @@
1
+ // Public API of @yysng/astro-boilerplate
2
+
3
+ export { loadContent } from "./content-system/loader.js";
4
+ export { updateContent } from "./content-system/updater.js";
5
+ export { CONTENT_REGISTRY } from "./content-system/registry.js";
@@ -0,0 +1,35 @@
1
+ import { updateContent } from "@yysng/astro-boilerplate";
2
+
3
+ export const prerender = false;
4
+
5
+ export async function POST({ request }) {
6
+ try {
7
+ const body = await request.json();
8
+ const { section, content } = body;
9
+
10
+ if (!section || !content) {
11
+ return new Response(
12
+ JSON.stringify({ error: "Missing section or content" }),
13
+ { status: 400 }
14
+ );
15
+ }
16
+
17
+ await updateContent(section, content);
18
+
19
+ return new Response(
20
+ JSON.stringify({ status: "ok", updated: section }),
21
+ { status: 200 }
22
+ );
23
+
24
+ } catch (error) {
25
+ console.error("AI Edit Error:", error);
26
+
27
+ return new Response(
28
+ JSON.stringify({
29
+ error: "Internal error",
30
+ details: error.message
31
+ }),
32
+ { status: 500 }
33
+ );
34
+ }
35
+ }
@@ -1,11 +1,25 @@
1
1
  ---
2
2
  import BaseHead from "@components/BaseHead.astro";
3
+
4
+ // Import AI-editable sections
5
+ import HeroSection from "../sections/HeroSection.astro";
6
+ import AboutSection from "../sections/AboutSection.astro";
7
+ import TestimonialsSection from "../sections/TestimonialsSection.astro";
8
+ import CTASection from "../sections/CTASection.astro";
3
9
  ---
4
10
 
5
- <html>
11
+ <html lang="en">
6
12
  <BaseHead title="Boilerplate Test" />
13
+
7
14
  <body>
15
+ <!-- Keep your original hero test message (optional) -->
8
16
  <h1>YY Astro-Sanity Boilerplate</h1>
9
17
  <p>If you can see this page, the boilerplate is working correctly.</p>
18
+
19
+ <!-- Your new section-based homepage -->
20
+ <HeroSection />
21
+ <AboutSection />
22
+ <TestimonialsSection />
23
+ <CTASection />
10
24
  </body>
11
25
  </html>
File without changes
File without changes
@@ -0,0 +1,12 @@
1
+ ---
2
+ import { loadContent } from "@yysng/astro-boilerplate";
3
+
4
+ const content = await loadContent("hero");
5
+ ---
6
+
7
+
8
+ <section class="py-20 text-center">
9
+ <h1 class="text-5xl font-bold">{hero.title}</h1>
10
+ <p class="text-gray-600">{hero.subtitle}</p>
11
+ {hero.cta && <a href={hero.cta.href} class="btn">{hero.cta.label}</a>}
12
+ </section>
File without changes
package/index.js DELETED
@@ -1,4 +0,0 @@
1
- export * from "./src/components";
2
- export * from "./src/layouts";
3
- export * from "./src/config";
4
- export * from "./src/utils";