create-ampless 0.2.0-alpha.8 → 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 +1282 -93
- 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.custom.ts +41 -0
- package/dist/templates/_shared/amplify/backend.ts +20 -2
- 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 +32 -0
- package/dist/templates/_shared/amplify/data/resource.ts +32 -15
- 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/handler.ts +4 -0
- package/dist/templates/_shared/amplify/functions/user-admin/resource.ts +13 -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/(admin)/admin/users/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 -40
- 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,29 +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
|
-
export default async function BlogHome(
|
|
13
|
-
const { siteId } = await params
|
|
10
|
+
export default async function BlogHome(_: ThemeRouteContext) {
|
|
14
11
|
const [settings, theme, postsResult] = await Promise.all([
|
|
15
|
-
loadSiteSettings(
|
|
16
|
-
loadThemeConfig(
|
|
17
|
-
listPublishedPosts(
|
|
12
|
+
ampless.loadSiteSettings(),
|
|
13
|
+
ampless.loadThemeConfig(),
|
|
14
|
+
ampless.listPublishedPosts(),
|
|
18
15
|
])
|
|
19
16
|
|
|
20
17
|
// Featured (pinned) post: render the body inline above the list,
|
|
21
18
|
// then drop the same slug from the feed so it doesn't show twice.
|
|
22
19
|
// Missing / unpublished slugs return null and the section is skipped.
|
|
23
20
|
const featuredSlug = theme.values.featuredSlug?.trim()
|
|
24
|
-
const featured = featuredSlug
|
|
25
|
-
? await getPublishedPost(featuredSlug, { siteId })
|
|
26
|
-
: null
|
|
21
|
+
const featured = featuredSlug ? await ampless.getPublishedPost(featuredSlug) : null
|
|
27
22
|
const posts = featured
|
|
28
23
|
? postsResult.items.filter((p) => p.slug !== featured.slug)
|
|
29
24
|
: postsResult.items
|
|
@@ -72,7 +67,7 @@ export default async function BlogHome({ params }: ThemeRouteContext) {
|
|
|
72
67
|
)}
|
|
73
68
|
|
|
74
69
|
{posts.length === 0 ? (
|
|
75
|
-
!featured && <p className="text-gray-500">{t('public.noPosts')}</p>
|
|
70
|
+
!featured && <p className="text-gray-500">{admin.t('public.noPosts')}</p>
|
|
76
71
|
) : (
|
|
77
72
|
<ul className="space-y-8">
|
|
78
73
|
{posts.map((post) => (
|
|
@@ -86,7 +81,7 @@ export default async function BlogHome({ params }: ThemeRouteContext) {
|
|
|
86
81
|
)}
|
|
87
82
|
{post.excerpt && <p className="mt-2 text-gray-700">{post.excerpt}</p>}
|
|
88
83
|
</Link>
|
|
89
|
-
<TagList tags={post.tags} className="mt-3" />
|
|
84
|
+
<TagList tags={post.tags} className="mt-3" max={3} />
|
|
90
85
|
</li>
|
|
91
86
|
))}
|
|
92
87
|
</ul>
|
|
@@ -2,35 +2,45 @@ 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
|
|
|
15
|
+
function buildPostUrl(siteUrl: string, slug: string) {
|
|
16
|
+
return new URL(`/${slug}`, siteUrl).toString()
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function buildXShareUrl(articleUrl: string, title: string, excerpt?: string | null) {
|
|
20
|
+
const text = [`"${title}"`, excerpt].filter(Boolean).join('\n\n')
|
|
21
|
+
const params = new URLSearchParams({ url: articleUrl, text })
|
|
22
|
+
return `https://x.com/intent/tweet?${params.toString()}`
|
|
23
|
+
}
|
|
24
|
+
|
|
18
25
|
export async function generatePostMetadata({ params }: PostCtx): Promise<Metadata> {
|
|
19
|
-
const {
|
|
20
|
-
const post = await getPublishedPost(slug
|
|
26
|
+
const { slug } = await params
|
|
27
|
+
const post = await ampless.getPublishedPost(slug)
|
|
21
28
|
if (!post) return {}
|
|
22
|
-
return postMetadata(post
|
|
29
|
+
return ampless.postMetadata(post)
|
|
23
30
|
}
|
|
24
31
|
|
|
25
32
|
export default async function BlogPost({ params }: PostCtx) {
|
|
26
|
-
const {
|
|
33
|
+
const { slug } = await params
|
|
27
34
|
const [post, settings, theme] = await Promise.all([
|
|
28
|
-
getPublishedPost(slug
|
|
29
|
-
loadSiteSettings(
|
|
30
|
-
loadThemeConfig(
|
|
35
|
+
ampless.getPublishedPost(slug),
|
|
36
|
+
ampless.loadSiteSettings(),
|
|
37
|
+
ampless.loadThemeConfig(),
|
|
31
38
|
])
|
|
32
39
|
if (!post) notFound()
|
|
33
40
|
|
|
41
|
+
const postBody = await ampless.publicBodyForPost(post)
|
|
42
|
+
const html = await ampless.publicHtmlForPost(post)
|
|
43
|
+
|
|
34
44
|
const defaultLightbox = settings.media.imageDisplay === 'lightbox'
|
|
35
45
|
const maxWidth = settings.media.imageMaxWidth ?? '100%'
|
|
36
46
|
const proseStyle: React.CSSProperties = {
|
|
@@ -39,6 +49,8 @@ export default async function BlogPost({ params }: PostCtx) {
|
|
|
39
49
|
const showHeader =
|
|
40
50
|
parseLinkList(theme.values.headerNav).length > 0 || !!theme.values.logoUrl?.trim()
|
|
41
51
|
const showFooter = parseLinkList(theme.values.footerLinks).length > 0
|
|
52
|
+
const articleUrl = buildPostUrl(settings.site.url, post.slug)
|
|
53
|
+
const xShareUrl = buildXShareUrl(articleUrl, post.title, post.excerpt)
|
|
42
54
|
|
|
43
55
|
return (
|
|
44
56
|
<>
|
|
@@ -53,7 +65,7 @@ export default async function BlogPost({ params }: PostCtx) {
|
|
|
53
65
|
|
|
54
66
|
<main className="mx-auto max-w-2xl px-6 py-12">
|
|
55
67
|
<nav className="mb-8">
|
|
56
|
-
<Link href="/" className="text-sm text-gray-500 hover:underline">{t('public.back')}</Link>
|
|
68
|
+
<Link href="/" className="text-sm text-gray-500 hover:underline">{admin.t('public.back')}</Link>
|
|
57
69
|
</nav>
|
|
58
70
|
|
|
59
71
|
<article>
|
|
@@ -66,6 +78,10 @@ export default async function BlogPost({ params }: PostCtx) {
|
|
|
66
78
|
)}
|
|
67
79
|
</header>
|
|
68
80
|
|
|
81
|
+
{postBody}
|
|
82
|
+
|
|
83
|
+
{html.beforeContent}
|
|
84
|
+
|
|
69
85
|
<div
|
|
70
86
|
id="post-body"
|
|
71
87
|
className="prose prose-neutral dark:prose-invert max-w-none [&_img]:max-w-[var(--ampless-img-max-width)] [&_img]:mx-auto"
|
|
@@ -73,7 +89,19 @@ export default async function BlogPost({ params }: PostCtx) {
|
|
|
73
89
|
dangerouslySetInnerHTML={{ __html: renderBody(post) }}
|
|
74
90
|
/>
|
|
75
91
|
|
|
92
|
+
{html.afterContent}
|
|
93
|
+
|
|
76
94
|
<TagList tags={post.tags} className="mt-8 border-t pt-6" />
|
|
95
|
+
|
|
96
|
+
<footer className="mt-6 flex flex-wrap items-center gap-x-6 gap-y-2 text-sm text-gray-500">
|
|
97
|
+
<a href={articleUrl} className="hover:text-foreground hover:underline">{admin.t('public.permalink')}</a>
|
|
98
|
+
<a href={xShareUrl} target="_blank" rel="noopener noreferrer" className="inline-flex items-center gap-1.5 hover:text-foreground hover:underline">
|
|
99
|
+
<svg aria-hidden="true" viewBox="0 0 24 24" className="h-3.5 w-3.5" fill="currentColor">
|
|
100
|
+
<path d="M13.8 10.4 21 2h-1.7l-6.2 7.3L8.1 2H2.3l7.6 11.1L2.3 22h1.7l6.7-7.8 5.4 7.8h5.8l-8.1-11.6Zm-2.4 2.8-.8-1.1L4.5 3.3h2.8l4.9 7.1.8 1.1 6.4 9.2h-2.8l-5.2-7.5Z" />
|
|
101
|
+
</svg>
|
|
102
|
+
{admin.t('public.shareOnX')}
|
|
103
|
+
</a>
|
|
104
|
+
</footer>
|
|
77
105
|
</article>
|
|
78
106
|
|
|
79
107
|
<LightboxBinder scopeSelector="#post-body" defaultLightbox={defaultLightbox} />
|
|
@@ -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
|
// /sitemap.xml proxy — plugin-seo regenerates the sitemap on every
|
|
9
|
-
// content event and writes it to `public/plugins/seo/
|
|
10
|
-
export async function blogSitemapHandler(
|
|
11
|
-
const url = publicAssetUrl(
|
|
8
|
+
// content event and writes it to `public/plugins/seo/sitemap.xml`.
|
|
9
|
+
export async function blogSitemapHandler(_ctx: Ctx): Promise<Response> {
|
|
10
|
+
const url = ampless.publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
12
11
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
13
12
|
if (!upstream.ok) {
|
|
14
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
|
-
const {
|
|
10
|
+
const { tag } = await params
|
|
13
11
|
const decodedTag = decodeURIComponent(tag)
|
|
14
12
|
const [{ items: posts }, settings, theme] = await Promise.all([
|
|
15
|
-
listPostsByTag(decodedTag, {
|
|
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
|
|
|
@@ -7,48 +7,34 @@
|
|
|
7
7
|
* loads, so `:root` selectors trump scoped attribute selectors of
|
|
8
8
|
* equal specificity. The dispatcher emits `--primary` etc. only for
|
|
9
9
|
* fields that have an override, leaving everything else to fall back
|
|
10
|
-
* to these defaults.
|
|
10
|
+
* to these defaults.
|
|
11
|
+
*
|
|
12
|
+
* Dark mode: tokens are declared with the CSS `light-dark(L, D)`
|
|
13
|
+
* function. The active `color-scheme` (set on `:root` and optionally
|
|
14
|
+
* pinned per-site via `html[data-color-scheme]`) selects whether L or
|
|
15
|
+
* D is rendered. `globals.css` opts the document into `color-scheme:
|
|
16
|
+
* light dark` by default — visitors with `prefers-color-scheme: dark`
|
|
17
|
+
* see the dark palette automatically.
|
|
18
|
+
*/
|
|
11
19
|
|
|
12
20
|
[data-theme='blog'] {
|
|
13
|
-
--background: oklch(1 0 0);
|
|
14
|
-
--foreground: oklch(0.145 0 0);
|
|
15
|
-
--card: oklch(1 0 0);
|
|
16
|
-
--card-foreground: oklch(0.145 0 0);
|
|
17
|
-
--primary: oklch(0.205 0 0);
|
|
18
|
-
--primary-foreground: oklch(0.985 0 0);
|
|
19
|
-
--secondary: oklch(0.97 0 0);
|
|
20
|
-
--secondary-foreground: oklch(0.205 0 0);
|
|
21
|
-
--muted: oklch(0.97 0 0);
|
|
22
|
-
--muted-foreground: oklch(0.556 0 0);
|
|
23
|
-
--accent: oklch(0.97 0 0);
|
|
24
|
-
--accent-foreground: oklch(0.205 0 0);
|
|
25
|
-
--destructive: oklch(0.577 0.245 27.325);
|
|
26
|
-
--destructive-foreground: oklch(0.985 0 0);
|
|
27
|
-
--border: oklch(0.922 0 0);
|
|
28
|
-
--input: oklch(0.922 0 0);
|
|
29
|
-
--ring: oklch(0.708 0 0);
|
|
21
|
+
--background: light-dark(oklch(1 0 0), oklch(0.145 0 0));
|
|
22
|
+
--foreground: light-dark(oklch(0.145 0 0), oklch(0.985 0 0));
|
|
23
|
+
--card: light-dark(oklch(1 0 0), oklch(0.145 0 0));
|
|
24
|
+
--card-foreground: light-dark(oklch(0.145 0 0), oklch(0.985 0 0));
|
|
25
|
+
--primary: light-dark(oklch(0.205 0 0), oklch(0.985 0 0));
|
|
26
|
+
--primary-foreground: light-dark(oklch(0.985 0 0), oklch(0.205 0 0));
|
|
27
|
+
--secondary: light-dark(oklch(0.97 0 0), oklch(0.269 0 0));
|
|
28
|
+
--secondary-foreground: light-dark(oklch(0.205 0 0), oklch(0.985 0 0));
|
|
29
|
+
--muted: light-dark(oklch(0.97 0 0), oklch(0.269 0 0));
|
|
30
|
+
--muted-foreground: light-dark(oklch(0.556 0 0), oklch(0.708 0 0));
|
|
31
|
+
--accent: light-dark(oklch(0.97 0 0), oklch(0.269 0 0));
|
|
32
|
+
--accent-foreground: light-dark(oklch(0.205 0 0), oklch(0.985 0 0));
|
|
33
|
+
--destructive: light-dark(oklch(0.577 0.245 27.325), oklch(0.396 0.141 25.723));
|
|
34
|
+
--destructive-foreground: light-dark(oklch(0.985 0 0), oklch(0.985 0 0));
|
|
35
|
+
--border: light-dark(oklch(0.922 0 0), oklch(0.269 0 0));
|
|
36
|
+
--input: light-dark(oklch(0.922 0 0), oklch(0.269 0 0));
|
|
37
|
+
--ring: light-dark(oklch(0.708 0 0), oklch(0.439 0 0));
|
|
30
38
|
--radius: 0.5rem;
|
|
31
39
|
--ampless-body-font: system-ui, -apple-system, sans-serif;
|
|
32
40
|
}
|
|
33
|
-
|
|
34
|
-
@media (prefers-color-scheme: dark) {
|
|
35
|
-
[data-theme='blog'] {
|
|
36
|
-
--background: oklch(0.145 0 0);
|
|
37
|
-
--foreground: oklch(0.985 0 0);
|
|
38
|
-
--card: oklch(0.145 0 0);
|
|
39
|
-
--card-foreground: oklch(0.985 0 0);
|
|
40
|
-
--primary: oklch(0.985 0 0);
|
|
41
|
-
--primary-foreground: oklch(0.205 0 0);
|
|
42
|
-
--secondary: oklch(0.269 0 0);
|
|
43
|
-
--secondary-foreground: oklch(0.985 0 0);
|
|
44
|
-
--muted: oklch(0.269 0 0);
|
|
45
|
-
--muted-foreground: oklch(0.708 0 0);
|
|
46
|
-
--accent: oklch(0.269 0 0);
|
|
47
|
-
--accent-foreground: oklch(0.985 0 0);
|
|
48
|
-
--destructive: oklch(0.396 0.141 25.723);
|
|
49
|
-
--destructive-foreground: oklch(0.985 0 0);
|
|
50
|
-
--border: oklch(0.269 0 0);
|
|
51
|
-
--input: oklch(0.269 0 0);
|
|
52
|
-
--ring: oklch(0.439 0 0);
|
|
53
|
-
}
|
|
54
|
-
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
> English: [README.md](./README.md)
|
|
2
|
+
>
|
|
3
|
+
# Corporate テーマ
|
|
4
|
+
|
|
5
|
+
企業サイト向けの落ち着いたレイアウト。明るい背景にネイビーの配色、ヒーロー + お知らせ一覧構成、ヘッダー / フッターナビ付き。
|
|
6
|
+
|
|
7
|
+
## カスタマイズ
|
|
8
|
+
|
|
9
|
+
`/admin/sites/<siteId>/theme` で設定:
|
|
10
|
+
|
|
11
|
+
- **タグライン** — ヒーロー内、サイト名の上に表示される短いフレーズ
|
|
12
|
+
- **プライマリカラー**
|
|
13
|
+
- **角丸**
|
|
14
|
+
- **トップストーリーのスラッグ** — ヒーローとお知らせ一覧の間に公開済み投稿を 1 件フィーチャー
|
|
15
|
+
- **ロゴ画像 URL**
|
|
16
|
+
- **ヘッダーナビ** — ラベル + URL のペア
|
|
17
|
+
- **フッターリンク** — ラベル + URL のペア
|
|
18
|
+
- **フッター注記** — 住所 / 会社情報 / 追加の注意書き
|
|
@@ -1,20 +1,18 @@
|
|
|
1
|
-
|
|
1
|
+
> 日本語版: [README.ja.md](./README.ja.md)
|
|
2
|
+
>
|
|
3
|
+
# Corporate theme
|
|
2
4
|
|
|
3
|
-
|
|
5
|
+
Conservative business / company-site layout with hero and news section. Navy on near-white, header + footer navigation.
|
|
4
6
|
|
|
5
7
|
## Customizing
|
|
6
8
|
|
|
7
9
|
In `/admin/sites/<siteId>/theme`:
|
|
8
10
|
|
|
9
|
-
- Tagline
|
|
10
|
-
-
|
|
11
|
-
-
|
|
12
|
-
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
npm install
|
|
18
|
-
npx ampx sandbox
|
|
19
|
-
npm run dev
|
|
20
|
-
```
|
|
11
|
+
- **Tagline** — short phrase shown above the site name in the hero
|
|
12
|
+
- **Primary color**
|
|
13
|
+
- **Corner radius**
|
|
14
|
+
- **Top story slug** — feature one published post between the hero and the news section
|
|
15
|
+
- **Logo image URL**
|
|
16
|
+
- **Header navigation** — label + URL pairs
|
|
17
|
+
- **Footer links** — label + URL pairs
|
|
18
|
+
- **Footer legend** — address / company info / extra small print
|
|
@@ -1,12 +1,11 @@
|
|
|
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
|
-
export async function corporateFeedHandler(
|
|
9
|
-
const url = publicAssetUrl(
|
|
7
|
+
export async function corporateFeedHandler(_ctx: Ctx): Promise<Response> {
|
|
8
|
+
const url = ampless.publicAssetUrl('public/plugins/rss/feed.xml')
|
|
10
9
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
11
10
|
if (!upstream.ok) {
|
|
12
11
|
return new Response(
|
|
@@ -1,26 +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
|
-
export default async function CorporateHome(
|
|
11
|
-
const { siteId } = await params
|
|
8
|
+
export default async function CorporateHome(_: ThemeRouteContext) {
|
|
12
9
|
const [settings, theme, postsResult] = await Promise.all([
|
|
13
|
-
loadSiteSettings(
|
|
14
|
-
loadThemeConfig(
|
|
15
|
-
listPublishedPosts({
|
|
10
|
+
ampless.loadSiteSettings(),
|
|
11
|
+
ampless.loadThemeConfig(),
|
|
12
|
+
ampless.listPublishedPosts({ limit: 8 }),
|
|
16
13
|
])
|
|
17
14
|
|
|
18
15
|
// Top-story embed between hero and news. Filtered out of news to
|
|
19
16
|
// avoid duplication. Skipped silently if missing / unpublished.
|
|
20
17
|
const featuredSlug = theme.values.featuredSlug?.trim()
|
|
21
|
-
const featured = featuredSlug
|
|
22
|
-
? await getPublishedPost(featuredSlug, { siteId })
|
|
23
|
-
: null
|
|
18
|
+
const featured = featuredSlug ? await ampless.getPublishedPost(featuredSlug) : null
|
|
24
19
|
const posts = featured
|
|
25
20
|
? postsResult.items.filter((p) => p.slug !== featured.slug)
|
|
26
21
|
: postsResult.items
|
|
@@ -2,35 +2,35 @@ 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
|
-
const {
|
|
20
|
-
const post = await getPublishedPost(slug
|
|
16
|
+
const { slug } = await params
|
|
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
|
-
const {
|
|
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
|
|
|
31
|
+
const postBody = await ampless.publicBodyForPost(post)
|
|
32
|
+
const html = await ampless.publicHtmlForPost(post)
|
|
33
|
+
|
|
34
34
|
const defaultLightbox = settings.media.imageDisplay === 'lightbox'
|
|
35
35
|
const maxWidth = settings.media.imageMaxWidth ?? '100%'
|
|
36
36
|
const proseStyle: React.CSSProperties = {
|
|
@@ -50,7 +50,7 @@ export default async function CorporatePost({ params }: PostCtx) {
|
|
|
50
50
|
<main className="mx-auto max-w-3xl px-6 py-12">
|
|
51
51
|
<nav className="mb-6">
|
|
52
52
|
<Link href="/" className="text-sm text-[var(--muted-foreground)] hover:text-[var(--primary)]">
|
|
53
|
-
{t('public.back')}
|
|
53
|
+
{admin.t('public.back')}
|
|
54
54
|
</Link>
|
|
55
55
|
</nav>
|
|
56
56
|
|
|
@@ -67,6 +67,10 @@ export default async function CorporatePost({ params }: PostCtx) {
|
|
|
67
67
|
)}
|
|
68
68
|
</header>
|
|
69
69
|
|
|
70
|
+
{postBody}
|
|
71
|
+
|
|
72
|
+
{html.beforeContent}
|
|
73
|
+
|
|
70
74
|
<div
|
|
71
75
|
id="post-body"
|
|
72
76
|
className="prose prose-neutral dark:prose-invert max-w-none [&_img]:max-w-[var(--ampless-img-max-width)] [&_img]:mx-auto"
|
|
@@ -74,6 +78,8 @@ export default async function CorporatePost({ params }: PostCtx) {
|
|
|
74
78
|
dangerouslySetInnerHTML={{ __html: renderBody(post) }}
|
|
75
79
|
/>
|
|
76
80
|
|
|
81
|
+
{html.afterContent}
|
|
82
|
+
|
|
77
83
|
<TagList tags={post.tags} className="mt-8 border-t pt-6" />
|
|
78
84
|
</article>
|
|
79
85
|
|
|
@@ -1,12 +1,11 @@
|
|
|
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
|
-
export async function corporateSitemapHandler(
|
|
9
|
-
const url = publicAssetUrl(
|
|
7
|
+
export async function corporateSitemapHandler(_ctx: Ctx): Promise<Response> {
|
|
8
|
+
const url = ampless.publicAssetUrl('public/plugins/seo/sitemap.xml')
|
|
10
9
|
const upstream = await fetch(url, { cache: 'no-store' })
|
|
11
10
|
if (!upstream.ok) {
|
|
12
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
|
-
const {
|
|
10
|
+
const { tag } = await params
|
|
13
11
|
const decodedTag = decodeURIComponent(tag)
|
|
14
12
|
const [{ items: posts }, settings, theme] = await Promise.all([
|
|
15
|
-
listPostsByTag(decodedTag, {
|
|
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
|
|
|
@@ -3,45 +3,23 @@
|
|
|
3
3
|
* selector pattern as the other themes. */
|
|
4
4
|
|
|
5
5
|
[data-theme='corporate'] {
|
|
6
|
-
--background: oklch(0.99 0 0);
|
|
7
|
-
--foreground: oklch(0.18 0.02 250);
|
|
8
|
-
--card: oklch(1 0 0);
|
|
9
|
-
--card-foreground: oklch(0.18 0.02 250);
|
|
10
|
-
--primary: oklch(0.4 0.13 250);
|
|
11
|
-
--primary-foreground: oklch(0.99 0 0);
|
|
12
|
-
--secondary: oklch(0.95 0.01 250);
|
|
13
|
-
--secondary-foreground: oklch(0.25 0.05 250);
|
|
14
|
-
--muted: oklch(0.96 0.005 250);
|
|
15
|
-
--muted-foreground: oklch(0.5 0.02 250);
|
|
16
|
-
--accent: oklch(0.95 0.02 250);
|
|
17
|
-
--accent-foreground: oklch(0.3 0.08 250);
|
|
18
|
-
--destructive: oklch(0.55 0.22 25);
|
|
19
|
-
--destructive-foreground: oklch(0.99 0 0);
|
|
20
|
-
--border: oklch(0.9 0.005 250);
|
|
21
|
-
--input: oklch(0.9 0.005 250);
|
|
22
|
-
--ring: oklch(0.4 0.13 250);
|
|
6
|
+
--background: light-dark(oklch(0.99 0 0), oklch(0.16 0.02 250));
|
|
7
|
+
--foreground: light-dark(oklch(0.18 0.02 250), oklch(0.96 0.005 250));
|
|
8
|
+
--card: light-dark(oklch(1 0 0), oklch(0.22 0.02 250));
|
|
9
|
+
--card-foreground: light-dark(oklch(0.18 0.02 250), oklch(0.96 0.005 250));
|
|
10
|
+
--primary: light-dark(oklch(0.4 0.13 250), oklch(0.7 0.14 250));
|
|
11
|
+
--primary-foreground: light-dark(oklch(0.99 0 0), oklch(0.16 0.02 250));
|
|
12
|
+
--secondary: light-dark(oklch(0.95 0.01 250), oklch(0.28 0.03 250));
|
|
13
|
+
--secondary-foreground: light-dark(oklch(0.25 0.05 250), oklch(0.96 0.005 250));
|
|
14
|
+
--muted: light-dark(oklch(0.96 0.005 250), oklch(0.26 0.02 250));
|
|
15
|
+
--muted-foreground: light-dark(oklch(0.5 0.02 250), oklch(0.7 0.02 250));
|
|
16
|
+
--accent: light-dark(oklch(0.95 0.02 250), oklch(0.32 0.05 250));
|
|
17
|
+
--accent-foreground: light-dark(oklch(0.3 0.08 250), oklch(0.96 0.005 250));
|
|
18
|
+
--destructive: light-dark(oklch(0.55 0.22 25), oklch(0.55 0.22 25));
|
|
19
|
+
--destructive-foreground: light-dark(oklch(0.99 0 0), oklch(0.99 0 0));
|
|
20
|
+
--border: light-dark(oklch(0.9 0.005 250), oklch(0.32 0.02 250));
|
|
21
|
+
--input: light-dark(oklch(0.9 0.005 250), oklch(0.32 0.02 250));
|
|
22
|
+
--ring: light-dark(oklch(0.4 0.13 250), oklch(0.7 0.14 250));
|
|
23
23
|
--radius: 0.25rem;
|
|
24
24
|
--ampless-body-font: system-ui, -apple-system, sans-serif;
|
|
25
25
|
}
|
|
26
|
-
|
|
27
|
-
@media (prefers-color-scheme: dark) {
|
|
28
|
-
[data-theme='corporate'] {
|
|
29
|
-
--background: oklch(0.16 0.02 250);
|
|
30
|
-
--foreground: oklch(0.96 0.005 250);
|
|
31
|
-
--card: oklch(0.22 0.02 250);
|
|
32
|
-
--card-foreground: oklch(0.96 0.005 250);
|
|
33
|
-
--primary: oklch(0.7 0.14 250);
|
|
34
|
-
--primary-foreground: oklch(0.16 0.02 250);
|
|
35
|
-
--secondary: oklch(0.28 0.03 250);
|
|
36
|
-
--secondary-foreground: oklch(0.96 0.005 250);
|
|
37
|
-
--muted: oklch(0.26 0.02 250);
|
|
38
|
-
--muted-foreground: oklch(0.7 0.02 250);
|
|
39
|
-
--accent: oklch(0.32 0.05 250);
|
|
40
|
-
--accent-foreground: oklch(0.96 0.005 250);
|
|
41
|
-
--destructive: oklch(0.55 0.22 25);
|
|
42
|
-
--destructive-foreground: oklch(0.99 0 0);
|
|
43
|
-
--border: oklch(0.32 0.02 250);
|
|
44
|
-
--input: oklch(0.32 0.02 250);
|
|
45
|
-
--ring: oklch(0.7 0.14 250);
|
|
46
|
-
}
|
|
47
|
-
}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
> English: [README.md](./README.md)
|
|
2
|
+
>
|
|
3
|
+
# DADS テーマ
|
|
4
|
+
|
|
5
|
+
デジタル庁デザインシステム準拠のレイアウト。政府・自治体・公共系サイト向け。高コントラスト、アクセシビリティ重視、装飾控えめ。公式の **[デジタル庁デザインシステム Tailwind プラグイン](https://github.com/digital-go-jp/tailwind-theme-plugin)**(`@digital-go-jp/tailwind-theme-plugin`、MIT)をベースに構築されています。
|
|
6
|
+
|
|
7
|
+
## プラグインが提供する機能
|
|
8
|
+
|
|
9
|
+
- **カラーパレット** — プライマリカラーに `solidBlue`(`#0017c1`)を使用し、DADS の全スケール(ライトブルー、シアン、グリーン、ライム、イエロー、オレンジ、レッド、マゼンタ)を Tailwind クラス(`bg-blue-900`、`text-blue-50` など)で利用可能
|
|
10
|
+
- **タイポグラフィ** — プラグイン経由で `fontFamily.sans` に Noto Sans JP を設定。`--ampless-body-font` として参照可能
|
|
11
|
+
- **ボーダー半径** — `rounded-4` / `rounded-6` が利用可能
|
|
12
|
+
|
|
13
|
+
`tokens.css` がプラグインの CSS 変数(`--color-blue-900` など)を ampless 標準のテーマ変数(`--primary`、`--background` など)にバインドするため、共有 chrome(SiteHeader、SiteFooter、shadcn ボタンなど)が自動的に DADS カラーで描画されます。
|
|
14
|
+
|
|
15
|
+
DADS が新しいパレットバージョンを公開した場合、`@digital-go-jp/tailwind-theme-plugin` をバージョンアップするだけでテーマに反映されます。
|
|
16
|
+
|
|
17
|
+
## カスタマイズ
|
|
18
|
+
|
|
19
|
+
`/admin/sites/<siteId>/theme` で設定:
|
|
20
|
+
|
|
21
|
+
- **ロゴ画像 URL** — 組織マーク
|
|
22
|
+
- **プライマリカラー** — デフォルトは DADS の `solidBlue`。DADS 以外の色に変更するとサイトは DADS 準拠ではなくなります。
|
|
23
|
+
- **トップストーリーのスラッグ** — ヒーローとお知らせ一覧の間に公開済み投稿を 1 件フィーチャー
|
|
24
|
+
- **ヘッダーナビ** — ラベル + URL のペア
|
|
25
|
+
- **フッターリンク** — ラベル + URL のペア
|
|
26
|
+
- **フッター注記** — 住所 / 機関情報 / 追加の注意書き
|
|
27
|
+
|
|
28
|
+
## 注意事項
|
|
29
|
+
|
|
30
|
+
- ダークモードは反転色による近似実装です。プラグイン 0.3.4 時点では DADS の公式ダークパレットは存在しません。公式ダークパレットが公開された際は、`tokens.css` のダーク変数バインディングを更新してください。
|
|
31
|
+
- このプラグインはデザイントークンのみを提供します。フル DADS コンポーネント(ボタン、アラート、タブなど)については [design-system-example-components](https://github.com/digital-go-jp/design-system-example-components) を参照し、必要に応じて取り込んでください。
|