EmDash installed - server mode, basic integration. Visual editor wiring deferred to fix build errors.

This commit is contained in:
Kunthawat Greethong
2026-05-06 10:07:39 +07:00
parent 0dcaf2f253
commit 9db1d12b9c
10 changed files with 4953 additions and 13 deletions

View File

@@ -32,7 +32,7 @@
"runtime": "Node.js 22.12.0"
},
"build": {
"buildCommand": "npm run build 2>&1 | tail -8",
"buildCommand": "pkill -f \"node.*entry.mjs\" 2>/dev/null; sleep 1; npm run build 2>&1 | tail -10",
"testCommand": null,
"lintCommand": null,
"devCommand": "npm run dev",
@@ -207,6 +207,12 @@
"lastAccessed": 1777990670077,
"type": "file"
},
{
"path": "src/layouts/Base.astro",
"accessCount": 4,
"lastAccessed": 1778036775836,
"type": "file"
},
{
"path": "src/styles/global.css",
"accessCount": 3,
@@ -219,6 +225,12 @@
"lastAccessed": 1777995178143,
"type": "directory"
},
{
"path": "astro.config.mjs",
"accessCount": 2,
"lastAccessed": 1778036187649,
"type": "file"
},
{
"path": "src/pages",
"accessCount": 1,
@@ -230,6 +242,24 @@
"accessCount": 1,
"lastAccessed": 1778035760907,
"type": "directory"
},
{
"path": "src/live.config.ts",
"accessCount": 1,
"lastAccessed": 1778036198221,
"type": "file"
},
{
"path": "seed/seed.json",
"accessCount": 1,
"lastAccessed": 1778036244021,
"type": "file"
},
{
"path": "src/utils/site-identity.ts",
"accessCount": 1,
"lastAccessed": 1778036594901,
"type": "file"
}
],
"userDirectives": []

View File

@@ -1,7 +1,7 @@
{
"tool_name": "Bash",
"tool_input_preview": "{\"command\":\"npm run build 2>&1\",\"timeout\":120000,\"description\":\"Build Astro site to check for errors\"}",
"error": "Exit code 1",
"timestamp": "2026-05-05T13:17:02.070Z",
"tool_name": "Write",
"tool_input_preview": "{\"file_path\":\"/Users/kunthawatgleethong/Gitea/moreminimore-emdash/moreminimore-site/src/utils/site-identity.ts\",\"content\":\"import { emdash } from \\\"emdash/astro\\\";\\nimport type { CollectionEntry } fro...",
"error": "EACCES: permission denied, mkdir '/Users/kunthawatgleethong'",
"timestamp": "2026-05-06T03:03:02.581Z",
"retry_count": 1
}

View File

@@ -1,5 +1,20 @@
// @ts-check
import { defineConfig } from 'astro/config';
import node from "@astrojs/node";
import react from "@astrojs/react";
import emdash, { local } from "emdash/astro";
import { sqlite } from "emdash/db";
// https://astro.build/config
export default defineConfig({});
export default defineConfig({
output: "server",
adapter: node({ mode: "standalone" }),
image: { layout: "constrained", responsiveStyles: true },
integrations: [
react(),
emdash({
database: sqlite({ url: "file:./data.db" }),
storage: local({ directory: "./uploads", baseUrl: "/_emdash/api/media/file" }),
}),
],
devToolbar: { enabled: false },
});

BIN
data.db Normal file

Binary file not shown.

39
emdash-env.d.ts vendored Normal file
View File

@@ -0,0 +1,39 @@
// Generated by EmDash on dev server start
// Do not edit manually
/// <reference types="emdash/locals" />
import type { ContentBylineCredit, PortableTextBlock } from "emdash";
export interface Page {
id: string;
slug: string | null;
status: string;
title: string;
content?: PortableTextBlock[];
createdAt: Date;
updatedAt: Date;
publishedAt: Date | null;
bylines?: ContentBylineCredit[];
}
export interface Post {
id: string;
slug: string | null;
status: string;
title: string;
featured_image?: { id: string; src?: string; alt?: string; width?: number; height?: number };
content?: PortableTextBlock[];
excerpt?: string;
createdAt: Date;
updatedAt: Date;
publishedAt: Date | null;
bylines?: ContentBylineCredit[];
}
declare module "emdash" {
interface EmDashCollections {
pages: Page;
posts: Post;
}
}

4745
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -12,6 +12,11 @@
"astro": "astro"
},
"dependencies": {
"astro": "^6.2.2"
"@astrojs/node": "^10.0.6",
"@astrojs/react": "^5.0.4",
"astro": "^6.2.2",
"emdash": "^0.9.0",
"react": "^19.2.5",
"react-dom": "^19.2.5"
}
}
}

