0.6.1 • Published 4 months ago

@distromade/distro-cms v0.6.1

Weekly downloads
-
License
MIT
Repository
gitlab
Last release
4 months ago

Distro CMS

Distro CMS is an open source CMS used to edit Nuxt 3 Content pages, right from your site. Content updates in real-time with 2-way binding.

Usage

1. Create a Nuxt 3 Content project

2. Install Distro CMS and Distro UI

# npm
npm install @distromade/distro-cms @distromade/distro-ui

# yarn
yarn add @distromade/distro-cms @distromade/distro-ui

# pnpm
pnpm add @distromade/distro-cms @distromade/distro-ui

3. Update app.vue

<script setup lang="ts">
import '@distromade/distro-ui/style.css';
import '@distromade/distro-cms/style.css';
import { LoginForm, PageWrapper } from '@distromade/distro-cms';
import type {
  LoginFunctionReturnType,
  UnsavedChangesType,
} from '@distromade/distro-cms/dist/types';

const contentStore = useContentStore();
const route = useRoute();

function login() {
  // Auth logic
}

function save(changes: UnsavedChangesType) {
   // Save changes to your project
   console.log('Saving changes:', JSON.parse(JSON.stringify(changes)));
}
</script>

<template>
  <PageWrapper :content="contentStore.content" :route="route.path" :save="save">
    <template #login-form>
      <LoginForm :login="login" />
    </template>

    <NuxtLoadingIndicator color="#222" :height="2" :throttle="400" />
    <NuxtLayout>
      <NuxtPage />
    </NuxtLayout>
  </PageWrapper>
</template>

4. How to open the CMS in your project

Add a button or link to open the CMS

<script lang="ts" setup>
   import { useGlobalCMSState } from '@distromade/distro-cms';

   const { showEditor } = useGlobalCMSState();

   function toggleEditor() {
      showEditor.value = !showEditor.value;
   }
</script>
<template>
   <button @click="toggleEditor" />
</template>

5. Add useThemeContent composable

Under /composables, create useThemeContent.ts:

import { computed } from 'vue';
import { v4 as uuid } from 'uuid';
import { useGlobalCMSState } from '@distromade/distro-cms';
import type {
  MarkdownElement,
  PlainTextElement,
  PageContentType,
} from '@distromade/distro-cms/dist/types';

export async function useThemeContent<
  M = Record<string, MarkdownElement>,
  P = Record<string, PlainTextElement>,
>(contentPath: string) {
  const { pageContent } = useGlobalCMSState();
  const contentStore = useContentStore();

  const content = (await queryContent(contentPath).findOne()) as unknown as PageContentType;
  contentStore.setContent(content);

  const mdElements = computed(() => {
    const { markdownElements } = content.cms;
    const { markdownElements: cmsMdElements } = JSON.parse(
      JSON.stringify(pageContent.value?.cms ?? {}),
    );
    if (cmsMdElements) return cmsMdElements as M;
    return markdownElements as M;
  });

  const textElements = computed(() => {
    const { plainTextElements } = content.cms;
    const { plainTextElements: cmsTextElements } = JSON.parse(
      JSON.stringify(pageContent.value?.cms ?? {}),
    );
    if (cmsTextElements) return cmsTextElements as P;
    return plainTextElements as P;
  });

  const pageTitle = computed<string>(() => {
    if (pageContent.value) return pageContent.value.cms.pageTitle;
    return content.cms.pageTitle;
  });

  /**
   * This is a hack to force elements bound to mdElements via v-html to re-render
   * when the pageContent changes.
   */
  const key = computed(() => {
    // does nothing; just triggers reactivity:
    pageContent.value?.cms;
    return uuid();
  });

  return {
    key,
    mdElements,
    textElements,
    pageTitle,
  };
}

6. Add useContentStore in stores

In your /stores directory, create useContentStore.ts:

import { defineStore } from 'pinia';
import type { PageContentType } from '@distromade/distro-cms/dist/types';

export interface ContentState {
  content: PageContentType | null;
}

export const useContentStore = defineStore('content', {
  state(): ContentState {
    return {
      content: null as PageContentType | null,
    };
  },
  actions: {
    setContent(content: PageContentType | null) {
      this.content = content;
    },
  },
});

7. Create .vue page

In your /pages directory, create a .vue page. In this example, we'll use about.vue for an about page.

<script lang="ts" setup>
   import { md, text } from '@distromade/distro-cms';
   import json from '~/content/about.json';
   import { useThemeContent } from '@/composables/useThemeContent';

   type Content = typeof json;
   type MD = Content['cms']['markdownElements'];
   type Text = Content['cms']['textElements'];

   const { mdElements, textElements, pageTitle, key } = await useThemeContent<MD, Text>('/about');

   useHead({
      title: () => pageTitle.value,
   });
</script>

<template>
  <section>
   <h1>{{ text(textElements.title) }}</h1>
   <div v-html="md(mdElements.about)" />
  </section>
</template>

You can render either as text in {{ }} or in v-html.

8. Create the .json file

In your /content directory, create about.json.

{
  "contentId": "about",
  "cms": {
    "pageTitle": "About us",
    "pageDescription": "About our company...",
    "plainTextElements": {
      "title": {
        "label": "About title",
        "text": "About Killer Coffee Co."
      }
    },
    "markdownElements": {
      "about": {
        "label": "About description",
        "markdown": "This is our company bio, **written in markdown**."
      }
    }
  }
}

9. Run project locally

npm run dev

Now, you can edit your static content with the CMS, right from your project.

Links:

Distro UI


Testing the CMS with Storyboook

To run the Storybook preview locally, while developing, run the following command:

Using NPM

npm install
npm run storybook

Using Yarn

yarn install
yarn storybook

Using PNPM

pnpm install
pnpm storybook
0.6.1

4 months ago

0.5.0

4 months ago

0.6.0

4 months ago

0.4.9

4 months ago

0.4.8

4 months ago

0.4.7

4 months ago

0.4.6

4 months ago

0.4.5

4 months ago

0.4.4

4 months ago

0.4.1

4 months ago

0.4.3

4 months ago

0.4.2

4 months ago

0.4.0

4 months ago

0.3.0

5 months ago

0.2.1

5 months ago

0.2.0

5 months ago

0.1.4

5 months ago

0.1.3

5 months ago

0.1.2

5 months ago

0.1.1

5 months ago

0.1.0

5 months ago

0.0.9

5 months ago

0.0.8

5 months ago

0.0.6

5 months ago

0.0.5

5 months ago

0.0.4

5 months ago

0.0.3

6 months ago

0.0.2

6 months ago

0.0.1

6 months ago