Skip to content

Provide a way for extending themes to add layouts #2547

Closed
@aentwist

Description

@aentwist

Is your feature request related to a problem? Please describe.

For my theme which extends the default theme, I want to have a contact page with a custom layout.

Describe the solution you'd like

Users
---
layout: contact
---

# Contact

content
Devs

Effectively add custom blocks here

<VPHome v-else-if="frontmatter.layout === 'home'">
<template #home-hero-before><slot name="home-hero-before" /></template>
<template #home-hero-info><slot name="home-hero-info" /></template>
<template #home-hero-image><slot name="home-hero-image" /></template>
<template #home-hero-after><slot name="home-hero-after" /></template>
<template #home-features-before><slot name="home-features-before" /></template>
<template #home-features-after><slot name="home-features-after" /></template>
</VPHome>
<VPDoc v-else>
<template #doc-top><slot name="doc-top" /></template>
<template #doc-bottom><slot name="doc-bottom" /></template>
<template #doc-footer-before><slot name="doc-footer-before" /></template>
<template #doc-before><slot name="doc-before" /></template>
<template #doc-after><slot name="doc-after" /></template>
<template #aside-top><slot name="aside-top" /></template>
<template #aside-outline-before><slot name="aside-outline-before" /></template>
<template #aside-outline-after><slot name="aside-outline-after" /></template>
<template #aside-ads-before><slot name="aside-ads-before" /></template>
<template #aside-ads-after><slot name="aside-ads-after" /></template>
<template #aside-bottom><slot name="aside-bottom" /></template>
</VPDoc>

For example

<MyContact v-if="frontmatter.layout === 'contact'">
  <!-- define slots for this layout, if any -->
</MyContact>

This needs a lot of consideration, but I might propose something like

import Contact from "./components/MyContact.vue";

export default <Theme>{
  // ...
  customLayouts: {
    contact: Contact,
  },
};

Then in VPContent,

<component v-else-if="customLayouts[frontmatter.layout]" :is="customLayouts[frontmatter.layout]"></component>

Describe alternatives you've considered

  • Override the VPContent component - very fragile coupling
  • Use the page layout with a custom frontmatter key under which additional layouts can be specified - cannot control Content, workaround hack
Users
---
layout: page
type: contact
---

# Contact

content
Devs

MyLayout.vue

<template>
  <Layout>
    <template v-if="frontmatter.type === 'about'" #page-top>
      about page top
    </template>
    <template v-if="frontmatter.type === 'about'" #page-bottom>
      about page bottom
    </template>

    <template v-if="frontmatter.type === 'contact'" #page-top>
      contact page top
    </template>
    <template v-if="frontmatter.type === 'contact'" #page-bottom>
      contact page bottom
    </template>
  </Layout>
</template>
An element cannot have multiple '<template>' elements which are distributed to the same slot.eslint[vue/valid-v-slot](https://eslint.vuejs.org/rules/valid-v-slot.html)

OR

<template>
  <Layout>
    <template #page-top>
      <template v-if="frontmatter.type === 'about'">
        about page top
      </template>
      <template v-if="frontmatter.type === 'contact'">
        contact page top
      </template>
    </template>

    <template #page-bottom>
      <template v-if="frontmatter.type === 'about'">
        about page bottom
      </template>
      <template v-if="frontmatter.type === 'contact'">
        contact page bottom
      </template>
    </template>
  </Layout>
</template>

(Terrible maintainability)

Additional context

No response

Validations

Metadata

Metadata

Assignees

No one assigned

    Labels

    themeRelated to the theme

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions