Build your site

Project structure

Learn what a new Pluto project contains.

A Pluto project is a Nuxt app. It extends one or more layers.

The blog template

The blog template (templates/blog in the templates repository) works with both backends: the Git CMS (no database) and Supabase. With the Git CMS, it has these files:

  • content/posts/ holds the posts as Markdown files (Git CMS only).
  • app/pages/ holds the public pages. They read posts with usePosts, usePost and useAdjacentPosts. See Public API.
  • app/components/PostArticle.vue renders one post, with the core component PlutoHtml for the body. The post page and the preview of the post editor (PlutoPostPreview.vue) both use it.
  • app/components/content/Callout.vue is a content component (a note, a tip or a warning). The post editor lists it under Insert a component, because it calls definePlutoBlock. Add your own components next to it.
  • main.css is the whole look, in Tailwind CSS: the colors as variables for light and dark, and the post body (.pluto-prose). Each color is also a Tailwind class, for example text-heading, text-muted and border-line. The template uses no UI library and no Pluto styles. To use them, see Styles.
  • The site starts in light mode (colorMode.preference in nuxt.config.ts). ColorModeButton of core in the navbar switches it.
  • The texts are in English, in the files. For a site in more than one language, see Internationalization.
  • nuxt.config.ts extends @plutocms/core, and the SEO add-on @plutocms/seo when you said yes to Add SEO?. When needed, it sets the plutoGithub options.
  • package.json lists @plutocms/core, nuxt, vue, and vue-router, and @plutocms/seo with SEO.

With Supabase, three things differ, and the CLI sets them:

  • nuxt.config.ts extends @plutocms/supabase-blog in place of core (and @plutocms/seo with SEO). The blog layer brings @plutocms/supabase and core.
  • package.json also lists @plutocms/supabase-blog, and has the supabase-types script.
  • There is no content/ folder: the posts are in the database.

The pages link to a post by its slug (/posts/<slug>), the same for both backends.

The template has no .env file. The CLI writes it when you create the project. With the Git CMS, Create the GitHub App in the admin gives the GitHub App values. See Deploy.

The shop template

The shop template (Supabase) has these files:

Its nuxt.config.ts extends @plutocms/supabase-shop and the 3D add-on @plutocms/3d, so a product can have a 3D model. The shop layer brings @plutocms/supabase and core.

The Dashboard only template

The Dashboard only template has no public site:

It has no CSS entry: it has no public pages, and the admin has its own CSS. See Styles.

A Supabase project (the shop, or the blog with Supabase) does not ship shared/types/supabase.ts. Git ignores it. In development, the server writes the generated database types to this file after it applies the migrations.

app.vue

app.vue is your site: the header, the layout, the footer. You write nothing for Pluto in it. Pluto wraps it:

  • The admin (/admin) and the preview of the visual editor never render your app.vue. They get the admin shell.
  • A public page renders your app.vue, with the admin bar for signed-in editors. When your app.vue has no UApp, Pluto adds one.

With no app.vue, Pluto uses its own: the page in the default layout.

To take control yourself, wrap your app in PlutoRoot. Pluto then leaves app.vue as it is:

app/app.vue
<template>
  <PlutoRoot>
    <NuxtPage />
  </PlutoRoot>
</template>

PlutoRoot includes the admin navbar, UApp, NuxtLayout, NuxtLoadingIndicator, and the base styles. On the admin routes and the preview route, render only <NuxtPage /> in it.

If the UApp of your site is in a layout or a component, Pluto cannot see it from app.vue. Tell it with plutoRoot: { siteApp: true } in nuxt.config.ts, so the page does not get a second one. plutoRoot: { wrap: false } turns the wrapping off.

nuxt.config.ts

The config extends the layer for the template. This example shows the core blog template:

nuxt.config.ts
export default defineNuxtConfig({
  extends: ['@plutocms/core', '@plutocms/seo'],
  css: ['~/assets/css/main.css']
})

The CMS is on by default. The plutoGithub options have defaults: the storage depends on the mode, and Pluto finds the repository from the environment. The template sets no plutoGithub option: the defaults are enough. See Git CMS reference.

The CSS entry

The admin has its own CSS, so this file is for your site only. The blog template uses Tailwind and no UI library:

app/assets/css/main.css
@import 'tailwindcss';

A site on Nuxt UI, such as the shop template, also imports Nuxt UI and the Pluto CSS:

app/assets/css/tailwind.css
@import 'tailwindcss';
@import '@nuxt/ui';
@import '@plutocms/css';
@import '@plutocms/css/base';
@import '@plutocms/css/site';

@plutocms/css/base gives the look of the Pluto components, such as PlutoHtml. Add your own @theme after these lines. See Styles.

The admin routes

Core owns the /admin routes. They need no page files in your app.

RoutePurpose
/adminRedirects to /admin/home
/admin/homeThe dashboard
/admin/loginThe sign-in page
/admin/no-accessThe page for a signed-in user with no capability
/admin/not-configuredThe page that shows in production when no backend registers an auth driver
/admin/mediaThe media library, when the backend has a media driver
/admin/settingsThe settings pages
/admin/usersGit CMS: the people with write access to the repository (read only)
/admin/content/<type>The generated list, new, and edit pages of a content type