About page

This lesson covers creating the page intro, prose, and image blocks for our website's About page, as well as extending the standard pages collection.


Page intro

The page intro block will serve as the primary block on all pages of our websites. It includes a H1 title and an optional kicker text:

# blocks/PageIntro.vue

<template>
  <Container>
    <div class="max-w-content space-y-2">
      <h1>{{ title }}</h1>
      <p v-if="kicker" class="text-sm">{{ kicker }}</p>
    </div>
  </Container>
</template>

<script lang="ts" setup>
import { defineBlock, textField } from '#pruvious'

defineBlock({
  icon: 'H1',
})

defineProps({
  title: textField({ required: true }),
  kicker: textField(),
})
</script>

Don't forget to register the new content spacing in your tailwind.config.js.

Image

The image block has only one field to store a relationship to an uploaded image:

# blocks/Image.vue

<template>
  <Container class="content-block">
    <PruviousPicture :image="image" class="max-w-content block h-auto w-full overflow-hidden rounded-md" />
  </Container>
</template>

<script lang="ts" setup>
import { defineBlock, imageField } from '#pruvious'

defineBlock({
  icon: 'Photo',
})

defineProps({
  image: imageField({
    required: true,
    minWidth: 1440,
    sources: [
      { media: '(max-width: 400px)', format: 'webp', width: 720 },
      { media: '(max-width: 400px)', format: 'jpeg', width: 720 },
      { format: 'webp', width: 1440 },
      { format: 'jpeg', width: 1440 },
    ],
  }),
})
</script>

You may have noticed that I used the content-block class in the Container component. Its purpose is to narrow the spacing between adjacent Image and Prose blocks. To achieve this, I added the following CSS to our tailwind.css:

# assets/css/tailwind.css

...

.content-block + .content-block {
  @apply !mt-8;
}

Prose

The prose block enables us to enter the text for our pages. We'll use the editor field for this purpose:

# blocks/Prose.vue

<template>
  <Container class="content-block">
    <PruviousHTML :html="text" class="max-w-content prose" />
  </Container>
</template>

<script lang="ts" setup>
import { defineBlock, editorField } from '#pruvious'

defineBlock({
  icon: 'Pencil',
})

defineProps({
  text: editorField({
    required: true,
    toolbar: ['bold', 'italic', 'link', 'heading2', 'heading3', 'paragraph', 'link', 'bulletList'],
  }),
})
</script>

To make our styles work, we can use this CSS code:

# assets/css/tailwind.css

...

.prose > * {
  @apply mb-[1.5em];
}

.prose > h1 {
  @apply text-5xl ph:text-4xl;
}

.prose > h2 {
  @apply text-4xl ph:text-3xl;
}

.prose > h3 {
  @apply text-3xl ph:text-2xl;
}

.prose > p {
  @apply text-sm leading-[1.375rem];
}

.prose > h1,
.prose > h2,
.prose > h3,
.prose > h4,
.prose > h5,
.prose > h6 {
  @apply mb-[0.5em] mt-[2em];
}

.prose > ul > li {
  @apply relative pl-5 before:absolute before:left-0 before:top-3 before:h-px before:w-2 before:bg-accent;
}

.prose > :first-child {
  @apply mt-0;
}

.prose > :last-child {
  @apply mb-0;
}

.prose a:not([class]) {
  @apply text-heading underline underline-offset-2 transition hocus:text-accent dark:text-white dark:hocus:text-accent;
}

We are now ready to create the About page:

Footer border

The final task is to add a border above the footer. We will achieve this by creating a toggleable collection field. Given that we are currently working within the existing pages collection, we must extend it somehow. To accomplish this, we first need to disable the default collection in the Pruvious module:

# nuxt.config.ts

export default defineNuxtConfig({
  ...
  pruvious: {
    ...
    standardCollections: {
      pages: false,
    },
  },
})

Now we can redefine the collection using the pageLikeCollection utility. This function will create the same configuration as the pages collection, allowing us to add extra fields. Here's the code:

# collections/pages.ts

import { defineCollection } from '#pruvious'
import { pageLikeCollection } from '#pruvious/standard'

export default defineCollection(
  pageLikeCollection({
    name: 'pages',
    additionalFields: {
      footerBorder: {
        type: 'switch',
        options: {
          description: 'Display a border above the footer.',
        },
      },
    },
    additionalPublicPagesFields: ['footerBorder'],
  }),
)

Now we can use the usePage composable to access the footerBorder field that we have explicitly exposed in the public API. We can include the border in our default layout:

# layouts/default.vue

<template>
  <Header class="mt-12" />

  <div class="my-23 space-y-23" :class="{ 'border-b pb-23 dark:border-white/10': page?.fields.footerBorder }">
    <!-- Our page blocks will be rendered here -->
    <slot />
  </div>

  <Footer class="mb-23" />
</template>

<script lang="ts" setup>
import { usePage } from '#pruvious/client'

const page = usePage()
</script>

Let's finalize the About page:

Playground

You can access the current project files at the following link:

Explore the GitHub repository.

Last updated on January 24, 2024 at 15:06