vue-slicezone

A component that maps other components to Prismic slices
- Static
- Latest Patch
- Latest Minor
- Latest Major
- 0.1.6
- 0.1.5
- 0.1.4
- 0.1.2
- 0.1.1
- 0.1.0
- 0.0.30
- 0.0.29
- 0.0.28
- 0.0.27
- 0.0.26
- 0.0.25
- 0.0.24
- 0.0.23
- 0.0.22
- 0.0.21
- 0.0.20
- 0.0.19
- 0.0.18
- 0.0.17
- 0.0.16
- 0.0.15
- 0.0.14
- 0.0.13
- 0.1.7-alpha.2
- 0.1.7-alpha.1
- 0.1.7-alpha.0
- 0.1.6-alpha.5
- 0.1.6-alpha.4
- 0.1.6-alpha.3
- 0.1.6-alpha.2
- 0.1.6-alpha.1
- 0.1.6-alpha.0
- 0.1.5-alpha.12
- 0.1.5-alpha.11
- 0.1.5-alpha.10
- 0.1.5-alpha.9
- 0.1.5-alpha.7
- 0.1.5-alpha.6
- 0.1.5-alpha.5
- 0.1.5-alpha.4
- 0.1.5-alpha.3
- 0.1.5-alpha.2
- 0.1.5-alpha.1
- 0.1.5-alpha.0
- 0.1.4-alpha.0
- 0.1.3-alpha.13
- 0.1.3-alpha.12
- 0.1.3-alpha.11
- 0.1.3-alpha.10
- 0.1.3-alpha.9
- 0.1.3-alpha.8
- 0.1.3-alpha.7
- 0.1.3-alpha.6
- 0.1.3-alpha.5
- 0.1.3-alpha.4
- 0.1.3-alpha.3
- 0.1.3-alpha.2
- 0.1.3-alpha.1
- 0.1.3-alpha.0
- 0.1.2-alpha.21
- 0.1.2-alpha.20
- 0.1.2-alpha.19
- 0.1.2-alpha.18
- 0.1.2-alpha.17
- 0.1.2-alpha.16
- 0.1.2-alpha.15
- 0.1.2-alpha.14
- 0.1.2-alpha.13
- 0.1.2-alpha.12
- 0.1.2-alpha.11
- 0.1.2-alpha.10
- 0.1.2-alpha.9
- 0.1.2-alpha.8
- 0.1.2-alpha.7
- 0.1.2-alpha.6
- 0.1.2-alpha.5
- 0.1.2-alpha.4
- 0.1.2-alpha.3
- 0.1.2-alpha.2
- 0.1.2-alpha.1
- 0.1.2-alpha.0
- 0.1.1-alpha.24
- 0.1.1-alpha.23
- 0.1.1-alpha.22
- 0.1.1-alpha.21
- 0.1.1-alpha.20
- 0.1.1-alpha.19
- 0.1.1-alpha.18
- 0.1.1-alpha.17
- 0.1.1-alpha.16
- 0.1.1-alpha.15
- 0.1.1-alpha.14
- 0.1.1-alpha.13
- 0.1.1-alpha.12
- 0.1.1-alpha.11
- 0.1.1-alpha.10
- 0.1.1-alpha.9
- 0.1.1-alpha.8
- 0.1.1-alpha.7
- 0.1.1-alpha.6
- 0.1.1-alpha.5
- 0.1.1-alpha.4
- 0.1.1-alpha.3
- 0.1.1-alpha.2
- 0.1.1-alpha.1
- 0.1.1-alpha.0
- 0.0.28-alpha.51
- 0.0.28-alpha.50
- 0.0.28-alpha.49
- 0.0.28-alpha.48
- 0.0.28-alpha.47
- 0.0.28-alpha.46
- 0.0.28-alpha.45
- 0.0.28-alpha.44
- 0.0.28-alpha.43
- 0.0.28-alpha.42
- 0.0.28-alpha.40
- 0.0.28-alpha.39
- 0.0.28-alpha.38
- 0.0.28-alpha.37
- 0.0.28-alpha.36
- 0.0.28-alpha.35
- 0.0.28-alpha.34
- 0.0.28-alpha.33
- 0.0.28-alpha.32
- 0.0.28-alpha.31
- 0.0.28-alpha.30
- 0.0.28-alpha.29
- 0.0.28-alpha.28
- 0.0.28-alpha.26
- 0.0.28-alpha.25
- 0.0.28-alpha.24
- 0.0.28-alpha.23
- 0.0.28-alpha.22
- 0.0.28-alpha.21
- 0.0.28-alpha.20
- 0.0.28-alpha.19
- 0.0.28-alpha.18
- 0.0.28-alpha.17
- 0.0.28-alpha.16
- 0.0.28-alpha.15
- 0.0.28-alpha.14
- 0.0.28-alpha.13
- 0.0.28-alpha.12
- 0.0.28-alpha.11
- 0.0.28-alpha.10
- 0.0.28-alpha.9
- 0.0.28-alpha.8
- 0.0.28-alpha.6
- 0.0.28-alpha.5
- 0.0.28-alpha.4
- 0.0.28-alpha.3
- 0.0.28-alpha.2
- 0.0.28-alpha.1
- 0.0.28-alpha.0
- 0.0.27-beta.2
- 0.0.27-beta.1
- 0.0.27-alpha.24
- 0.0.27-alpha.0
- 0.0.26-alpha.1
- 0.0.26-alpha.0
- 0.0.24-alpha.6
- 0.0.24-alpha.5
- 0.0.20-alpha.2
- 0.0.17-alpha.1
- 0.0.16-alpha.0
- 0.0.15-alpha.3
- 0.0.15-alpha.2
- 0.0.14-alpha.53
- 0.0.14-alpha.52
- 0.0.14-alpha.5
- 0.0.14-alpha.0
SliceZone
A Slice Machine component that matches Vue/Nuxt components with Prismic data components (that we call slices). You can see it as an hybrid between a "components registry" and a router:
- at build time, it scans and lists all available components via a resolver (README wip)
- when a page is hit, it fetches the corresponding content on Prismic
- it then matches Prismic slices with components, and renders them accordingly
This implementation is meant to work with both Vue and Nuxt projects, although the auto-fetch feature is currently only available with Nuxt. Also, feel free to use this repository as a reference for building SliceZones for other frameworks ✌️
Installation
yarn add vue-slicezone
You may have to configure your bundler to transpile it from es6:
// nuxt.config.js
build: {
transpile: ["vue-slicezone"];
}
It expects a $prismic
object to be injected by @prismicio/vue
or @nuxtjs/prismic
. If you don't have a running project yet, the easisest way would be to take SliceMachine's quick start guide.
Examples
Depending on your context, you may use the SliceZone with or without nuxt-sm
. Its role is to auto-scan your librairies and make a resolver out of them. As this became irrelevant in Nuxt 2.10+ thanks to @nuxt/components, we'll deprecate nuxt-sm
in favour of extending components folder (see this paragraph).
with nuxt-sm and auto-fetch
This example assumes you created an sm.json
file at the root of your project, and listed nuxt-sm
in your Nuxt modules config:
sm.json
{"libraries": ["@/slices", "vue-essential-slices"]}
pages/_uid.vue
<template>
<slice-zone type="page" :uid="$route.params.uid" />
</template>
<script>
import SliceZone from "vue-slicezone";
export default {
components: {
SliceZone,
},
};
</script>
👆 This would fetch a Prismic document of type "page", by its UID. For each slice found, it would take its slice_type
and find a related PascalNamed components in /slices
folder or in vue-essential-slices
node module.
with custom query & w/o nuxt-sm
You can also pass a slices
array to the SliceZone. usually, this would be the data.body
of a Prismic API response. You can pass your custom resolver too:
<template>
<slice-zone type="page" :resolver="resolver" :slices="page.data.body" />
</template>
<script>
import * as MySlices from '@/slices'
import SliceZone from 'vue-slicezone'
export default {
components: {
SliceZone
},
async asyncData({ params, $prismic }) {
return {
page: await $prismic.api.getByUID('page', params.uid)
}
},
methods: {
resolver({ sliceName, slice, i }) {
return MySlices[sliceName]
}
}
}
</script>
Features
Feature requests much appreciated 👇
Auto-fetch Prismic data
If no slices
are provided, the SliceZone will auto-fetch a document based on its type and uid.
<slice-zone type="myCustomType" uid="contact" />
👆 this is like passing a prop queryType
with value repeat
or repeatable
.
This is how you would fetch a single document:
<slice-zone type="mySingleCustomType" queryType="single" />
If slices are not stored in body
, pass a body
param with the key name of your zone:
<slice-zone type="mySingleCustomType" queryType="single" body="another_body" />
If you need to pass params to the API call (like fetch links), pass the SliceZone a params
object:
<slice-zone
type="myCustomType"
:uid="$route.params.uid"
:params="{ key: 'value' }"
/>
If you just need to pass a lang, to the API, pass the prop directly:
<slice-zone type="myCustomType" :uid="$route.params.uid" lang="fr-fr" />
Auto-match components
Instead of passing a resolver to the SliceZone, we offer a nuxt-sm
module that lists and scans your components folder and creates a custom resolver out of them. Your SliceZone then acts as a large "bucket" of components that would get rendered solely based on how they match Prismic slices.
How it scans
nuxt-sm
looks for a key libraries
inside the sm.json
file at the root of your project. It then scans each folder, whether it's local or in node_modules, and registers it. This is similar to how prismic sm --ls
command works.
Order matters. If 2 slices have the same name, the first one found is used. This lets you progressively enhance your app, by replacing a default component with your own.
How it works
In Prismic, each slice returned by the API contains a snake_cased slice_type
. The SliceZone simply PascalCases this slice_type
and asks the resolver if a component with given SliceName has been registered. If something is returned, it then passes a slice
prop to the component and renders it.
If you created a slice in Prismic with a slice_type of value my_component
, the SliceZone wil ask for a component with a file/folder name MyComponent
.
** custom **
You can also pass your own resolver to the SliceZone. It expects one of thesse to be returned:
- a component (see 2nd example)
- a promise that returns a component
- an array of promises
methods: {
resolver({ sliceName }) {
return Slices[sliceName]
},
resolverP({ sliceName }) {
return import(`path/to/slices/${sliceName}/index.vue`)
},
resolverPs({ sliceName }) {
return [
import(`path/to/slices/${sliceName}/index.vue`),
import(`a/default/path/to${sliceName}/index.vue`),
]
},
}
Theme
Inspired by theme-ui
, the SliceZone supports passing a theme object or function to rendered slices. We think it's super handy for developers/designers to enforce ceertain design rules on specific pages, or if they're working with external libraries.
theme object
If you wanted your contact page to use a b&w theme, you could pass an object like this one:
<template>
<slice-zone type="page" uid="contact" :theme="theme" />
</template>
<script>
const theme = {
color: '#FFF',
wrapper: {
style: 'background: #111'
}
}
export default {
data() {
return {
theme
}
}
}
</script>
👆 How this is used depends on your implementation. See vue-essential-slices for a real world example.
scoped theme
To scope theme values to specific components, use their name as key. None of the root values would be used in that case. If you need to share some properties, spread them multiple times.
const theme = {
color: "#111",
CallToAction: {
color: "#FFF",
},
};
as function
Alternatively , you can pass a function as theme...
const theme = ({ sliceName, i }) =>
i % 2 ? { color: "#111" } : { color: "pink" };
...including in a scoped theme:
const theme = {
CallToAction: ({ sliceName, i }) =>
i % 2 ? { color: "#111" } : { color: "pink" },
};
Named slots
The SliceZone takes advantage of Vue named slots. To use them, prefix them with the name of your component. For example, if your HeroAction components defines a header
slot, you can access it this way in the SliceZone:
<template>
<slice-zone type="page" uid="contact" :theme="theme" :slices="page.data.body">
<template v-slot:HeroAction.header="primary">
<header>
<h1>Header {{ primary.someContent }}</h1>
</header>
</template>
</slice-zone
</template>
Usually, slice components would bind primary
or items
to the slot, for you to use in your template. Note that we're passing slices
here, as named slots does not work yet with auto-fetching content.