Skip to content

johannschopplich/cacao-kit-frontend

Repository files navigation

Cacao Kit Frontend

Cacao Kit (Frontend)

A production-ready Nuxt starter kit for headless Kirby CMS.

Usage β€’ Architecture β€’ Deployment

Tip

If internationalization is not a requirement for your project, check out the 🧱 branch without Nuxt i18n.

If this is your first time building an application with Nuxt and Kirby, take a look at the πŸ’š Kirby Nuxt Starterkit first to get a basic understanding of this tech stack.

This is a minimal but feature-rich Nuxt starter kit and the evolved version of the Kirby Nuxt Starterkit. It pairs with the 🍫 Cacao Kit backend.

Key Features

  • πŸ† Motto: "Everything is a block" – Kirby blocks define what to render for each page
  • πŸ›£οΈ All pages are rendered by the catch-all route by default (you can still create Nuxt pages)
  • 🌌 Use Kirby's page structure as the source of truth
  • πŸ«‚ Kirby Query Language with nuxt-kirby
  • 🌐 Internationalization with @nuxtjs/i18n
  • 🎨 UnoCSS and VueUse pre-wired
  • πŸ› Global site data similar to Kirby's $site
  • πŸ”Ž SSR-generated SEO data
  • πŸ“ Prettier & ESLint
  • πŸ”’ Pre-configured VSCode settings

If you need custom Kirby page blueprints with custom fields, you can create dedicated Nuxt pages and query the content using KQL. See app/pages/about.vue for an example.

Usage

Prerequisites

  1. Enable Corepack using corepack enable
  2. Install dependencies using pnpm install
  3. Adapt the relevant environment variables:
# Base URL of the Kirby backend
KIRBY_BASE_URL=
# Token for bearer authentication
# See https://kirby.tools/docs/headless/configuration/authentication
KIRBY_API_TOKEN=

Development

  1. Start the development server using pnpm run dev
  2. Visit localhost:3000

Production

Build the application for production with pnpm run build.

Check out the deployment documentation.

Architecture & Development

Project Structure

The Cacao Kit follows a clear architectural pattern designed around its block-first approach:

app/
β”œβ”€β”€ components/
β”‚   └── Kirby/
β”‚       β”œβ”€β”€ Block/           # Individual block components
β”‚       β”œβ”€β”€ Blocks.vue       # Block renderer
β”‚       └── Layouts.vue      # Layout renderer
β”œβ”€β”€ composables/
β”‚   β”œβ”€β”€ links.ts             # Internal link handling
β”‚   β”œβ”€β”€ page.ts              # Page data and SEO meta
β”‚   β”œβ”€β”€ proxy.ts             # Development proxy utilities
β”‚   └── site.ts              # Site data access
β”œβ”€β”€ pages/
β”‚   β”œβ”€β”€ [...slug].vue        # Universal page renderer
β”‚   └── about.vue            # Custom page example
β”œβ”€β”€ plugins/
β”‚   └── site.ts              # Global site data management
└── queries/                 # KQL query definitions
    β”œβ”€β”€ index.ts
    β”œβ”€β”€ about.ts
    β”œβ”€β”€ notes.ts
    β”œβ”€β”€ page.ts
    β”œβ”€β”€ site.ts
    └── prefetch.ts

Block-First Architecture

Every page is rendered through the catch-all route [...slug].vue, which dynamically renders either:

  • Layouts: Column-based content using KirbyLayouts
  • Blocks: Linear content using KirbyBlocks
<template>
  <div>
    <KirbyLayouts v-if="page?.layouts?.length" :layouts="page.layouts" />
    <KirbyBlocks v-else-if="page?.blocks" :blocks="page.blocks" />
  </div>
</template>

Adding New Blocks

  1. Create the block component in app/components/Kirby/Block/:
<!-- app/components/Kirby/Block/MyCustomBlock.vue -->
<script setup lang="ts">
import type { KirbyBlock } from '#nuxt-kirby'

defineProps<{
  block: KirbyBlock<'my-custom-block'>
}>()
</script>

<template>
  <section class="my-custom-block">
    <h2>{{ block.content.title }}</h2>
    <div v-html="block.content.text" />
  </section>
</template>
  1. Register the block in app/components/Kirby/Blocks.vue:
import { LazyKirbyBlockMyCustomBlock } from '#components'

const blockComponents: Record<string, Component> = {
  // Custom blocks
  'my-custom-block': LazyKirbyBlockMyCustomBlock,
}

Working with KQL Queries

Define reusable queries in the queries/ directory:

// app/queries/blog.ts
import type { KirbyQuerySchema } from 'kirby-types'

export const blogQuery: KirbyQuerySchema = {
  query: 'page("blog")',
  select: {
    title: true,
    children: {
      query: 'page.children.listed',
      select: {
        title: true,
        date: true,
        excerpt: 'page.text.excerpt(300)',
        cover: {
          query: 'page.cover.toFile?.resize(600)',
          select: ['url', 'alt'],
        },
      },
    },
  },
}

Use them in components:

<script setup lang="ts">
import { blogQuery } from '~/queries/blog'

const { locale } = useI18n()
const { data } = await useKql(blogQuery, {
  language: locale.value,
})
</script>

Internationalization

The kit includes full i18n support with @nuxtjs/i18n.

Custom Styling

This kit uses semantic HTML with minimal styling via new.css for demonstration. To implement your own styling, remove the import in app/app.vue and add your custom styles – UnoCSS is already set up.

Deployment

Static Site Generation

For maximum performance and CDN compatibility, generate a static site:

pnpm run generate

This creates a fully static version in the dist/ directory that can be hosted on any static hosting service.

Server-Side Rendering

Deploy with full SSR capabilities:

pnpm run build

Environment Configuration

Ensure these environment variables are set in production:

# Required: Your Kirby backend URL
KIRBY_BASE_URL=https://your-kirby-backend.com

# Required: Authentication token for KQL queries
KIRBY_API_TOKEN=your-secret-token

# Optional: Public site URL for SEO and social sharing
NUXT_PUBLIC_SITE_URL=https://your-frontend.com

Preview

What's Kirby?
  • getkirby.com – Get to know the CMS.
  • Try it – Take a test ride with our online demo. Or download one of our kits to get started.
  • Documentation – Read the official guide, reference and cookbook recipes.
  • Issues – Report bugs and other problems.
  • Feedback – You have an idea for Kirby? Share it.
  • Forum – Whenever you get stuck, don't hesitate to reach out for questions and support.
  • Discord – Hang out and meet the community.
  • YouTube – Watch the latest video tutorials with Bastian.
  • Mastodon – Spread the word.
  • Instagram – Share your creations: #madewithkirby.

License

MIT License Β© 2023-PRESENT Johann Schopplich

About

🍫 Best practice Nuxt and KQL starter for your headless Kirby CMS

Topics

Resources

License

Stars

51 stars

Watchers

3 watching

Forks

Releases

No releases published

Packages

 
 
 

Contributors