ElMassimo / iles

🏝 The joyful site generator
https://iles.pages.dev
MIT License
1.08k stars 31 forks source link

Configure layouts dynamically via properties #109

Closed mseele closed 2 years ago

mseele commented 2 years ago

Is your feature request related to a problem? Please describe. I'm trying to migrate a page from gridsome and have some problems with configuring my default layout via properties: In gridsome it is possible to import the Layout as Vue Component and therefore you can use normal vue properties to configure the layout. E.g. prop transparent true/false if the header of the page should be transparent or not (depending on the page). On my dynamic sites (blog posts fetched from a headless cms) i need to define transparent true or false depending on the data a get from the headless cms. I found no way to do this with iles.

Describe the solution you'd like Some way to configure a layout with simple properties dynamically.

Describe alternatives you've considered A way to dynamically select the layout to choose. Imagine to create multiple layouts of all configurable combinations and choose them dynamically on the page via code.

mseele commented 2 years ago

A workaround i found right now is to use an empty layout and use a custom Vue Layout Component in each page as outer Component.

But thats kinda ugly workaround...

davidlueder commented 2 years ago

I would think that you can use frontmatter for that: https://iles-docs.netlify.app/guide/development#pages

In your layout any frontmatter can be accessed with the usePage() helper:

<script setup>
const { frontmatter, meta } = usePage()
</script>

If you only need the frontmatter values within your layout template, this doesn't even require you to add the script content, you can access the frontmatter with $frontmatter:

<template>
    <h1 v-if="$frontmatter.showTitle">Page title</h1>
</template>
mseele commented 2 years ago

@davidlueder Thank you. Unfortunately it does not work reliable in dynamic pages for me. I generate two pages that are configured the same via the frontmatter attributes and one looks good after build and one did not apply the configuration.

davidlueder commented 2 years ago

Could you share the code with us that is responsible for the generation of those dynamic pages? Maybe something that can be solved by wrapping the variables with ref(...) and changing the value of the reference instead of the variable itself

mseele commented 2 years ago

Yes, i will provide an example as soon as I have time (for now my workaround works quite well and I need to get forward).

ElMassimo commented 2 years ago

The problem with choosing a layout dynamically, is that in order to bundle the app consistently (specially CSS), it's important to resolve which page uses which layout statically at build time.

In most cases, extendFrontmatter provides enough flexibility to set layout accordingly for each page:

  // Example: Configure all posts to use a different layout without having to
  // add `layout: 'post'` in every file.
  extendFrontmatter (frontmatter, filename) {
    if (filename.includes('/posts/'))
      frontmatter.layout ||= 'post'
  },

However, since you are referring to blog posts fetched from a CMS, you are probably using Dynamic Paths, in which case using extendFrontmatter is not an option.

Something that should work well for this use case, is to use props (a computed ref) in the layout:

<script setup lang="ts"> 
const { props } = usePage()
</script>

<template>
  <Header :transparent="props.transparent"/>
  <slot/>
</template>

You would then provide transparent in the props for that dynamic path.


Moving this to Discussions, feel free to ask additional questions, or propose and share alternative solutions.