create-ampless 0.2.0-alpha.9 → 1.0.0-alpha.100
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/README.ja.md +77 -0
- package/README.md +6 -3
- package/dist/index.js +743 -84
- package/dist/templates/_shared/AGENTS.ja.md +94 -0
- package/dist/templates/_shared/AGENTS.md +94 -0
- package/dist/templates/_shared/README.ja.md +239 -0
- package/dist/templates/_shared/README.md +239 -0
- package/dist/templates/_shared/RUNBOOK.ja.md +120 -0
- package/dist/templates/_shared/RUNBOOK.md +32 -58
- package/dist/templates/_shared/THEMES.ja.md +495 -0
- package/dist/templates/_shared/THEMES.md +523 -0
- package/dist/templates/_shared/amplify/auth/post-confirmation/resource.ts +7 -0
- package/dist/templates/_shared/amplify/backend.ts +10 -0
- package/dist/templates/_shared/amplify/data/get-media-by-src.js +45 -0
- package/dist/templates/_shared/amplify/data/get-published-post.js +9 -12
- package/dist/templates/_shared/amplify/data/list-posts-by-tag.js +6 -9
- package/dist/templates/_shared/amplify/data/list-published-posts.js +10 -11
- package/dist/templates/_shared/amplify/data/resource.custom.ts +1 -2
- package/dist/templates/_shared/amplify/data/resource.ts +28 -7
- package/dist/templates/_shared/amplify/events/dispatcher/resource.ts +1 -0
- package/dist/templates/_shared/amplify/events/processor-trusted/resource.ts +1 -0
- package/dist/templates/_shared/amplify/events/processor-untrusted/resource.ts +5 -0
- package/dist/templates/_shared/amplify/functions/api-key-renewer/resource.ts +1 -0
- package/dist/templates/_shared/amplify/functions/mcp-handler/handler.ts +1 -0
- package/dist/templates/_shared/amplify/functions/mcp-handler/resource.ts +12 -0
- package/dist/templates/_shared/amplify/functions/plugin-secret-handler/handler.ts +11 -0
- package/dist/templates/_shared/amplify/functions/plugin-secret-handler/resource.ts +12 -0
- package/dist/templates/_shared/amplify/functions/user-admin/resource.ts +7 -0
- package/dist/templates/_shared/amplify/secrets/.gitkeep +0 -0
- package/dist/templates/_shared/amplify/secrets/encryption-key.ts +9 -0
- package/dist/templates/_shared/app/(admin)/admin/mcp-tokens/page.tsx +5 -0
- package/dist/templates/_shared/app/(admin)/admin/plugins/page.tsx +5 -0
- package/dist/templates/_shared/app/globals.css +55 -39
- package/dist/templates/_shared/app/layout.tsx +51 -16
- package/dist/templates/_shared/app/providers.tsx +0 -2
- package/dist/templates/_shared/app/raw/[slug]/route.ts +10 -0
- package/dist/templates/_shared/app/static/[slug]/[[...path]]/route.ts +14 -0
- package/dist/templates/_shared/cms.config.ts +64 -23
- package/dist/templates/_shared/components/site-chrome/site-sidebar.tsx +3 -4
- package/dist/templates/_shared/components/tag-list.tsx +9 -2
- package/dist/templates/_shared/components.json +1 -1
- package/dist/templates/_shared/docs/plugin-author-guide.ja.md +934 -0
- package/dist/templates/_shared/docs/plugin-author-guide.md +1336 -0
- package/dist/templates/_shared/lib/admin.ts +12 -12
- package/dist/templates/_shared/lib/ampless.ts +2 -8
- package/dist/templates/_shared/lib/amplify.ts +0 -5
- package/dist/templates/_shared/package.json +51 -43
- package/dist/templates/_shared/plugins/README.ja.md +139 -0
- package/dist/templates/_shared/plugins/README.md +143 -0
- package/dist/templates/_shared/proxy.ts +23 -8
- package/dist/templates/blog/README.ja.md +22 -0
- package/dist/templates/blog/README.md +17 -47
- package/dist/templates/blog/manifest.ts +1 -1
- package/dist/templates/blog/pages/feed.ts +4 -5
- package/dist/templates/blog/pages/home.tsx +10 -15
- package/dist/templates/blog/pages/post.tsx +42 -14
- package/dist/templates/blog/pages/sitemap.ts +4 -5
- package/dist/templates/blog/pages/tag.tsx +8 -10
- package/dist/templates/blog/tokens.css +26 -40
- package/dist/templates/corporate/README.ja.md +18 -0
- package/dist/templates/corporate/README.md +12 -14
- package/dist/templates/corporate/pages/feed.ts +3 -4
- package/dist/templates/corporate/pages/home.tsx +7 -12
- package/dist/templates/corporate/pages/post.tsx +20 -14
- package/dist/templates/corporate/pages/sitemap.ts +3 -4
- package/dist/templates/corporate/pages/tag.tsx +8 -10
- package/dist/templates/corporate/tokens.css +17 -39
- package/dist/templates/dads/README.ja.md +31 -0
- package/dist/templates/dads/README.md +13 -17
- package/dist/templates/dads/pages/feed.ts +3 -4
- package/dist/templates/dads/pages/home.tsx +7 -12
- package/dist/templates/dads/pages/post.tsx +20 -14
- package/dist/templates/dads/pages/sitemap.ts +3 -4
- package/dist/templates/dads/pages/tag.tsx +8 -10
- package/dist/templates/dads/tokens.css +22 -42
- package/dist/templates/docs/README.ja.md +24 -0
- package/dist/templates/docs/README.md +10 -13
- package/dist/templates/docs/pages/feed.ts +3 -4
- package/dist/templates/docs/pages/home.tsx +6 -9
- package/dist/templates/docs/pages/post.tsx +19 -13
- package/dist/templates/docs/pages/sitemap.ts +3 -4
- package/dist/templates/docs/pages/tag.tsx +8 -10
- package/dist/templates/docs/tokens.css +17 -39
- package/dist/templates/landing/README.ja.md +20 -0
- package/dist/templates/landing/README.md +14 -19
- package/dist/templates/landing/pages/feed.ts +4 -5
- package/dist/templates/landing/pages/home.tsx +7 -12
- package/dist/templates/landing/pages/post.tsx +20 -14
- package/dist/templates/landing/pages/sitemap.ts +3 -4
- package/dist/templates/landing/pages/tag.tsx +8 -10
- package/dist/templates/landing/tokens.css +17 -39
- package/dist/templates/minimal/README.ja.md +14 -0
- package/dist/templates/minimal/README.md +9 -47
- package/dist/templates/minimal/pages/feed.ts +4 -5
- package/dist/templates/minimal/pages/home.tsx +6 -8
- package/dist/templates/minimal/pages/post.tsx +19 -12
- package/dist/templates/minimal/pages/sitemap.ts +4 -5
- package/dist/templates/minimal/pages/tag.tsx +7 -8
- package/dist/templates/minimal/tokens.css +17 -39
- package/dist/templates/plugin-local/README.md +34 -0
- package/dist/templates/plugin-local/index.ts +39 -0
- package/dist/templates/plugin-standalone/CHANGELOG.md +1 -0
- package/dist/templates/plugin-standalone/README.ja.md +43 -0
- package/dist/templates/plugin-standalone/README.md +43 -0
- package/dist/templates/plugin-standalone/package.json +47 -0
- package/dist/templates/plugin-standalone/src/index.test.ts +16 -0
- package/dist/templates/plugin-standalone/src/index.ts +29 -0
- package/dist/templates/plugin-standalone/tsconfig.json +16 -0
- package/dist/templates/plugin-standalone/tsup.config.ts +8 -0
- package/package.json +1 -1
- package/dist/templates/_shared/app/(admin)/admin/sites/page.tsx +0 -5
- package/dist/templates/_shared/app/site/[siteId]/raw/[slug]/route.ts +0 -5
- package/dist/templates/_shared/components/i18n-provider.tsx +0 -15
- package/dist/templates/_shared/lib/admin-site-client.ts +0 -10
- package/dist/templates/_shared/lib/admin-site.ts +0 -12
- package/dist/templates/_shared/lib/amplify-server.ts +0 -7
- package/dist/templates/_shared/lib/auth-server.ts +0 -15
- package/dist/templates/_shared/lib/cn.ts +0 -5
- package/dist/templates/_shared/lib/i18n.ts +0 -35
- package/dist/templates/_shared/lib/kv-provider.ts +0 -7
- package/dist/templates/_shared/lib/media.ts +0 -6
- package/dist/templates/_shared/lib/posts-provider.ts +0 -7
- package/dist/templates/_shared/lib/posts-public.ts +0 -27
- package/dist/templates/_shared/lib/posts.ts +0 -12
- package/dist/templates/_shared/lib/seo.ts +0 -11
- package/dist/templates/_shared/lib/site-settings.ts +0 -11
- package/dist/templates/_shared/lib/storage.ts +0 -10
- package/dist/templates/_shared/lib/theme-actions.ts +0 -5
- package/dist/templates/_shared/lib/theme-active.ts +0 -10
- package/dist/templates/_shared/lib/theme-config.ts +0 -12
- package/dist/templates/_shared/lib/upload.ts +0 -6
- /package/dist/templates/_shared/app/{site/[siteId]/[slug] → [slug]}/page.tsx +0 -0
- /package/dist/templates/_shared/app/{site/[siteId]/feed.xml → feed.xml}/route.ts +0 -0
- /package/dist/templates/_shared/app/{site/[siteId]/og → og}/[slug]/route.ts +0 -0
- /package/dist/templates/_shared/app/{site/[siteId]/page.tsx → page.tsx} +0 -0
- /package/dist/templates/_shared/app/{site/[siteId]/sitemap.xml → sitemap.xml}/route.ts +0 -0
- /package/dist/templates/_shared/app/{site/[siteId]/tag → tag}/[tag]/page.tsx +0 -0
|
@@ -1,19 +1,18 @@
|
|
|
1
1
|
// Wired-up admin UI factory. Single source of truth for the admin
|
|
2
2
|
// library — every admin route shell, API route shell, and form
|
|
3
|
-
//
|
|
4
|
-
//
|
|
5
|
-
// L2 architectural change (admin extraction): admin UI now lives in
|
|
6
|
-
// `@ampless/admin`. This module wires the project's
|
|
3
|
+
// imports the `admin` value from here. Admin UI lives in
|
|
4
|
+
// `@ampless/admin`; this module wires the project's
|
|
7
5
|
// `amplify_outputs.json` and `cms.config` into a single `Admin`
|
|
8
6
|
// instance.
|
|
9
7
|
//
|
|
10
|
-
// NOTE:
|
|
11
|
-
//
|
|
12
|
-
//
|
|
13
|
-
//
|
|
14
|
-
// ReferenceError on `ampless` at module init.
|
|
15
|
-
//
|
|
16
|
-
//
|
|
8
|
+
// NOTE: we pass `ampless` as a thunk (not the resolved instance) so we
|
|
9
|
+
// don't have a static `import './ampless'` at the top of this file.
|
|
10
|
+
// A static import would form the cycle
|
|
11
|
+
// `lib/admin.ts → lib/ampless.ts → themes-registry → themes → lib/admin.ts`
|
|
12
|
+
// and crash with a TDZ ReferenceError on `ampless` at module init.
|
|
13
|
+
// The thunk uses dynamic `import()` so `lib/ampless.ts` only loads on
|
|
14
|
+
// the first `loadSiteSettings` / `loadThemeConfig` call (request
|
|
15
|
+
// time), by which point every module has finished initialising.
|
|
17
16
|
|
|
18
17
|
import outputs from '../amplify_outputs.json'
|
|
19
18
|
import cmsConfig from '@/cms.config'
|
|
@@ -22,9 +21,10 @@ import { createAdmin } from '@ampless/admin'
|
|
|
22
21
|
export const admin = createAdmin({
|
|
23
22
|
outputs,
|
|
24
23
|
cmsConfig,
|
|
24
|
+
ampless: async () => (await import('./ampless')).ampless,
|
|
25
25
|
locale: (cmsConfig as { locale?: string }).locale ?? 'en',
|
|
26
26
|
})
|
|
27
27
|
|
|
28
28
|
// Convenience: the server-side translation helper. Client components
|
|
29
|
-
// should use `useT()` from
|
|
29
|
+
// should use `useT()` from `@ampless/admin/components` instead.
|
|
30
30
|
export const t = admin.t
|
|
@@ -1,15 +1,9 @@
|
|
|
1
1
|
// Wired-up ampless runtime instance. Single source of truth for the
|
|
2
2
|
// public-side library — every route handler, dispatcher, and theme
|
|
3
|
-
// component imports the `ampless` value from here.
|
|
4
|
-
//
|
|
5
|
-
// L1 architectural change (runtime extraction): public-side
|
|
6
|
-
// behaviour now lives in `@ampless/runtime`. This module wires the
|
|
3
|
+
// component imports the `ampless` value from here. Public-side
|
|
4
|
+
// behaviour lives in `@ampless/runtime`; this module wires the
|
|
7
5
|
// project's `amplify_outputs.json`, `cms.config`, and themes registry
|
|
8
6
|
// into a single `Ampless` instance.
|
|
9
|
-
//
|
|
10
|
-
// Admin-side modules (post providers, kv-provider, auth, etc.) stay
|
|
11
|
-
// in `templates/_shared/lib/` for now — they move into `@ampless/admin`
|
|
12
|
-
// in L2.
|
|
13
7
|
|
|
14
8
|
import outputs from '../amplify_outputs.json'
|
|
15
9
|
import cmsConfig from '@/cms.config'
|
|
@@ -13,8 +13,3 @@ import { Amplify } from 'aws-amplify'
|
|
|
13
13
|
import outputs from '../amplify_outputs.json'
|
|
14
14
|
|
|
15
15
|
Amplify.configure(outputs, { ssr: true })
|
|
16
|
-
|
|
17
|
-
export function configureAmplify() {
|
|
18
|
-
// module-level side effect above already ran; keep this as a no-op
|
|
19
|
-
// for callers that still import it as a function for back-compat.
|
|
20
|
-
}
|
|
@@ -3,64 +3,72 @@
|
|
|
3
3
|
"version": "0.1.0",
|
|
4
4
|
"private": true,
|
|
5
5
|
"type": "module",
|
|
6
|
+
"engines": {
|
|
7
|
+
"node": ">=22"
|
|
8
|
+
},
|
|
6
9
|
"scripts": {
|
|
7
10
|
"dev": "next dev",
|
|
8
11
|
"build": "next build",
|
|
9
12
|
"start": "next start",
|
|
10
13
|
"lint": "next lint",
|
|
11
|
-
"sandbox": "ampx sandbox",
|
|
12
|
-
"
|
|
13
|
-
"
|
|
14
|
-
"copy-theme": "npx create-ampless@alpha copy-theme"
|
|
14
|
+
"sandbox": "ampx sandbox --once && next dev",
|
|
15
|
+
"update-ampless": "npx create-ampless@latest upgrade",
|
|
16
|
+
"copy-theme": "npx create-ampless@latest copy-theme"
|
|
15
17
|
},
|
|
16
18
|
"dependencies": {
|
|
17
|
-
"@aws-amplify/adapter-nextjs": "^1.
|
|
18
|
-
"@radix-ui/react-dialog": "^1.1.
|
|
19
|
-
"@radix-ui/react-label": "^2.1.
|
|
20
|
-
"@radix-ui/react-slot": "^1.
|
|
21
|
-
"@tiptap/extension-image": "^3.23.
|
|
22
|
-
"@tiptap/extension-link": "^3.23.
|
|
23
|
-
"@tiptap/pm": "^3.23.
|
|
24
|
-
"@tiptap/react": "^3.23.
|
|
25
|
-
"@tiptap/starter-kit": "^3.23.
|
|
26
|
-
"@ampless/plugin-
|
|
27
|
-
"@ampless/plugin-
|
|
28
|
-
"@ampless/plugin-
|
|
29
|
-
"@ampless/plugin-
|
|
30
|
-
"@ampless/
|
|
31
|
-
"@ampless/
|
|
32
|
-
"@ampless/
|
|
19
|
+
"@aws-amplify/adapter-nextjs": "^1.7.3",
|
|
20
|
+
"@radix-ui/react-dialog": "^1.1.15",
|
|
21
|
+
"@radix-ui/react-label": "^2.1.8",
|
|
22
|
+
"@radix-ui/react-slot": "^1.2.4",
|
|
23
|
+
"@tiptap/extension-image": "^3.23.6",
|
|
24
|
+
"@tiptap/extension-link": "^3.23.6",
|
|
25
|
+
"@tiptap/pm": "^3.23.6",
|
|
26
|
+
"@tiptap/react": "^3.23.6",
|
|
27
|
+
"@tiptap/starter-kit": "^3.23.6",
|
|
28
|
+
"@ampless/plugin-analytics-ga4": "^0.2.0-alpha.14",
|
|
29
|
+
"@ampless/plugin-cookie-consent": "^0.1.0-alpha.5",
|
|
30
|
+
"@ampless/plugin-gtm": "^0.2.0-alpha.13",
|
|
31
|
+
"@ampless/plugin-og-image": "^0.2.0-alpha.30",
|
|
32
|
+
"@ampless/plugin-plausible": "^0.2.0-alpha.13",
|
|
33
|
+
"@ampless/plugin-reading-time": "^0.1.0-alpha.3",
|
|
34
|
+
"@ampless/plugin-rss": "^0.2.0-alpha.30",
|
|
35
|
+
"@ampless/plugin-schema-jsonld": "^0.1.1-alpha.9",
|
|
36
|
+
"@ampless/plugin-seo": "^0.2.0-alpha.30",
|
|
37
|
+
"@ampless/plugin-webhook": "^0.2.0-alpha.31",
|
|
38
|
+
"@ampless/admin": "^1.0.0-alpha.59",
|
|
39
|
+
"@ampless/backend": "^1.0.0-alpha.49",
|
|
40
|
+
"@ampless/runtime": "^1.0.0-alpha.38",
|
|
33
41
|
"@digital-go-jp/tailwind-theme-plugin": "^0.3.4",
|
|
34
|
-
"ampless": "^0.
|
|
35
|
-
"aws-amplify": "^6.
|
|
42
|
+
"ampless": "^1.0.0-alpha.30",
|
|
43
|
+
"aws-amplify": "^6.17.0",
|
|
36
44
|
"class-variance-authority": "^0.7.1",
|
|
37
45
|
"clsx": "^2.1.1",
|
|
38
46
|
"lucide-react": "^1.16.0",
|
|
39
47
|
"next": "^16.2.6",
|
|
40
|
-
"react": "^19.
|
|
41
|
-
"react-dom": "^19.
|
|
42
|
-
"react-image-crop": "^11.0.
|
|
48
|
+
"react": "^19.2.6",
|
|
49
|
+
"react-dom": "^19.2.6",
|
|
50
|
+
"react-image-crop": "^11.0.10",
|
|
43
51
|
"tailwind-merge": "^3.6.0"
|
|
44
52
|
},
|
|
45
53
|
"devDependencies": {
|
|
46
|
-
"@aws-amplify/backend": "^1.
|
|
47
|
-
"@aws-amplify/backend-cli": "^1.
|
|
48
|
-
"@aws-sdk/client-appsync": "^3.
|
|
49
|
-
"@aws-sdk/client-cognito-identity-provider": "^3.
|
|
50
|
-
"@aws-sdk/client-dynamodb": "^3.
|
|
51
|
-
"@aws-sdk/client-s3": "^3.
|
|
52
|
-
"@aws-sdk/client-sqs": "^3.
|
|
53
|
-
"@aws-sdk/lib-dynamodb": "^3.
|
|
54
|
-
"@aws-sdk/util-dynamodb": "^3.
|
|
55
|
-
"@tailwindcss/postcss": "^4.
|
|
56
|
-
"@tailwindcss/typography": "^0.5.
|
|
57
|
-
"@types/aws-lambda": "^8.10.
|
|
58
|
-
"@types/node": "^22.
|
|
59
|
-
"@types/react": "^19.
|
|
60
|
-
"@types/react-dom": "^19.
|
|
61
|
-
"aws-cdk-lib": "^2.
|
|
62
|
-
"postcss": "^8.
|
|
63
|
-
"tailwindcss": "^4.
|
|
54
|
+
"@aws-amplify/backend": "^1.22.0",
|
|
55
|
+
"@aws-amplify/backend-cli": "^1.8.2",
|
|
56
|
+
"@aws-sdk/client-appsync": "^3.1053.0",
|
|
57
|
+
"@aws-sdk/client-cognito-identity-provider": "^3.1053.0",
|
|
58
|
+
"@aws-sdk/client-dynamodb": "^3.1053.0",
|
|
59
|
+
"@aws-sdk/client-s3": "^3.1053.0",
|
|
60
|
+
"@aws-sdk/client-sqs": "^3.1053.0",
|
|
61
|
+
"@aws-sdk/lib-dynamodb": "^3.1053.0",
|
|
62
|
+
"@aws-sdk/util-dynamodb": "^3.996.2",
|
|
63
|
+
"@tailwindcss/postcss": "^4.3.0",
|
|
64
|
+
"@tailwindcss/typography": "^0.5.19",
|
|
65
|
+
"@types/aws-lambda": "^8.10.161",
|
|
66
|
+
"@types/node": "^22.19.19",
|
|
67
|
+
"@types/react": "^19.2.15",
|
|
68
|
+
"@types/react-dom": "^19.2.3",
|
|
69
|
+
"aws-cdk-lib": "^2.257.0",
|
|
70
|
+
"postcss": "^8.5.15",
|
|
71
|
+
"tailwindcss": "^4.3.0",
|
|
64
72
|
"typescript": "^6.0.3"
|
|
65
73
|
}
|
|
66
74
|
}
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
> English: [README.md](./README.md)
|
|
2
|
+
|
|
3
|
+
# サイトローカルプラグイン
|
|
4
|
+
|
|
5
|
+
このディレクトリは **このサイト専用のプラグイン置き場**。別 npm
|
|
6
|
+
パッケージとして publish したくない小さなカスタマイズを書く場所。
|
|
7
|
+
|
|
8
|
+
`update-ampless` はこのディレクトリのファイルに一切触らない。ここに置いた
|
|
9
|
+
ものは消えない、上書きされない。
|
|
10
|
+
|
|
11
|
+
## いつ使うか
|
|
12
|
+
|
|
13
|
+
詳しい判断軸は [プラグイン作者ガイド](../docs/plugin-author-guide.ja.md)
|
|
14
|
+
§0「テーマとプラグインの境界線」に書いてある。プラグインが初めて、または
|
|
15
|
+
「これはテーマ側に書くべきか、プラグインか」で迷ったら先にそちらを読む。
|
|
16
|
+
ざっくり言うと:
|
|
17
|
+
|
|
18
|
+
- **テーマ** = ページの見た目 (レイアウト / コンポーネント / CSS)
|
|
19
|
+
- **プラグイン** = admin で編集する設定、バックグラウンド処理、
|
|
20
|
+
テーマを横断する注入、機械可読メタデータ、複数サイトで共有したい機能
|
|
21
|
+
|
|
22
|
+
その中でも *ローカル* プラグイン (このディレクトリ) を使うのは、サイト
|
|
23
|
+
固有の機能で:
|
|
24
|
+
|
|
25
|
+
- プラグイン surface (`publicHead` / `publicBodyEnd` / `metadata` /
|
|
26
|
+
`eventHooks` 等) が必要
|
|
27
|
+
- このサイト限定の用途 (一度きりのフッタークレジット、サイト特有の
|
|
28
|
+
JSON-LD 拡張、まだ汎用化したくない analytics スニペット等)
|
|
29
|
+
- 別パッケージとして version 上げて publish するのは大袈裟
|
|
30
|
+
|
|
31
|
+
複数サイトで使いたくなったら、独立 npm パッケージに切り出す:
|
|
32
|
+
`npx create-ampless@latest plugin <name> --standalone` で publish 用の
|
|
33
|
+
ディレクトリ一式が scaffold される。
|
|
34
|
+
|
|
35
|
+
## クライアントサイドスクリプトに関する注意
|
|
36
|
+
|
|
37
|
+
`publicHead` / `publicBodyEnd` で `inlineScript` を返す場合、その body の
|
|
38
|
+
中で **可視 DOM 要素を挿入してはいけない**。React の hydration は DOM が
|
|
39
|
+
virtual DOM と一致していることを前提にしていて、外部からの DOM 操作は
|
|
40
|
+
reconciliation で消されてコンソールに hydration error が出る。
|
|
41
|
+
安全なパターンは `window.dataLayer` 等のグローバル状態操作、自分で隔離
|
|
42
|
+
コンテナを持つ外部ウィジェットローダ、そして SSR 専用 descriptor (`meta` /
|
|
43
|
+
`link` / `noscript` / `iframe`)。詳細は [作者ガイド §6](../docs/plugin-author-guide.ja.md)
|
|
44
|
+
「クライアント側 DOM 変更は禁止」セクションを参照。
|
|
45
|
+
|
|
46
|
+
## 最小例
|
|
47
|
+
|
|
48
|
+
`plugins/footer-credit/index.ts`:
|
|
49
|
+
|
|
50
|
+
```typescript
|
|
51
|
+
import { definePlugin, type AmplessPlugin } from 'ampless'
|
|
52
|
+
|
|
53
|
+
export interface FooterCreditOptions {
|
|
54
|
+
instanceId?: string
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export default function footerCreditPlugin(
|
|
58
|
+
options: FooterCreditOptions = {}
|
|
59
|
+
): AmplessPlugin {
|
|
60
|
+
const instanceId = options.instanceId ?? 'footer-credit'
|
|
61
|
+
return definePlugin({
|
|
62
|
+
name: 'footer-credit',
|
|
63
|
+
instanceId,
|
|
64
|
+
apiVersion: 1,
|
|
65
|
+
trust_level: 'untrusted',
|
|
66
|
+
displayName: { en: 'Footer credit', ja: 'フッタークレジット' },
|
|
67
|
+
capabilities: ['publicBody', 'adminSettings'],
|
|
68
|
+
settings: {
|
|
69
|
+
public: [
|
|
70
|
+
{
|
|
71
|
+
type: 'text',
|
|
72
|
+
key: 'html',
|
|
73
|
+
label: { en: 'Snippet', ja: 'スニペット' },
|
|
74
|
+
default: '',
|
|
75
|
+
},
|
|
76
|
+
],
|
|
77
|
+
},
|
|
78
|
+
publicBodyEnd(ctx) {
|
|
79
|
+
const html = (ctx.setting<string>('html') ?? '').trim()
|
|
80
|
+
if (!html) return []
|
|
81
|
+
return [{ type: 'noscript', id: `footer-credit-${instanceId}`, html }]
|
|
82
|
+
},
|
|
83
|
+
})
|
|
84
|
+
}
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
`cms.config.ts` で register:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
import footerCreditPlugin from './plugins/footer-credit'
|
|
91
|
+
|
|
92
|
+
export default defineConfig({
|
|
93
|
+
// ...
|
|
94
|
+
plugins: [
|
|
95
|
+
// ...既存 plugin...
|
|
96
|
+
footerCreditPlugin(),
|
|
97
|
+
],
|
|
98
|
+
})
|
|
99
|
+
```
|
|
100
|
+
|
|
101
|
+
これだけ。`next dev` 再起動 → `/admin/plugins` でスニペットを設定すれば、
|
|
102
|
+
すべての公開ページの `</body>` 直前にレンダされる。
|
|
103
|
+
|
|
104
|
+
## 宣言できる surface
|
|
105
|
+
|
|
106
|
+
プラグインは `definePlugin({...})` で組み立てるただのオブジェクト。型は
|
|
107
|
+
`node_modules/ampless/dist/plugin.d.ts` を見るか、[プラグイン作者ガイド][guide]
|
|
108
|
+
の散文で。
|
|
109
|
+
|
|
110
|
+
現状 active な capability:
|
|
111
|
+
|
|
112
|
+
| capability | 用途 |
|
|
113
|
+
|---|---|
|
|
114
|
+
| `publicHead` | `<head>` に site-wide で挿入される descriptor |
|
|
115
|
+
| `publicBody` | `</body>` 直前に site-wide で挿入される descriptor |
|
|
116
|
+
| `metadata` | post ごとの Next.js Metadata 拡張 |
|
|
117
|
+
| `eventHooks` | trusted/untrusted の背景ハンドラ (content lifecycle / media event 等) |
|
|
118
|
+
| `adminSettings` | `settings.public[]` で宣言する admin 編集可能な設定 |
|
|
119
|
+
| `writePublicAsset` | trusted plugin が `public/plugins/<instanceId>/...` に書き込み |
|
|
120
|
+
| `schema` | post ごとの JSON-LD を `publicBodyForPost` 経由で (テーマ側で `ampless.publicBodyForPost(post)` を呼ぶ前提) |
|
|
121
|
+
| `publicHtmlForPost` | post ごとの可視 HTML(読了時間バッジ等)を `publicHtmlForPost` 経由で(テーマ側で `ampless.publicHtmlForPost(post)` を呼ぶ前提) |
|
|
122
|
+
|
|
123
|
+
**`publicHtmlForPost` を使うファーストパーティプラグイン:**
|
|
124
|
+
- `@ampless/plugin-reading-time` — 投稿本文から読了時間を推定し、本文の前後に設定可能なバッジを注入します。
|
|
125
|
+
|
|
126
|
+
[guide]: https://github.com/heavymoons/ampless/blob/main/packages/ampless/docs/plugin-author-guide.md
|
|
127
|
+
|
|
128
|
+
## TypeScript 設定
|
|
129
|
+
|
|
130
|
+
`tsconfig.json` の `**/*.ts` include glob でこのディレクトリも自動的に
|
|
131
|
+
カバーされている。`import x from './plugins/foo'` も
|
|
132
|
+
`import x from '@/plugins/foo'` も追加設定なしで動く。
|
|
133
|
+
|
|
134
|
+
## `update-ampless` はどうなるか
|
|
135
|
+
|
|
136
|
+
何もしない。`plugins/` は upgrade ツールの protected list に入っているので、
|
|
137
|
+
ここに置いたファイルは上書きも削除もされない。代償として **この README
|
|
138
|
+
も更新されない** — プラグイン API に大きな変更があるときは、本家リポジトリの
|
|
139
|
+
[プラグイン作者ガイド][guide] で最新版を確認すること。
|
|
@@ -0,0 +1,143 @@
|
|
|
1
|
+
> 日本語版: [README.ja.md](./README.ja.md)
|
|
2
|
+
|
|
3
|
+
# Site-local plugins
|
|
4
|
+
|
|
5
|
+
This directory is for **plugins that belong only to this site** — small
|
|
6
|
+
customizations you don't want to publish as a separate npm package.
|
|
7
|
+
|
|
8
|
+
`update-ampless` never touches files in this directory, so anything you
|
|
9
|
+
add here is yours to keep.
|
|
10
|
+
|
|
11
|
+
## When to use a local plugin
|
|
12
|
+
|
|
13
|
+
The longer answer lives in §0 ("Theme vs Plugin Boundary") of the
|
|
14
|
+
[plugin author guide](../docs/plugin-author-guide.md) — read that
|
|
15
|
+
first if you're new to plugins, or if you're unsure whether a feature
|
|
16
|
+
belongs in a plugin or a theme. Short version:
|
|
17
|
+
|
|
18
|
+
- **Theme** = what the page looks like (layout, components, CSS).
|
|
19
|
+
- **Plugin** = admin-editable config, background processing,
|
|
20
|
+
theme-agnostic injection, machine-readable metadata, or anything
|
|
21
|
+
you want to share between sites.
|
|
22
|
+
|
|
23
|
+
Reach for a *local* plugin (this directory) when you want a feature
|
|
24
|
+
that:
|
|
25
|
+
|
|
26
|
+
- needs a plugin surface (`publicHead` / `publicBodyEnd` /
|
|
27
|
+
`metadata` / `eventHooks` / etc.)
|
|
28
|
+
- is specific to this site (a one-off footer credit, a custom JSON-LD
|
|
29
|
+
enrichment, an analytics snippet you're not yet ready to ship as a
|
|
30
|
+
reusable package)
|
|
31
|
+
- you'd rather not version-bump or republish to iterate on
|
|
32
|
+
|
|
33
|
+
When the plugin grows useful for more than one site, lift it into its
|
|
34
|
+
own npm package — `npx create-ampless@latest plugin <name> --standalone`
|
|
35
|
+
scaffolds the directory ready for `npm publish`.
|
|
36
|
+
|
|
37
|
+
## A note on client-side scripts
|
|
38
|
+
|
|
39
|
+
If your `publicHead` / `publicBodyEnd` returns an `inlineScript`, the
|
|
40
|
+
script body **must not insert visible DOM elements** into the page.
|
|
41
|
+
React's hydration assumes the DOM matches its virtual DOM, and any
|
|
42
|
+
foreign nodes get wiped during reconciliation (plus a console error).
|
|
43
|
+
Safe patterns are `window.dataLayer`-style global state, external
|
|
44
|
+
widget loaders that manage their own isolated container, and
|
|
45
|
+
SSR-only descriptors (`meta` / `link` / `noscript` / `iframe`).
|
|
46
|
+
See the [author guide §6](../docs/plugin-author-guide.md) "Client-side
|
|
47
|
+
DOM mutation: don't" section for the full story.
|
|
48
|
+
|
|
49
|
+
## Minimal example
|
|
50
|
+
|
|
51
|
+
`plugins/footer-credit/index.ts`:
|
|
52
|
+
|
|
53
|
+
```typescript
|
|
54
|
+
import { definePlugin, type AmplessPlugin } from 'ampless'
|
|
55
|
+
|
|
56
|
+
export interface FooterCreditOptions {
|
|
57
|
+
instanceId?: string
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
export default function footerCreditPlugin(
|
|
61
|
+
options: FooterCreditOptions = {}
|
|
62
|
+
): AmplessPlugin {
|
|
63
|
+
const instanceId = options.instanceId ?? 'footer-credit'
|
|
64
|
+
return definePlugin({
|
|
65
|
+
name: 'footer-credit',
|
|
66
|
+
instanceId,
|
|
67
|
+
apiVersion: 1,
|
|
68
|
+
trust_level: 'untrusted',
|
|
69
|
+
displayName: { en: 'Footer credit', ja: 'フッタークレジット' },
|
|
70
|
+
capabilities: ['publicBody', 'adminSettings'],
|
|
71
|
+
settings: {
|
|
72
|
+
public: [
|
|
73
|
+
{
|
|
74
|
+
type: 'text',
|
|
75
|
+
key: 'html',
|
|
76
|
+
label: { en: 'Snippet', ja: 'スニペット' },
|
|
77
|
+
default: '',
|
|
78
|
+
},
|
|
79
|
+
],
|
|
80
|
+
},
|
|
81
|
+
publicBodyEnd(ctx) {
|
|
82
|
+
const html = (ctx.setting<string>('html') ?? '').trim()
|
|
83
|
+
if (!html) return []
|
|
84
|
+
return [{ type: 'noscript', id: `footer-credit-${instanceId}`, html }]
|
|
85
|
+
},
|
|
86
|
+
})
|
|
87
|
+
}
|
|
88
|
+
```
|
|
89
|
+
|
|
90
|
+
Register it in `cms.config.ts`:
|
|
91
|
+
|
|
92
|
+
```typescript
|
|
93
|
+
import footerCreditPlugin from './plugins/footer-credit'
|
|
94
|
+
|
|
95
|
+
export default defineConfig({
|
|
96
|
+
// ...
|
|
97
|
+
plugins: [
|
|
98
|
+
// ...existing plugins...
|
|
99
|
+
footerCreditPlugin(),
|
|
100
|
+
],
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
That's it. Restart `next dev` and visit `/admin/plugins` to configure
|
|
105
|
+
the snippet, then any public page renders it before `</body>`.
|
|
106
|
+
|
|
107
|
+
## What you can declare
|
|
108
|
+
|
|
109
|
+
A plugin is just an object built with `definePlugin({...})`. The full
|
|
110
|
+
shape lives in `node_modules/ampless/dist/plugin.d.ts` (or [the plugin
|
|
111
|
+
author guide][guide] if you prefer prose).
|
|
112
|
+
|
|
113
|
+
Capabilities currently active:
|
|
114
|
+
|
|
115
|
+
| capability | purpose |
|
|
116
|
+
|---|---|
|
|
117
|
+
| `publicHead` | descriptors rendered in `<head>` site-wide |
|
|
118
|
+
| `publicBody` | descriptors rendered before `</body>` site-wide |
|
|
119
|
+
| `metadata` | per-post Next.js Metadata contributions |
|
|
120
|
+
| `eventHooks` | trusted/untrusted background handlers (content lifecycle, media events, ...) |
|
|
121
|
+
| `adminSettings` | admin-editable settings declared via `settings.public[]` |
|
|
122
|
+
| `writePublicAsset` | trusted plugins can write namespaced files under `public/plugins/<instanceId>/...` |
|
|
123
|
+
| `schema` | per-post JSON-LD via `publicBodyForPost` (theme template must call `ampless.publicBodyForPost(post)`) |
|
|
124
|
+
| `publicHtmlForPost` | per-post visible HTML (e.g. reading-time badge, breadcrumbs) via `publicHtmlForPost` (theme template must call `ampless.publicHtmlForPost(post)`) |
|
|
125
|
+
|
|
126
|
+
**First-party plugins that use `publicHtmlForPost`:**
|
|
127
|
+
- `@ampless/plugin-reading-time` — estimates read time from the post body and injects a configurable badge before or after the content.
|
|
128
|
+
|
|
129
|
+
[guide]: https://github.com/heavymoons/ampless/blob/main/packages/ampless/docs/plugin-author-guide.md
|
|
130
|
+
|
|
131
|
+
## What about TypeScript?
|
|
132
|
+
|
|
133
|
+
`tsconfig.json` already covers this directory through its `**/*.ts`
|
|
134
|
+
include glob. Both `import x from './plugins/foo'` and
|
|
135
|
+
`import x from '@/plugins/foo'` work; no extra setup needed.
|
|
136
|
+
|
|
137
|
+
## What `update-ampless` does
|
|
138
|
+
|
|
139
|
+
Nothing. `plugins/` is in the upgrade tool's protected list, so files
|
|
140
|
+
here are never overwritten or deleted on upgrade. The flip side is that
|
|
141
|
+
this README does not get refreshed either — when ampless ships
|
|
142
|
+
significant changes to the plugin API, check the [plugin author guide][guide]
|
|
143
|
+
in the canonical repo for the up-to-date version.
|
|
@@ -1,18 +1,33 @@
|
|
|
1
1
|
// Public-site proxy (Next.js 16 rename of "middleware"). Implementation
|
|
2
2
|
// moved to `@ampless/runtime` (L1 extraction); this file wires the
|
|
3
|
-
// project's `cms.config` into the factory and
|
|
4
|
-
// matcher. The runtime export name is still
|
|
5
|
-
// for API stability; only the user-side
|
|
6
|
-
// `export const proxy`) follows Next 16's
|
|
3
|
+
// project's `cms.config` + AppSync endpoint into the factory and
|
|
4
|
+
// re-exports the default matcher. The runtime export name is still
|
|
5
|
+
// `createAmplessMiddleware` for API stability; only the user-side
|
|
6
|
+
// file convention (proxy.ts + `export const proxy`) follows Next 16's
|
|
7
|
+
// rename.
|
|
7
8
|
//
|
|
8
|
-
// See `@ampless/runtime/middleware` for behaviour details:
|
|
9
|
-
//
|
|
10
|
-
//
|
|
9
|
+
// See `@ampless/runtime/middleware` for behaviour details: AppSync
|
|
10
|
+
// flag fetch + Lambda-memory LRU + `/raw/<slug>` rewrite for no_layout
|
|
11
|
+
// HTML, `/static/<slug>(/<path>)` rewrite for static bundles, plus
|
|
12
|
+
// per-post Cache-Control.
|
|
11
13
|
|
|
12
14
|
import cmsConfig from './cms.config'
|
|
15
|
+
import outputs from './amplify_outputs.json'
|
|
13
16
|
import { createAmplessMiddleware } from '@ampless/runtime/middleware'
|
|
14
17
|
|
|
15
|
-
|
|
18
|
+
// `amplify_outputs.json` is generated by `npx ampx sandbox` /
|
|
19
|
+
// `npx ampx pipeline-deploy` — the public API key has a 365-day TTL
|
|
20
|
+
// and is rotated monthly by the api-key-renewer Lambda. See
|
|
21
|
+
// RUNBOOK.md §"API key rotation".
|
|
22
|
+
export const proxy = createAmplessMiddleware({
|
|
23
|
+
cmsConfig,
|
|
24
|
+
appsyncUrl: outputs.data.url,
|
|
25
|
+
// The public API key is always present in production deploys (the
|
|
26
|
+
// backend declares `apiKeyAuthorizationMode`). The non-null assertion
|
|
27
|
+
// is honest about the assumption; `ampx sandbox` will surface a clear
|
|
28
|
+
// error long before middleware ever runs if it ever isn't.
|
|
29
|
+
apiKey: outputs.data.api_key!,
|
|
30
|
+
})
|
|
16
31
|
|
|
17
32
|
// Next.js 16's Turbopack requires `config` to be a statically
|
|
18
33
|
// analysable object literal — referencing an imported variable
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
> English: [README.md](./README.md)
|
|
2
|
+
>
|
|
3
|
+
# Blog テーマ
|
|
4
|
+
|
|
5
|
+
shadcn/ui のデフォルトに準じたニュートラル系モノクロ。時系列の投稿フィード、個別投稿ページ、タグ別一覧を提供します。
|
|
6
|
+
|
|
7
|
+
## カスタマイズ
|
|
8
|
+
|
|
9
|
+
`/admin/sites/<siteId>/theme` で設定:
|
|
10
|
+
|
|
11
|
+
- **プライマリカラー** — ボタン、リンク、強調表示の背景色
|
|
12
|
+
- **アクセントカラー**
|
|
13
|
+
- **フォーカスリング**
|
|
14
|
+
- **破壊的操作** — 削除等の操作色
|
|
15
|
+
- **角丸**
|
|
16
|
+
- **本文フォント** — システムサンセリフ / セリフ (Georgia) / セリフ (Iowan) / 等幅
|
|
17
|
+
- **トップに固定する記事のスラッグ** — 公開済み投稿を 1 件ホームの先頭に固定
|
|
18
|
+
- **ロゴ画像 URL**
|
|
19
|
+
- **ヘッダーナビ** — ラベル + URL のペア
|
|
20
|
+
- **フッターリンク** — ラベル + URL のペア
|
|
21
|
+
|
|
22
|
+
サイトごとのライト/ダークカラースキームは ampless の標準テーマトークン経由で反映されます。
|
|
@@ -1,52 +1,22 @@
|
|
|
1
|
-
|
|
1
|
+
> 日本語版: [README.ja.md](./README.ja.md)
|
|
2
|
+
>
|
|
3
|
+
# Blog theme
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Neutral monochrome with shadcn/ui defaults. Chronological post feed, single-post page, and tag listing.
|
|
4
6
|
|
|
5
|
-
##
|
|
7
|
+
## Customizing
|
|
6
8
|
|
|
7
|
-
|
|
9
|
+
In `/admin/sites/<siteId>/theme`:
|
|
8
10
|
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
11
|
+
- **Primary color** — buttons, links, accent fills
|
|
12
|
+
- **Accent color**
|
|
13
|
+
- **Focus ring**
|
|
14
|
+
- **Destructive** — color used for destructive actions
|
|
15
|
+
- **Corner radius**
|
|
16
|
+
- **Body font** — System sans / Serif (Georgia) / Serif (Iowan) / Monospace
|
|
17
|
+
- **Featured post slug** — pin one published post to the top of the home page
|
|
18
|
+
- **Logo image URL**
|
|
19
|
+
- **Header navigation** — label + URL pairs
|
|
20
|
+
- **Footer links** — label + URL pairs
|
|
12
21
|
|
|
13
|
-
|
|
14
|
-
# Requires AWS credentials configured (`aws configure`).
|
|
15
|
-
# First run takes ~5–10 min to provision resources.
|
|
16
|
-
# Generates amplify_outputs.json when ready.
|
|
17
|
-
npx ampx sandbox
|
|
18
|
-
|
|
19
|
-
# 3. Start the Next.js dev server (terminal 2)
|
|
20
|
-
npm run dev
|
|
21
|
-
```
|
|
22
|
-
|
|
23
|
-
Then open [http://localhost:3000](http://localhost:3000).
|
|
24
|
-
|
|
25
|
-
## First admin user
|
|
26
|
-
|
|
27
|
-
Open [http://localhost:3000/login](http://localhost:3000/login) and click **Create admin account**. The first user to register is automatically added to the `ampless-admin` Cognito group.
|
|
28
|
-
|
|
29
|
-
After that, manage content from `/admin`:
|
|
30
|
-
|
|
31
|
-
- `/admin` — dashboard
|
|
32
|
-
- `/admin/posts` — list / create / edit posts (tiptap editor)
|
|
33
|
-
- `/admin/media` — upload images to S3
|
|
34
|
-
|
|
35
|
-
## Production deploy
|
|
36
|
-
|
|
37
|
-
```bash
|
|
38
|
-
git init && git add . && git commit -m "init"
|
|
39
|
-
git remote add origin <your-repo>
|
|
40
|
-
git push
|
|
41
|
-
# Then connect the repo to AWS Amplify Hosting in the AWS console.
|
|
42
|
-
```
|
|
43
|
-
|
|
44
|
-
## Customize
|
|
45
|
-
|
|
46
|
-
- `cms.config.ts` — site name, media delivery mode, plugins
|
|
47
|
-
- `app/` — Next.js App Router pages (`(public)/` for the blog, `(admin)/` for the CMS)
|
|
48
|
-
- `amplify/` — Amplify Gen 2 backend definitions (auth / data / storage)
|
|
49
|
-
|
|
50
|
-
## Plugins
|
|
51
|
-
|
|
52
|
-
Enabled: {{plugins}}
|
|
22
|
+
Per-site light/dark color scheme is honored through the standard ampless theme tokens.
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { defineTheme } from 'ampless'
|
|
2
2
|
|
|
3
3
|
// Customizable fields for the Blog theme. Edit values in
|
|
4
|
-
// `/admin/sites
|
|
4
|
+
// `/admin/sites/default/theme` — they're stored in KvStore and applied
|
|
5
5
|
// at render time as CSS variables on every public page.
|
|
6
6
|
//
|
|
7
7
|
// Labels / descriptions / groups accept either a plain string (works in
|
|
@@ -1,14 +1,13 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
|
-
siteId: string
|
|
5
4
|
request: Request
|
|
6
5
|
}
|
|
7
6
|
|
|
8
7
|
// /feed.xml proxy — plugin-rss regenerates the feed on content events
|
|
9
|
-
// and writes it to `public/plugins/rss/
|
|
10
|
-
export async function blogFeedHandler(
|
|
11
|
-
const url = publicAssetUrl(
|
|
8
|
+
// and writes it to `public/plugins/rss/feed.xml`.
|
|
9
|
+
export async function blogFeedHandler(_ctx: Ctx): Promise<Response> {
|
|
10
|
+
const url = ampless.publicAssetUrl('public/plugins/rss/feed.xml')
|
|
12
11
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
13
12
|
if (!upstream.ok) {
|
|
14
13
|
return new Response(
|