├── .gitignore ├── .storybook ├── main.js ├── preview.js └── theme.js ├── LICENSE ├── README.md ├── netlify.toml ├── package.json ├── sm.config.json ├── sm.json ├── src ├── Fetch.vue ├── components │ ├── PsAccordion │ │ └── index.vue │ ├── PsButton │ │ └── index.vue │ ├── PsDescription │ │ └── index.vue │ ├── PsEyebrow │ │ └── index.vue │ ├── PsSection │ │ └── index.vue │ ├── PsSlider │ │ └── index.vue │ ├── PsTitle │ │ └── index.vue │ └── index.js ├── index.js ├── slices │ ├── AlternateGrid │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── CallToAction │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── CardsCarousel │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── CustomerLogos │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── FaqSection │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── FeatureTestimonials │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── mock.json │ │ ├── model.json │ │ ├── preview.png │ │ └── quote-triangle.svg │ ├── ImagesSlider │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── PricingTable │ │ ├── README.md │ │ ├── icons.js │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── TestimonialsSlider │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── mock.json │ │ ├── model.json │ │ └── preview.png │ ├── VideoHighlights │ │ ├── README.md │ │ ├── index.stories.js │ │ ├── index.vue │ │ ├── meta.json │ │ ├── mock.json │ │ ├── model.json │ │ ├── preview.png │ │ ├── prismic-embed.js │ │ ├── video-play-icon--black.svg │ │ ├── video-play-icon--dark-grey.svg │ │ ├── video-play-icon--grey.svg │ │ └── video-play-icon--white.svg │ └── index.js ├── styles │ ├── _alternate.scss │ ├── _button.scss │ ├── _pl.scss │ ├── _settings.scss │ ├── _slice.scss │ ├── _slider.scss │ ├── _tabs.scss │ ├── _typography.scss │ ├── _utilities.scss │ ├── fonts.scss │ └── styles.scss └── utils.js ├── stories └── Intro.stories.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | dist 2 | storybook-static 3 | 4 | # Logs 5 | logs 6 | *.log 7 | npm-debug.log* 8 | yarn-debug.log* 9 | yarn-error.log* 10 | lerna-debug.log* 11 | 12 | # Diagnostic reports (https://nodejs.org/api/report.html) 13 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 14 | 15 | # Runtime data 16 | pids 17 | *.pid 18 | *.seed 19 | *.pid.lock 20 | 21 | # Directory for instrumented libs generated by jscoverage/JSCover 22 | lib-cov 23 | 24 | # Coverage directory used by tools like istanbul 25 | coverage 26 | *.lcov 27 | 28 | # nyc test coverage 29 | .nyc_output 30 | 31 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 32 | .grunt 33 | 34 | # Bower dependency directory (https://bower.io/) 35 | bower_components 36 | 37 | # node-waf configuration 38 | .lock-wscript 39 | 40 | # Compiled binary addons (https://nodejs.org/api/addons.html) 41 | build/Release 42 | 43 | # Dependency directories 44 | node_modules/ 45 | jspm_packages/ 46 | 47 | # TypeScript v1 declaration files 48 | typings/ 49 | 50 | # TypeScript cache 51 | *.tsbuildinfo 52 | 53 | # Optional npm cache directory 54 | .npm 55 | 56 | # Optional eslint cache 57 | .eslintcache 58 | 59 | # Optional REPL history 60 | .node_repl_history 61 | 62 | # Output of 'npm pack' 63 | *.tgz 64 | 65 | # Yarn Integrity file 66 | .yarn-integrity 67 | 68 | # dotenv environment variables file 69 | .env 70 | .env.test 71 | 72 | # parcel-bundler cache (https://parceljs.org/) 73 | .cache 74 | 75 | # next.js build output 76 | .next 77 | 78 | # nuxt.js build output 79 | .nuxt 80 | 81 | # vuepress build output 82 | .vuepress/dist 83 | 84 | # Serverless directories 85 | .serverless/ 86 | 87 | # FuseBox cache 88 | .fusebox/ 89 | 90 | # DynamoDB Local files 91 | .dynamodb/ 92 | 93 | .DS_* 94 | 95 | # Local Netlify folder 96 | .netlify -------------------------------------------------------------------------------- /.storybook/main.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const theme = require('./theme') 3 | 4 | const filterRules = filters => rule => { 5 | return filters.some(filter => String(rule.test) === String(filter)); 6 | }; 7 | 8 | 9 | module.exports = { 10 | theme, 11 | stories: ['../stories/**/*.stories.js', '../src/slices/**/*.stories.js'], 12 | // addons: ['@storybook/addon-knobs', '@storybook/addon-docs/'], 13 | webpackFinal(config) { 14 | //add addon-storysource 15 | config.module.rules.push({ 16 | test: [/\.stories\.js$/, /index\.js$/], 17 | loaders: [require.resolve('@storybook/source-loader')], 18 | include: [path.resolve(__dirname, '../src')], 19 | enforce: 'pre' 20 | }); 21 | // allow SCSS 22 | config.module.rules.push({ 23 | test: /\.scss$/, 24 | loaders: ['style-loader', 'css-loader', 'sass-loader'], 25 | include: path.resolve(__dirname, '../') 26 | }); 27 | 28 | config.module.rules.push({ 29 | test: /\.vue$/, 30 | include: path.resolve(__dirname), 31 | loader: 'vue-loader', 32 | }) 33 | // setup URL Alias 34 | config.resolve.alias = { 35 | ...config.resolve.alias, 36 | '@': path.resolve(__dirname, '../src') 37 | }; 38 | 39 | const rules = config.module.rules; 40 | const mdxRules = rules.filter( 41 | filterRules([/\.mdx$/, /\.(stories|story).mdx$/]) 42 | ); 43 | let [jsxRule] = rules.filter(filterRules([/\.(mjs|jsx?)$/])); 44 | 45 | mdxRules.forEach(mdxRule => { 46 | const [babelLoader] = mdxRule.use.filter( 47 | ({ 48 | loader 49 | }) => loader === 'babel-loader' 50 | ); 51 | babelLoader.options.presets = babelLoader.options.presets.filter( 52 | preset => !preset.includes('babel-preset-vue') 53 | ); 54 | }); 55 | 56 | const [babelLoader] = jsxRule.use.filter(({ 57 | loader 58 | }) => loader === 'babel-loader') 59 | babelLoader.options = { 60 | cacheDirectory: path.resolve(__dirname, '..', 'node_modules', '.cache', 'storybook'), 61 | presets: ['@vue/app'], 62 | babelrc: false 63 | } 64 | 65 | // config.plugins.push(new VueLoaderPlugin()) 66 | 67 | return config; 68 | } 69 | }; 70 | -------------------------------------------------------------------------------- /.storybook/preview.js: -------------------------------------------------------------------------------- 1 | import Vue from 'vue'; 2 | import { configure } from '@storybook/vue'; 3 | 4 | import "../src/styles/styles.scss" 5 | // import "./demo.css" 6 | 7 | import { common } from "@prismicio/vue/components"; 8 | 9 | Object.entries(common).forEach(([_, c]) => { 10 | Vue.component(c.name, c); 11 | }); 12 | 13 | Vue.prototype.$endpoint = 'https://repoz.prismic.io/api/v2' 14 | 15 | Vue.prototype.$prismic = { 16 | linkResolver() {}, 17 | asText(richText) { 18 | return richText && Array.isArray(richText) && richText[0] 19 | ? richText[0].text 20 | : ""; 21 | } 22 | } 23 | 24 | configure(require.context('../stories', true, /\.stories\.js$/), module); -------------------------------------------------------------------------------- /.storybook/theme.js: -------------------------------------------------------------------------------- 1 | const { 2 | create 3 | } = require('@storybook/theming/create') 4 | 5 | module.exports = create({ 6 | base: 'light', 7 | 8 | colorPrimary: 'hotpink', 9 | colorSecondary: 'deepskyblue', 10 | 11 | // UI 12 | appBg: 'white', 13 | appContentBg: 'silver', 14 | appBorderColor: 'grey', 15 | appBorderRadius: 4, 16 | 17 | // Typography 18 | fontBase: '"Open Sans", sans-serif', 19 | fontCode: 'monospace', 20 | 21 | // Text colors 22 | textColor: 'black', 23 | textInverseColor: 'rgba(255,255,255,0.9)', 24 | 25 | // Toolbar default and active colors 26 | barTextColor: 'silver', 27 | barSelectedColor: 'black', 28 | barBg: 'hotpink', 29 | 30 | // Form colors 31 | inputBg: 'white', 32 | inputBorder: 'silver', 33 | inputTextColor: 'black', 34 | inputBorderRadius: 4, 35 | 36 | brandTitle: 'Vue Essential Slices', 37 | brandUrl: 'https://github.com/prismicio/vue-essential-slices', 38 | brandImage: 'data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHdpZHRoPSIxNDAiIGhlaWdodD0iMzYiPgogIDxwYXRoIGZpbGw9IiMyMTI3MzUiIGZpbGwtcnVsZT0iZXZlbm9kZCIgZD0iTTM1LjUzOCAxOC43NGwtMi42NTUtMi42NmExLjEyNiAxLjEyNiAwIDAgMS0uMzI5LS43OTZ2LTMuMjU2YzAtMy4wMDktLjMxMy00LjEtLjktNS4yYTYuMTI3IDYuMTI3IDAgMCAwLTIuNTQ2LTIuNTUxYy0xLjA5Ny0uNTg5LTIuMTg2LS45MDItNS4xODgtLjkwMmgtNC4yOTVhLjIyNS4yMjUgMCAwIDEtLjE1OC0uMzg0TDIyLjEyMi4zM2MuMjEtLjIxMS40OTYtLjMzLjc5NC0uMzNoMS40OTNjNC4wMDMgMCA1LjQ1NS40MTggNi45MTkgMS4yMDJhOC4xNjkgOC4xNjkgMCAwIDEgMy4zOTQgMy40MDJjLjc4MyAxLjQ2NyAxLjIgMi45MjIgMS4yIDYuOTMzdjcuMDQ1YS4yMjUuMjI1IDAgMCAxLS4zODQuMTU5ek0xNy4yMjIgMzUuNjE3bDIuNjU1LTIuNjYxYy4yMS0uMjExLjQ5Ni0uMzMuNzk0LS4zM2gzLjI0OWMzLjAwMiAwIDQuMDktLjMxMyA1LjE4OC0uOTAyYTYuMTI3IDYuMTI3IDAgMCAwIDIuNTQ2LTIuNTUxYy41ODctMS4xLjktMi4xOTEuOS01LjJ2LTQuMzA0YS4yMjUuMjI1IDAgMCAxIC4zODMtLjE1OWwyLjY1NiAyLjY2MWMuMjEuMjExLjMyOS40OTguMzI5Ljc5NnYxLjQ5N2MwIDQuMDExLS40MTcgNS40NjYtMS4yIDYuOTMzYTguMTY5IDguMTY5IDAgMCAxLTMuMzk0IDMuNDAyQzI5Ljg2NCAzNS41ODIgMjguNDEyIDM2IDI0LjQwOSAzNkgxNy4zOGEuMjI1LjIyNSAwIDAgMS0uMTU4LS4zODR6TS4zODMgMTcuMjU5TDMuMDQgMTkuOTJjLjIxLjIxMS4zMjkuNDk4LjMyOS43OTZ2My4yNTZjMCAzLjAwOS4zMTIgNC4xLjkgNS4yYTYuMTI3IDYuMTI3IDAgMCAwIDIuNTQ1IDIuNTUxYzEuMDk4LjU4OSAyLjE4Ny45MDIgNS4xODkuOTAyaDQuMjk0YS4yMjUuMjI1IDAgMCAxIC4xNi4zODRsLTIuNjU3IDIuNjYxYy0uMjEuMjExLS40OTYuMzMtLjc5My4zM2gtMS40OTRjLTQuMDAzIDAtNS40NTQtLjQxOC02LjkxOC0xLjIwMkE4LjE2OSA4LjE2OSAwIDAgMSAxLjIgMzEuMzk2Qy40MTcgMjkuOTI5IDAgMjguNDc0IDAgMjQuNDYzdi03LjA0NWEuMjI1LjIyNSAwIDAgMSAuMzgzLS4xNTl6TTE2LjA0NSAzLjA0NWMtLjIxMS4yMTEtLjQ5Ni4zMy0uNzk0LjMzaC0zLjI0OWMtMy4wMDIgMC00LjA5MS4zMTMtNS4xODkuOTAyYTYuMTI3IDYuMTI3IDAgMCAwLTIuNTQ2IDIuNTUxYy0uNTg3IDEuMS0uOSAyLjE5MS0uOSA1LjJ2NC4zMDRhLjIyNS4yMjUgMCAwIDEtLjM4My4xNTlMLjMzIDEzLjgzQTEuMTI2IDEuMTI2IDAgMCAxIDAgMTMuMDM0di0xLjQ5N2MwLTQuMDExLjQxNy01LjQ2NiAxLjItNi45MzNhOC4xNjkgOC4xNjkgMCAwIDEgMy4zOTQtMy40MDJDNi4wNTguNDE4IDcuNTEgMCAxMS41MTIgMGg3LjAzYS4yMjUuMjI1IDAgMCAxIC4xNTguMzg0bC0yLjY1NSAyLjY2MXptMTMuODg0IDEwLjA5MWwtMy42Mi0zLjQ2OGMtLjI0LS4yNC0uNTItLjQxNC0uODE5LS41MjNBMi4yMzYgMi4yMzYgMCAwIDAgMjQuNjk2IDlIMTQuMDFhLjIyNS4yMjUgMCAwIDEtLjE1OS0uMzg0bDIuNjU5LTIuNjYyYy4yMS0uMjEuNDk1LS4zMjkuNzkzLS4zMjloOC41MTZjMi40OCAwIDQuNDkgMi4wMTUgNC40OSA0LjV2Mi44NDlhLjIyNS4yMjUgMCAwIDEtLjM4LjE2MnptLTcuMTE1IDE2Ljg2MWwzLjQ2LTMuNjI5Yy4yNC0uMjQuNDE0LS41Mi41MjMtLjgyYTIuMjUgMi4yNSAwIDAgMCAuMTQ0LS43OTV2LTEwLjcxYS4yMjUuMjI1IDAgMCAxIC4zODQtLjE1OWwyLjY1NiAyLjY2NGMuMjEuMjExLjMyOC40OTcuMzI4Ljc5NnY4LjUzNGMwIDIuNDg1LTIuMDEgNC41LTQuNDkgNC41aC0yLjg0M2EuMjI1LjIyNSAwIDAgMS0uMTYyLS4zOHpNNS45OTIgMjIuODY0bDMuNjIyIDMuNDY4Yy4yMzkuMjQuNTIuNDE0LjgxOC41MjMuMjQ2LjA5NC41MTQuMTQ1Ljc5NC4xNDVoMTAuNjg2YS4yMjUuMjI1IDAgMCAxIC4xNTguMzg0bC0yLjY1OCAyLjY2MmMtLjIxLjIxLS40OTYuMzI5LS43OTMuMzI5aC04LjUxNmE0LjQ5NSA0LjQ5NSAwIDAgMS00LjQ5LTQuNXYtMi44NDlhLjIyNS4yMjUgMCAwIDEgLjM4LS4xNjJ6bTcuMTE2LTE2Ljg1OWwtMy40NjEgMy42M2MtLjI0LjI0LS40MTMuNTItLjUyMi44MmEyLjI1IDIuMjUgMCAwIDAtLjE0NS43OTV2MTAuNzFhLjIyNS4yMjUgMCAwIDEtLjM4My4xNThsLTIuNjU2LTIuNjY0YTEuMTI2IDEuMTI2IDAgMCAxLS4zMjgtLjc5NXYtOC41MzRjMC0yLjQ4NSAyLjAxLTQuNSA0LjQ5LTQuNWgyLjg0M2EuMjI1LjIyNSAwIDAgMSAuMTYyLjM4em0zMy4xMDUgNC4zNzloLjg2OGMuNTkzIDAgMS4wNzQuNDggMS4wNzQgMS4wNzR2MS4wMTZjMCAuMDMyLjAyNi4wNTcuMDU3LjA1Ny40OTUtLjg3NSAxLjE2LTEuNTEgMS45OTgtMS45MDlhNi4yMzYgNi4yMzYgMCAwIDEgMi43MS0uNTk2YzEuMDQ3IDAgMS45ODkuMTk0IDIuODI2LjU4Mi44MzcuMzg3IDEuNTUuOTIgMi4xNCAxLjU5NWE2Ljg5NiA2Ljg5NiAwIDAgMSAxLjM0IDIuMzg2Yy4zMDUuOTE1LjQ1NyAxLjkuNDU3IDIuOTUzYTguNzk1IDguNzk1IDAgMCAxLS40ODUgMi45NTMgNy40MTggNy40MTggMCAwIDEtMS4zNTUgMi4zODYgNi4yNjkgNi4yNjkgMCAwIDEtMi4wOTcgMS41OTUgNi4xODIgNi4xODIgMCAwIDEtMi42ODMuNTgyYy0uNjQ3IDAtMS4yMTctLjA3LTEuNzEyLS4yMDlhNS43NTEgNS43NTEgMCAwIDEtMS4zMTItLjUzNyA1LjI1MiA1LjI1MiAwIDAgMS0uOTctLjcgNS4wMTIgNS4wMTIgMCAwIDEtLjY1Ny0uNzMxLjA4Ni4wODYgMCAwIDAtLjA4Ni4wODV2Ny4yMjRhMS4zMSAxLjMxIDAgMCAxLTEuMzEgMS4zMWgtLjgwM2ExLjMxIDEuMzEgMCAwIDEtMS4zMS0xLjMxVjExLjY5NGMwLS43MjMuNTg2LTEuMzEgMS4zMS0xLjMxem0xMC4wNDYgNy4xNThjMC0uNTU3LS4wOS0xLjA5NC0uMjctMS42MWE0LjA3OCA0LjA3OCAwIDAgMC0uOC0xLjM3MyAzLjk5IDMuOTkgMCAwIDAtMS4yNy0uOTU0Yy0uNDk0LS4yMzktMS4wNTUtLjM1OC0xLjY4My0uMzU4LS42MjggMC0xLjE5LjEyLTEuNjg0LjM1OGEzLjk5IDMuOTkgMCAwIDAtMS4yNy45NTQgNC4wNzggNC4wNzggMCAwIDAtLjc5OSAxLjM3MiA0Ljg0NSA0Ljg0NSAwIDAgMC0uMjcgMS42MWMwIC41NTguMDkgMS4wOTQuMjcgMS42MTEuMTgxLjUxNy40NDcuOTc1LjggMS4zNzJhMy45OSAzLjk5IDAgMCAwIDEuMjcuOTU1Yy40OTQuMjM4IDEuMDU1LjM1OCAxLjY4My4zNTguNjI4IDAgMS4xODktLjEyIDEuNjgzLS4zNThhMy45OSAzLjk5IDAgMCAwIDEuMjctLjk1NWMuMzUyLS4zOTcuNjE4LS44NTUuOC0xLjM3Mi4xOC0uNTE3LjI3LTEuMDUzLjI3LTEuNjF6bTguMzU5LTcuMTU4aC45OGMuNjI2IDAgMS4xMzQuNTA3IDEuMTM0IDEuMTMzdjEuMDc3YzAgLjAzMS4wMjUuMDU3LjA1Ny4wNTcuMzgtLjgzNi45MjItMS40ODIgMS42MjYtMS45MzkuNzA0LS40NTcgMS41MTMtLjY4NiAyLjQyNi0uNjg2LjIwOSAwIC40MTQuMDIuNjEzLjA2YS43NjIuNzYyIDAgMCAxIC42MTQuNzQ3djEuOTY0YS43MTUuNzE1IDAgMCAxLS44NDIuNzA0IDQuNTggNC41OCAwIDAgMC0uODEzLS4wNzVjLS44IDAtMS40NDEuMTU0LTEuOTI2LjQ2Mi0uNDg1LjMwOS0uODU2LjY2MS0xLjExMyAxLjA2YTMuNiAzLjYgMCAwIDAtLjUxNCAxLjE5MmMtLjA4Ni4zOTgtLjEyOC42OTYtLjEyOC44OTV2Ni4zNTVhMS4zMSAxLjMxIDAgMCAxLTEuMzEgMS4zMWgtLjgwNGExLjMxIDEuMzEgMCAwIDEtMS4zMS0xLjMxVjExLjY5NGMwLS43MjMuNTg2LTEuMzEgMS4zMS0xLjMxem0xMS41ODUgMGguODA0Yy43MjMgMCAxLjMxLjU4NyAxLjMxIDEuMzFWMjMuMzlhMS4zMSAxLjMxIDAgMCAxLTEuMzEgMS4zMWgtLjgwNGExLjMxIDEuMzEgMCAwIDEtMS4zMS0xLjMxVjExLjY5NGMwLS43MjMuNTg2LTEuMzEgMS4zMS0xLjMxem0tMS43OTUtNC44NjJjMC0uNTc2LjIwNC0xLjA3OC42MTMtMS41MDYuNDEtLjQyNy45MjgtLjY0MSAxLjU1NS0uNjQxLjYyOCAwIDEuMTU2LjIwNCAxLjU4NC42MTEuNDI4LjQwOC42NDIuOTIuNjQyIDEuNTM2IDAgLjYxNy0uMjE0IDEuMTI5LS42NDIgMS41MzYtLjQyOC40MDgtLjk1Ni42MTItMS41ODQuNjEyLS42MjcgMC0xLjE0Ni0uMjE0LTEuNTU1LS42NDFhMi4xMDggMi4xMDggMCAwIDEtLjYxMy0xLjUwN3ptMTQuNzUzIDguMTMzYy0uNjk1LS41MS0xLjMxNC0uNzY2LTEuODU1LS43NjYtLjQ1NyAwLS45MDQuMTItMS4zNDIuMzU4LS40MzcuMjM5LS42NTYuNjI2LS42NTYgMS4xNjMgMCAuNDM4LjE4Ljc1Ni41NDIuOTU1LjM2Mi4xOTguODE4LjM2OCAxLjM3LjUwNy41NTIuMTM5IDEuMTQ2LjI4MyAxLjc4My40MzIuNjM4LjE1IDEuMjMyLjM3OCAxLjc4NC42ODYuNTUyLjMwOCAxLjAwOC43MyAxLjM3IDEuMjY4LjM2MS41MzcuNTQyIDEuMjcyLjU0MiAyLjIwNyAwIC44NTUtLjE3NiAxLjU3NS0uNTI4IDIuMTYyYTQuMjQxIDQuMjQxIDAgMCAxLTEuMzcgMS40MTcgNS45MjcgNS45MjcgMCAwIDEtMS44OTcuNzc1IDkuNTUzIDkuNTUzIDAgMCAxLTIuMTEyLjIzOWMtMS4wNjUgMC0yLjA0NS0uMTYtMi45NC0uNDc3LS4zNS0uMTI1LS43Ny0uMzc1LTEuMjYtLjc1MWExLjMxIDEuMzEgMCAwIDEtLjExOS0xLjk3NmwuMzU1LS4zNDhhMS4zMSAxLjMxIDAgMCAxIDEuNzgzLS4wNDhjLjIwOC4xODMuMzg4LjMyNC41NC40MjMuNTA0LjMyOSAxLjExOC40OTMgMS44NC40OTMuMjQ4IDAgLjUwNS0uMDMuNzcxLS4wOS4yNjctLjA2LjUxNC0uMTU5Ljc0Mi0uMjk4LjIyOC0uMTQuNDE0LS4zMTMuNTU3LS41MjIuMTQyLS4yMDkuMjE0LS40NTIuMjE0LS43MyAwLS40OTgtLjE4MS0uODY2LS41NDMtMS4xMDQtLjM2MS0uMjM5LS44MTgtLjQzMy0xLjM3LS41ODJhMjguNzQ2IDI4Ljc0NiAwIDAgMC0xLjc4My0uNDE3IDYuNzA3IDYuNzA3IDAgMCAxLTEuNzgzLS42MjcgMy43OTUgMy43OTUgMCAwIDEtMS4zNy0xLjIwOGMtLjM2MS0uNTE3LS41NDItMS4yMzMtLjU0Mi0yLjE0NyAwLS43OTUuMTU3LTEuNDg2LjQ3LTIuMDczYTQuMjY1IDQuMjY1IDAgMCAxIDEuMjQyLTEuNDQ2IDUuMjU2IDUuMjU2IDAgMCAxIDEuNzctLjgzNiA3Ljc3MyA3Ljc3MyAwIDAgMSAyLjAyNS0uMjY4Yy45MTMgMCAxLjgxNy4xNjQgMi43MTEuNDkyLjMyNC4xMTkuNjg1LjMzOSAxLjA4NC42NmExLjMxIDEuMzEgMCAwIDEgLjA3NSAxLjk3NWwtLjQyNi40MDFhMS4zMSAxLjMxIDAgMCAxLTEuNjc0LjEwMXptNy43ODctMy4yNzFoLjYzM2MuNzIzIDAgMS4zMS41ODcgMS4zMSAxLjMxdi45MjdhNS42MDIgNS42MDIgMCAwIDEgMS41MjctMS44MDVjLjY3NS0uNTI3IDEuNTgzLS43OSAyLjcyNS0uNzkgMi4xNSAwIDMuNTc2Ljg4NSA0LjI4IDIuNjU0LjQ5NS0uOTE0IDEuMTEzLTEuNTg1IDEuODU1LTIuMDEzLjc0Mi0uNDI3IDEuNjI2LS42NDEgMi42NTQtLjY0MS45MTMgMCAxLjY4My4xNTkgMi4zMTEuNDc3YTQuMDg0IDQuMDg0IDAgMCAxIDEuNTI3IDEuMzEyYy4zOS41NTcuNjcgMS4yMDguODQxIDEuOTU0LjE3Mi43NDYuMjU3IDEuNTQ2LjI1NyAyLjR2Ny4yMmExLjMxIDEuMzEgMCAwIDEtMS4zMSAxLjMxaC0uODA0YTEuMzEgMS4zMSAwIDAgMS0xLjMxLTEuMzF2LTYuODAyYzAtLjQzNy0uMDM4LS44Ni0uMTE0LTEuMjY3YTMuMTExIDMuMTExIDAgMCAwLS40LTEuMDc0IDIuMDYyIDIuMDYyIDAgMCAwLS43Ny0uNzNjLS4zMjQtLjE4LS43NDItLjI2OS0xLjI1Ni0uMjY5LS41MzIgMC0uOTg0LjEwNC0xLjM1NS4zMTNhMi42ODYgMi42ODYgMCAwIDAtLjkxMy44MzUgMy41MDggMy41MDggMCAwIDAtLjUxNCAxLjE5MyA1Ljk0IDUuOTQgMCAwIDAtLjE1NyAxLjM1N3Y2LjQ0NWExLjMxIDEuMzEgMCAwIDEtMS4zMSAxLjMxaC0uODA0YTEuMzEgMS4zMSAwIDAgMS0xLjMxLTEuMzF2LTcuMjJjMC0uODk1LS4xOC0xLjYwNi0uNTQyLTIuMTMzLS4zNjItLjUyNi0uOTYtLjc5LTEuNzk4LS43OS0uNTcgMC0xLjA1MS4xLTEuNDQxLjI5OC0uMzkuMi0uNzEzLjQ2OC0uOTcuODA2YTMuMjYgMy4yNiAwIDAgMC0uNTU3IDEuMTYzIDUuNDEzIDUuNDEzIDAgMCAwLS4xNyAxLjM3MnY2LjUwNGExLjMxIDEuMzEgMCAwIDEtMS4zMTEgMS4zMWgtLjgwNGExLjMxIDEuMzEgMCAwIDEtMS4zMS0xLjMxVjExLjY5NGMwLS43MjMuNTg3LTEuMzEgMS4zMS0xLjMxem0yNS40NTQgMGguODAzYy43MjQgMCAxLjMxLjU4NyAxLjMxIDEuMzFWMjMuMzlhMS4zMSAxLjMxIDAgMCAxLTEuMzEgMS4zMWgtLjgwM2ExLjMxIDEuMzEgMCAwIDEtMS4zMS0xLjMxVjExLjY5NGMwLS43MjMuNTg2LTEuMzEgMS4zMS0xLjMxem0tMS43OTYtNC44NjJjMC0uNTc2LjIwNS0xLjA3OC42MTQtMS41MDYuNDA5LS40MjcuOTI3LS42NDEgMS41NTUtLjY0MS42MjggMCAxLjE1Ni4yMDQgMS41ODQuNjExLjQyOC40MDguNjQyLjkyLjY0MiAxLjUzNiAwIC42MTctLjIxNCAxLjEyOS0uNjQyIDEuNTM2LS40MjguNDA4LS45NTYuNjEyLTEuNTg0LjYxMi0uNjI4IDAtMS4xNDYtLjIxNC0xLjU1NS0uNjQxYTIuMTA4IDIuMTA4IDAgMCAxLS42MTQtMS41MDd6bTE2Ljc1MSA4LjM3M2EzLjU2NCAzLjU2NCAwIDAgMC0uMzcxLS4yNiAyLjYwNyAyLjYwNyAwIDAgMC0xLjM0Mi0uMzg4Yy0uNjI3IDAtMS4xODkuMTItMS42ODMuMzU4YTMuOTkgMy45OSAwIDAgMC0xLjI3Ljk1NCA0LjA3OCA0LjA3OCAwIDAgMC0uNzk5IDEuMzcyIDQuODQ1IDQuODQ1IDAgMCAwLS4yNzEgMS42MWMwIC41NTguMDkgMS4wOTQuMjcxIDEuNjExLjE4LjUxNy40NDcuOTc1LjggMS4zNzJhMy45OSAzLjk5IDAgMCAwIDEuMjY5Ljk1NWMuNDk0LjIzOCAxLjA1Ni4zNTggMS42ODMuMzU4LjUzMyAwIDEuMDI4LS4xMTUgMS40ODQtLjM0My4wOTMtLjA0Ny4xOTMtLjExLjMtLjE4OWExLjMxIDEuMzEgMCAwIDEgMS43NTYuMTg1bC41Mi41ODRhMS4yNDggMS4yNDggMCAwIDEtLjMwNyAxLjkxIDcuOTggNy45OCAwIDAgMS0yLjY2OC45N2MtLjQxOS4wNjktLjc4LjEwNC0xLjA4NS4xMDRhNy45MDQgNy45MDQgMCAwIDEtMi45MS0uNTM3QTYuOTM4IDYuOTM4IDAgMCAxIDEzMC4zNjUgMjNhNy4yMyA3LjIzIDAgMCAxLTEuNTgzLTIuMzcxYy0uMzktLjkyNS0uNTg1LTEuOTU0LS41ODUtMy4wODcgMC0xLjEzMy4xOTUtMi4xNjIuNTg1LTMuMDg3YTcuMjMgNy4yMyAwIDAgMSAxLjU4My0yLjM3MSA2LjkzOCA2LjkzOCAwIDAgMSAyLjM2OS0xLjUyMSA3LjkwNCA3LjkwNCAwIDAgMSAyLjkxLS41MzdjLjg3NiAwIDEuNzU1LjE3NCAyLjY0LjUyMi4zMzcuMTMzLjczNS4zNyAxLjE5My43MTFhMS4zMSAxLjMxIDAgMCAxIC4xNjQgMS45NTdsLS41My41NTNhMS4zMSAxLjMxIDAgMCAxLTEuNzU0LjEyNnoiLz4KPC9zdmc+', 39 | }); -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Vue Essential Slices 2 | 3 | A set of responsive, accessible, and customizable website sections (think Hero, Faq...), 4 | connected to a ([Prismic.io](https://prismic.io)) backend. You most probably want to use this with [SliceMachine](https://slicemachine.dev)! 5 | 6 | Components can be viewed on our Storybook: https://vue-essential-slices.netlify.com. 7 | 8 | ## Getting started (WIP) 9 | 10 | The easiest way to get started with vue-essential-slices is to follow the [Getting started](https://www.slicemachine.dev/documentation/getting-started) of SliceMachine: 11 | 12 | ```bash 13 | npx create-nuxt-app my-app && cd my-app; 14 | npx prismic-cli sm --setup; 15 | ```` 16 | 👆 Because vue-essential-slices is the default library of SliceMachine, Your project should now be configured to use it. Your next step would be to declare a `slice-zone` in one of your pages: 17 | 18 | ```javascript 19 | 25 | 34 | ```` 35 | If you've correctly setup a SliceMachine project and created a page of uid "homepage" on your Prismic writing room, your page should now render a full landing page. If you're unsure why or how this works, please refer to SliceMachien documentation or refer to the [sliceZone README](https://github.com/prismicio/sm-commons/tree/master/packages/vue-slicezone) ✌️ 36 | 37 | ## Manual use 38 | 39 | At the moment of writing, manual installation is not advised, as Prismic does not offer a simple way to update Slice models to your own Prismic writing room. But if you want to get a better understanding of what the Prismic CLI does for you, this is how you could manually install these slices: 40 | 41 | #### 1/ Create a custom type on Prismic 42 | 1/ Create a repeatable Custom Type of type "Page" in your Prismic writing room. Then click on "Add a SliceZone". The JSON viewer should show you an empty "choices" object there. 43 | 44 | #### 2/ Copy-paste the slices models 45 | Open our `sm.json` file and find the "slices" key. Copy-paste this part of the file (the object inside the "slice" key, without the key itself) and copy-paste it inside the "choices" object of the JSON viewer. 46 | 47 | #### 3/ Create a first page on Prismic 48 | The UI should now display all the slices forms. Now, go to your Prismic documents, create a first page, and give it a uid "homepage". 49 | 50 | #### 4/ Create a first page in Nuxt 51 | Now, run `yarn add vue-slicezone vue-essential-slices`, create a first page in Nuxt and query your Prismic API: 52 | 53 | ```javascript 54 | 57 | 58 | 77 | ```` 78 | 79 | 👆 If you've configured everything correctly, congrats! 80 | Otherwise, hit the forum: https://community.prismic.io 81 | 82 | ### CSS variables 83 | 84 | The library comes with some stylesheets that are automatically added to your Nuxt config file, when bootstrapping a project from the command line. You can find the full list of variables [in this CSS file](https://github.com/prismicio/vue-essential-slices/blob/master/src/styles/_settings.scss). WIP: for component, we will soon describe which CSS variables are available and how they affect the design. 85 | 86 | ### Theme prop (wip) 87 | 88 | Each slice also takes an optional `theme` prop as argument. Inspired by css-in-js solutions like Emotion, it's meant to provide a quick access to deeply-nested style properties. We are currently on the path to unify defined properties, across various SliceMachine libraries. 89 | 90 | At the moment, these theme properties should be available for all components: 91 | 92 | - `align`, which defines the alignement of the text in the section 93 | - `color`, which defines the text color of the section 94 | - `wrapper`, an arbitrary object bound to the wrapper component of each slice 95 | - `title`, object passed to titles in the section, of accepted keys `align`, `color` and `background` 96 | - `description`, object passed to descriptions in the section, of accepted keys `align`, `color` and `background` 97 | - `eyebrow`, object passed to eyebrow headines in the section, of accepted keys `align`, `color` and `background` 98 | 99 | For example, this is how you would use the theme prop in a SliceMachine project: 100 | 101 | ```javascript 102 | 105 | 106 | 136 | ```` 137 | 138 | 👆 We'll soon document which theme properties are available to each component, and how these properties affect the design. 139 | 140 | ## Project structure 141 | In order for a folder to become an actual SliceMachine library, it needs to follow a certain sctructure, that may be accomodated to your requirements but still follows some conditions: 142 | 143 | ```bash 144 | Starter structure: 145 | ├── .storybook # Design guide config 146 | ├── slices # actual components 147 | │ ├── ComponentName # see "slices" section 148 | │ ├── ... 149 | ├── index.js # exports * from './slices' 150 | ├── sm.json # auto-generated, see "bundling" section 151 | ├── sm.config.json # SliceMachine config 152 | 153 | ``` 154 | #### 1 - slices 155 | What we call slices are **website sections linked to a Prismic backend**. Basically, you can see them as front-end components that contain a schema (or database definition) to tell Prismic how to create an editor that matches their own state. 156 | 157 | Each SM project should contain a non-empty `slices` folder. Each of its subfolder being treated as Slice components by SliceMachine. For this reason they need to be: 158 | - PascalCased (minimum 2 words starting with capital letters) 159 | - an `index.[js|ts|vue]` file (the actual component) 160 | - a `model.json` file, that contains the **slice definition** 161 | - a `mock.json` file, that contains a valid API response 162 | - a `preview.png` file, that displays the preview of the component 163 | 164 | ⚠️ Because this can become overwhelming for library creators, we are thinking about solutions to help you in the process. Fell free to raise an issue if something comes to your mind to solve this with us! 165 | 166 | #### 2 - sm.config.json 167 | A configuration file that helps SliceMachine bundle script understand how it should build the library. 168 | 169 | ```json 170 | { 171 | "libraryName": "Vue essentials", 172 | "framework": "nuxt", 173 | "gitUrl": "//github.com/prismicio/vue-essential-slices", 174 | "pathToLibrary": "src", 175 | "dependencies": [], 176 | "css": ["vue-essential-slices/src/styles/styles.scss"], 177 | "script": [{ 178 | "src": "https://cdn.polyfill.io/v2/polyfill.min.js?features=Element.prototype.classList" 179 | }, { 180 | "src": "https://cdn.jsdelivr.net/npm/focus-visible@5.0.2/dist/focus-visible.min.js" 181 | }], 182 | "devDependencies": ["node-sass", "sass-loader"] 183 | } 184 | ```` 185 | `libraryName`, `framework`and `gitUrl` are mandatory. Other info (like `pathToLibrary`) helps SliceMachine bundler to find your slice definitions. `dependencies`, `css`, `script` and `devDependencies` being information picked up by SliceMachine CLI to kickstart a project. 186 | 187 | Most of the time, you would be fine with this: 188 | 189 | ```json 190 | { 191 | "libraryName": "Name of your Lib", 192 | "framework": "nuxt|next", 193 | "gitUrl": "...", 194 | "pathToLibrary": "src" 195 | } 196 | ```` 197 | 198 | ## Bundling 199 | 200 | Everytime you publish your library on NPM, Prismic servers download your library definition file. This definition file is what the writing room uses to select/preview your slices. In order to generate a valid JSON definition for your library, add our `sm-commons` development package and run its bundle script everytime you want to publish a new version of your library: 201 | 202 | ```bash 203 | npm i --save-dev sm-commons 204 | ```` 205 | 206 | Then, add this script line to your package.json file : 207 | 208 | ```json 209 | "scripts": { 210 | "bundle": "node ./node_modules/sm-commons/scripts/bundle" 211 | } 212 | ```` 213 | 👆 This script is in active development and subject to lots of change. Make sure you update it as often as possible. A lot of effort will be made to help you understand if and why a folder structure is considered invalid. Feel free [to read the script](https://github.com/prismicio/sm-commons/blob/master/packages/sm-commons/scripts/bundle.js) of course, it's really simple atm. 214 | 215 | Here is the structure of our actual SM definition file: 216 | 217 | ```json 218 | { 219 | "libraryName":"Vue essentials", 220 | "framework":"nuxt", 221 | "packageName":"vue-essential-slices", 222 | "gitUrl":"//github.com/prismicio/vue-essential-slices", 223 | "pathToLibrary":"src", 224 | "dependencies":[], 225 | "css":["vue-essential-slices/src/styles/styles.scss"], 226 | "package": {}, 227 | "slices": { "call_to_action": {} } 228 | 229 | ```` 230 | 231 | ### Styling your components 232 | 233 | To be discussed. 234 | 235 | ### Resources 236 | 237 | - [StoryBook](https://storybook.js.org/) 238 | - [SliceMachine packages](https://github.com/prismicio/sm-commons) (including sm-commons and sm-api) 239 | - [components](https://front-end--prismic-sm.netlify.com/components/detail/call-to-action.html) 240 | 241 | -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | base = "/" 3 | command = "npm run build-storybook" 4 | publish = "storybook-static" -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "vue-essential-slices", 3 | "version": "0.3.0", 4 | "description": "A set of professionally made, accessible Vue components, linked to a (Prismic) backend", 5 | "main": "src/index.js", 6 | "scripts": { 7 | "dev": "start-storybook", 8 | "test": "echo \"Error: no test specified\" && exit 1", 9 | "build-storybook": "build-storybook", 10 | "prepack": "yarn bundle", 11 | "bundle": "node ./node_modules/sm-commons/scripts/bundle", 12 | "storybook": "start-storybook -p 6006" 13 | }, 14 | "pre-commit": [ 15 | "bundle" 16 | ], 17 | "repository": { 18 | "type": "git", 19 | "url": "git+https://github.com/prismicio/vue-essential-slices.git" 20 | }, 21 | "keywords": [ 22 | "Nuxtjs", 23 | "Vuejs", 24 | "Prismic", 25 | "slices" 26 | ], 27 | "author": "", 28 | "license": "GPL-3.0-or-later", 29 | "bugs": { 30 | "url": "https://github.com/prismicio/vue-essential-slices/issues" 31 | }, 32 | "homepage": "https://github.com/prismicio/vue-essential-slices#readme", 33 | "devDependencies": { 34 | "@babel/core": "^7.9.6", 35 | "@prismicio/vue": "^2.0.2", 36 | "@storybook/addon-actions": "^5.3.18", 37 | "@storybook/addon-docs": "^5.3.19", 38 | "@storybook/addon-knobs": "^5.3.18", 39 | "@storybook/addon-links": "^5.3.18", 40 | "@storybook/addons": "^5.3.18", 41 | "@storybook/source-loader": "^5.3.19", 42 | "@storybook/vue": "^5.3.18", 43 | "@vue/babel-preset-app": "^4.2.3", 44 | "@vue/component-compiler-utils": "^3.1.1", 45 | "babel-loader": "^8.0.6", 46 | "babel-preset-vue": "^2.0.2", 47 | "node-sass": "^4.14.1", 48 | "pre-commit": "^1.2.2", 49 | "prismic-dom": "^2.1.0", 50 | "prismic-javascript": "^2.1.5", 51 | "sass-loader": "^8.0.2", 52 | "sm-commons": "^0.0.23", 53 | "vue": "^2.6.11", 54 | "vue-hot-reload-api": "^2.3.4", 55 | "vue-loader": "^15.9.2", 56 | "vue-slicezone": "^0.0.25", 57 | "vue-template-compiler": "^2.6.11" 58 | }, 59 | "dependencies": {} 60 | } -------------------------------------------------------------------------------- /sm.config.json: -------------------------------------------------------------------------------- 1 | { 2 | "libraryName": "Vue essentials", 3 | "framework": "nuxt", 4 | "gitUrl": "//github.com/prismicio/vue-essential-slices", 5 | "pathToLibrary": "src", 6 | "dependencies": [], 7 | "css": ["vue-essential-slices/src/styles/styles.scss"], 8 | "script": [{ 9 | "src": "https://cdn.polyfill.io/v2/polyfill.min.js?features=Element.prototype.classList" 10 | }, { 11 | "src": "https://cdn.jsdelivr.net/npm/focus-visible@5.0.2/dist/focus-visible.min.js" 12 | }], 13 | "devDependencies": ["sass@1.32.7", "sass-loader@10.1.1"] 14 | } -------------------------------------------------------------------------------- /sm.json: -------------------------------------------------------------------------------- 1 | {"libraryName":"Vue essentials","framework":"nuxt","gitUrl":"//github.com/prismicio/vue-essential-slices","pathToLibrary":"src","dependencies":[],"css":["vue-essential-slices/src/styles/styles.scss"],"script":[{"src":"https://cdn.polyfill.io/v2/polyfill.min.js?features=Element.prototype.classList"},{"src":"https://cdn.jsdelivr.net/npm/focus-visible@5.0.2/dist/focus-visible.min.js"}],"devDependencies":["sass@1.32.7","sass-loader@10.1.1"],"packageName":"vue-essential-slices","package":{"name":"vue-essential-slices","version":"0.3.0","description":"A set of professionally made, accessible Vue components, linked to a (Prismic) backend","main":"src/index.js","scripts":{"dev":"start-storybook","test":"echo \"Error: no test specified\" && exit 1","build-storybook":"build-storybook","prepack":"yarn bundle","bundle":"node ./node_modules/sm-commons/scripts/bundle","storybook":"start-storybook -p 6006"},"pre-commit":["bundle"],"repository":{"type":"git","url":"git+https://github.com/prismicio/vue-essential-slices.git"},"keywords":["Nuxtjs","Vuejs","Prismic","slices"],"author":"","license":"GPL-3.0-or-later","bugs":{"url":"https://github.com/prismicio/vue-essential-slices/issues"},"homepage":"https://github.com/prismicio/vue-essential-slices#readme","devDependencies":{"@babel/core":"^7.9.6","@prismicio/vue":"^2.0.2","@storybook/addon-actions":"^5.3.18","@storybook/addon-docs":"^5.3.19","@storybook/addon-knobs":"^5.3.18","@storybook/addon-links":"^5.3.18","@storybook/addons":"^5.3.18","@storybook/source-loader":"^5.3.19","@storybook/vue":"^5.3.18","@vue/babel-preset-app":"^4.2.3","@vue/component-compiler-utils":"^3.1.1","babel-loader":"^8.0.6","babel-preset-vue":"^2.0.2","node-sass":"^4.14.1","pre-commit":"^1.2.2","prismic-dom":"^2.1.0","prismic-javascript":"^2.1.5","sass-loader":"^8.0.2","sm-commons":"^0.0.23","vue":"^2.6.11","vue-hot-reload-api":"^2.3.4","vue-loader":"^15.9.2","vue-slicezone":"^0.0.25","vue-template-compiler":"^2.6.11"},"dependencies":{}},"slices":{"alternate_grid":{"type":"Slice","fieldset":"AlternateGrid","description":"A predesigned Text Grid with Image left or right","icon":"wrap_text","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Eyebrow headline"}},"title":{"type":"StructuredText","config":{"single":"heading1, heading2, heading3, heading4, heading5, heading6","label":"title"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"description"}},"optional_image":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Optional image"}},"image_side":{"type":"Select","config":{"options":["left","right"],"default_value":"left","label":"Image side"}}},"repeat":{"optional_icon":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Optional Icon"}},"title":{"type":"StructuredText","config":{"single":"heading3","label":"title"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"description"}}}},"call_to_action":{"type":"Slice","fieldset":"Call to action","description":"A predesigned 'Call to action' for section for your site","icon":"notifications_active","display":"list","non-repeat":{"icon_image":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Icon Image"}},"title":{"type":"StructuredText","config":{"single":"heading1, heading2, heading3, heading4, heading5, heading6","label":"Title"}},"paragraph":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","label":"Paragraph"}},"button_link":{"type":"Link","config":{"label":"Button Link"}},"button_label":{"type":"Text","config":{"label":"Button Label","placeholder":"Text for button"}}},"repeat":{}},"cards_carousel":{"type":"Slice","fieldset":"Cards Carousel","description":"A carousel with text + image cards","icon":"image","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Eyebrow headline"}},"title":{"type":"StructuredText","config":{"single":"heading1, heading2, heading3, heading4, heading5, heading6","label":"Title"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Description"}}},"repeat":{"image":{"type":"Image","config":{"constraint":{"width":null,"height":null},"thumbnails":[],"label":"Image"}},"title":{"type":"StructuredText","config":{"single":"heading3","label":"Title"}},"content":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Content"}},"additional_info":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading3, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Additional Info","placeholder":"eg. name of person in testimonial"}}}},"customer_logos":{"type":"Slice","fieldset":"Customer logos","description":"Display a list of your customers logos","icon":"person","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"single":"heading2","label":"Eyebrow Headline","placeholder":"Trusted by"}},"call_to_action":{"type":"StructuredText","config":{"single":"paragraph","label":"Call To Action","placeholder":"View customer stories"}},"call_to_action_link":{"type":"Link","config":{"allowTargetBlank":true,"label":"Call to Action Link","placeholder":"Could be a signup link, or a link to customer stories"}}},"repeat":{"logo":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Logo"}},"link":{"type":"Link","config":{"allowTargetBlank":true,"label":"link","placeholder":"Could be a link to use case, press article, signup..."}}}},"faq_section":{"type":"Slice","fieldset":"FAQ","description":"List of common questions + answers","icon":"question_answer","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"single":"paragraph","label":"Eyebrow headline","placeholder":"Reinforce your copy with a key-worded text, to be displayed before title"}},"title":{"type":"StructuredText","config":{"single":"heading2","label":"title","placeholder":"Title"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, strong, em, hyperlink","allowTargetBlank":true,"label":"Description"}},"optional_image":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Optional image"}}},"repeat":{"title":{"type":"StructuredText","config":{"single":"heading3","label":"Title","placeholder":"Which browsers do you support?"}},"text":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, strong, em, hyperlink, list-item, o-list-item","allowTargetBlank":true,"label":"Text","placeholder":"The answer to the question"}}}},"feature_testimonials":{"type":"Slice","fieldset":"Feature Testimonials","description":"Testimonial proving the value of a specific feature","icon":"ondemand_video","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"label":"Eyebrow headline","placeholder":"Reinforce your copy with a key-worded text, to be displayed before title","single":"paragraph"}},"title":{"type":"StructuredText","config":{"label":"Title","placeholder":"Our testimonial","single":"heading2"}},"description":{"type":"StructuredText","config":{"label":"Description","placeholder":"These are some awesome tutorials from our awesome clients ...","multi":"paragraph, strong, em, hyperlink","allowTargetBlank":true}},"feature_illustration":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"Feature Illustration"}}},"repeat":{"client_logo":{"type":"Image","config":{"constraint":{"width":100,"height":100},"thumbnails":[],"label":"Client logo"}},"profile_pic":{"type":"Image","config":{"constraint":{"width":80,"height":80},"thumbnails":[],"label":"Profile Pic"}},"quote":{"type":"StructuredText","config":{"multi":"paragraph","label":"Quote","placeholder":"Lorem ipsum dolor sit amet, ...."}},"name":{"type":"StructuredText","config":{"single":"paragraph","label":"Name","placeholder":"John McJohn"}},"role_position":{"type":"StructuredText","config":{"single":"paragraph","label":"Role position","placeholder":"Creative Director"}}}},"images_slider":{"type":"Slice","fieldset":"Images Slider","description":"A slider of full-width images + description","icon":"image","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Eyebrow headline"}},"title":{"type":"StructuredText","config":{"single":"heading1, heading2, heading3, heading4, heading5, heading6","label":"Title"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Description"}}},"repeat":{"image":{"type":"Image","config":{"constraint":{"width":null,"height":null},"thumbnails":[],"label":"Full Width Image"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Description"}}}},"pricing_table":{"type":"Slice","fieldset":"Pricing Table","description":"Display a list of pricing plans","icon":"attach_money","display":"grid","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"single":"paragraph","label":"Eyebrow Headline","placeholder":"Pricing plans"}},"title":{"type":"StructuredText","config":{"single":"heading2","label":"Title","placeholder":"Choose the plan"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, strong, em, hyperlink","allowTargetBlank":true,"label":"Description","placeholder":"Choose the version that works for you ..."}}},"repeat":{"plan_title":{"type":"StructuredText","config":{"single":"heading3","label":"Plan title","placeholder":"Simple, Gold, Premium..."}},"price_option":{"type":"StructuredText","config":{"multi":"heading4","label":"Price Option","placeholder":"Free, $19, Contact us..."}},"features":{"type":"StructuredText","config":{"multi":"list-item","label":"Features","placeholder":"A list of features using bullet list"}},"call_to_action":{"type":"Link","config":{"allowTargetBlank":true,"label":"Call To Action","placeholder":"Link to Signup / More info..."}},"call_to_action_text":{"type":"StructuredText","config":{"multi":"paragraph","label":"Call To Action Text","placeholder":"Start your free trial"}}}},"testimonials_slider":{"type":"Slice","fieldset":"Testimonials Slider","description":"A predesigned Slider with rich testimonial","icon":"notifications_active","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","allowTargetBlank":true,"label":"Eyebrow headline"}},"title":{"type":"StructuredText","config":{"single":"heading1, heading2, heading3, heading4, heading5, heading6","label":"Title"}},"paragraph":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","label":"Paragraph"}},"button_link":{"type":"Link","config":{"label":"Button Link"}},"button_label":{"type":"Text","config":{"label":"Button Label","placeholder":"Text for button"}}},"repeat":{"image":{"type":"Image","config":{"constraint":{},"thumbnails":[],"label":"image"}},"testimonial":{"type":"StructuredText","config":{"multi":"paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item","label":"testimonial"}},"person":{"type":"Text","config":{"label":"person","placeholder":"Their full name"}},"title":{"type":"Text","config":{"label":"title","placeholder":"Their title"}}}},"video_highlights":{"type":"Slice","fieldset":"Video Highlights","description":"Highlights of your video channel","icon":"ondemand_video","display":"list","non-repeat":{"eyebrow_headline":{"type":"StructuredText","config":{"single":"paragraph","label":"Eyebrow headline","placeholder":"Reinforce your copy with a key-worded text, to be displayed before title"}},"title":{"type":"StructuredText","config":{"single":"heading2","label":"Title","placeholder":"Video Highlights"}},"description":{"type":"StructuredText","config":{"multi":"paragraph, strong, em, hyperlink","allowTargetBlank":true,"label":"Description","placeholder":"These are some awesome videos ..."}}},"repeat":{"video_title":{"type":"StructuredText","config":{"multi":"paragraph, strong","label":"Video title","placeholder":"My awesome video"}},"video_src":{"type":"Embed","config":{"label":"Video src"}}}}}} -------------------------------------------------------------------------------- /src/Fetch.vue: -------------------------------------------------------------------------------- 1 | 6 | -------------------------------------------------------------------------------- /src/components/PsAccordion/index.vue: -------------------------------------------------------------------------------- 1 | 47 | 93 | 181 | -------------------------------------------------------------------------------- /src/components/PsButton/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/PsDescription/index.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/PsEyebrow/index.vue: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /src/components/PsSection/index.vue: -------------------------------------------------------------------------------- 1 | 10 | -------------------------------------------------------------------------------- /src/components/PsTitle/index.vue: -------------------------------------------------------------------------------- 1 | 8 | -------------------------------------------------------------------------------- /src/components/index.js: -------------------------------------------------------------------------------- 1 | export { default as PsAccordion } from './PsAccordion' 2 | export { default as PsButton } from './PsButton' 3 | export { default as PsDescription } from './PsDescription' 4 | export { default as PsEyebrow } from './PsEyebrow' 5 | export { default as PsSection } from './PsSection' 6 | export { default as PsSlider } from './PsSlider' 7 | export { default as PsTitle } from './PsTitle' -------------------------------------------------------------------------------- /src/index.js: -------------------------------------------------------------------------------- 1 | import './styles/styles.scss' 2 | 3 | export * from './slices' 4 | -------------------------------------------------------------------------------- /src/slices/AlternateGrid/index.stories.js: -------------------------------------------------------------------------------- 1 | import Fetch from '../../Fetch' 2 | 3 | import AlternateGrid from "./index.vue"; 4 | import mock from './mock.json' 5 | 6 | import { 7 | formatThemeProps 8 | } from 'vue-slicezone/theme.js' 9 | 10 | export const Default = () => ({ 11 | components: { 12 | AlternateGrid 13 | }, 14 | methods: { 15 | render() { 16 | return AlternateGrid 17 | } 18 | }, 19 | props: { 20 | slice: { 21 | type: Object, 22 | default() { 23 | return { 24 | ...mock, 25 | items: mock.items.map((e) => ({ ...e, optional_icon: null })) 26 | } 27 | } 28 | }, 29 | }, 30 | template: `` 31 | }); 32 | 33 | export const WithIcons = () => ({ 34 | components: { 35 | AlternateGrid, 36 | }, 37 | methods: { 38 | render() { 39 | return AlternateGrid 40 | } 41 | }, 42 | props: { 43 | slice: { 44 | type: Object, 45 | default() { 46 | return mock 47 | } 48 | }, 49 | }, 50 | template: `` 51 | }); 52 | 53 | export const NoImage = () => ({ 54 | components: { 55 | AlternateGrid 56 | }, 57 | props: { 58 | slice: { 59 | type: Object, 60 | default: { 61 | ...mock, 62 | primary: { 63 | ...mock.primary, 64 | optional_image: null 65 | } 66 | } 67 | }, 68 | }, 69 | template: `` 70 | }); 71 | 72 | export const WithCustomTheme = () => ({ 73 | components: { 74 | AlternateGrid, 75 | Fetch 76 | }, 77 | methods: { 78 | render() { 79 | return AlternateGrid 80 | } 81 | }, 82 | props: { 83 | slice: { 84 | type: Object, 85 | default: { 86 | ...mock, 87 | primary: { 88 | ...mock.primary, 89 | image_side: 'right' 90 | } 91 | } 92 | }, 93 | theme: { 94 | default () { 95 | return formatThemeProps({ 96 | align: 'left', 97 | button: { 98 | style: 'background: #FFF;color: #111' 99 | }, 100 | wrapper: { 101 | style: 'background: #F7F7F7' 102 | }, 103 | eyebrow: { 104 | color: 'tomato' 105 | }, 106 | item: { 107 | class: 'custom-class', 108 | style: 'background: #FFF; border: 1px solid #111;padding: 12px' 109 | } 110 | }, { 111 | i: 0 112 | }) 113 | } 114 | } 115 | }, 116 | template: `` 117 | }); 118 | 119 | export const WithCustomSpans = () => ({ 120 | components: { 121 | AlternateGrid 122 | }, 123 | methods: { 124 | render() { 125 | return AlternateGrid 126 | } 127 | }, 128 | props: { 129 | slice: { 130 | type: Object, 131 | default: { 132 | ...mock, 133 | primary: { 134 | ...mock.primary, 135 | image_side: 'right' 136 | } 137 | } 138 | }, 139 | theme: { 140 | default () { 141 | return formatThemeProps({ 142 | grid: { 143 | spans: ['1-2', '3-12'] 144 | } 145 | }) 146 | } 147 | } 148 | }, 149 | template: `` 150 | }); 151 | 152 | export default { 153 | title: "AlternateGrid", 154 | }; 155 | -------------------------------------------------------------------------------- /src/slices/AlternateGrid/index.vue: -------------------------------------------------------------------------------- 1 | 34 | -------------------------------------------------------------------------------- /src/slices/AlternateGrid/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "alternate_grid", 3 | "slice_label": null, 4 | "items": [{ 5 | "optional_icon": { 6 | "dimensions": { 7 | "width": 2048, 8 | "height": 1536 9 | }, 10 | "alt": null, 11 | "copyright": null, 12 | "url": "https://images.prismic.io/repoz/0b72eb6f-1824-4891-914a-c43fdee5b893_running.png?auto=compress,format" 13 | }, 14 | "title": [{ 15 | "type": "heading3", 16 | "text": "Integrate with the SliceZone", 17 | "spans": [] 18 | }], 19 | "description": [{ 20 | "type": "paragraph", 21 | "text": "This component has been matched by the SliceZone. Its model has been fetched from vue-essential-slices.", 22 | "spans": [] 23 | }] 24 | }, { 25 | "optional_icon": { 26 | "dimensions": { 27 | "width": 2048, 28 | "height": 1536 29 | }, 30 | "alt": null, 31 | "copyright": null, 32 | "url": "https://images.prismic.io/repoz/b9b0d289-a1df-4067-a8b8-593bc3752c20_dog-jump.png?auto=compress,format" 33 | }, 34 | "title": [{ 35 | "type": "heading3", 36 | "text": "Add icons if required", 37 | "spans": [] 38 | }], 39 | "description": [{ 40 | "type": "paragraph", 41 | "text": "This component has been matched by the SliceZone. Its model has been fetched from vue-essential-slices.", 42 | "spans": [] 43 | }] 44 | }, { 45 | "optional_icon": { 46 | "dimensions": { 47 | "width": 2048, 48 | "height": 1536 49 | }, 50 | "alt": null, 51 | "copyright": null, 52 | "url": "https://images.prismic.io/repoz/60377285-4f61-4500-b342-224f4715ec35_moshing.png?auto=compress,format" 53 | }, 54 | "title": [{ 55 | "type": "heading3", 56 | "text": "Add a custom theme", 57 | "spans": [] 58 | }], 59 | "description": [{ 60 | "type": "paragraph", 61 | "text": "This component has been matched by the SliceZone. Its model has been fetched from vue-essential-slices.", 62 | "spans": [] 63 | }] 64 | }, { 65 | "optional_icon": { 66 | "dimensions": { 67 | "width": 2048, 68 | "height": 1536 69 | }, 70 | "alt": null, 71 | "copyright": null, 72 | "url": "https://images.prismic.io/repoz/c7b4408a-84f5-42f2-bd10-39785b66fbb1_laying.png?auto=compress,format" 73 | }, 74 | "title": [{ 75 | "type": "heading3", 76 | "text": "Create your own", 77 | "spans": [] 78 | }], 79 | "description": [{ 80 | "type": "paragraph", 81 | "text": "This component has been matched by the SliceZone. Its model has been fetched from vue-essential-slices.", 82 | "spans": [] 83 | }] 84 | }], 85 | "primary": { 86 | "eyebrow_headline": [{ 87 | "type": "paragraph", 88 | "text": "Eyebrow", 89 | "spans": [] 90 | }], 91 | "title": [{ 92 | "type": "heading1", 93 | "text": "Alternate like a star", 94 | "spans": [] 95 | }], 96 | "description": [{ 97 | "type": "paragraph", 98 | "text": "A predesigned AlternateGrid component, that you can use to list your skills or features of a product.", 99 | "spans": [] 100 | }], 101 | "optional_image": { 102 | "dimensions": { 103 | "width": 1114, 104 | "height": 1522 105 | }, 106 | "alt": null, 107 | "copyright": null, 108 | "url": "https://images.prismic.io/repoz/9aea6f86-1695-4ee9-9d34-335e020ed007_selfie2.png?auto=compress,format" 109 | }, 110 | "image_side": "left" 111 | } 112 | } -------------------------------------------------------------------------------- /src/slices/AlternateGrid/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "AlternateGrid", 4 | "description": "A predesigned Text Grid with Image left or right", 5 | "icon": "wrap_text", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "multi": "paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 12 | "allowTargetBlank": true, 13 | "label": "Eyebrow headline" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading1, heading2, heading3, heading4, heading5, heading6", 20 | "label": "title" 21 | } 22 | }, 23 | "description": { 24 | "type": "StructuredText", 25 | "config": { 26 | "multi": "paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 27 | "allowTargetBlank": true, 28 | "label": "description" 29 | } 30 | }, 31 | "optional_image": { 32 | "type": "Image", 33 | "config": { 34 | "constraint": {}, 35 | "thumbnails": [], 36 | "label": "Optional image" 37 | } 38 | }, 39 | "image_side": { 40 | "type": "Select", 41 | "config": { 42 | "options": ["left", "right"], 43 | "default_value": "left", 44 | "label": "Image side" 45 | } 46 | } 47 | }, 48 | "repeat": { 49 | "optional_icon": { 50 | "type": "Image", 51 | "config": { 52 | "constraint": {}, 53 | "thumbnails": [], 54 | "label": "Optional Icon" 55 | } 56 | }, 57 | "title": { 58 | "type": "StructuredText", 59 | "config": { 60 | "single": "heading3", 61 | "label": "title" 62 | } 63 | }, 64 | "description": { 65 | "type": "StructuredText", 66 | "config": { 67 | "multi": "paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 68 | "allowTargetBlank": true, 69 | "label": "description" 70 | } 71 | } 72 | } 73 | } -------------------------------------------------------------------------------- /src/slices/AlternateGrid/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/AlternateGrid/preview.png -------------------------------------------------------------------------------- /src/slices/CallToAction/README.md: -------------------------------------------------------------------------------- 1 | # Call to action Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive call to action section. Install it in your project, add the model in your custom type and fill in the content in the document and your are ready to go. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ----------- | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | icon_image | Image \|\| URL | false | An Icon image for the feature | true | -- | 15 | | title | RichText \|\| String | false | A short title | true | -- | 16 | | paragraph | RichText \|\| String | false | A short paragraph | true | -- | 17 | | button_label| Key Text \|\| String | false | A label for the button input | true | -- | 18 | | button_link | String \|\| URL | false | Url that will be used to redirect user | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/CallToAction/index.stories.js: -------------------------------------------------------------------------------- 1 | import CallToAction from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme.js' 5 | 6 | export const Default = () => ({ 7 | components: { CallToAction }, 8 | props: { 9 | slice: { 10 | type: Object, 11 | default: mock 12 | }, 13 | }, 14 | template: `` 15 | }); 16 | 17 | export const WithCustomTheme = () => ({ 18 | components: { 19 | CallToAction 20 | }, 21 | props: { 22 | slice: { 23 | type: Object, 24 | default() { 25 | return mock 26 | } 27 | }, 28 | theme: { 29 | default () { 30 | return formatThemeProps({ 31 | align: 'left', 32 | button: { 33 | style: 'background: #FFF;color: #111' 34 | }, 35 | wrapper: { 36 | style: 'background: tomato' 37 | } 38 | }, { 39 | i: 0 40 | }) 41 | } 42 | } 43 | }, 44 | template: `` 45 | }); 46 | 47 | 48 | export const NoImage = () => ({ 49 | components: { 50 | CallToAction 51 | }, 52 | props: { 53 | slice: { 54 | type: Object, 55 | default: { 56 | ...mock, 57 | primary: { 58 | ...mock.primary, 59 | icon_image: null 60 | } 61 | } 62 | }, 63 | }, 64 | template: `` 65 | }); 66 | 67 | export const DarkMode = () => ({ 68 | components: { 69 | CallToAction 70 | }, 71 | props: { 72 | slice: { 73 | type: Object, 74 | default () { 75 | return mock 76 | } 77 | }, 78 | darkMode: true, 79 | }, 80 | template: `` 81 | }); 82 | 83 | export default { 84 | title: "CallToAction", 85 | }; 86 | -------------------------------------------------------------------------------- /src/slices/CallToAction/index.vue: -------------------------------------------------------------------------------- 1 | 33 | 66 | 67 | 90 | -------------------------------------------------------------------------------- /src/slices/CallToAction/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Call to Action Section", 3 | "description": "A Call to action section by Philip Snow", 4 | "contributors": ["https://github.com/phillysnow/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/CallToAction/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "call_to_action", 3 | "slice_label": "", 4 | "items": [{}], 5 | "primary": { 6 | "icon_image": { 7 | "dimensions": { 8 | "width": 72, 9 | "height": 72 10 | }, 11 | "alt": "Some alt text for the image.", 12 | "copyright": null, 13 | "url": "https://images.prismic.io/slicesexamples/0a64ab37-8ba3-4882-a766-53bad869d3cf_cta-eyebrow-icon.svg?auto=compress,format&w=900" 14 | }, 15 | "title": [{ 16 | "type": "heading1", 17 | "text": "Collector Slices kit", 18 | "spans": [] 19 | }], 20 | "paragraph": [{ 21 | "type": "paragraph", 22 | "text": "It’s very easy to create stylish and beautiful prototypes for your future projects, both graphical and dynamic.", 23 | "spans": [] 24 | }], 25 | "button_link": { 26 | "link_type": "Web", 27 | "url": "https://prismic.io" 28 | }, 29 | "button_label": "Click Here" 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /src/slices/CallToAction/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Call to action", 4 | "description": "A predesigned 'Call to action' for section for your site", 5 | "icon": "notifications_active", 6 | "display": "list", 7 | "non-repeat": { 8 | "icon_image": { 9 | "type": "Image", 10 | "config": { 11 | "constraint": {}, 12 | "thumbnails": [], 13 | "label": "Icon Image" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading1, heading2, heading3, heading4, heading5, heading6", 20 | "label": "Title" 21 | } 22 | }, 23 | "paragraph": { 24 | "type": "StructuredText", 25 | "config": { 26 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 27 | "label": "Paragraph" 28 | } 29 | }, 30 | "button_link": { 31 | "type": "Link", 32 | "config": { 33 | "label": "Button Link" 34 | } 35 | }, 36 | "button_label": { 37 | "type": "Text", 38 | "config": { 39 | "label": "Button Label", 40 | "placeholder": "Text for button" 41 | } 42 | } 43 | }, 44 | "repeat": {} 45 | } -------------------------------------------------------------------------------- /src/slices/CallToAction/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/CallToAction/preview.png -------------------------------------------------------------------------------- /src/slices/CardsCarousel/README.md: -------------------------------------------------------------------------------- 1 | # Call to action Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive call to action section. Install it in your project, add the model in your custom type and fill in the content in the document and your are ready to go. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ----------- | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | icon_image | Image \|\| URL | false | An Icon image for the feature | true | -- | 15 | | title | RichText \|\| String | false | A short title | true | -- | 16 | | paragraph | RichText \|\| String | false | A short paragraph | true | -- | 17 | | button_label| Key Text \|\| String | false | A label for the button input | true | -- | 18 | | button_link | String \|\| URL | false | Url that will be used to redirect user | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/index.stories.js: -------------------------------------------------------------------------------- 1 | import CardsCarousel from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme.js' 5 | 6 | export const Default = () => ({ 7 | components: { 8 | CardsCarousel 9 | }, 10 | props: { 11 | slice: { 12 | type: Object, 13 | default: mock 14 | } 15 | }, 16 | template: `` 17 | }); 18 | 19 | export const WithCustomTheme = () => ({ 20 | components: { 21 | CardsCarousel 22 | }, 23 | props: { 24 | slice: { 25 | type: Object, 26 | default: mock 27 | }, 28 | theme: { 29 | default () { 30 | return formatThemeProps({ 31 | CardsCarousel: { 32 | color: '#FFF', 33 | wrapper: { 34 | style: 'background: rgb(112, 99, 255); border: 8px solid pink' 35 | }, 36 | eyebrow: { 37 | color: 'pink', 38 | 39 | }, 40 | }, 41 | }, { 42 | i: 0, 43 | slice: mock, 44 | sliceName: 'CardsCarousel' 45 | }) 46 | } 47 | } 48 | }, 49 | template: `` 50 | }); 51 | 52 | 53 | export default { 54 | title: "CardsCarousel" 55 | }; 56 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/index.vue: -------------------------------------------------------------------------------- 1 | 41 | 63 | 64 | 243 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Cards Carousel Section", 3 | "description": "A Carousel section by ", 4 | "contributors": ["https://github.com/phillysnow/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "cards_carousel", 3 | "slice_label": "large_images", 4 | "items": [ 5 | { 6 | "image": { 7 | "dimensions": { 8 | "width": 2048, 9 | "height": 1536 10 | }, 11 | "alt": null, 12 | "copyright": null, 13 | "url": "https://images.prismic.io/slicesexamples/b4aeb1e2-e9c1-43ab-82ab-0d0519f9c3cd_float.png?auto=compress,format" 14 | }, 15 | "title": [ 16 | { 17 | "type": "heading3", 18 | "text": "Title 1", 19 | "spans": [] 20 | } 21 | ], 22 | "content": [ 23 | { 24 | "type": "paragraph", 25 | "text": "Content hello", 26 | "spans": [] 27 | } 28 | ], 29 | "additional_info": [ 30 | { 31 | "type": "paragraph", 32 | "text": "", 33 | "spans": [] 34 | } 35 | ] 36 | }, 37 | { 38 | "image": { 39 | "dimensions": { 40 | "width": 2048, 41 | "height": 1536 42 | }, 43 | "alt": null, 44 | "copyright": null, 45 | "url": "https://images.prismic.io/slicesexamples/032aad44-343c-4ad6-b694-57bb9322ce88_clumsy.png?auto=compress,format" 46 | }, 47 | "title": [ 48 | { 49 | "type": "heading3", 50 | "text": "Title 2", 51 | "spans": [] 52 | } 53 | ], 54 | "content": [ 55 | { 56 | "type": "paragraph", 57 | "text": "lalala", 58 | "spans": [] 59 | } 60 | ], 61 | "additional_info": [] 62 | }, 63 | { 64 | "image": { 65 | "dimensions": { 66 | "width": 2048, 67 | "height": 1536 68 | }, 69 | "alt": null, 70 | "copyright": null, 71 | "url": "https://images.prismic.io/slicesexamples/7e9ead9f-accf-418b-9c5c-654f162d95ee_groovy.png?auto=compress,format" 72 | }, 73 | "title": [ 74 | { 75 | "type": "heading1", 76 | "text": "Title 3", 77 | "spans": [] 78 | } 79 | ], 80 | "content": [ 81 | { 82 | "type": "paragraph", 83 | "text": "content 1", 84 | "spans": [] 85 | } 86 | ], 87 | "additional_info": [] 88 | }, 89 | { 90 | "image": { 91 | "dimensions": { 92 | "width": 2048, 93 | "height": 1536 94 | }, 95 | "alt": null, 96 | "copyright": null, 97 | "url": "https://images.prismic.io/slicesexamples/f55cf641-b6d3-41f2-86f3-368a16b5decf_meditating.png?auto=compress,format" 98 | }, 99 | "title": [ 100 | { 101 | "type": "heading1", 102 | "text": "Title 4", 103 | "spans": [] 104 | } 105 | ], 106 | "content": [ 107 | { 108 | "type": "paragraph", 109 | "text": "Hello", 110 | "spans": [] 111 | } 112 | ], 113 | "additional_info": [] 114 | }, 115 | { 116 | "image": { 117 | "dimensions": { 118 | "width": 2048, 119 | "height": 1536 120 | }, 121 | "alt": null, 122 | "copyright": null, 123 | "url": "https://images.prismic.io/slicesexamples/bd0f784c-1039-44b8-8b73-f4978019d21b_dog-jump.png?auto=compress,format" 124 | }, 125 | "title": [ 126 | { 127 | "type": "heading1", 128 | "text": "Title 5", 129 | "spans": [] 130 | } 131 | ], 132 | "content": [ 133 | { 134 | "type": "paragraph", 135 | "text": "Hello", 136 | "spans": [] 137 | } 138 | ], 139 | "additional_info": [] 140 | }, 141 | { 142 | "image": { 143 | "dimensions": { 144 | "width": 2048, 145 | "height": 1536 146 | }, 147 | "alt": null, 148 | "copyright": null, 149 | "url": "https://images.prismic.io/slicesexamples/da71d741-4bf5-4b11-9b96-b97458c41ff0_dancing.png?auto=compress,format" 150 | }, 151 | "title": [ 152 | { 153 | "type": "heading1", 154 | "text": "Title 6", 155 | "spans": [] 156 | } 157 | ], 158 | "content": [ 159 | { 160 | "type": "paragraph", 161 | "text": "Saloud", 162 | "spans": [] 163 | } 164 | ], 165 | "additional_info": [ 166 | { 167 | "type": "paragraph", 168 | "text": "Additional info", 169 | "spans": [] 170 | } 171 | ] 172 | }, 173 | { 174 | "image": { 175 | "dimensions": { 176 | "width": 2048, 177 | "height": 1536 178 | }, 179 | "alt": null, 180 | "copyright": null, 181 | "url": "https://images.prismic.io/slicesexamples/c2d957c2-cef3-4e55-ab52-4b5af1917f2f_ballet.png?auto=compress,format" 182 | }, 183 | "title": [ 184 | { 185 | "type": "heading3", 186 | "text": "Title 7", 187 | "spans": [] 188 | } 189 | ], 190 | "content": [ 191 | { 192 | "type": "paragraph", 193 | "text": "Bi1 ou cmt?", 194 | "spans": [] 195 | } 196 | ], 197 | "additional_info": [] 198 | }, 199 | { 200 | "image": { 201 | "dimensions": { 202 | "width": 2048, 203 | "height": 1536 204 | }, 205 | "alt": null, 206 | "copyright": null, 207 | "url": "https://images.prismic.io/slicesexamples/360d18f5-87f1-49f1-b749-17d7657e824a_chilling.png?auto=compress,format" 208 | }, 209 | "title": [ 210 | { 211 | "type": "heading3", 212 | "text": "Title 8", 213 | "spans": [] 214 | } 215 | ], 216 | "content": [ 217 | { 218 | "type": "paragraph", 219 | "text": "Some content again", 220 | "spans": [] 221 | } 222 | ], 223 | "additional_info": [] 224 | }, 225 | { 226 | "image": { 227 | "dimensions": { 228 | "width": 2048, 229 | "height": 1536 230 | }, 231 | "alt": null, 232 | "copyright": null, 233 | "url": "https://images.prismic.io/slicesexamples/c828478d-36eb-46b6-a96d-328c128059cb_ice-cream.png?auto=compress,format" 234 | }, 235 | "title": [ 236 | { 237 | "type": "heading3", 238 | "text": "Title 9", 239 | "spans": [] 240 | } 241 | ], 242 | "content": [ 243 | { 244 | "type": "paragraph", 245 | "text": "This is it!", 246 | "spans": [] 247 | } 248 | ], 249 | "additional_info": [] 250 | } 251 | ], 252 | "primary": { 253 | "eyebrow_headline": [ 254 | { 255 | "type": "paragraph", 256 | "text": "The Carousel", 257 | "spans": [] 258 | } 259 | ], 260 | "title": [ 261 | { 262 | "type": "heading2", 263 | "text": "It’s more than a budget manager", 264 | "spans": [] 265 | } 266 | ], 267 | "description": [ 268 | { 269 | "type": "paragraph", 270 | "text": "This carousel moves by one card at a time when the next and previous arrows are clicked.", 271 | "spans": [] 272 | } 273 | ] 274 | } 275 | } 276 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Cards Carousel", 4 | "description": "A carousel with text + image cards", 5 | "icon": "image", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 12 | "allowTargetBlank": true, 13 | "label": "Eyebrow headline" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading1, heading2, heading3, heading4, heading5, heading6", 20 | "label": "Title" 21 | } 22 | }, 23 | "description": { 24 | "type": "StructuredText", 25 | "config": { 26 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 27 | "allowTargetBlank": true, 28 | "label": "Description" 29 | } 30 | } 31 | }, 32 | "repeat": { 33 | "image": { 34 | "type": "Image", 35 | "config": { 36 | "constraint": { 37 | "width": null, 38 | "height": null 39 | }, 40 | "thumbnails": [], 41 | "label": "Image" 42 | } 43 | }, 44 | "title": { 45 | "type": "StructuredText", 46 | "config": { 47 | "single": "heading3", 48 | "label": "Title" 49 | } 50 | }, 51 | "content": { 52 | "type": "StructuredText", 53 | "config": { 54 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 55 | "allowTargetBlank": true, 56 | "label": "Content" 57 | } 58 | }, 59 | "additional_info": { 60 | "type": "StructuredText", 61 | "config": { 62 | "multi": "paragraph, preformatted, heading3, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 63 | "allowTargetBlank": true, 64 | "label": "Additional Info", 65 | "placeholder": "eg. name of person in testimonial" 66 | } 67 | } 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /src/slices/CardsCarousel/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/CardsCarousel/preview.png -------------------------------------------------------------------------------- /src/slices/CustomerLogos/README.md: -------------------------------------------------------------------------------- 1 | # Customer Logos Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive section for showcasing companies and customers that you've worked with. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ------------------ | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | eyebrow_headline | RichText \|\| String | false | A short headline for the slice | true | -- | 15 | | link | String \|\| URL | true | Url that will be used to redirect user | false | https://test.com | 16 | | logo | Key Text \|\| String | true | A image field for company logo | true | -- | 17 | | call_to_action | Key Text \|\| String | false | A label for the CTA | true | -- | 18 | | call_to_action_link| String \|\| URL | false | Call to action link | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/index.stories.js: -------------------------------------------------------------------------------- 1 | import CustomerLogos from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme' 5 | 6 | export const Default = () => ({ 7 | components: { 8 | CustomerLogos 9 | }, 10 | props: { 11 | slice: { 12 | type: Object, 13 | default: mock 14 | } 15 | }, 16 | template: `` 17 | }); 18 | 19 | export const WithCustomTheme = () => ({ 20 | components: { 21 | CustomerLogos 22 | }, 23 | props: { 24 | slice: { 25 | type: Object, 26 | default: mock 27 | }, 28 | theme: { 29 | default () { 30 | return formatThemeProps({ 31 | wrapper: { 32 | style: 'background: rgb(238,174,202);background: radial-gradient(circle, rgba(238, 174, 202, 1) 0% , rgba(148, 187, 233, 1) 100% );' 33 | }, 34 | color: 'red', 35 | }, { 36 | i: 0, 37 | slice: mock, 38 | }) 39 | } 40 | } 41 | }, 42 | template: `` 43 | }); 44 | 45 | 46 | export default { 47 | title: "CustomerLogos" 48 | }; 49 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/index.vue: -------------------------------------------------------------------------------- 1 | 48 | 63 | 117 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Customer Logos Section", 3 | "description": "A Customer Logos section by Philip Snow", 4 | "contributors": ["https://github.com/phillysnow/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "customer_logos", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "logo": { 7 | "dimensions": { "width": 144, "height": 38 }, 8 | "alt": null, 9 | "copyright": null, 10 | "url": "https://images.prismic.io/slicesexamples/95a608cd-8d3c-40c1-a554-0bec1b89eda5_logo-3.svg?auto=compress,format" 11 | }, 12 | "link": { "link_type": "Any" } 13 | }, 14 | { 15 | "logo": { 16 | "dimensions": { "width": 116, "height": 19 }, 17 | "alt": null, 18 | "copyright": null, 19 | "url": "https://images.prismic.io/slicesexamples/b62a8629-f7f1-4d2e-885a-bd7c6bcff201_logo-2.svg?auto=compress,format" 20 | }, 21 | "link": { "link_type": "Any" } 22 | }, 23 | { 24 | "logo": { 25 | "dimensions": { "width": 137, "height": 23 }, 26 | "alt": null, 27 | "copyright": null, 28 | "url": "https://images.prismic.io/slicesexamples/23461395-458d-41f5-be25-bac37a4ff53e_logo-6.svg?auto=compress,format" 29 | }, 30 | "link": { "link_type": "Any" } 31 | }, 32 | { 33 | "logo": { 34 | "dimensions": { "width": 92, "height": 30 }, 35 | "alt": null, 36 | "copyright": null, 37 | "url": "https://images.prismic.io/slicesexamples/4360a72b-bfe4-4144-911c-597146f72c00_logo-5.svg?auto=compress,format" 38 | }, 39 | "link": { "link_type": "Any" } 40 | }, 41 | { 42 | "logo": { 43 | "dimensions": { "width": 92, "height": 25 }, 44 | "alt": null, 45 | "copyright": null, 46 | "url": "https://images.prismic.io/slicesexamples/846576e2-c93c-40dd-8aaa-b97f4e99e7aa_logo-1.svg?auto=compress,format" 47 | }, 48 | "link": { "link_type": "Any" } 49 | } 50 | ], 51 | "primary": { 52 | "eyebrow_headline": [ 53 | { "type": "heading2", "text": "Trusted by", "spans": [] } 54 | ], 55 | "call_to_action": [ 56 | { "type": "paragraph", "text": "View customer stories", "spans": [] } 57 | ], 58 | "call_to_action_link": { 59 | "link_type": "Web", 60 | "url": "https://prismic.io", 61 | "target": "_blank" 62 | } 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Customer logos", 4 | "description": "Display a list of your customers logos", 5 | "icon": "person", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "single": "heading2", 12 | "label": "Eyebrow Headline", 13 | "placeholder": "Trusted by" 14 | } 15 | }, 16 | "call_to_action": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "paragraph", 20 | "label": "Call To Action", 21 | "placeholder": "View customer stories" 22 | } 23 | }, 24 | "call_to_action_link": { 25 | "type": "Link", 26 | "config": { 27 | "allowTargetBlank": true, 28 | "label": "Call to Action Link", 29 | "placeholder": "Could be a signup link, or a link to customer stories" 30 | } 31 | } 32 | }, 33 | "repeat": { 34 | "logo": { 35 | "type": "Image", 36 | "config": { 37 | "constraint": {}, 38 | "thumbnails": [], 39 | "label": "Logo" 40 | } 41 | }, 42 | "link": { 43 | "type": "Link", 44 | "config": { 45 | "allowTargetBlank": true, 46 | "label": "link", 47 | "placeholder": "Could be a link to use case, press article, signup..." 48 | } 49 | } 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /src/slices/CustomerLogos/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/CustomerLogos/preview.png -------------------------------------------------------------------------------- /src/slices/FaqSection/README.md: -------------------------------------------------------------------------------- 1 | # FAQ Section 2 | 3 | ### Purpose of the component 4 | Component with repeatable dropdown section for creating FAQ sections. 5 | The accordion uses progressive enhancement as an approach to build the interactivity of the component. 6 | This means that the accordion starts out as a non-interactive component, and then interactivity and appropriate styles are added to it when the JavaScript runs. 7 | 8 | ### Variations 9 | 1. Default 10 | This default version on the component use the simple dropdowns to be used where and as you require. 11 | 2. Faq 12 | This version is a more complete website section, including a title and description to create a a basic FAQ page. 13 | 3. With Image 14 | Much like the full section but using the optional image for more destinct styling. 15 | 16 | ### Properties 17 | ``` 18 | | Property | Type | Repeatable | Description | Required | 19 | | ---------------- | -------------------- | -----------| ------------------------------ | -------- | 20 | | eyebrow_headline | RichText \|\| String | false | A short headline for the slice | true | 21 | | title | RichText \|\| String | false | A title for the slice | true | 22 | | description | RichText \|\| String | false | A paragraph for the slice | true | 23 | | optional_image | Image \|\| URL | false | An Icon image for the slice | false | 24 | | title | RichText \|\| String | true | A title for the dropdowns | true | 25 | | text | RichText \|\| String | true | A paragraph for the dropdowns | true | 26 | -------------------------------------------------------------------------------- /src/slices/FaqSection/index.stories.js: -------------------------------------------------------------------------------- 1 | import FaqSection from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme' 5 | 6 | export const Default = () => ({ 7 | components: { 8 | FaqSection 9 | }, 10 | props: { 11 | slice: { 12 | type: Object, 13 | default: mock 14 | } 15 | }, 16 | template: `` 17 | }); 18 | 19 | export const WithoutImage = () => ({ 20 | components: { 21 | FaqSection 22 | }, 23 | props: { 24 | slice: { 25 | type: Object, 26 | default: { 27 | ...mock, 28 | primary: { 29 | ...mock.primary, 30 | optional_image: null 31 | } 32 | } 33 | } 34 | }, 35 | template: `` 36 | }); 37 | 38 | export const WithCustomTheme = () => ({ 39 | components: { 40 | FaqSection 41 | }, 42 | props: { 43 | slice: { 44 | type: Object, 45 | default: { 46 | ...mock, 47 | primary: { 48 | ...mock.primary, 49 | optional_image: null 50 | } 51 | } 52 | }, 53 | theme: { 54 | default () { 55 | return formatThemeProps({ 56 | FaqSection: { 57 | eyebrow: { 58 | color: 'tomato', 59 | 60 | }, 61 | wrapper: { 62 | style: 'transform: rotateZ(2deg);' 63 | }, 64 | }, 65 | }, { 66 | i: 0, 67 | slice: mock, 68 | sliceName: 'FaqSection' 69 | }) 70 | } 71 | } 72 | }, 73 | template: `` 74 | }); 75 | 76 | 77 | export default { 78 | title: "FaqSection" 79 | }; 80 | -------------------------------------------------------------------------------- /src/slices/FaqSection/index.vue: -------------------------------------------------------------------------------- 1 | 26 | 59 | 66 | -------------------------------------------------------------------------------- /src/slices/FaqSection/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "FAQ section", 3 | "description": "Display an accordion FAQ, with optional image", 4 | "contributors": [ 5 | "https://github.com/SaraSoueidan", 6 | "https://github.com/hypervillain/" 7 | ], 8 | "sandboxUrl": "", 9 | "components": ["ps-accordion"], 10 | "tags": [ 11 | "Essentials", 12 | "Landing pages" 13 | ], 14 | "collection": "prismic-essentials", 15 | "dependencies": [] 16 | } -------------------------------------------------------------------------------- /src/slices/FaqSection/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "faq_section", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "title": [{ "type": "heading3", "text": "Test tracking", "spans": [] }], 7 | "text": [ 8 | { 9 | "type": "paragraph", 10 | "text": "Only use them when the content is appropriate. If the panels are too long, the user will end up scrolling too much (esp. on mobile), which negates the whole purpose of using an accordion. For very long panels, using links to separate pages is preferred.", 11 | "spans": [] 12 | }, 13 | { 14 | "type": "paragraph", 15 | "text": "If you use accordions to replace page steps such as checkout form steps, make sure you stop the default browser BACK button behavior so that the BACK button would move up a step in the accordion, because this is the behavior that most users expect, as tests show.", 16 | "spans": [] 17 | } 18 | ] 19 | }, 20 | { 21 | "title": [ 22 | { "type": "heading3", "text": "What's a headless CMS?", "spans": [] } 23 | ], 24 | "text": [ 25 | { 26 | "type": "paragraph", 27 | "text": "The default markup is enhanced using JavaScript so that the buttons are added to the headings. The buttons should NOT be in the headings by default. The markup should always consider what the component or content would look like if no Javascript is enabled and therefore the accordion is not functional. The content is most likely going to be all visible — either as a series of panels with headings or a definition list, depending on the type of content.", 28 | "spans": [] 29 | } 30 | ] 31 | }, 32 | { 33 | "title": [ 34 | { 35 | "type": "heading3", 36 | "text": "What so special about you?", 37 | "spans": [] 38 | } 39 | ], 40 | "text": [ 41 | { 42 | "type": "paragraph", 43 | "text": "The buttons need to specify which panels they control usingaria-controls, and they need to reflect the state of the panel (collapsed/expanded) usingaria-expanded=\"true/false\". The panel itself also should havearia-hiddenset to true or false if it is hidden or shown, respectively.", 44 | "spans": [] 45 | }, 46 | { 47 | "type": "paragraph", 48 | "text": "The accordion needs to be able to trap keyboard focus when the user is IN the accordion and uses the arrow keys to traverse the items in it. Tabbing out of the accordion must be enabled.", 49 | "spans": [] 50 | } 51 | ] 52 | }, 53 | { 54 | "title": [ 55 | { "type": "heading3", "text": "Are you that different?", "spans": [] } 56 | ], 57 | "text": [ 58 | { 59 | "type": "paragraph", 60 | "text": "You can allow one or more panels to be always collapsed or expanded. You can also set a panel to be open by default (e.g. the first one). All this functionality can be tied to the markup using data attributes as flags.", 61 | "spans": [] 62 | } 63 | ] 64 | } 65 | ], 66 | "primary": { 67 | "eyebrow_headline": [{ "type": "paragraph", "text": "FAQ", "spans": [] }], 68 | "title": [ 69 | { "type": "heading2", "text": "Answers to common questions", "spans": [] } 70 | ], 71 | "description": [ 72 | { 73 | "type": "paragraph", 74 | "text": "Learn about Prismic by reading questions and answers. It’s almost like talking to a human – and maybe even better.", 75 | "spans": [] 76 | } 77 | ], 78 | "optional_image": { 79 | "dimensions": { "width": 2048, "height": 1536 }, 80 | "alt": null, 81 | "copyright": null, 82 | "url": "https://images.prismic.io/slicesexamples/b4aeb1e2-e9c1-43ab-82ab-0d0519f9c3cd_float.png?auto=compress,format" 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /src/slices/FaqSection/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "FAQ", 4 | "description": "List of common questions + answers", 5 | "icon": "question_answer", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "single": "paragraph", 12 | "label": "Eyebrow headline", 13 | "placeholder": "Reinforce your copy with a key-worded text, to be displayed before title" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading2", 20 | "label": "title", 21 | "placeholder": "Title" 22 | } 23 | }, 24 | "description": { 25 | "type": "StructuredText", 26 | "config": { 27 | "multi": "paragraph, strong, em, hyperlink", 28 | "allowTargetBlank": true, 29 | "label": "Description" 30 | } 31 | }, 32 | "optional_image": { 33 | "type": "Image", 34 | "config": { 35 | "constraint": {}, 36 | "thumbnails": [], 37 | "label": "Optional image" 38 | } 39 | } 40 | }, 41 | "repeat": { 42 | "title": { 43 | "type": "StructuredText", 44 | "config": { 45 | "single": "heading3", 46 | "label": "Title", 47 | "placeholder": "Which browsers do you support?" 48 | } 49 | }, 50 | "text": { 51 | "type": "StructuredText", 52 | "config": { 53 | "multi": "paragraph, preformatted, strong, em, hyperlink, list-item, o-list-item", 54 | "allowTargetBlank": true, 55 | "label": "Text", 56 | "placeholder": "The answer to the question" 57 | } 58 | } 59 | } 60 | } 61 | -------------------------------------------------------------------------------- /src/slices/FaqSection/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/FaqSection/preview.png -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/README.md: -------------------------------------------------------------------------------- 1 | # Call to action Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive call to action section. Install it in your project, add the model in your custom type and fill in the content in the document and your are ready to go. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ----------- | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | icon_image | Image \|\| URL | false | An Icon image for the feature | true | -- | 15 | | title | RichText \|\| String | false | A short title | true | -- | 16 | | paragraph | RichText \|\| String | false | A short paragraph | true | -- | 17 | | button_label| Key Text \|\| String | false | A label for the button input | true | -- | 18 | | button_link | String \|\| URL | false | Url that will be used to redirect user | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/index.stories.js: -------------------------------------------------------------------------------- 1 | import FeatureTestimonials from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | export const Default = () => ({ 5 | components: { 6 | FeatureTestimonials 7 | }, 8 | props: { 9 | slice: { 10 | type: Object, 11 | default: mock 12 | } 13 | }, 14 | template: `` 15 | }); 16 | 17 | 18 | export default { 19 | title: "FeatureTestimonials" 20 | }; 21 | -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/index.vue: -------------------------------------------------------------------------------- 1 | 66 | 90 | -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "features_testimonials", 3 | "slice_label": null, 4 | "items": [{ 5 | "client_logo": { 6 | "dimensions": { 7 | "width": 100, 8 | "height": 100 9 | }, 10 | "alt": null, 11 | "copyright": null, 12 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/74e96244-08dc-4253-ac73-cdcbfad04001_testimonial-logo-3.svg?auto=compress,format&rect=0,11,28,28&w=100&h=100" 13 | }, 14 | "profile_pic": { 15 | "dimensions": { 16 | "width": 80, 17 | "height": 80 18 | }, 19 | "alt": null, 20 | "copyright": null, 21 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 22 | }, 23 | "quote": [{ 24 | "type": "paragraph", 25 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 26 | "spans": [] 27 | }], 28 | "name": [{ 29 | "type": "paragraph", 30 | "text": "Femke Van Schoohoven", 31 | "spans": [] 32 | }], 33 | "role_position": [{ 34 | "type": "paragraph", 35 | "text": "Creative Director at Netflix", 36 | "spans": [] 37 | }] 38 | }, { 39 | "client_logo": { 40 | "dimensions": { 41 | "width": 100, 42 | "height": 100 43 | }, 44 | "alt": null, 45 | "copyright": null, 46 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/edfeea23-bc22-433a-8208-1112d4a63899_testimonial-logo-1.svg?auto=compress,format&rect=0,1,46,46&w=100&h=100" 47 | }, 48 | "profile_pic": { 49 | "dimensions": { 50 | "width": 80, 51 | "height": 80 52 | }, 53 | "alt": null, 54 | "copyright": null, 55 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 56 | }, 57 | "quote": [{ 58 | "type": "paragraph", 59 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 60 | "spans": [] 61 | }], 62 | "name": [{ 63 | "type": "paragraph", 64 | "text": "Femke Van Schoohoven", 65 | "spans": [] 66 | }], 67 | "role_position": [{ 68 | "type": "paragraph", 69 | "text": "Someone at Deliveroo", 70 | "spans": [] 71 | }] 72 | }, { 73 | "client_logo": { 74 | "dimensions": { 75 | "width": 100, 76 | "height": 100 77 | }, 78 | "alt": null, 79 | "copyright": null, 80 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/a40dff92-2344-49aa-948e-e3cd10c922bd_testimonial-logo-2.svg?auto=compress,format&rect=10,0,50,50&w=100&h=100" 81 | }, 82 | "profile_pic": { 83 | "dimensions": { 84 | "width": 80, 85 | "height": 80 86 | }, 87 | "alt": null, 88 | "copyright": null, 89 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 90 | }, 91 | "quote": [{ 92 | "type": "paragraph", 93 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 94 | "spans": [] 95 | }], 96 | "name": [{ 97 | "type": "paragraph", 98 | "text": "Hay work at Docker", 99 | "spans": [] 100 | }], 101 | "role_position": [{ 102 | "type": "paragraph", 103 | "text": "Creative Director at Netflix", 104 | "spans": [] 105 | }] 106 | }, { 107 | "client_logo": { 108 | "dimensions": { 109 | "width": 100, 110 | "height": 100 111 | }, 112 | "alt": null, 113 | "copyright": null, 114 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/edfeea23-bc22-433a-8208-1112d4a63899_testimonial-logo-1.svg?auto=compress,format&rect=0,1,46,46&w=100&h=100" 115 | }, 116 | "profile_pic": { 117 | "dimensions": { 118 | "width": 80, 119 | "height": 80 120 | }, 121 | "alt": null, 122 | "copyright": null, 123 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 124 | }, 125 | "quote": [{ 126 | "type": "paragraph", 127 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 128 | "spans": [] 129 | }], 130 | "name": [{ 131 | "type": "paragraph", 132 | "text": "Femke Van Schoohoven", 133 | "spans": [] 134 | }], 135 | "role_position": [{ 136 | "type": "paragraph", 137 | "text": "Creative Director at Netflix", 138 | "spans": [] 139 | }] 140 | }, { 141 | "client_logo": { 142 | "dimensions": { 143 | "width": 100, 144 | "height": 100 145 | }, 146 | "alt": null, 147 | "copyright": null, 148 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/a683c476-2898-4e20-908b-c9523e700648_testimonial-logo-4.svg?auto=compress,format&rect=0,1,48,48&w=100&h=100" 149 | }, 150 | "profile_pic": { 151 | "dimensions": { 152 | "width": 80, 153 | "height": 80 154 | }, 155 | "alt": null, 156 | "copyright": null, 157 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 158 | }, 159 | "quote": [{ 160 | "type": "paragraph", 161 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 162 | "spans": [] 163 | }], 164 | "name": [{ 165 | "type": "paragraph", 166 | "text": "Femke Van Schoohoven", 167 | "spans": [] 168 | }], 169 | "role_position": [{ 170 | "type": "paragraph", 171 | "text": "Creative Director at Netflix", 172 | "spans": [] 173 | }] 174 | }, { 175 | "client_logo": { 176 | "dimensions": { 177 | "width": 100, 178 | "height": 100 179 | }, 180 | "alt": null, 181 | "copyright": null, 182 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/da32a17b-fdb4-437e-a528-5aacd024736a_testimonial-logo-6.svg?auto=compress,format&rect=0,0,50,50&w=100&h=100" 183 | }, 184 | "profile_pic": { 185 | "dimensions": { 186 | "width": 80, 187 | "height": 80 188 | }, 189 | "alt": null, 190 | "copyright": null, 191 | "url": "https://images.prismic.io/nuxt-sm-app-example-9/3e808742-9253-4979-a2f8-791bc2054ab5_progile-pic.jpg?auto=compress,format&rect=0,0,416,416&w=80&h=80" 192 | }, 193 | "quote": [{ 194 | "type": "paragraph", 195 | "text": "“Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nullam volutpat risus id tristique tincidunt.”", 196 | "spans": [] 197 | }], 198 | "name": [{ 199 | "type": "paragraph", 200 | "text": "Femke Van Schoohoven", 201 | "spans": [] 202 | }], 203 | "role_position": [{ 204 | "type": "paragraph", 205 | "text": "Creative Director at Netflix", 206 | "spans": [] 207 | }] 208 | }], 209 | "primary": { 210 | "eyebrow_headline": [{ 211 | "type": "paragraph", 212 | "text": "Testimonials", 213 | "spans": [] 214 | }], 215 | "title": [{ 216 | "type": "heading2", 217 | "text": "It's more than a budget manager", 218 | "spans": [] 219 | }], 220 | "description": [{ 221 | "type": "paragraph", 222 | "text": "Learn about Prismic by reading questions and answers. It’s almost like talking to a human – and maybe even better.", 223 | "spans": [] 224 | }], 225 | "feature_illustration": { 226 | "dimensions": { 227 | "width": 2048, 228 | "height": 1536 229 | }, 230 | "alt": null, 231 | "copyright": null, 232 | "url": "https://images.prismic.io/slicemachine-blank/26d81419-4d65-46b8-853e-8ea902e160c1_groovy.png?auto=compress,format" 233 | } 234 | } 235 | } -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Feature Testimonials", 4 | "description": "Testimonial proving the value of a specific feature", 5 | "icon": "ondemand_video", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "label": "Eyebrow headline", 12 | "placeholder": "Reinforce your copy with a key-worded text, to be displayed before title", 13 | "single": "paragraph" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "label": "Title", 20 | "placeholder": "Our testimonial", 21 | "single": "heading2" 22 | } 23 | }, 24 | "description": { 25 | "type": "StructuredText", 26 | "config": { 27 | "label": "Description", 28 | "placeholder": "These are some awesome tutorials from our awesome clients ...", 29 | "multi": "paragraph, strong, em, hyperlink", 30 | "allowTargetBlank": true 31 | } 32 | }, 33 | "feature_illustration": { 34 | "type": "Image", 35 | "config": { 36 | "constraint": {}, 37 | "thumbnails": [], 38 | "label": "Feature Illustration" 39 | } 40 | } 41 | }, 42 | "repeat": { 43 | "client_logo": { 44 | "type": "Image", 45 | "config": { 46 | "constraint": { 47 | "width": 100, 48 | "height": 100 49 | }, 50 | "thumbnails": [], 51 | "label": "Client logo" 52 | } 53 | }, 54 | "profile_pic": { 55 | "type": "Image", 56 | "config": { 57 | "constraint": { 58 | "width": 80, 59 | "height": 80 60 | }, 61 | "thumbnails": [], 62 | "label": "Profile Pic" 63 | } 64 | }, 65 | "quote": { 66 | "type": "StructuredText", 67 | "config": { 68 | "multi": "paragraph", 69 | "label": "Quote", 70 | "placeholder": "Lorem ipsum dolor sit amet, ...." 71 | } 72 | }, 73 | "name": { 74 | "type": "StructuredText", 75 | "config": { 76 | "single": "paragraph", 77 | "label": "Name", 78 | "placeholder": "John McJohn" 79 | } 80 | }, 81 | "role_position": { 82 | "type": "StructuredText", 83 | "config": { 84 | "single": "paragraph", 85 | "label": "Role position", 86 | "placeholder": "Creative Director" 87 | } 88 | } 89 | } 90 | } -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/FeatureTestimonials/preview.png -------------------------------------------------------------------------------- /src/slices/FeatureTestimonials/quote-triangle.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | Rectangle 5 | Created with Sketch. 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/README.md: -------------------------------------------------------------------------------- 1 | # Call to action Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive call to action section. Install it in your project, add the model in your custom type and fill in the content in the document and your are ready to go. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ----------- | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | icon_image | Image \|\| URL | false | An Icon image for the feature | true | -- | 15 | | title | RichText \|\| String | false | A short title | true | -- | 16 | | paragraph | RichText \|\| String | false | A short paragraph | true | -- | 17 | | button_label| Key Text \|\| String | false | A label for the button input | true | -- | 18 | | button_link | String \|\| URL | false | Url that will be used to redirect user | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/index.stories.js: -------------------------------------------------------------------------------- 1 | import ImagesSlider from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme' 5 | 6 | export const Default = () => ({ 7 | components: { 8 | ImagesSlider 9 | }, 10 | props: { 11 | slice: { 12 | type: Object, 13 | default: mock 14 | } 15 | }, 16 | template: `` 17 | }); 18 | 19 | export const WithCustomTheme = () => ({ 20 | components: { 21 | ImagesSlider 22 | }, 23 | props: { 24 | slice: { 25 | type: Object, 26 | default: { 27 | ...mock, 28 | primary: { 29 | ...mock.primary, 30 | optional_image: null 31 | } 32 | } 33 | }, 34 | theme: { 35 | default () { 36 | return formatThemeProps({ 37 | ImagesSlider: { 38 | color: '#FFF', 39 | wrapper: { 40 | style: 'background: rgb(112, 99, 255); border: 8px solid pink' 41 | }, 42 | eyebrow: { 43 | color: 'pink', 44 | 45 | }, 46 | slider: { 47 | dot: { 48 | style: 'fill: #FFF' 49 | } 50 | } 51 | }, 52 | }, { 53 | i: 0, 54 | slice: mock, 55 | sliceName: 'ImagesSlider' 56 | }) 57 | } 58 | } 59 | }, 60 | template: `` 61 | }); 62 | 63 | 64 | export default { 65 | title: "ImagesSlider" 66 | }; 67 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/index.vue: -------------------------------------------------------------------------------- 1 | 44 | 66 | 67 | 85 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Cards Carousel Section", 3 | "description": "A Carousel section by ", 4 | "contributors": ["https://github.com/phillysnow/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "images_slider", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "image": { 7 | "dimensions": { 8 | "width": 5184, 9 | "height": 3456 10 | }, 11 | "alt": "Alt text", 12 | "copyright": null, 13 | "url": "https://images.prismic.io/slicesexamples%2F995a4f19-2830-43ee-85cf-89f3c8dd1f1b_aj-robbie-t5v1rup9dcy-unsplash.jpg?auto=compress,format" 14 | }, 15 | "description": [ 16 | { 17 | "type": "paragraph", 18 | "text": "This one is an elephant. Simply dummy text of the printing and typesetting industry.", 19 | "spans": [] 20 | } 21 | ] 22 | }, 23 | { 24 | "image": { 25 | "dimensions": { 26 | "width": 720, 27 | "height": 432 28 | }, 29 | "alt": "Alt text", 30 | "copyright": null, 31 | "url": "https://images.prismic.io/slicesexamples%2F0ee40f69-8329-4c8f-83d0-f9db9391f9d8_caramel_slices.jpg?auto=compress,format" 32 | }, 33 | "description": [ 34 | { 35 | "type": "paragraph", 36 | "text": "This one is a cake I guess? Simply dummy text of the printing and typesetting industry.", 37 | "spans": [] 38 | } 39 | ] 40 | } 41 | ], 42 | "primary": { 43 | "eyebrow_headline": [ 44 | { 45 | "type": "paragraph", 46 | "text": "Eyebrow", 47 | "spans": [] 48 | } 49 | ], 50 | "title": [ 51 | { 52 | "type": "heading1", 53 | "text": "This is it. The slider.", 54 | "spans": [] 55 | } 56 | ], 57 | "description": [ 58 | { 59 | "type": "paragraph", 60 | "text": "Simply dummy text of the printing and typesetting industry. Lorem Ipsum has been the industry's standard dummy text ever since the 1500s.", 61 | "spans": [] 62 | } 63 | ] 64 | } 65 | } 66 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Images Slider", 4 | "description": "A slider of full-width images + description", 5 | "icon": "image", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 12 | "allowTargetBlank": true, 13 | "label": "Eyebrow headline" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading1, heading2, heading3, heading4, heading5, heading6", 20 | "label": "Title" 21 | } 22 | }, 23 | "description": { 24 | "type": "StructuredText", 25 | "config": { 26 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 27 | "allowTargetBlank": true, 28 | "label": "Description" 29 | } 30 | } 31 | }, 32 | "repeat": { 33 | "image": { 34 | "type": "Image", 35 | "config": { 36 | "constraint": { 37 | "width": null, 38 | "height": null 39 | }, 40 | "thumbnails": [], 41 | "label": "Full Width Image" 42 | } 43 | }, 44 | "description": { 45 | "type": "StructuredText", 46 | "config": { 47 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 48 | "allowTargetBlank": true, 49 | "label": "Description" 50 | } 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/slices/ImagesSlider/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/ImagesSlider/preview.png -------------------------------------------------------------------------------- /src/slices/PricingTable/README.md: -------------------------------------------------------------------------------- 1 | # Pricing Table Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled pricing table section for your company website. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ------------------ | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | eyebrow_headline | RichText \|\| String | false | A short headline for the slice | true | -- | 15 | | title | RichText \|\| String | false | A title for the slice | true | -- | 16 | | description | RichText \|\| String | false | A paragraph for the slice | true | -- | 17 | | plan_title | RichText \|\| String | true | A title for the plan | true | -- | 18 | | price_option | RichText \|\| String | true | A price for the plan | true | -- | 19 | | features | RichText \|\| String | true | List of features for the plan | true | -- | 20 | | call_to_action_text| Key Text \|\| String | true | A label for the CTA | true | -- | 21 | | call_to_action | String \|\| URL | true | Call to action link | false | https://test.com | 22 | ``` -------------------------------------------------------------------------------- /src/slices/PricingTable/icons.js: -------------------------------------------------------------------------------- 1 | export const featureIcon = ` 2 | ` 20 | 21 | export const notIncludedIcon = ` 22 | ` 40 | -------------------------------------------------------------------------------- /src/slices/PricingTable/index.stories.js: -------------------------------------------------------------------------------- 1 | import PricingTable from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme.js' 5 | 6 | export const Default = () => ({ 7 | components: { PricingTable }, 8 | props: { 9 | slice: { 10 | type: Object, 11 | default: mock 12 | }, 13 | }, 14 | template: `` 15 | }); 16 | 17 | export const WithCustomTheme = () => ({ 18 | components: { 19 | PricingTable 20 | }, 21 | props: { 22 | slice: { 23 | type: Object, 24 | default() { 25 | return mock 26 | } 27 | }, 28 | theme: { 29 | default () { 30 | return formatThemeProps({ 31 | align: 'left', 32 | button: { 33 | style: 'background: #FFF;color: #111' 34 | }, 35 | wrapper: { 36 | style: 'background: tomato' 37 | }, 38 | eyebrow: { 39 | color: '#FFF', 40 | align: 'left' 41 | }, 42 | button: { 43 | primary: true 44 | } 45 | }, { 46 | i: 0 47 | }) 48 | } 49 | } 50 | }, 51 | template: `` 52 | }); 53 | 54 | export default { 55 | title: "PricingTable", 56 | }; 57 | -------------------------------------------------------------------------------- /src/slices/PricingTable/index.vue: -------------------------------------------------------------------------------- 1 | 63 | 109 | 153 | -------------------------------------------------------------------------------- /src/slices/PricingTable/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Pricing Table Section", 3 | "description": "A Pricing Table section by Philip Snow", 4 | "contributors": ["https://github.com/phillysnow/"], 5 | "sandboxUrl": "", 6 | "components": [], 7 | "tags": ["Banner", "Call to action"], 8 | "collection": "", 9 | "dependencies": [] 10 | } 11 | -------------------------------------------------------------------------------- /src/slices/PricingTable/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "pricing_table", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "plan_title": [ 7 | { 8 | "type": "paragraph", 9 | "text": "Small", 10 | "spans": [] 11 | } 12 | ], 13 | "price_option": [ 14 | { 15 | "type": "paragraph", 16 | "text": "Free", 17 | "spans": [] 18 | } 19 | ], 20 | "features": [ 21 | { 22 | "type": "list-item", 23 | "text": "Figma and Sketch Files", 24 | "spans": [] 25 | }, 26 | { 27 | "type": "list-item", 28 | "text": "Auto-Updatable Styles", 29 | "spans": [] 30 | }, 31 | { 32 | "type": "list-item", 33 | "text": "Base Elements", 34 | "spans": [] 35 | }, 36 | { 37 | "type": "list-item", 38 | "text": "Page Layouts", 39 | "spans": [ 40 | { 41 | "start": 0, 42 | "end": 12, 43 | "type": "label", 44 | "data": { 45 | "label": "not-included" 46 | } 47 | } 48 | ] 49 | }, 50 | { 51 | "type": "list-item", 52 | "text": "24/7 Free Support", 53 | "spans": [ 54 | { 55 | "start": 0, 56 | "end": 17, 57 | "type": "label", 58 | "data": { 59 | "label": "not-included" 60 | } 61 | } 62 | ] 63 | } 64 | ], 65 | "call_to_action": { 66 | "link_type": "Web", 67 | "url": "https://prismic.io", 68 | "target": "_blank" 69 | }, 70 | "call_to_action_text": [ 71 | { 72 | "type": "paragraph", 73 | "text": "Start your free trial", 74 | "spans": [] 75 | } 76 | ] 77 | }, 78 | { 79 | "plan_title": [ 80 | { 81 | "type": "paragraph", 82 | "text": "Medium", 83 | "spans": [] 84 | } 85 | ], 86 | "price_option": [ 87 | { 88 | "type": "paragraph", 89 | "text": "From $18", 90 | "spans": [] 91 | } 92 | ], 93 | "features": [ 94 | { 95 | "type": "list-item", 96 | "text": "Figma and Sketch Files", 97 | "spans": [] 98 | }, 99 | { 100 | "type": "list-item", 101 | "text": "Auto-Updatable Styles", 102 | "spans": [] 103 | }, 104 | { 105 | "type": "list-item", 106 | "text": "Base Elements", 107 | "spans": [] 108 | }, 109 | { 110 | "type": "list-item", 111 | "text": "Page Layouts", 112 | "spans": [] 113 | }, 114 | { 115 | "type": "list-item", 116 | "text": "24/7 Free Support", 117 | "spans": [ 118 | { 119 | "start": 0, 120 | "end": 17, 121 | "type": "label", 122 | "data": { 123 | "label": "not-included" 124 | } 125 | } 126 | ] 127 | } 128 | ], 129 | "call_to_action": { 130 | "link_type": "Any" 131 | }, 132 | "call_to_action_text": [ 133 | { 134 | "type": "paragraph", 135 | "text": "Call To Action", 136 | "spans": [] 137 | } 138 | ] 139 | }, 140 | { 141 | "plan_title": [ 142 | { 143 | "type": "paragraph", 144 | "text": "Large", 145 | "spans": [] 146 | } 147 | ], 148 | "price_option": [ 149 | { 150 | "type": "paragraph", 151 | "text": "From $39", 152 | "spans": [] 153 | } 154 | ], 155 | "features": [ 156 | { 157 | "type": "list-item", 158 | "text": "Figma and Sketch Files", 159 | "spans": [] 160 | }, 161 | { 162 | "type": "list-item", 163 | "text": "Auto-Updatable Styles", 164 | "spans": [] 165 | }, 166 | { 167 | "type": "list-item", 168 | "text": "Base Elements", 169 | "spans": [] 170 | }, 171 | { 172 | "type": "list-item", 173 | "text": "Page Layouts", 174 | "spans": [] 175 | }, 176 | { 177 | "type": "list-item", 178 | "text": "24/7 Free Support", 179 | "spans": [] 180 | } 181 | ], 182 | "call_to_action": { 183 | "link_type": "Web", 184 | "url": "https://prismic.io", 185 | "target": "_blank" 186 | }, 187 | "call_to_action_text": [ 188 | { 189 | "type": "paragraph", 190 | "text": "Contact us", 191 | "spans": [] 192 | } 193 | ] 194 | } 195 | ], 196 | "primary": { 197 | "eyebrow_headline": [ 198 | { 199 | "type": "paragraph", 200 | "text": "Pricing", 201 | "spans": [] 202 | } 203 | ], 204 | "title": [ 205 | { 206 | "type": "heading2", 207 | "text": "Choose a plan", 208 | "spans": [] 209 | } 210 | ], 211 | "description": [ 212 | { 213 | "type": "paragraph", 214 | "text": "Choose the plan that works for you and streamline your design process in an unlimited number of projects.", 215 | "spans": [] 216 | } 217 | ] 218 | } 219 | } 220 | -------------------------------------------------------------------------------- /src/slices/PricingTable/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Pricing Table", 4 | "description": "Display a list of pricing plans", 5 | "icon": "attach_money", 6 | "display": "grid", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "single": "paragraph", 12 | "label": "Eyebrow Headline", 13 | "placeholder": "Pricing plans" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading2", 20 | "label": "Title", 21 | "placeholder": "Choose the plan" 22 | } 23 | }, 24 | "description": { 25 | "type": "StructuredText", 26 | "config": { 27 | "multi": "paragraph, strong, em, hyperlink", 28 | "allowTargetBlank": true, 29 | "label": "Description", 30 | "placeholder": "Choose the version that works for you ..." 31 | } 32 | } 33 | }, 34 | "repeat": { 35 | "plan_title": { 36 | "type": "StructuredText", 37 | "config": { 38 | "single": "heading3", 39 | "label": "Plan title", 40 | "placeholder": "Simple, Gold, Premium..." 41 | } 42 | }, 43 | "price_option": { 44 | "type": "StructuredText", 45 | "config": { 46 | "multi": "heading4", 47 | "label": "Price Option", 48 | "placeholder": "Free, $19, Contact us..." 49 | } 50 | }, 51 | "features": { 52 | "type": "StructuredText", 53 | "config": { 54 | "multi": "list-item", 55 | "label": "Features", 56 | "placeholder": "A list of features using bullet list" 57 | } 58 | }, 59 | "call_to_action": { 60 | "type": "Link", 61 | "config": { 62 | "allowTargetBlank": true, 63 | "label": "Call To Action", 64 | "placeholder": "Link to Signup / More info..." 65 | } 66 | }, 67 | "call_to_action_text": { 68 | "type": "StructuredText", 69 | "config": { 70 | "multi": "paragraph", 71 | "label": "Call To Action Text", 72 | "placeholder": "Start your free trial" 73 | } 74 | } 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/slices/PricingTable/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/PricingTable/preview.png -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/README.md: -------------------------------------------------------------------------------- 1 | # Call to action Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily create a beautifully styled responsive call to action section. Install it in your project, add the model in your custom type and fill in the content in the document and your are ready to go. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 10 | ### Properties 11 | ``` 12 | | Property | Type | Repeatable | Description | Required | Default | 13 | | ----------- | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 14 | | icon_image | Image \|\| URL | false | An Icon image for the feature | true | -- | 15 | | title | RichText \|\| String | false | A short title | true | -- | 16 | | paragraph | RichText \|\| String | false | A short paragraph | true | -- | 17 | | button_label| Key Text \|\| String | false | A label for the button input | true | -- | 18 | | button_link | String \|\| URL | false | Url that will be used to redirect user | false | https://test.com | 19 | ``` 20 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/index.stories.js: -------------------------------------------------------------------------------- 1 | import TestimonialsSlider from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { 5 | withKnobs 6 | } from "@storybook/addon-knobs"; 7 | 8 | export const Default = () => ({ 9 | components: { 10 | TestimonialsSlider 11 | }, 12 | props: { 13 | slice: { 14 | type: Object, 15 | default: mock 16 | } 17 | }, 18 | template: `` 19 | }); 20 | 21 | 22 | export default { 23 | title: "Testimonials Slider" 24 | }; 25 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/index.vue: -------------------------------------------------------------------------------- 1 | 50 | 73 | 74 | 222 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "testimonials_slider", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "image": { 7 | "dimensions": { 8 | "width": 400, 9 | "height": 400 10 | }, 11 | "alt": null, 12 | "copyright": null, 13 | "url": "https://images.prismic.io/slicesexamples/342cc816-3eeb-403c-a63b-79a678921258_OTg3ODQuanBn.jpg?auto=compress,format&rect=0,0,512,512&w=400&h=400" 14 | }, 15 | "testimonial": [ 16 | { 17 | "type": "paragraph", 18 | "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words", 19 | "spans": [] 20 | } 21 | ], 22 | "person": "John Doe", 23 | "title": "Software eng. at Prismic" 24 | }, 25 | { 26 | "image": { 27 | "dimensions": { 28 | "width": 400, 29 | "height": 400 30 | }, 31 | "alt": null, 32 | "copyright": null, 33 | "url": "https://images.prismic.io/slicesexamples/b3f9c02d-40f9-41b0-b0b7-4b05bcad0556_Mjk0MDIuanBn.jpg?auto=compress,format&rect=0,0,512,512&w=400&h=400" 34 | }, 35 | "testimonial": [ 36 | { 37 | "type": "paragraph", 38 | "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words", 39 | "spans": [] 40 | } 41 | ], 42 | "person": "Janine Doe", 43 | "title": "Software eng. at Prismic" 44 | }, 45 | { 46 | "image": { 47 | "dimensions": { 48 | "width": 400, 49 | "height": 400 50 | }, 51 | "alt": null, 52 | "copyright": null, 53 | "url": "https://images.prismic.io/slicesexamples/e273a2ed-45c1-4c61-8183-c7ff6fea8445_XzA4MDY2NzIuanBn.jpg?auto=compress,format&rect=0,0,512,512&w=400&h=400" 54 | }, 55 | "testimonial": [ 56 | { 57 | "type": "paragraph", 58 | "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words", 59 | "spans": [] 60 | } 61 | ], 62 | "person": "Josiane Doe", 63 | "title": "Software eng. at Prismic" 64 | }, 65 | { 66 | "image": { 67 | "dimensions": { 68 | "width": 400, 69 | "height": 400 70 | }, 71 | "alt": null, 72 | "copyright": null, 73 | "url": "https://images.prismic.io/slicesexamples/883af32f-539a-415f-9429-241195543d1b_OTk2NjQuanBn.jpg?auto=compress,format&rect=0,0,512,512&w=400&h=400" 74 | }, 75 | "testimonial": [ 76 | { 77 | "type": "paragraph", 78 | "text": "Contrary to popular belief, Lorem Ipsum is not simply random text. It has roots in a piece of classical Latin literature from 45 BC, making it over 2000 years old. Richard McClintock, a Latin professor at Hampden-Sydney College in Virginia, looked up one of the more obscure Latin words", 79 | "spans": [] 80 | } 81 | ], 82 | "person": "Jasmine Doe", 83 | "title": "Software eng. at Prismic" 84 | } 85 | ], 86 | "primary": { 87 | "eyebrow_headline": [ 88 | { 89 | "type": "paragraph", 90 | "text": "The Carousel", 91 | "spans": [] 92 | } 93 | ], 94 | "title": [ 95 | { 96 | "type": "heading1", 97 | "text": "It’s more than a budget manager", 98 | "spans": [] 99 | } 100 | ], 101 | "description": [ 102 | { 103 | "type": "paragraph", 104 | "text": "This carousel moves by one card at a time when the next and previous arrows are clicked?", 105 | "spans": [] 106 | } 107 | ] 108 | } 109 | } 110 | -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Testimonials Slider", 4 | "description": "A predesigned Slider with rich testimonial", 5 | "icon": "notifications_active", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 12 | "allowTargetBlank": true, 13 | "label": "Eyebrow headline" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading1, heading2, heading3, heading4, heading5, heading6", 20 | "label": "Title" 21 | } 22 | }, 23 | "paragraph": { 24 | "type": "StructuredText", 25 | "config": { 26 | "multi": "paragraph, preformatted, heading1, heading2, heading3, heading4, heading5, heading6, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 27 | "label": "Paragraph" 28 | } 29 | }, 30 | "button_link": { 31 | "type": "Link", 32 | "config": { 33 | "label": "Button Link" 34 | } 35 | }, 36 | "button_label": { 37 | "type": "Text", 38 | "config": { 39 | "label": "Button Label", 40 | "placeholder": "Text for button" 41 | } 42 | } 43 | }, 44 | "repeat": { 45 | "image": { 46 | "type": "Image", 47 | "config": { 48 | "constraint": {}, 49 | "thumbnails": [], 50 | "label": "image" 51 | } 52 | }, 53 | "testimonial": { 54 | "type": "StructuredText", 55 | "config": { 56 | "multi": "paragraph, preformatted, strong, em, hyperlink, image, embed, list-item, o-list-item, o-list-item", 57 | "label": "testimonial" 58 | } 59 | }, 60 | "person": { 61 | "type": "Text", 62 | "config": { 63 | "label": "person", 64 | "placeholder": "Their full name" 65 | } 66 | }, 67 | "title": { 68 | "type": "Text", 69 | "config": { 70 | "label": "title", 71 | "placeholder": "Their title" 72 | } 73 | } 74 | } 75 | } -------------------------------------------------------------------------------- /src/slices/TestimonialsSlider/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/TestimonialsSlider/preview.png -------------------------------------------------------------------------------- /src/slices/VideoHighlights/README.md: -------------------------------------------------------------------------------- 1 | # Video Highlights Section 2 | 3 | ### Purpose of the component 4 | This component allows you to easily add a list of videos, great for showcasing playlists or video courses. 5 | 6 | ### Variations 7 | 1. Default 8 | This default version on the component is the only variation. 9 | 1. Dark 10 | This variation allows you to enable a dark mode for the section 11 | 12 | ### Properties 13 | ``` 14 | | Property | Type | Repeatable | Description | Required | Default | 15 | | ------------------ | -------------------- | -----------| -------------------------------------- | -------- | ---------------- | 16 | | eyebrow_headline | RichText \|\| String | false | A short headline for the slice | true | -- | 17 | | title | RichText \|\| String | false | A title for the slice | true | -- | 18 | | description | RichText \|\| String | false | A paragraph for the slice | true | -- | 19 | | title | RichText \|\| String | true | A title to select the video | true | -- | 20 | | src.embed_url | String \|\| URL | true | The link to your video | true | -- | 21 | ``` -------------------------------------------------------------------------------- /src/slices/VideoHighlights/index.stories.js: -------------------------------------------------------------------------------- 1 | import VideoHighlights from "./index.vue"; 2 | import mock from './mock.json' 3 | 4 | import { formatThemeProps } from 'vue-slicezone/theme.js' 5 | 6 | export const Default = () => ({ 7 | components: { VideoHighlights }, 8 | props: { 9 | slice: { 10 | type: Object, 11 | default: mock 12 | }, 13 | }, 14 | template: `` 15 | }); 16 | 17 | export const WithCustomTheme = () => ({ 18 | components: { 19 | VideoHighlights 20 | }, 21 | props: { 22 | slice: { 23 | type: Object, 24 | default() { 25 | return mock 26 | } 27 | }, 28 | theme: { 29 | default () { 30 | return formatThemeProps({ 31 | CardsCarousel: { 32 | align: 'right', 33 | color: '#FFF', 34 | wrapper: { 35 | style: 'background: rgb(112, 99, 255); border: 8px solid pink' 36 | }, 37 | eyebrow: { 38 | color: 'pink', 39 | 40 | }, 41 | }, 42 | }, { 43 | i: 0, 44 | slice: mock, 45 | sliceName: 'CardsCarousel' 46 | }) 47 | } 48 | } 49 | }, 50 | template: `` 51 | }); 52 | 53 | export default { 54 | title: "VideoHighlights", 55 | }; 56 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/index.vue: -------------------------------------------------------------------------------- 1 | 63 | 160 | 290 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/meta.json: -------------------------------------------------------------------------------- 1 | { 2 | "title": "Video Highlights", 3 | "description": "A list of video elements", 4 | "imageUrl": "", 5 | "contributors": [ 6 | "https://github.com/sarasoueidan/" 7 | ], 8 | "sandboxUrl": "", 9 | "components": [], 10 | "tags": [ 11 | "Essentials", 12 | "Videos", 13 | "Slider" 14 | ], 15 | "collection": "essentials", 16 | "dependencies": [] 17 | } 18 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/mock.json: -------------------------------------------------------------------------------- 1 | { 2 | "slice_type": "video_highlights", 3 | "slice_label": null, 4 | "items": [ 5 | { 6 | "video_title": [ 7 | { 8 | "type": "paragraph", 9 | "text": "Single Page Apps - Fat frontend or fat backend, not both", 10 | "spans": [] 11 | } 12 | ], 13 | "video_src": { 14 | "type": "video", 15 | "thumbnail_height": 360, 16 | "provider_url": "https://www.youtube.com/", 17 | "thumbnail_url": "https://i.ytimg.com/vi/gYm9Q6J5gp8/hqdefault.jpg", 18 | "html": "", 19 | "provider_name": "YouTube", 20 | "version": "1.0", 21 | "title": "Single Page Apps - Fat frontend or fat backend, not both", 22 | "author_name": "Prismic", 23 | "height": 270, 24 | "author_url": "https://www.youtube.com/channel/UCJq6AEgtWeZt7ziQ-fLKOeA", 25 | "thumbnail_width": 480, 26 | "width": 480, 27 | "embed_url": "https://www.youtube.com/watch?v=gYm9Q6J5gp8" 28 | } 29 | }, 30 | { 31 | "video_title": [ 32 | { 33 | "type": "paragraph", 34 | "text": "Journey to JavaScript development", 35 | "spans": [] 36 | } 37 | ], 38 | "video_src": { 39 | "thumbnail_height": 360, 40 | "thumbnail_url": "https://i.ytimg.com/vi/62C-E6WL0_A/hqdefault.jpg", 41 | "width": 480, 42 | "provider_url": "https://www.youtube.com/", 43 | "type": "video", 44 | "author_name": "Prismic", 45 | "height": 270, 46 | "version": "1.0", 47 | "thumbnail_width": 480, 48 | "title": "Journey to JavaScript development", 49 | "author_url": "https://www.youtube.com/channel/UCJq6AEgtWeZt7ziQ-fLKOeA", 50 | "provider_name": "YouTube", 51 | "html": "", 52 | "embed_url": "https://www.youtube.com/watch?v=62C-E6WL0_A" 53 | } 54 | }, 55 | { 56 | "video_title": [ 57 | { 58 | "type": "paragraph", 59 | "text": "So many frameworks out there?", 60 | "spans": [] 61 | } 62 | ], 63 | "video_src": { 64 | "version": "1.0", 65 | "author_name": "Prismic", 66 | "html": "", 67 | "title": "So many frameworks out there! What should you do?", 68 | "author_url": "https://www.youtube.com/channel/UCJq6AEgtWeZt7ziQ-fLKOeA", 69 | "thumbnail_width": 480, 70 | "thumbnail_height": 360, 71 | "provider_url": "https://www.youtube.com/", 72 | "type": "video", 73 | "provider_name": "YouTube", 74 | "width": 480, 75 | "thumbnail_url": "https://i.ytimg.com/vi/ZAz5_lp_3SI/hqdefault.jpg", 76 | "height": 270, 77 | "embed_url": "https://www.youtube.com/watch?v=ZAz5_lp_3SI" 78 | } 79 | } 80 | ], 81 | "primary": { 82 | "eyebrow_headline": "Feature", 83 | "title": [{ "type": "heading2", "text": "Video Highlights", "spans": [] }], 84 | "description": [ 85 | { 86 | "type": "paragraph", 87 | "text": "These are some awesome videos that teach you how to use Prismic Slices to quickly create a great Web site.", 88 | "spans": [] 89 | } 90 | ] 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/model.json: -------------------------------------------------------------------------------- 1 | { 2 | "type": "Slice", 3 | "fieldset": "Video Highlights", 4 | "description": "Highlights of your video channel", 5 | "icon": "ondemand_video", 6 | "display": "list", 7 | "non-repeat": { 8 | "eyebrow_headline": { 9 | "type": "StructuredText", 10 | "config": { 11 | "single": "paragraph", 12 | "label": "Eyebrow headline", 13 | "placeholder": "Reinforce your copy with a key-worded text, to be displayed before title" 14 | } 15 | }, 16 | "title": { 17 | "type": "StructuredText", 18 | "config": { 19 | "single": "heading2", 20 | "label": "Title", 21 | "placeholder": "Video Highlights" 22 | } 23 | }, 24 | "description": { 25 | "type": "StructuredText", 26 | "config": { 27 | "multi": "paragraph, strong, em, hyperlink", 28 | "allowTargetBlank": true, 29 | "label": "Description", 30 | "placeholder": "These are some awesome videos ..." 31 | } 32 | } 33 | }, 34 | "repeat": { 35 | "video_title": { 36 | "type": "StructuredText", 37 | "config": { 38 | "multi": "paragraph, strong", 39 | "label": "Video title", 40 | "placeholder": "My awesome video" 41 | } 42 | }, 43 | "video_src": { 44 | "type": "Embed", 45 | "config": { 46 | "label": "Video src" 47 | } 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/slices/VideoHighlights/preview.png -------------------------------------------------------------------------------- /src/slices/VideoHighlights/prismic-embed.js: -------------------------------------------------------------------------------- 1 | export default { 2 | name: 'PrismicEmbed', 3 | functional: true, 4 | props: { 5 | field: { 6 | type: Object, 7 | required: true 8 | }, 9 | wrapper: { 10 | type: String, 11 | required: false, 12 | default: 'div' 13 | } 14 | }, 15 | render(h, { props, data }) { 16 | const { field, wrapper } = props 17 | if (!field || !field.html) { 18 | return null 19 | } 20 | 21 | const { embed_url: embedUrl, type, provider_name: providerName } = field 22 | 23 | const attrs = { 24 | ...data.attrs, 25 | ...(embedUrl && { 'data-oembed': embedUrl }), 26 | ...(type && { 'data-oembed-type': type }), 27 | ...(providerName && { 'data-oembed-provider': providerName }) 28 | } 29 | 30 | return h(wrapper, { 31 | ...Object.assign(data, { attrs }), 32 | domProps: { 33 | innerHTML: field.html 34 | } 35 | }) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/video-play-icon--black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/video-play-icon--dark-grey.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/video-play-icon--grey.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/slices/VideoHighlights/video-play-icon--white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/slices/index.js: -------------------------------------------------------------------------------- 1 | export { default as CallToAction } from './CallToAction' 2 | export { default as CardsCarousel } from './CardsCarousel' 3 | export { default as CustomerLogos } from './CustomerLogos' 4 | export { default as FaqSection } from './FaqSection' 5 | export { default as ImagesSlider } from './ImagesSlider' 6 | export { default as PricingTable } from './PricingTable' 7 | export { default as TestimonialsSlider } from './TestimonialsSlider' 8 | export { default as VideoHighlights } from './VideoHighlights' 9 | -------------------------------------------------------------------------------- /src/styles/_alternate.scss: -------------------------------------------------------------------------------- 1 | /********************************* \ 2 | * 3 | * Common styles for: 4 | * Alternate | List 5 | * Alternate | Grid 6 | * Alternate | Image + Text 7 | * 8 | *********************************/ 9 | 10 | .ps-alternate__ctas { 11 | display: flex; 12 | flex-direction: column; 13 | 14 | @media all and (min-width: 40rem) { 15 | flex-direction: row; 16 | } 17 | } 18 | 19 | .ps-alternate .ps-button { 20 | flex: 1; 21 | margin-top: var(--h-padding); 22 | 23 | @media all and (min-width: 40rem) { 24 | margin-right: var(--h-padding); 25 | margin-top: 0; 26 | } 27 | 28 | &:last-of-type { 29 | margin-right: 0; 30 | } 31 | } 32 | 33 | .ps-alternate__module { 34 | margin-bottom: var(--v-margin); 35 | } 36 | 37 | .ps-alternate__module__title { 38 | font-size: 1rem; 39 | margin-top: 1em; 40 | } 41 | 42 | .ps-alternate__module__img { 43 | max-height: 48px; 44 | margin-bottom: var(--c-margin); 45 | } 46 | 47 | @media all and (min-width: 40rem) { 48 | @supports (display: grid) { 49 | .ps-alternate--list { 50 | .ps-alternate__module { 51 | display: grid; 52 | grid-template-columns: auto 1fr; 53 | grid-column-gap: var(--h-padding); 54 | } 55 | 56 | .ps-alternate__module__title { 57 | margin-top: 0; 58 | } 59 | } 60 | } 61 | 62 | .ps-alternate--grid { 63 | .ps-alternate__module { 64 | display: inline-block; 65 | width: calc(50% - var(--h-padding)); 66 | margin-right: var(--h-padding); 67 | 68 | &:nth-of-type(even) { 69 | margin-right: 0; 70 | } 71 | } 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /src/styles/_button.scss: -------------------------------------------------------------------------------- 1 | .ps-button, 2 | a.ps-button { 3 | display: block; 4 | text-align: center; 5 | border: none; 6 | border-radius: 4px; 7 | padding: 1em 3em; 8 | text-decoration: none; 9 | font: inherit; 10 | line-height: 1.3; 11 | font-weight: 500; 12 | transition: all 0.1s linear; 13 | margin-top: var(--v-margin); 14 | } 15 | 16 | .ps-button--primary, 17 | a.ps-button--primary { 18 | background-color: var(--color--primary); 19 | color: #fff; 20 | 21 | &:hover { 22 | background-color: var(--color--primary--dark); 23 | } 24 | } 25 | 26 | .ps-button--secondary, 27 | a.ps-button--secondary { 28 | background-color: #000; 29 | color: #fff; 30 | 31 | &:hover { 32 | background-color: var(--color-grey-20); 33 | } 34 | } 35 | 36 | .ps-button--ghost, 37 | a.ps-button--ghost { 38 | background-color: transparent; 39 | color: black; 40 | border: 2px solid black; 41 | 42 | &:hover, 43 | &:focus { 44 | background-color: var(--color-grey-20); 45 | color: #fff; 46 | } 47 | } 48 | -------------------------------------------------------------------------------- /src/styles/_pl.scss: -------------------------------------------------------------------------------- 1 | /* pattern library-specific styles */ 2 | 3 | // Adds some padding to the component's live preview panel so the component doesn't stick to the edges 4 | body { 5 | padding: 3vw; 6 | } 7 | -------------------------------------------------------------------------------- /src/styles/_settings.scss: -------------------------------------------------------------------------------- 1 | :root { 2 | --primary-hue: 167; 3 | --secondary-hue: 30; 4 | --color--primary: hsl(var(--primary-hue), 66%, 31%); 5 | --color--primary--dark: hsl(var(--primary-hue), 68%, 27%); 6 | --color--primary--darker: hsl(var(--primary-hue), 75%, 21%); 7 | --color--secondary: hsl(var(--secondary-hue), 27%, 94%); 8 | --color-grey-0: hsl(0, 0%, 0%); 9 | --color-grey-20: hsl(0, 0%, 20%); 10 | --color-grey-90: hsl(0, 0%, 90%); 11 | --color-grey-53: hsl(0, 0%, 53%); 12 | --color-text-grey: var(--color-grey-53); 13 | 14 | 15 | /* default font family is the static Inter font */ 16 | --font-family: "Inter", Arial, sans-serif; 17 | 18 | /* in supporting browsers, the variable Inter font is used */ 19 | @supports (font-variation-settings: normal) { 20 | --font-family: "Inter var", Arial, sans-serif; 21 | } 22 | 23 | --scrollbar: 0; 24 | 25 | /* this variable is set using JS. See CS Utilities documentation for details */ 26 | --h-padding: 2rem; // horizontal padding for the slice relative to the page borders; 30px default when font size is base 16 27 | --c-padding: 1.25rem; // component-level padding 28 | --c-margin: 1rem; // component-level padding 29 | --v-margin: 2rem; // vertical component-level external margin (margin between two components) 30 | --v-space: 8vw; // vertical space within sections 31 | 32 | @media all and (max-width: 640px) { 33 | --h-padding: 1.25rem; 34 | } 35 | 36 | --focus-outline: 3px solid currentColor; 37 | 38 | 39 | 40 | /******************************************************************************************************* \ 41 | * 42 | * Repsonsive Typography 43 | * Two scales: one for small screens, one for large screens 44 | * And scaling the text between two viewport sizes 45 | * See https://www.smashingmagazine.com/2016/05/fluid-typography/ & accompanying Codepens for details 46 | * 47 | ********************************************************************************************************/ 48 | 49 | --scale--small: 1.125; // modular scale on small screens 50 | --scale--large: 1.25; // modular scale on large screens 51 | 52 | // calculate the modular scale (unitless) 53 | --text-min-4xl: calc(1 * var(--scale--small) * var(--scale--small) * var(--scale--small) * var(--scale--small) * var(--scale--small)); 54 | --text-max-4xl: calc(1 * var(--scale--large) * var(--scale--large) * var(--scale--large) * var(--scale--large) * var(--scale--large)); 55 | --text-min-3xl: calc(1 * var(--scale--small) * var(--scale--small) * var(--scale--small) * var(--scale--small)); 56 | --text-max-3xl: calc(1 * var(--scale--large) * var(--scale--large) * var(--scale--large) * var(--scale--large)); 57 | --text-min-2xl: calc(1 * var(--scale--small) * var(--scale--small) * var(--scale--small)); 58 | --text-max-2xl: calc(1 * var(--scale--large) * var(--scale--large) * var(--scale--large)); 59 | --text-min-xl: calc(1 * var(--scale--small) * var(--scale--small)); 60 | --text-max-xl: calc(1 * var(--scale--large) * var(--scale--large)); 61 | --text-min-l: calc(1 * var(--scale--small)); 62 | --text-max-l: calc(1 * var(--scale--large)); 63 | --text-min-small: calc(1 / var(--scale--small)); 64 | --text-max-small: calc(1 / var(--scale--large)); 65 | 66 | // --text--small ~= 0.875rem; // 14px; 67 | // --text--base ~= 1rem; // 16px; 68 | // --text--large ~= 1.125rem; // 18px; 69 | // --text--xl ~= 1.25rem; // 20px; 70 | // --text--2xl ~= 1.375rem; // 22px; 71 | // --text--3xl ~= 1.5rem; // 24px; 72 | // --text--4xl ~= calc(1.6rem + 1.2vw); //52px 73 | } 74 | -------------------------------------------------------------------------------- /src/styles/_slice.scss: -------------------------------------------------------------------------------- 1 | /************************************************************************************************ \ 2 | * 3 | * Styles common to all slices/components, such as spacing and layout of the common elements 4 | * including the kicker (a.k.a. eyebrow header), main heading, and description 5 | * The `.ps` prefix stands for "prismic slice" 6 | * 7 | ************************************************************************************************/ 8 | 9 | .ps { 10 | width: 100vw; 11 | width: calc(100vw - var(--scrollbar)); 12 | position: relative; 13 | padding-left: 2rem; // h-padding 14 | padding-right: 2rem; // h-padding 15 | padding-top: 8vw; // v-space 16 | padding-bottom: 8vw; // v-space 17 | 18 | @media all and (max-width: 640px) { 19 | padding: 8vw 1.25rem; 20 | } 21 | } 22 | 23 | .ps--black { 24 | background-color: #000; 25 | color: #fff; 26 | } 27 | 28 | .ps--beige { 29 | background-color: var(--color--secondary); 30 | } 31 | 32 | .ps__wrap { 33 | margin: 0 auto; 34 | 35 | @media all and (min-width: 1024px) { 36 | max-width: 80%; 37 | } 38 | 39 | @media all and (min-width: 1200px) { 40 | max-width: 75%; 41 | } 42 | } 43 | 44 | .ps__head { 45 | @media all and (min-width: 50em) { 46 | margin: 0 auto; 47 | text-align: center; 48 | } 49 | } 50 | 51 | .ps__title { 52 | 53 | @extend .text--4xl; 54 | } 55 | 56 | .ps__title > * { 57 | margin-bottom: 0; 58 | } 59 | 60 | .ps__desc { 61 | max-width: 42rem; 62 | 63 | @extend .text--xl; 64 | 65 | @media all and (min-width: 800px) { 66 | margin-left: auto; 67 | margin-right: auto; 68 | } 69 | 70 | font-weight: 350; 71 | 72 | p { 73 | line-height: 1.4; 74 | } 75 | 76 | p:last-of-type { 77 | margin-bottom: 0; 78 | } 79 | } 80 | 81 | .ps__desc.right { 82 | @media all and (min-width: 800px) { 83 | text-align: right; 84 | margin-right: 0; 85 | } 86 | } 87 | 88 | .ps__desc.left { 89 | @media all and (min-width: 800px) { 90 | text-align: left; 91 | margin-left: 0; 92 | } 93 | } 94 | 95 | // when the description is preceded with a heading, add margin between them 96 | .ps__header + .ps__desc { 97 | margin-top: calc(var(--v-margin) / 2); 98 | 99 | @media all and (min-width: 50em) { 100 | margin-top: var(--v-margin); 101 | } 102 | } 103 | 104 | .ps__head--left { 105 | margin-bottom: var(--v-margin); 106 | 107 | @media all and (min-width: 40em) { 108 | margin: 0; 109 | margin-bottom: calc(var(--v-margin) * 1.5); 110 | } 111 | 112 | .ps__header *, 113 | .ps__desc { 114 | text-align: left; 115 | margin-left: 0; 116 | } 117 | 118 | .ps__header + .ps__desc { 119 | margin-top: 0.5rem; 120 | } 121 | } 122 | 123 | // only when the main section is preceded with a head section does it have a top margin 124 | // otherwise it's not needed 125 | .ps__head + .ps__main { 126 | margin-top: calc(var(--v-margin) * 2); 127 | } 128 | 129 | .ps__kicker { 130 | display: block; 131 | color: var(--color--primary); 132 | font-weight: 500; 133 | 134 | @extend .text--l; 135 | 136 | margin: 0 0 0.6em; 137 | line-height: 1.3; 138 | } 139 | 140 | .ps__kicker-icon { 141 | display: inline-block; 142 | margin: 0 0 1rem; 143 | width: 100%; 144 | max-width: 120px; 145 | } 146 | 147 | .ps__img { 148 | display: block; 149 | margin: 0 auto calc(var(--c-padding) * 2); 150 | 151 | img { 152 | display: inline-block; 153 | max-width: 100%; 154 | } 155 | } 156 | 157 | .ps__features-list { 158 | list-style: none; 159 | padding: 0; 160 | margin-bottom: 0; 161 | margin-top: var(--v-margin); 162 | 163 | li { 164 | margin-bottom: 1rem; 165 | padding-left: 2rem; 166 | position: relative; 167 | 168 | &::before { 169 | content: ''; 170 | display: block; 171 | width: 1em; 172 | height: 1em; 173 | background-image: url("data:image/svg+xml,%3Csvg width='20' height='20' viewBox='0 0 20 20' xmlns='http://www.w3.org/2000/svg'%3E%3Ctitle%3Echeck_circle-24px%3C/title%3E%3Cdesc%3ECreated with Sketch.%3C/desc%3E%3Cg fill='none'%3E%3Cpath d='M-2-2h24v24h-24z'/%3E%3Cpath d='M10 0c-5.52 0-10 4.48-10 10s4.48 10 10 10 10-4.48 10-10-4.48-10-10-10zm-2 15l-5-5 1.41-1.41 3.59 3.58 7.59-7.59 1.41 1.42-9 9z' fill='%2347C1AF' fill-rule='nonzero'/%3E%3C/g%3E%3C/svg%3E"); 174 | background-repeat: no-repeat; 175 | background-size: 95% 95%; 176 | background-position: center center; 177 | position: absolute; 178 | left: 0; 179 | top: 50%; 180 | margin-top: -0.5em; 181 | } 182 | } 183 | } 184 | 185 | .ps__card-list { 186 | list-style: none; 187 | padding: 0; 188 | margin: 0; 189 | } 190 | 191 | .ps__card-item { 192 | border-radius: 8px; 193 | margin-bottom: var(--v-space); 194 | } 195 | 196 | .ps__card-item--full { 197 | background-color: var(--color--secondary); 198 | padding: calc(var(--h-padding) * 1.25) var(--h-padding); 199 | } 200 | 201 | .ps__card-item__title { 202 | @extend .text--l; 203 | 204 | margin-bottom: calc(var(--c-margin) / 2); 205 | } 206 | 207 | .ps__card-item__content { 208 | margin-top: var(--c-padding); 209 | 210 | p:last-of-type { 211 | margin-bottom: 0; 212 | } 213 | } 214 | 215 | .ps__card-item__cta { 216 | text-align: center; 217 | 218 | .ps-button { 219 | display: block; 220 | } 221 | } 222 | 223 | @media all and (min-width: 40em) { 224 | .ps__card-item { 225 | display: inline-block; 226 | margin-right: var(--h-padding); 227 | } 228 | 229 | @supports (display: grid) { 230 | .ps__card-list { 231 | display: grid; 232 | grid-template-columns: repeat(auto-fit, minmax(300px, 1fr)); 233 | grid-column-gap: var(--v-margin); 234 | // grid-row-gap: var(--v-space); 235 | } 236 | 237 | .ps__card-item { 238 | margin-right: 0; 239 | } 240 | } 241 | } 242 | 243 | /* slice main content area grid layout */ 244 | @media all and (min-width: 50em) { 245 | // 800px 246 | .ps__main.grid { 247 | [class^='span-'] { 248 | display: inline-block; 249 | margin-left: -4px; 250 | vertical-align: middle; 251 | width: 48%; 252 | margin-right: 4%; 253 | 254 | &:nth-of-type(even) { 255 | margin-right: 0; 256 | } 257 | } 258 | 259 | [class='span-1-12'] { 260 | width: 100%; 261 | } 262 | 263 | @supports (display: grid) { 264 | display: grid; 265 | grid-auto-flow: dense; 266 | 267 | [class^='span-'] { 268 | display: block; 269 | margin: 0; 270 | width: 100%; 271 | } 272 | } 273 | 274 | &.grid--align-center { 275 | align-items: center; 276 | } 277 | 278 | &.grid--align-stretch { 279 | align-items: stretch; 280 | } 281 | 282 | &.grid--align-top { 283 | align-items: top; 284 | } 285 | } 286 | 287 | .ps__main.grid--12 { 288 | grid-template-columns: repeat(12, 1fr); 289 | grid-column-gap: var(--h-padding); 290 | grid-row-gap: var(--v-space); 291 | } 292 | 293 | .span-1-12 { 294 | grid-column: 1 / 13; 295 | } 296 | 297 | .span-1-11 { 298 | grid-column: 1 / 12; 299 | } 300 | 301 | .span-1-10 { 302 | grid-column: 1 / 11; 303 | } 304 | 305 | .span-1-9 { 306 | grid-column: 1 / 10; 307 | } 308 | 309 | .span-10-12 { 310 | grid-column: 10 / 13; 311 | } 312 | 313 | .span-1-8 { 314 | grid-column: 1 / 9; 315 | } 316 | 317 | .span-9-12 { 318 | grid-column: 9 / 13; 319 | } 320 | 321 | .span-1-7 { 322 | grid-column: 1 / 8; 323 | } 324 | 325 | .span-8-12 { 326 | grid-column: 8 / 13; 327 | } 328 | 329 | .span-1-6 { 330 | grid-column: 1 / 7; 331 | } 332 | 333 | .span-7-12 { 334 | grid-column: 7 / 13; 335 | } 336 | 337 | .span-1-5 { 338 | grid-column: 1 / 6; 339 | } 340 | 341 | .span-6-12 { 342 | grid-column: 6 / 13; 343 | } 344 | 345 | .span-1-4 { 346 | grid-column: 1 / 5; 347 | } 348 | 349 | .span-5-12 { 350 | grid-column: 5 / 13; 351 | } 352 | 353 | .span-1-3 { 354 | grid-column: 1 / 4; 355 | } 356 | 357 | .span-4-12 { 358 | grid-column: 4 / 13; 359 | } 360 | 361 | .span-1-2 { 362 | grid-column: 1 / 3; 363 | } 364 | 365 | .span-3-12 { 366 | grid-column: 3 / 13; 367 | } 368 | } 369 | -------------------------------------------------------------------------------- /src/styles/_slider.scss: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/prismicio/vue-essential-slices/6c174652cdf9c92a9c0268f0184079be5e052d12/src/styles/_slider.scss -------------------------------------------------------------------------------- /src/styles/_tabs.scss: -------------------------------------------------------------------------------- 1 | /***************************************************************************************** \ 2 | * * 3 | * General Tabs styles common to all tabs components * 4 | * Styles specific to each tabs component are in that component's directory * 5 | * * 6 | \ ****************************************************************************************/ 7 | 8 | .c-tabs { 9 | @supports (display: grid) { 10 | @media all and (min-width: 50em) { 11 | display: grid; 12 | grid-template-columns: repeat(12, 1fr); 13 | grid-template-columns: subgrid; 14 | grid-column-gap: var(--h-padding); 15 | } 16 | } 17 | } 18 | 19 | .c-tabs__tablist { 20 | margin-bottom: calc(var(--v-margin) * 1.5); 21 | white-space: nowrap; 22 | overflow-x: auto; 23 | overflow-y: hidden; 24 | 25 | .js-tabs & { 26 | display: flex; 27 | justify-content: space-between; 28 | } 29 | 30 | -webkit-overflow-scrolling: touch; 31 | background: 32 | linear-gradient(90deg, #fff 30%, rgba(255, 255, 255, 0)), 33 | linear-gradient(90deg, rgba(255, 255, 255, 0), #fff 70%) 0 100%, 34 | radial-gradient(farthest-side at 0 50%, rgba(0, 0, 0, 0.25), transparent), 35 | radial-gradient(farthest-side at 100% 50%, rgba(0, 0, 0, 0.25), transparent) 36 | 0 100%; 37 | background-color: #fff; 38 | background-position: 0 0, 100%, 0 0, 100%; 39 | background-repeat: no-repeat; 40 | background-attachment: local, local, scroll, scroll; 41 | background-size: 20px 100%, 20px 100%, 10px 100%, 10px 100%; 42 | 43 | &::-webkit-scrollbar { 44 | display: none; 45 | } 46 | 47 | -ms-overflow-style: none; 48 | 49 | /* Internet Explorer 10+ */ 50 | scrollbar-width: none; 51 | 52 | /* Firefox */ 53 | 54 | &:focus, 55 | &.focus-visible { 56 | outline: 2px dotted #888; 57 | outline-offset: 5px; 58 | } 59 | } 60 | 61 | .c-tabs__tab { 62 | display: inline-block; 63 | line-height: 1; 64 | text-align: left; 65 | position: relative; 66 | transition: all 0.1s linear; 67 | } 68 | 69 | .js-tabs .c-tabs__tablist--dotnav { 70 | justify-content: center; 71 | } 72 | 73 | .c-tabs__tablist--dotnav .c-tabs__tab { 74 | padding: 0.75rem; 75 | border-radius: 50%; 76 | color: #000; 77 | border: 2px dotted transparent; 78 | 79 | &::before { 80 | content: ''; 81 | display: block; 82 | background-color: #000; 83 | width: 1rem; 84 | height: 1rem; 85 | border-radius: 50%; 86 | transition: background-color 0.1s linear; 87 | } 88 | 89 | &[aria-selected='true'] { 90 | color: var(--color--primary); 91 | 92 | &::before { 93 | background-color: var(--color--primary); 94 | } 95 | } 96 | 97 | &:hover { 98 | &::before { 99 | background-color: var(--color--primary); 100 | } 101 | } 102 | 103 | @media screen and (-ms-high-contrast: active) { 104 | /* All high contrast styling rules */ 105 | &::before { 106 | background-color: windowText; 107 | } 108 | 109 | &[aria-selected='true'] { 110 | &::before { 111 | background: highlight; 112 | } 113 | } 114 | } 115 | 116 | &:focus, 117 | &.focus-visible { 118 | outline: none; 119 | border-color: currentColor; 120 | outline-offset: -4px; 121 | } 122 | 123 | &:focus:not(:focus-visible) { 124 | border-color: transparent; 125 | } 126 | 127 | .js-focus-visible &:focus:not(.focus-visible) { 128 | border-color: transparent; 129 | } 130 | } 131 | 132 | /* styles for visible labels for the dotnav for voice dictation users */ 133 | .c-tabs__tablist--dotnav .c-tabs__tab { 134 | position: relative; 135 | 136 | .dot-label { 137 | position: absolute; 138 | left: 1.25rem; 139 | transform: translateX(-50%); 140 | bottom: -2.75rem; 141 | z-index: 1; 142 | line-height: 1; 143 | background-color: var(--color--secondary); 144 | padding: 0.5em 0.75em; 145 | border-radius: 4px; 146 | pointer-events: none; 147 | opacity: 0; 148 | transition: opacity 0.2s linear; 149 | 150 | &::after { 151 | /* up arrow */ 152 | content: ''; 153 | position: absolute; 154 | left: 50%; 155 | margin-left: -1rem; 156 | top: -0.5rem; 157 | width: 0; 158 | height: 0; 159 | border-left: 1rem solid transparent; 160 | border-right: 1rem solid transparent; 161 | border-bottom: 1rem solid var(--color--secondary); 162 | } 163 | } 164 | 165 | &:focus, 166 | &:hover { 167 | .dot-label { 168 | opacity: 1; 169 | } 170 | } 171 | 172 | &:focus:not(:focus-visible) { 173 | .dot-label { 174 | opacity: 0; 175 | } 176 | } 177 | 178 | .js-focus-visible &:focus:not(.focus-visible) { 179 | .dot-label { 180 | opacity: 0; 181 | } 182 | } 183 | } 184 | 185 | .c-tabs__tabpanel { 186 | margin-bottom: 8rem; 187 | 188 | .js-tabs & { 189 | margin-bottom: 0; 190 | } 191 | 192 | &:focus, 193 | &.focus-visible { 194 | outline: 2px dotted #888; 195 | outline-offset: 5px; 196 | } 197 | 198 | &:focus:not(:focus-visible) { 199 | outline: none; 200 | border-color: transparent; 201 | } 202 | 203 | .js-focus-visible &:focus:not(.focus-visible) { 204 | outline: none; 205 | border-color: transparent; 206 | } 207 | } 208 | 209 | .c-tabs__tabpanel__title { 210 | margin-bottom: 2em; 211 | } 212 | 213 | // when the js is enabled, the tabpanels are labelled by their tabs 214 | // you may choose to hide or keep the headings inside of them visible 215 | .js-tabs .c-tabs__tabpanel__title { 216 | display: none; 217 | } 218 | -------------------------------------------------------------------------------- /src/styles/_typography.scss: -------------------------------------------------------------------------------- 1 | html { 2 | font-size: 0.9rem; // 1rem is default. Set to 0.9 just to scale the whole design down a little 3 | // default font 4 | font-family: 5 | -apple-system, 6 | BlinkMacSystemFont, 7 | "Segoe UI", 8 | Roboto, 9 | Oxygen-Sans, 10 | Ubuntu, 11 | Cantarell, 12 | "Helvetica Neue", 13 | sans-serif; 14 | // web font 15 | // font-family: var(--font-family); 16 | } 17 | 18 | body { 19 | font-size: 1rem; 20 | font-weight: 350; 21 | line-height: 1.6; 22 | } 23 | 24 | p { 25 | margin: 0 0 1.5em; 26 | line-height: 1.6; 27 | } 28 | 29 | h1, 30 | h2, 31 | h3, 32 | h4, 33 | h5, 34 | h6 { 35 | line-height: 1.3; 36 | margin-top: 0; 37 | font-weight: bold; 38 | color: inherit; 39 | } 40 | 41 | h1 { 42 | font-weight: 700; 43 | } 44 | 45 | h2 { 46 | font-weight: 600; 47 | } 48 | 49 | h1, 50 | .text--4xl { 51 | line-height: 1.3; 52 | font-size: calc(1rem * var(--text-min-4xl)); 53 | 54 | @media screen and (min-width: 40rem) { 55 | font-size: calc(calc(1rem * var(--text-min-4xl)) + (var(--text-max-4xl) - var(--text-min-4xl)) * (100vw - 40rem) / (80 - 40)); 56 | } 57 | 58 | @media screen and (min-width: 80rem) { 59 | font-size: calc(1rem * var(--text-max-4xl)); 60 | } 61 | } 62 | 63 | h2, 64 | .text--3xl { 65 | line-height: 1.3; 66 | font-size: calc(1rem * var(--text-min-3xl)); 67 | 68 | @media screen and (min-width: 40rem) { 69 | font-size: calc(calc(1rem * var(--text-min-3xl)) + (var(--text-max-3xl) - var(--text-min-3xl)) * (100vw - 40rem) / (80 - 40)); 70 | } 71 | 72 | @media screen and (min-width: 80rem) { 73 | font-size: calc(1rem * var(--text-max-3xl)); 74 | } 75 | } 76 | 77 | h3, 78 | .text--2xl { 79 | line-height: 1.3; 80 | font-size: calc(1rem * var(--text-min-2xl)); 81 | 82 | @media screen and (min-width: 40rem) { 83 | font-size: calc(calc(1rem * var(--text-min-2xl)) + (var(--text-max-2xl) - var(--text-min-2xl)) * (100vw - 40rem) / (80 - 40)); 84 | } 85 | 86 | @media screen and (min-width: 80rem) { 87 | font-size: calc(1rem * var(--text-max-2xl)); 88 | } 89 | } 90 | 91 | h4, 92 | .text--xl { 93 | line-height: 1.2; 94 | font-size: calc(1rem * var(--text-min-xl)); 95 | 96 | @media screen and (min-width: 40rem) { 97 | font-size: calc(calc(1rem * var(--text-min-xl)) + (var(--text-max-xl) - var(--text-min-xl)) * (100vw - 40rem) / (80 - 40)); 98 | } 99 | 100 | @media screen and (min-width: 80rem) { 101 | font-size: calc(1rem * var(--text-max-xl)); 102 | } 103 | } 104 | 105 | h5, 106 | .text--l { 107 | font-size: calc(1rem * var(--text-min-l)); 108 | 109 | @media screen and (min-width: 40rem) { 110 | font-size: calc(calc(1rem * var(--text-min-l)) + (var(--text-max-l) - var(--text-min-l)) * (100vw - 40rem) / (80 - 40)); 111 | } 112 | 113 | @media screen and (min-width: 80rem) { 114 | font-size: calc(1rem * var(--text-max-l)); 115 | } 116 | } 117 | 118 | h6, 119 | .text--base { 120 | font-size: 1rem; 121 | margin-top: 2.5em; 122 | } 123 | 124 | small, 125 | .text--small { 126 | font-size: calc(1rem * var(--text-min-small)); 127 | 128 | @media screen and (min-width: 40rem) { 129 | font-size: calc(calc(1rem * var(--text-min-small)) + (var(--text-max-small) - var(--text-min-small)) * (100vw - 40rem) / (80 - 40)); 130 | } 131 | 132 | @media screen and (min-width: 80rem) { 133 | font-size: calc(1rem * var(--text-max-small)); 134 | } 135 | } 136 | -------------------------------------------------------------------------------- /src/styles/_utilities.scss: -------------------------------------------------------------------------------- 1 | [hidden] { 2 | display: none; 3 | } 4 | 5 | /* Visually hide any element (mostly text) accessibly. 6 | Support includes IE9+ */ 7 | .sr-only { 8 | clip: rect(0 0 0 0); 9 | clip-path: inset(100%); 10 | height: 1px; 11 | overflow: hidden; 12 | position: absolute; 13 | width: 1px; 14 | white-space: nowrap; 15 | } 16 | -------------------------------------------------------------------------------- /src/styles/fonts.scss: -------------------------------------------------------------------------------- 1 | /********************************************************************************************************** \ 2 | * 3 | * This stylesheet is here for the SVG charts embedded as s 4 | * External SVGs need to have Web fonts defined or referenced (external stylesheet) either inside them 5 | * 6 | **********************************************************************************************************/ 7 | 8 | @font-face { 9 | font-family: "Lato"; 10 | src: 11 | url("../fonts/lato-bold-webfont.woff2") format("woff2"), 12 | url("../fonts/lato-bold-webfont.woff") format("woff"); 13 | font-weight: bold; 14 | font-style: normal; 15 | font-display: swap; 16 | } 17 | 18 | @font-face { 19 | font-family: "Lato"; 20 | src: 21 | url("../fonts/lato-regular-webfont.woff2") format("woff2"), 22 | url("../fonts/lato-regular-webfont.woff") format("woff"); 23 | font-weight: normal; 24 | font-style: normal; 25 | font-display: swap; 26 | } 27 | 28 | @font-face { 29 | font-family: "Source Serif Pro"; 30 | src: 31 | url("../fonts/sourceserifpro-regular-webfont.woff2") format("woff2"), 32 | url("../fonts/sourceserifpro-regular-webfont.woff") format("woff"); 33 | font-weight: normal; 34 | font-style: normal; 35 | font-display: swap; 36 | } 37 | 38 | @font-face { 39 | font-family: "Source Serif Pro"; 40 | src: 41 | url("../fonts/sourceserifpro-bold-webfont.woff2") format("woff2"), 42 | url("../fonts/sourceserifpro-bold-webfont.woff") format("woff"); 43 | font-style: normal; 44 | font-weight: bold; 45 | font-display: swap; 46 | } 47 | -------------------------------------------------------------------------------- /src/styles/styles.scss: -------------------------------------------------------------------------------- 1 | *, 2 | *::before, 3 | *::after { 4 | box-sizing: border-box; 5 | } 6 | 7 | body { 8 | margin: 0; 9 | padding: 0; 10 | min-height: 100vh; 11 | 12 | @media all and (max-width: 640px) { 13 | overflow-x: hidden; 14 | } 15 | } 16 | 17 | #main:focus { 18 | outline: none; 19 | } 20 | 21 | a { 22 | text-decoration: none; 23 | color: var(--color--primary); 24 | font-weight: bold; 25 | 26 | &:hover { 27 | text-decoration: underline; 28 | color: var(--color--primary--dark); 29 | } 30 | 31 | &:active { 32 | color: var(--color--primary--darker); 33 | } 34 | 35 | &:visited { 36 | color: #755ebb; 37 | } 38 | 39 | &:focus, 40 | &.focus-visible { 41 | outline: var(--focus-outline); 42 | outline-offset: 3px; 43 | } 44 | 45 | &:focus:not(:focus-visible) { 46 | outline: none; 47 | } 48 | 49 | .js-focus-visible &:focus:not(.focus-visible) { 50 | outline: none; 51 | } 52 | 53 | &:-moz-focusring { 54 | outline: none; 55 | background: none; 56 | } 57 | } 58 | 59 | img { 60 | max-width: 100%; // repsonsify the image to override the width attr set on it 61 | height: auto; // to prevent imge squishing with width and height attrs set 62 | } 63 | 64 | button { 65 | background: none; 66 | font: inherit; 67 | font-size: 1rem; 68 | cursor: pointer; 69 | border: none; 70 | 71 | &:-moz-focusring { 72 | outline: none; 73 | } 74 | 75 | &:focus:not(:focus-visible) { 76 | outline: none; 77 | } 78 | 79 | .js-focus-visible &:focus:not(.focus-visible) { 80 | outline: none; 81 | } 82 | } 83 | 84 | @import '_settings.scss'; 85 | @import '_utilities.scss'; 86 | @import '_typography.scss'; 87 | @import '_tabs.scss'; 88 | @import '_slice.scss'; 89 | @import '_button.scss'; 90 | @import '_alternate.scss'; 91 | -------------------------------------------------------------------------------- /src/utils.js: -------------------------------------------------------------------------------- 1 | // eslint-disable-next-line 2 | export const isRichText = data => Array.isArray(data) 3 | 4 | export const maybeRichTextValidator = prop => { 5 | const type = typeof prop 6 | return ['string', 'object'].includes(type) 7 | } 8 | 9 | const camelizeRE = /-(\w)/g 10 | export const camelize = str => { 11 | str = str.replace(/_/g, '-').replace(camelizeRE, (_, c) => { 12 | return c ? c.toUpperCase() : '' 13 | }) 14 | return str[0].toUpperCase() + str.slice(1) 15 | } 16 | 17 | export const computeProp = 18 | (propName)=> (props) => Object.keys(props.theme).length ? props.theme[propName] : props[propName] 19 | 20 | export const createComputedProps = (...args) => args.reduce((acc, propName) => ({ 21 | ...acc, 22 | [`applied${propName.charAt(0).toUpperCase()}${propName.slice(1)}`]: computeProp(propName) 23 | }), {}) 24 | 25 | export const commonProps = { 26 | slice: { 27 | validator: function({ slice_type: sliceType, primary, items }) { 28 | return sliceType && primary && items 29 | } 30 | }, 31 | theme: { 32 | type: Object, 33 | required: false, 34 | default() { 35 | return {} 36 | } 37 | }, 38 | darkMode: { 39 | type: Boolean, 40 | required: false, 41 | default: false 42 | } 43 | } -------------------------------------------------------------------------------- /stories/Intro.stories.js: -------------------------------------------------------------------------------- 1 | import { 2 | PsSection, 3 | PsEyebrow, 4 | PsTitle, 5 | PsDescription 6 | } from '../src/components' 7 | 8 | export const Wip = () => ({ 9 | components: { 10 | PsTitle, 11 | PsSection, 12 | PsEyebrow, 13 | PsDescription, 14 | }, 15 | props: { 16 | }, 17 | template: ` 18 | 19 |
20 |
21 |
22 | 23 | Vue essential slices 24 | 25 |

26 | Nicely made website sections, connected to a backend. 27 |

28 |

29 |

30 | This library is part of SliceMachine, a tool for component-based approach on both the front-end and the back-end. 31 |

32 |

33 | The easiest way to get started is by following the Getting started here 34 | but if you're more of an adventurer, create a fresh Nuxt project and run this command in your CLI: 35 |

36 |

37 | $> npx prismic-cli sm --setup 38 |

39 |
40 |
41 |
42 | 43 | ` 44 | }); 45 | 46 | export default { 47 | title: "Introduction 👋", 48 | }; 49 | --------------------------------------------------------------------------------