Starter frontend Next.js App Router dengan sumber konten dari Cockpit CMS, termasuk dukungan Cockpit Pro (Pages, Detektivo, Personi) dan render layout dinamis.
- Integrasi Cockpit API client dan query helper untuk konten, menu, post, page, dan settings.
- Routing locale berbasis path
/{locale}(default:id,en). - Blog listing dan detail post.
- Dynamic page route
/{locale}/[...slug]. - Draft mode dan disable draft mode endpoint.
- Cockpit Pro integration:
- Pages API (
/pages/*) untuk menu, route, dan page. - Detektivo search proxy endpoint (
/api/detektivo/{index}). - Personi helper untuk audience-based variant resolution.
- Pages API (
- Dynamic layout rendering dari field layout/content/body page Cockpit.
Buat file .env.local:
COCKPIT_API_URL=https://your-cockpit-domain/api
COCKPIT_API_KEY=your-public-read-key
# Optional, dipakai saat Draft Mode
COCKPIT_PREVIEW_API_KEY=your-preview-read-key
COCKPIT_PREVIEW_SECRET=your-preview-secret
# Optional, custom locale
COCKPIT_LOCALES=id,en
COCKPIT_DEFAULT_LOCALE=id
# Optional, locale behavior for Cockpit API
# true -> kirim locale mengikuti route aktif (dengan mapping jika ada)
# false -> pakai 1 locale API tetap (lihat COCKPIT_DEFAULT_API_LOCALE)
COCKPIT_MULTI_LANGUAGE_ENABLED=true
COCKPIT_DEFAULT_API_LOCALE=id_ID
# Format: appLocale:cockpitLocale, dipisah koma
COCKPIT_LOCALE_MAP=id:id_ID,en:en_US
# Optional, override nama model Cockpit (fallback mode non-Pro)
COCKPIT_MODEL_POSTS=posts
COCKPIT_MODEL_PAGES=pages
COCKPIT_MODEL_SITE_SETTINGS=site_settings
COCKPIT_MODEL_MENUS=menus
# Cockpit Pro switches
COCKPIT_PRO_PAGES_ENABLED=true
COCKPIT_PRO_PAGES_DEFAULT_MENU=main
COCKPIT_PRO_DETEKTIVO_ENABLED=true
COCKPIT_PRO_PERSONI_ENABLED=trueCatatan:
- Jika flag Pro dimatikan, aplikasi fallback ke model collection/tree standard.
- Jika flag Pro diaktifkan, query menu/page akan otomatis memakai endpoint Pro.
npm install
npm run devBuka http://localhost:3000.
- Singleton
site_settingsuntuk data global situs. - Collection
postsuntuk blog. - Collection
pagesuntuk halaman. - Tree
menusuntuk navigasi.
- Pages addon menjadi sumber menu, route, dan page.
- Dynamic route dan homepage akan membaca payload page dari endpoint
/pages/page.
Renderer layout ada di components/layout-renderer.jsx dan dipakai pada:
app/[locale]/[...slug]/page.jsapp/[locale]/page.js
Prioritas field yang dirender:
page.layout(array)page.content(array)page.body(array)- fallback ke HTML string
content/body
Komponen layout yang sudah didukung:
headingrichtexthtmlmarkdownimagelinkbuttonsection(nested children)grid(nested columns)spacerhero
Gunakan tabel ini saat membuat blok layout di Cockpit Admin.
| Component | Field utama yang dibaca | Catatan |
|---|---|---|
heading |
data.text, data.level |
level default ke 2 jika kosong. |
richtext |
data.html atau data.content |
Dirender sebagai HTML. |
html |
data.html |
HTML mentah. Pastikan konten aman. |
markdown |
data.markdown atau data.content |
Dirender dengan parser markdown sederhana. |
image |
data.src, data.alt, data.caption |
src bisa absolute URL atau asset URL Cockpit. |
link |
data.href, data.label, data.target |
label fallback ke href. |
button |
data.href, data.label, data.variant |
variant opsional untuk styling. |
section |
components[] atau data.components[] |
Bisa nested blok lain. |
grid |
columns[].components[], data.colWidth |
Cocok untuk layout 2-3 kolom. |
spacer |
data.size atau data.height |
Untuk jarak vertikal antarblok. |
hero |
data.headline, data.subheadline, data.cta_text, data.cta_url |
Komponen highlight di atas halaman. |
Contoh ringkas per komponen:
[
{ "component": "heading", "data": { "level": 1, "text": "Judul Halaman" } },
{ "component": "richtext", "data": { "html": "<p>Intro dari editor.</p>" } },
{ "component": "markdown", "data": { "markdown": "## Subjudul\n\nIsi markdown" } },
{ "component": "image", "data": { "src": "/storage/uploads/hero.jpg", "alt": "Hero" } },
{ "component": "button", "data": { "label": "Lihat Produk", "href": "/id/products" } }
]Contoh payload layout minimal:
[
{
"component": "hero",
"data": {
"headline": "Selamat Datang",
"subheadline": "Konten dari Cockpit Pro Pages",
"cta_text": "Mulai",
"cta_url": "/blog"
}
},
{
"component": "grid",
"data": { "colWidth": "1-2" },
"columns": [
{
"components": [
{
"component": "heading",
"data": { "level": 2, "text": "Kolom A" }
}
]
},
{
"components": [
{
"component": "markdown",
"data": { "markdown": "## Kolom B\n\nIsi markdown" }
}
]
}
]
}
]File: lib/pro/pages.js
fetchMenus()->/pages/menusfetchMenu(name)->/pages/menu/{name}fetchPagesTree()->/pages/pagesfetchPageByRoute()->/pages/pagefetchPageById(id)->/pages/page/{id}fetchRoutes()->/pages/routesfetchPagesSettings()->/pages/settingsfetchSitemap()->/pages/sitemap
File: lib/pro/detektivo.js
advancedSearch({ index, q, ... })->/detektivo/search/{index}
Endpoint proxy Next.js:
GET /api/detektivo/{index}?q=keyword&limit=10&offset=0&locale=id
File: lib/pro/personi.js
resolveVariant(content, audienceContext)untuk memilih varian terbaik berbasis audience.personiToQuery(audienceContext)untuk membentuk query parampersoni,personi_vars, dantz_offset.
Enable:
/api/draft?secret=<COCKPIT_PREVIEW_SECRET>&slug=/id/blog/my-post
Disable:
/api/draft/disable
- Dynamic metadata page sudah membaca field SEO Pro (
seo.title,seo.description) dengan fallback ke field legacy. - Homepage locale akan mencoba render page route
/dari Pages Pro saat flag aktif. - Untuk mapping komponen layout tambahan, tambahkan case baru di
components/layout-renderer.jsxlalu update tabel mapping di atas agar sinkron.