create-ampless 1.0.0-alpha.58 → 1.0.0-alpha.60
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/dist/index.js +1 -10
- package/dist/templates/_shared/AGENTS.ja.md +10 -8
- package/dist/templates/_shared/AGENTS.md +10 -8
- package/dist/templates/_shared/README.ja.md +22 -2
- package/dist/templates/_shared/README.md +22 -2
- package/dist/templates/_shared/app/layout.tsx +8 -8
- package/dist/templates/_shared/app/providers.tsx +0 -2
- package/dist/templates/_shared/components/site-chrome/site-sidebar.tsx +2 -2
- package/dist/templates/_shared/components.json +1 -1
- package/dist/templates/_shared/lib/admin.ts +4 -6
- package/dist/templates/_shared/lib/ampless.ts +2 -8
- package/dist/templates/_shared/lib/amplify.ts +0 -5
- package/dist/templates/_shared/package.json +2 -2
- package/dist/templates/blog/pages/feed.ts +2 -2
- package/dist/templates/blog/pages/home.tsx +8 -10
- package/dist/templates/blog/pages/post.tsx +9 -12
- package/dist/templates/blog/pages/sitemap.ts +2 -2
- package/dist/templates/blog/pages/tag.tsx +7 -9
- package/dist/templates/corporate/pages/feed.ts +2 -2
- package/dist/templates/corporate/pages/home.tsx +6 -8
- package/dist/templates/corporate/pages/post.tsx +9 -12
- package/dist/templates/corporate/pages/sitemap.ts +2 -2
- package/dist/templates/corporate/pages/tag.tsx +7 -9
- package/dist/templates/dads/pages/feed.ts +2 -2
- package/dist/templates/dads/pages/home.tsx +6 -8
- package/dist/templates/dads/pages/post.tsx +9 -12
- package/dist/templates/dads/pages/sitemap.ts +2 -2
- package/dist/templates/dads/pages/tag.tsx +7 -9
- package/dist/templates/docs/pages/feed.ts +2 -2
- package/dist/templates/docs/pages/home.tsx +4 -6
- package/dist/templates/docs/pages/post.tsx +7 -10
- package/dist/templates/docs/pages/sitemap.ts +2 -2
- package/dist/templates/docs/pages/tag.tsx +6 -8
- package/dist/templates/landing/pages/feed.ts +2 -2
- package/dist/templates/landing/pages/home.tsx +6 -8
- package/dist/templates/landing/pages/post.tsx +9 -12
- package/dist/templates/landing/pages/sitemap.ts +2 -2
- package/dist/templates/landing/pages/tag.tsx +7 -9
- package/dist/templates/minimal/pages/feed.ts +2 -2
- package/dist/templates/minimal/pages/home.tsx +5 -6
- package/dist/templates/minimal/pages/post.tsx +8 -10
- package/dist/templates/minimal/pages/sitemap.ts +2 -2
- package/dist/templates/minimal/pages/tag.tsx +6 -7
- package/package.json +1 -1
- package/dist/templates/_shared/components/i18n-provider.tsx +0 -15
- 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 -8
- package/dist/templates/_shared/lib/media.ts +0 -6
- package/dist/templates/_shared/lib/posts-provider.ts +0 -8
- 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/index.js
CHANGED
|
@@ -1747,16 +1747,7 @@ var AMPLESS_MANAGED_APP_PATHS = [
|
|
|
1747
1747
|
"app/login",
|
|
1748
1748
|
"app/site"
|
|
1749
1749
|
];
|
|
1750
|
-
var AMPLESS_RETIRED_PATHS = [
|
|
1751
|
-
// Retired alongside the in-deploy multi-site drop.
|
|
1752
|
-
"lib/admin-site.ts",
|
|
1753
|
-
"lib/admin-site-client.ts",
|
|
1754
|
-
// Split into app/raw/[slug]/route.ts + app/static/[slug]/[[...path]]/route.ts.
|
|
1755
|
-
// The old unified internal handler at app/r/[slug]/[[...path]]/route.ts
|
|
1756
|
-
// is no longer wired to anything (middleware rewrites to /raw or
|
|
1757
|
-
// /static now).
|
|
1758
|
-
"app/r/[slug]/[[...path]]/route.ts"
|
|
1759
|
-
];
|
|
1750
|
+
var AMPLESS_RETIRED_PATHS = [];
|
|
1760
1751
|
var AMPLESS_PACKAGES = /* @__PURE__ */ new Set([
|
|
1761
1752
|
"ampless",
|
|
1762
1753
|
"@ampless/admin",
|
|
@@ -43,22 +43,24 @@
|
|
|
43
43
|
レスポンシブの目視確認、Markdown 要素のデザイン方針、よくある失敗
|
|
44
44
|
— は [THEMES.ja.md](./THEMES.ja.md) を参照する。
|
|
45
45
|
|
|
46
|
-
## MCP
|
|
46
|
+
## MCP サーバー(HTTP トランスポート)
|
|
47
47
|
|
|
48
|
-
|
|
48
|
+
エージェントが `mcp-handler` Lambda 経由で投稿コンテンツを直接クエリ・編集できる。公開ツール: `list_posts`、`get_post`、`create_post`、`update_post`、`delete_post`、`upload_media`、`get_schema`、`upload_static_bundle`、`list_static_files`、`delete_static_file`、`get_site_context`。
|
|
49
49
|
|
|
50
50
|
登録方法:
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
1. 管理画面の `/admin/mcp-tokens` で Bearer トークンを発行する。
|
|
53
|
+
2. Amplify コンソールまたは `amplify_outputs.json` で `mcp-handler` の Function URL を確認する。
|
|
54
|
+
3. プロジェクトルートの `.mcp.json` に追加する:
|
|
55
|
+
|
|
53
56
|
```json
|
|
54
57
|
{
|
|
55
58
|
"mcpServers": {
|
|
56
59
|
"ampless": {
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"AMPLESS_MCP_PASSWORD": "<your-admin-password>"
|
|
60
|
+
"url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
|
|
61
|
+
"transport": "http",
|
|
62
|
+
"headers": {
|
|
63
|
+
"Authorization": "Bearer amk_..."
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
}
|
|
@@ -43,22 +43,24 @@ standard copy-and-edit flow, Claude Design handoff, AI-assisted
|
|
|
43
43
|
implementation, responsive visual QA, Markdown styling expectations,
|
|
44
44
|
and the common failure modes — see [THEMES.md](./THEMES.md).
|
|
45
45
|
|
|
46
|
-
## MCP server (
|
|
46
|
+
## MCP server (HTTP transport)
|
|
47
47
|
|
|
48
|
-
Lets agents query and modify post content directly. Tools exposed: `list_posts`, `get_post`, `create_post`, `update_post`, `delete_post`, `upload_media`, `get_schema`.
|
|
48
|
+
Lets agents query and modify post content directly via the `mcp-handler` Lambda. Tools exposed: `list_posts`, `get_post`, `create_post`, `update_post`, `delete_post`, `upload_media`, `get_schema`, `upload_static_bundle`, `list_static_files`, `delete_static_file`, `get_site_context`.
|
|
49
49
|
|
|
50
50
|
Registration:
|
|
51
51
|
|
|
52
|
-
|
|
52
|
+
1. Issue a Bearer token from `/admin/mcp-tokens` in the admin UI.
|
|
53
|
+
2. Find the `mcp-handler` Function URL in the Amplify console or `amplify_outputs.json`.
|
|
54
|
+
3. Add to `.mcp.json` at the project root:
|
|
55
|
+
|
|
53
56
|
```json
|
|
54
57
|
{
|
|
55
58
|
"mcpServers": {
|
|
56
59
|
"ampless": {
|
|
57
|
-
"
|
|
58
|
-
"
|
|
59
|
-
"
|
|
60
|
-
"
|
|
61
|
-
"AMPLESS_MCP_PASSWORD": "<your-admin-password>"
|
|
60
|
+
"url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
|
|
61
|
+
"transport": "http",
|
|
62
|
+
"headers": {
|
|
63
|
+
"Authorization": "Bearer amk_..."
|
|
62
64
|
}
|
|
63
65
|
}
|
|
64
66
|
}
|
|
@@ -190,9 +190,29 @@ Amplify Hosting アプリの **Domain management** からドメインをバイ
|
|
|
190
190
|
|
|
191
191
|
## AI 連携(MCP)
|
|
192
192
|
|
|
193
|
-
ampless は MCP(Model Context Protocol)サーバーを同梱しているので、Claude Desktop / Cursor / Claude Code など MCP に対応した AI クライアントから投稿の読み書きができます。
|
|
193
|
+
ampless は HTTP トランスポート + Bearer トークン認証による MCP(Model Context Protocol)サーバーを同梱しているので、Claude Desktop / Cursor / Claude Code など MCP に対応した AI クライアントから投稿の読み書きができます。
|
|
194
|
+
|
|
195
|
+
**セットアップ手順:**
|
|
196
|
+
|
|
197
|
+
1. 管理画面の `/admin/mcp-tokens` にアクセスし、Bearer トークン(`amk_...`)を発行する。
|
|
198
|
+
2. Amplify コンソールまたは `amplify_outputs.json` で `mcp-handler` Lambda の Function URL を確認する。
|
|
199
|
+
3. MCP クライアントの設定ファイル(プロジェクトルートの `.mcp.json`、`claude_desktop_config.json` など)にエントリを追加する:
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"mcpServers": {
|
|
204
|
+
"ampless": {
|
|
205
|
+
"url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
|
|
206
|
+
"transport": "http",
|
|
207
|
+
"headers": {
|
|
208
|
+
"Authorization": "Bearer amk_..."
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
194
214
|
|
|
195
|
-
|
|
215
|
+
MCP のセットアップとトークン管理の詳細については [docs/architecture/04-access-layer-mcp.md](./docs/architecture/04-access-layer-mcp.md) を参照してください。
|
|
196
216
|
|
|
197
217
|
## ampless の更新
|
|
198
218
|
|
|
@@ -190,9 +190,29 @@ Bind a domain to your Amplify Hosting app in **Domain management** — Amplify p
|
|
|
190
190
|
|
|
191
191
|
## AI integration (MCP)
|
|
192
192
|
|
|
193
|
-
ampless ships an MCP (Model Context Protocol) server so Claude Desktop / Cursor / Claude Code / anything that speaks MCP can read and write your posts.
|
|
193
|
+
ampless ships an MCP (Model Context Protocol) server so Claude Desktop / Cursor / Claude Code / anything that speaks MCP can read and write your posts via HTTP transport with Bearer token authentication.
|
|
194
|
+
|
|
195
|
+
**Setup:**
|
|
196
|
+
|
|
197
|
+
1. Go to `/admin/mcp-tokens` in your admin UI and issue a Bearer token (`amk_...`).
|
|
198
|
+
2. Find the `mcp-handler` Lambda Function URL in your Amplify console or `amplify_outputs.json`.
|
|
199
|
+
3. Add an entry to your MCP client's config (`.mcp.json` at the project root, `claude_desktop_config.json`, etc.):
|
|
200
|
+
|
|
201
|
+
```json
|
|
202
|
+
{
|
|
203
|
+
"mcpServers": {
|
|
204
|
+
"ampless": {
|
|
205
|
+
"url": "https://<function-url-id>.lambda-url.<region>.on.aws/",
|
|
206
|
+
"transport": "http",
|
|
207
|
+
"headers": {
|
|
208
|
+
"Authorization": "Bearer amk_..."
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
}
|
|
212
|
+
}
|
|
213
|
+
```
|
|
194
214
|
|
|
195
|
-
|
|
215
|
+
See [docs/architecture/04-access-layer-mcp.md](./docs/architecture/04-access-layer-mcp.md) for the full MCP setup and token management guide.
|
|
196
216
|
|
|
197
217
|
## Updating ampless
|
|
198
218
|
|
|
@@ -1,22 +1,22 @@
|
|
|
1
1
|
import type { Metadata } from 'next'
|
|
2
2
|
import { headers } from 'next/headers'
|
|
3
|
-
import { validateColorScheme } from '@ampless/runtime'
|
|
3
|
+
import { renderThemeCss, validateColorScheme } from '@ampless/runtime'
|
|
4
|
+
import { getDictionary } from '@ampless/admin'
|
|
5
|
+
import { I18nProvider } from '@ampless/admin/components'
|
|
6
|
+
import { ampless } from '@/lib/ampless'
|
|
7
|
+
import { admin } from '@/lib/admin'
|
|
4
8
|
import { Providers } from './providers'
|
|
5
|
-
import { siteMetadata } from '@/lib/seo'
|
|
6
|
-
import { loadThemeConfig, renderThemeCss } from '@/lib/theme-config'
|
|
7
|
-
import { getLocale, getDictionary } from '@/lib/i18n'
|
|
8
|
-
import { I18nProvider } from '@/components/i18n-provider'
|
|
9
9
|
import './globals.css'
|
|
10
10
|
|
|
11
11
|
export async function generateMetadata(): Promise<Metadata> {
|
|
12
|
-
return siteMetadata()
|
|
12
|
+
return ampless.siteMetadata()
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
export default async function RootLayout({ children }: { children: React.ReactNode }) {
|
|
16
16
|
const h = await headers()
|
|
17
|
-
const theme = await loadThemeConfig()
|
|
17
|
+
const theme = await ampless.loadThemeConfig()
|
|
18
18
|
const themeCss = renderThemeCss(theme.cssVars)
|
|
19
|
-
const locale =
|
|
19
|
+
const locale = admin.locale
|
|
20
20
|
const dict = getDictionary(locale)
|
|
21
21
|
// `data-color-scheme` pins the visitor to light or dark regardless
|
|
22
22
|
// of their system `prefers-color-scheme`. `'auto'` (the default)
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
import { parseLinkList, isTagListUrl } from 'ampless'
|
|
3
|
-
import {
|
|
3
|
+
import { ampless } from '@/lib/ampless'
|
|
4
4
|
|
|
5
5
|
interface Props {
|
|
6
6
|
links: string | undefined
|
|
@@ -27,7 +27,7 @@ export async function SiteSidebar({ links, className }: Props) {
|
|
|
27
27
|
items.map(async (item) => {
|
|
28
28
|
const tagRef = isTagListUrl(item.url)
|
|
29
29
|
if (!tagRef) return { type: 'link' as const, label: item.label, url: item.url }
|
|
30
|
-
const { items: posts } = await listPostsByTag(tagRef.tag, { limit: 50 })
|
|
30
|
+
const { items: posts } = await ampless.listPostsByTag(tagRef.tag, { limit: 50 })
|
|
31
31
|
return {
|
|
32
32
|
type: 'tagSection' as const,
|
|
33
33
|
label: item.label,
|
|
@@ -1,16 +1,14 @@
|
|
|
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
8
|
// NOTE: we pass `ampless` as a thunk (not the resolved instance) so we
|
|
11
9
|
// don't have a static `import './ampless'` at the top of this file.
|
|
12
10
|
// A static import would form the cycle
|
|
13
|
-
// `lib/admin.ts → lib/ampless.ts → themes-registry → themes → lib/
|
|
11
|
+
// `lib/admin.ts → lib/ampless.ts → themes-registry → themes → lib/admin.ts`
|
|
14
12
|
// and crash with a TDZ ReferenceError on `ampless` at module init.
|
|
15
13
|
// The thunk uses dynamic `import()` so `lib/ampless.ts` only loads on
|
|
16
14
|
// the first `loadSiteSettings` / `loadThemeConfig` call (request
|
|
@@ -28,5 +26,5 @@ export const admin = createAdmin({
|
|
|
28
26
|
})
|
|
29
27
|
|
|
30
28
|
// Convenience: the server-side translation helper. Client components
|
|
31
|
-
// should use `useT()` from
|
|
29
|
+
// should use `useT()` from `@ampless/admin/components` instead.
|
|
32
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
|
-
}
|
|
@@ -29,8 +29,8 @@
|
|
|
29
29
|
"@ampless/plugin-rss": "^0.2.0-alpha.15",
|
|
30
30
|
"@ampless/plugin-seo": "^0.2.0-alpha.15",
|
|
31
31
|
"@ampless/plugin-webhook": "^0.2.0-alpha.15",
|
|
32
|
-
"@ampless/admin": "^1.0.0-alpha.
|
|
33
|
-
"@ampless/backend": "^1.0.0-alpha.
|
|
32
|
+
"@ampless/admin": "^1.0.0-alpha.39",
|
|
33
|
+
"@ampless/backend": "^1.0.0-alpha.30",
|
|
34
34
|
"@ampless/runtime": "^1.0.0-alpha.21",
|
|
35
35
|
"@digital-go-jp/tailwind-theme-plugin": "^0.3.4",
|
|
36
36
|
"ampless": "^1.0.0-alpha.15",
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
4
|
request: Request
|
|
@@ -7,7 +7,7 @@ interface Ctx {
|
|
|
7
7
|
// /feed.xml proxy — plugin-rss regenerates the feed on content events
|
|
8
8
|
// and writes it to `public/plugins/rss/feed.xml`.
|
|
9
9
|
export async function blogFeedHandler(_ctx: Ctx): Promise<Response> {
|
|
10
|
-
const url = publicAssetUrl('public/plugins/rss/feed.xml')
|
|
10
|
+
const url = ampless.publicAssetUrl('public/plugins/rss/feed.xml')
|
|
11
11
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
12
12
|
if (!upstream.ok) {
|
|
13
13
|
return new Response(
|
|
@@ -1,26 +1,24 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
import { formatDate, parseLinkList, type ThemeRouteContext } from 'ampless'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { renderBody } from '@/lib/posts'
|
|
3
|
+
import { renderBody } from '@ampless/runtime'
|
|
4
|
+
import { ampless } from '@/lib/ampless'
|
|
5
|
+
import { admin } from '@/lib/admin'
|
|
7
6
|
import { TagList } from '@/components/tag-list'
|
|
8
7
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
9
8
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
10
|
-
import { t } from '@/lib/i18n'
|
|
11
9
|
|
|
12
10
|
export default async function BlogHome(_: ThemeRouteContext) {
|
|
13
11
|
const [settings, theme, postsResult] = await Promise.all([
|
|
14
|
-
loadSiteSettings(),
|
|
15
|
-
loadThemeConfig(),
|
|
16
|
-
listPublishedPosts(),
|
|
12
|
+
ampless.loadSiteSettings(),
|
|
13
|
+
ampless.loadThemeConfig(),
|
|
14
|
+
ampless.listPublishedPosts(),
|
|
17
15
|
])
|
|
18
16
|
|
|
19
17
|
// Featured (pinned) post: render the body inline above the list,
|
|
20
18
|
// then drop the same slug from the feed so it doesn't show twice.
|
|
21
19
|
// Missing / unpublished slugs return null and the section is skipped.
|
|
22
20
|
const featuredSlug = theme.values.featuredSlug?.trim()
|
|
23
|
-
const featured = featuredSlug ? await getPublishedPost(featuredSlug) : null
|
|
21
|
+
const featured = featuredSlug ? await ampless.getPublishedPost(featuredSlug) : null
|
|
24
22
|
const posts = featured
|
|
25
23
|
? postsResult.items.filter((p) => p.slug !== featured.slug)
|
|
26
24
|
: postsResult.items
|
|
@@ -69,7 +67,7 @@ export default async function BlogHome(_: ThemeRouteContext) {
|
|
|
69
67
|
)}
|
|
70
68
|
|
|
71
69
|
{posts.length === 0 ? (
|
|
72
|
-
!featured && <p className="text-gray-500">{t('public.noPosts')}</p>
|
|
70
|
+
!featured && <p className="text-gray-500">{admin.t('public.noPosts')}</p>
|
|
73
71
|
) : (
|
|
74
72
|
<ul className="space-y-8">
|
|
75
73
|
{posts.map((post) => (
|
|
@@ -2,32 +2,29 @@ import type { Metadata } from 'next'
|
|
|
2
2
|
import Link from 'next/link'
|
|
3
3
|
import { notFound } from 'next/navigation'
|
|
4
4
|
import { formatDate, parseLinkList, type ThemeRouteContext } from 'ampless'
|
|
5
|
-
import { renderBody } from '
|
|
5
|
+
import { renderBody } from '@ampless/runtime'
|
|
6
|
+
import { ampless } from '@/lib/ampless'
|
|
7
|
+
import { admin } from '@/lib/admin'
|
|
6
8
|
import { LightboxBinder } from '@/components/lightbox-content'
|
|
7
9
|
import { TagList } from '@/components/tag-list'
|
|
8
|
-
import { postMetadata } from '@/lib/seo'
|
|
9
|
-
import { loadSiteSettings } from '@/lib/site-settings'
|
|
10
|
-
import { loadThemeConfig } from '@/lib/theme-config'
|
|
11
|
-
import { getPublishedPost } from '@/lib/posts-public'
|
|
12
10
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
13
11
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
14
|
-
import { t } from '@/lib/i18n'
|
|
15
12
|
|
|
16
13
|
type PostCtx = ThemeRouteContext<{ slug: string }>
|
|
17
14
|
|
|
18
15
|
export async function generatePostMetadata({ params }: PostCtx): Promise<Metadata> {
|
|
19
16
|
const { slug } = await params
|
|
20
|
-
const post = await getPublishedPost(slug)
|
|
17
|
+
const post = await ampless.getPublishedPost(slug)
|
|
21
18
|
if (!post) return {}
|
|
22
|
-
return postMetadata(post)
|
|
19
|
+
return ampless.postMetadata(post)
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
export default async function BlogPost({ params }: PostCtx) {
|
|
26
23
|
const { slug } = await params
|
|
27
24
|
const [post, settings, theme] = await Promise.all([
|
|
28
|
-
getPublishedPost(slug),
|
|
29
|
-
loadSiteSettings(),
|
|
30
|
-
loadThemeConfig(),
|
|
25
|
+
ampless.getPublishedPost(slug),
|
|
26
|
+
ampless.loadSiteSettings(),
|
|
27
|
+
ampless.loadThemeConfig(),
|
|
31
28
|
])
|
|
32
29
|
if (!post) notFound()
|
|
33
30
|
|
|
@@ -53,7 +50,7 @@ export default async function BlogPost({ params }: PostCtx) {
|
|
|
53
50
|
|
|
54
51
|
<main className="mx-auto max-w-2xl px-6 py-12">
|
|
55
52
|
<nav className="mb-8">
|
|
56
|
-
<Link href="/" className="text-sm text-gray-500 hover:underline">{t('public.back')}</Link>
|
|
53
|
+
<Link href="/" className="text-sm text-gray-500 hover:underline">{admin.t('public.back')}</Link>
|
|
57
54
|
</nav>
|
|
58
55
|
|
|
59
56
|
<article>
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
4
|
request: Request
|
|
@@ -7,7 +7,7 @@ interface Ctx {
|
|
|
7
7
|
// /sitemap.xml proxy — plugin-seo regenerates the sitemap on every
|
|
8
8
|
// content event and writes it to `public/plugins/seo/sitemap.xml`.
|
|
9
9
|
export async function blogSitemapHandler(_ctx: Ctx): Promise<Response> {
|
|
10
|
-
const url = publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
10
|
+
const url = ampless.publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
11
11
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
12
12
|
if (!upstream.ok) {
|
|
13
13
|
return new Response(
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
import { notFound } from 'next/navigation'
|
|
3
3
|
import { formatDate, parseLinkList, type ThemeRouteContext } from 'ampless'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { loadThemeConfig } from '@/lib/theme-config'
|
|
4
|
+
import { ampless } from '@/lib/ampless'
|
|
5
|
+
import { admin } from '@/lib/admin'
|
|
7
6
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
8
7
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
9
|
-
import { t } from '@/lib/i18n'
|
|
10
8
|
|
|
11
9
|
export default async function BlogTag({ params }: ThemeRouteContext<{ tag: string }>) {
|
|
12
10
|
const { tag } = await params
|
|
13
11
|
const decodedTag = decodeURIComponent(tag)
|
|
14
12
|
const [{ items: posts }, settings, theme] = await Promise.all([
|
|
15
|
-
listPostsByTag(decodedTag, { limit: 50 }),
|
|
16
|
-
loadSiteSettings(),
|
|
17
|
-
loadThemeConfig(),
|
|
13
|
+
ampless.listPostsByTag(decodedTag, { limit: 50 }),
|
|
14
|
+
ampless.loadSiteSettings(),
|
|
15
|
+
ampless.loadThemeConfig(),
|
|
18
16
|
])
|
|
19
17
|
|
|
20
18
|
if (posts.length === 0) notFound()
|
|
@@ -36,11 +34,11 @@ export default async function BlogTag({ params }: ThemeRouteContext<{ tag: strin
|
|
|
36
34
|
|
|
37
35
|
<main className="mx-auto max-w-2xl px-6 py-12">
|
|
38
36
|
<nav className="mb-8">
|
|
39
|
-
<Link href="/" className="text-sm text-gray-500 hover:underline">{t('public.home')}</Link>
|
|
37
|
+
<Link href="/" className="text-sm text-gray-500 hover:underline">{admin.t('public.home')}</Link>
|
|
40
38
|
</nav>
|
|
41
39
|
|
|
42
40
|
<header className="mb-12 border-b pb-6">
|
|
43
|
-
<p className="text-sm text-gray-500">{t('public.tagLabel')}</p>
|
|
41
|
+
<p className="text-sm text-gray-500">{admin.t('public.tagLabel')}</p>
|
|
44
42
|
<h1 className="text-4xl font-bold tracking-tight">#{decodedTag}</h1>
|
|
45
43
|
</header>
|
|
46
44
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
4
|
request: Request
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export async function corporateFeedHandler(_ctx: Ctx): Promise<Response> {
|
|
8
|
-
const url = publicAssetUrl('public/plugins/rss/feed.xml')
|
|
8
|
+
const url = ampless.publicAssetUrl('public/plugins/rss/feed.xml')
|
|
9
9
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
10
10
|
if (!upstream.ok) {
|
|
11
11
|
return new Response(
|
|
@@ -1,23 +1,21 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
import { formatDate, type ThemeRouteContext } from 'ampless'
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
import { loadThemeConfig } from '@/lib/theme-config'
|
|
6
|
-
import { renderBody } from '@/lib/posts'
|
|
3
|
+
import { renderBody } from '@ampless/runtime'
|
|
4
|
+
import { ampless } from '@/lib/ampless'
|
|
7
5
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
8
6
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
9
7
|
|
|
10
8
|
export default async function CorporateHome(_: ThemeRouteContext) {
|
|
11
9
|
const [settings, theme, postsResult] = await Promise.all([
|
|
12
|
-
loadSiteSettings(),
|
|
13
|
-
loadThemeConfig(),
|
|
14
|
-
listPublishedPosts({ limit: 8 }),
|
|
10
|
+
ampless.loadSiteSettings(),
|
|
11
|
+
ampless.loadThemeConfig(),
|
|
12
|
+
ampless.listPublishedPosts({ limit: 8 }),
|
|
15
13
|
])
|
|
16
14
|
|
|
17
15
|
// Top-story embed between hero and news. Filtered out of news to
|
|
18
16
|
// avoid duplication. Skipped silently if missing / unpublished.
|
|
19
17
|
const featuredSlug = theme.values.featuredSlug?.trim()
|
|
20
|
-
const featured = featuredSlug ? await getPublishedPost(featuredSlug) : null
|
|
18
|
+
const featured = featuredSlug ? await ampless.getPublishedPost(featuredSlug) : null
|
|
21
19
|
const posts = featured
|
|
22
20
|
? postsResult.items.filter((p) => p.slug !== featured.slug)
|
|
23
21
|
: postsResult.items
|
|
@@ -2,32 +2,29 @@ import type { Metadata } from 'next'
|
|
|
2
2
|
import Link from 'next/link'
|
|
3
3
|
import { notFound } from 'next/navigation'
|
|
4
4
|
import { formatDate, type ThemeRouteContext } from 'ampless'
|
|
5
|
-
import { renderBody } from '
|
|
5
|
+
import { renderBody } from '@ampless/runtime'
|
|
6
|
+
import { ampless } from '@/lib/ampless'
|
|
7
|
+
import { admin } from '@/lib/admin'
|
|
6
8
|
import { LightboxBinder } from '@/components/lightbox-content'
|
|
7
9
|
import { TagList } from '@/components/tag-list'
|
|
8
|
-
import { postMetadata } from '@/lib/seo'
|
|
9
|
-
import { loadSiteSettings } from '@/lib/site-settings'
|
|
10
|
-
import { loadThemeConfig } from '@/lib/theme-config'
|
|
11
|
-
import { getPublishedPost } from '@/lib/posts-public'
|
|
12
10
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
13
11
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
14
|
-
import { t } from '@/lib/i18n'
|
|
15
12
|
|
|
16
13
|
type PostCtx = ThemeRouteContext<{ slug: string }>
|
|
17
14
|
|
|
18
15
|
export async function generatePostMetadata({ params }: PostCtx): Promise<Metadata> {
|
|
19
16
|
const { slug } = await params
|
|
20
|
-
const post = await getPublishedPost(slug)
|
|
17
|
+
const post = await ampless.getPublishedPost(slug)
|
|
21
18
|
if (!post) return {}
|
|
22
|
-
return postMetadata(post)
|
|
19
|
+
return ampless.postMetadata(post)
|
|
23
20
|
}
|
|
24
21
|
|
|
25
22
|
export default async function CorporatePost({ params }: PostCtx) {
|
|
26
23
|
const { slug } = await params
|
|
27
24
|
const [post, settings, theme] = await Promise.all([
|
|
28
|
-
getPublishedPost(slug),
|
|
29
|
-
loadSiteSettings(),
|
|
30
|
-
loadThemeConfig(),
|
|
25
|
+
ampless.getPublishedPost(slug),
|
|
26
|
+
ampless.loadSiteSettings(),
|
|
27
|
+
ampless.loadThemeConfig(),
|
|
31
28
|
])
|
|
32
29
|
if (!post) notFound()
|
|
33
30
|
|
|
@@ -50,7 +47,7 @@ export default async function CorporatePost({ params }: PostCtx) {
|
|
|
50
47
|
<main className="mx-auto max-w-3xl px-6 py-12">
|
|
51
48
|
<nav className="mb-6">
|
|
52
49
|
<Link href="/" className="text-sm text-[var(--muted-foreground)] hover:text-[var(--primary)]">
|
|
53
|
-
{t('public.back')}
|
|
50
|
+
{admin.t('public.back')}
|
|
54
51
|
</Link>
|
|
55
52
|
</nav>
|
|
56
53
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
4
|
request: Request
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export async function corporateSitemapHandler(_ctx: Ctx): Promise<Response> {
|
|
8
|
-
const url = publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
8
|
+
const url = ampless.publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
9
9
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
10
10
|
if (!upstream.ok) {
|
|
11
11
|
return new Response(
|
|
@@ -1,20 +1,18 @@
|
|
|
1
1
|
import Link from 'next/link'
|
|
2
2
|
import { notFound } from 'next/navigation'
|
|
3
3
|
import { formatDate, type ThemeRouteContext } from 'ampless'
|
|
4
|
-
import {
|
|
5
|
-
import {
|
|
6
|
-
import { loadThemeConfig } from '@/lib/theme-config'
|
|
4
|
+
import { ampless } from '@/lib/ampless'
|
|
5
|
+
import { admin } from '@/lib/admin'
|
|
7
6
|
import { SiteHeader } from '@/components/site-chrome/site-header'
|
|
8
7
|
import { SiteFooter } from '@/components/site-chrome/site-footer'
|
|
9
|
-
import { t } from '@/lib/i18n'
|
|
10
8
|
|
|
11
9
|
export default async function CorporateTag({ params }: ThemeRouteContext<{ tag: string }>) {
|
|
12
10
|
const { tag } = await params
|
|
13
11
|
const decodedTag = decodeURIComponent(tag)
|
|
14
12
|
const [{ items: posts }, settings, theme] = await Promise.all([
|
|
15
|
-
listPostsByTag(decodedTag, { limit: 50 }),
|
|
16
|
-
loadSiteSettings(),
|
|
17
|
-
loadThemeConfig(),
|
|
13
|
+
ampless.listPostsByTag(decodedTag, { limit: 50 }),
|
|
14
|
+
ampless.loadSiteSettings(),
|
|
15
|
+
ampless.loadThemeConfig(),
|
|
18
16
|
])
|
|
19
17
|
if (posts.length === 0) notFound()
|
|
20
18
|
|
|
@@ -32,12 +30,12 @@ export default async function CorporateTag({ params }: ThemeRouteContext<{ tag:
|
|
|
32
30
|
<main className="mx-auto max-w-4xl px-6 py-12">
|
|
33
31
|
<nav className="mb-6">
|
|
34
32
|
<Link href="/" className="text-sm text-[var(--muted-foreground)] hover:text-[var(--primary)]">
|
|
35
|
-
{t('public.home')}
|
|
33
|
+
{admin.t('public.home')}
|
|
36
34
|
</Link>
|
|
37
35
|
</nav>
|
|
38
36
|
|
|
39
37
|
<header className="mb-10">
|
|
40
|
-
<p className="text-sm text-[var(--muted-foreground)]">{t('public.tagLabel')}</p>
|
|
38
|
+
<p className="text-sm text-[var(--muted-foreground)]">{admin.t('public.tagLabel')}</p>
|
|
41
39
|
<h1 className="text-3xl font-bold tracking-tight">#{decodedTag}</h1>
|
|
42
40
|
</header>
|
|
43
41
|
|
|
@@ -1,11 +1,11 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { ampless } from '@/lib/ampless'
|
|
2
2
|
|
|
3
3
|
interface Ctx {
|
|
4
4
|
request: Request
|
|
5
5
|
}
|
|
6
6
|
|
|
7
7
|
export async function dadsFeedHandler(_ctx: Ctx): Promise<Response> {
|
|
8
|
-
const url = publicAssetUrl('public/plugins/rss/feed.xml')
|
|
8
|
+
const url = ampless.publicAssetUrl('public/plugins/rss/feed.xml')
|
|
9
9
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
10
10
|
if (!upstream.ok) {
|
|
11
11
|
return new Response(
|