85
seed/seed.json Normal file
View File

@@ -0,0 +1,85 @@
{
"collections": [
{
"name": "pages",
"label": "Pages",
"fields": [
{ "name": "title", "type": "string", "label": "Title" },
{ "name": "subtitle", "type": "string", "label": "Subtitle" },
{ "name": "badge", "type": "string", "label": "Badge" },
{ "name": "heroImage", "type": "image", "label": "Hero Image" },
{ "name": "theme", "type": "select", "label": "Theme", "options": ["yellow", "accent"] },
{ "name": "showCTA", "type": "boolean", "label": "Show CTA" },
{ "name": "ctaText", "type": "string", "label": "CTA Text" },
{ "name": "ctaLink", "type": "string", "label": "CTA Link" },
{ "name": "variant", "type": "select", "label": "Hero Variant", "options": ["split", "centered", "text-only", "floating-cards"] },
{ "name": "size", "type": "select", "label": "Hero Size", "options": ["full", "compact"] }
]
},
{
"name": "services",
"label": "Services",
"fields": [
{ "name": "title", "type": "string", "label": "Title" },
{ "name": "subtitle", "type": "string", "label": "Subtitle" },
{ "name": "badge", "type": "string", "label": "Badge" },
{ "name": "heroImage", "type": "image", "label": "Hero Image" },
{ "name": "content", "type": "richtext", "label": "Content" },
{ "name": "features", "type": "array", "label": "Features", "fields": [
{ "name": "icon", "type": "string", "label": "Icon" },
{ "name": "title", "type": "string", "label": "Title" },
{ "name": "description", "type": "string", "label": "Description" }
]}
]
},
{
"name": "portfolio",
"label": "Portfolio",
"fields": [
{ "name": "name", "type": "string", "label": "Name" },
{ "name": "url", "type": "string", "label": "URL" },
{ "name": "category", "type": "select", "label": "Category", "options": ["webdev", "ecommerce", "marketing"] },
{ "name": "categoryLabel", "type": "string", "label": "Category Label" },
{ "name": "thumbnail", "type": "image", "label": "Thumbnail" },
{ "name": "description", "type": "string", "label": "Description" },
{ "name": "services", "type": "array", "label": "Services", "fields": [
{ "name": "name", "type": "string", "label": "Name" }
]}
]
},
{
"name": "blog",
"label": "Blog",
"fields": [
{ "name": "title", "type": "string", "label": "Title" },
{ "name": "excerpt", "type": "string", "label": "Excerpt" },
{ "name": "image", "type": "image", "label": "Image" },
{ "name": "date", "type": "date", "label": "Date" },
{ "name": "category", "type": "string", "label": "Category" },
{ "name": "content", "type": "richtext", "label": "Content" }
]
},
{
"name": "faq",
"label": "FAQ",
"fields": [
{ "name": "category", "type": "string", "label": "Category" },
{ "name": "question", "type": "string", "label": "Question" },
{ "name": "answer", "type": "string", "label": "Answer" }
]
},
{
"name": "settings",
"label": "Site Settings",
"fields": [
{ "name": "siteName", "type": "string", "label": "Site Name" },
{ "name": "email", "type": "string", "label": "Contact Email" },
{ "name": "phone", "type": "string", "label": "Contact Phone" },
{ "name": "address", "type": "string", "label": "Address" },
{ "name": "facebook", "type": "string", "label": "Facebook URL" },
{ "name": "line", "type": "string", "label": "LINE URL" },
{ "name": "linkedin", "type": "string", "label": "LinkedIn URL" }
]
}
]
}

6
src/live.config.ts Normal file
View File

@@ -0,0 +1,6 @@
import { defineLiveCollection } from "astro:content";
import { emdashLoader } from "emdash/runtime";
export const collections = {
_emdash: defineLiveCollection({ loader: emdashLoader() }),
};

View File

@@ -0,0 +1,23 @@
import { emdash } from "emdash/astro";
import type { CollectionEntry } from "astro:content";
export async function getSiteSettings() {
const context = await emdash(Astro);
const settings = context.entries.settings?.[0];
return settings;
}
export function resolveBlogSiteIdentity(entry: CollectionEntry<"blog">) {
return {
title: entry.data.title,
description: entry.data.excerpt,
image: entry.data.image,
};
}
export function getReadingTime(content: string): string {
const wordsPerMinute = 200;
const words = content.split(/\s+/).length;
const minutes = Math.ceil(words / wordsPerMinute);
return `${minutes} นาที`;
}