- How to build a component for Funkhaus
- 1. Request a component to build
- 2. Clone the project repo into your GitHub account
- 3. Install packages
- 4. Setup developer environment
- Node
- ENV vars
- Vue DevTools
- Linting and Prettier
- 6. Create a Storybook Story
- 7. Using Storybook
- 8. Mock data and Props
- 9. Develop your component
- Planning
- Component name
- Design
- Props
- HTML structure
- CSS structure
- Fonts
- Images and SVGs
- CSS vars needed
- Vue events
- 10. Common mistakes - Don’t do these
- Don’t access the DOM directly
- Don’t use logic in your template
- Don’t import a component and name it something other than it’s file path.
- Don’t use extra markup to solve a style
- Don’t use v-if for showing/hiding content at certain breakpoints
- Don’t deeply nest your CSS for no reason
- Don’t use string concatenation
- Don’t use index’s for keys in Vue
- 11. Finished - Make a PR
1. Request a component to build
2. Clone the project repo into your GitHub account
3. Install packages
npm install
4. Setup developer environment
6. Create a Storybook Story
import BlockWork from "~/components/block/work"
export default {
title: "Project name / BlockWork",
}
export const Default = () => ({ // The first story should be called Default
components: { BlockWork },
template: `<block-work/>`, // You probably will have props on here
})
export default {
title: "WpComponents / WpImage",
parameters: {
backgrounds: {
default: "black",
},
},
}
7. Using Storybook
npm run storybook
8. Mock data and Props
import BlockWork from "~/components/block/work"
import { data as API } from "~/stories/mock-api.json"
export default {
title: "Project name / BlockWork",
}
export const Default = () => ({
components: { BlockWork },
data() {
return {
API, // This loads the mock API into the template for use below
}
},
template: `<block-work :image="API.image.node"/>`,
})
9. Develop your component
props: {
image: {
type: Object,
default: () => {}
},
items: {
type: Array,
default: () => []
},
to: {
type: String,
default: ""
}
}
<template>
<div class="block-work">
<h2 class="title"/>
</div>
</template>
<style lang="scss" scopped>
.block-work {
// Styles here
.title {
// Styles here
}
// Hover states
@media #{$has-hover} {
&:hover {
// Styles here
}
}
// Breakpoints
@media #{$lt-tablet} {
// Styles here
}
}
</style>
.sub-title {
font-family: var(--font-secondary);
}
<template>
<div class="block-work">
<svg-funkhaus-logo/>
</div>
</template>
<script>
import SvgFunkhausLogo from "~/assets/svg/funkhaus-logo"
export default {
components: {
SvgFunkhausLogo
}
}
</script>
10. Common mistakes - Don’t do these
<template>
<div class="panel-menu" @click="onClick">
<!-- Some code here -->
</div>
</template>
<script>
export default {
methods: {
onClick() {
element = document.querySelector('panel-menu')
element.style.transform = 'translateX(100%)'
}
}
}
</script>
<template>
<div :class="classes" @click="onClick">
<!-- Some code here -->
</div>
</template>
<script>
export default {
data() {
return {
isOpened: false
}
},
computed: {
classes() {
return ["panel-menu", {"is-opened": this.isOpened}]
}
},
methods: {
onClick() {
this.isOpened = !this.isOpened
}
}
}
</script>
<style scoped>
.panel-menu {
// States
&.is-opened {
transform: translateX(100%);
}
}
</style>
<template>
<div :class="['panel-menu', {'is-opened': isOpened}]">
<nuxt-link
v-if="user.role == 'admin '? true : false"
v-text="Admin Dashboard"
/>
<button @click="isOpened = false">Close menu</button>
</div>
</template>
<template>
<div :class="classes">
<nuxt-link
v-if="isAdmin"
v-text="Admin Dashboard"
/>
<button @click="closeMenu">Close menu</button>
</div>
</template>
<script>
export default {
computed: {
classes() {
return ['panel-menu', {'is-opened': this.isOpened}]
},
isAdmin() {
return user.role == 'admin
}
},
data() {
return {
isOpened: true
}
},
methods: {
closeMenu() {
this.isOpened = false
}
}
}
</script>
<template>
<div class="grid-work">
<block v-for="item in items" :key="item.id"/>
</div>
</template>
<script>
import Block from "~/components/block/work"
</script>
<template>
<div class="grid-work">
<block-work v-for="item in items" :key="item.id"/>
</div>
</template>
<script>
import BlockWork from "~/components/block/work"
</script>
<template>
<div class="global-logo">
<nuxt-link to="/">
<svg-logo-funkhaus/>
</nuxt-link>
</div>
</template>
<template>
<nuxt-link class="global-logo" to="/">
<svg-logo-funkhaus/>
</nuxt-link>
</template>
<style scoped>
.global-logo {
display: block;
}
</style>
<style lang="scss" scoped>
.menu-main {
.list {
// Some style
.item {
a.link {
// Some style
}
}
}
}
</style>
<style lang="scss" scoped>
.menu-main {
.list {
// Some style
}
.link {
// Some style
}
}
</style>
:href="'mailto:' + item.email"
:href="`mailto:${item.email}`"
<div
v-for="(item, i) in items"
:key="i"
>
<div
v-for="(item, i) in items"
:key="item.id"
>
11. Finished - Make a PR