Last active
May 18, 2020 19:36
-
-
Save viniazvd/a7719e339925c7d3af87df0d2a3c0f1e to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<div ref="steppers" class="c-steppers" :style="lineSizes"> | |
<div | |
v-for="(step, index) in steps" | |
:key="index" | |
:class="stepClasses(index)" | |
:style="{ width: `${100 / steps.length}%` }" | |
> | |
<c-flag | |
class="icon" | |
circled-border | |
:icon-size="22" | |
:size="iconSize" | |
:grey="index > active" | |
:success="index < active" | |
:primary="index === active" | |
:icon="index < active ? 'check' : step.icon" | |
:style="{ '--line': 100 / steps.length }" | |
/> | |
<span v-if="!isMobile" class="label">{{ step.label }}</span> | |
</div> | |
</div> | |
</template> | |
<script> | |
import { MediaQuery } from '../../mixins' | |
export default { | |
name: 'CSteppers', | |
mixins: [ MediaQuery ], | |
props: { | |
steps: { | |
type: Array, | |
default: () => ([ | |
{ | |
icon: 'user', | |
label: 'Foto de perfil' | |
} | |
]) | |
}, | |
active: { type: Number, default: 0 }, | |
stepSize: { | |
type: Object, | |
default: () => ({ mobile: 40, desktop: 50 }) | |
} | |
}, | |
mounted () { | |
this.setLineSizes() | |
// future improvement proposal | |
// this.observer = new MutationObserver(this.setLineSizes) | |
// this.observer.observe(this.$refs.steppers, { childList: true }) | |
// window.addEventListener('resize', this.setLineSizes) | |
// this.$refs.steppers.addEventListener('scroll', this.setLineSizes) | |
}, | |
data () { | |
return { | |
sizes: { left: '', width: '' } | |
// observer: null, // future improvement proposal | |
} | |
}, | |
computed: { | |
// step size of the icon (mobile or desktop) | |
iconSize () { | |
const { mobile, desktop } = this.stepSize | |
return this.isMobile ? mobile : desktop | |
}, | |
lineSizes () { | |
return { | |
'--left': this.sizes.left, | |
'--width': this.sizes.width, | |
'--top': (this.iconSize / 2) - 5 // 5 = border diff | |
} | |
} | |
}, | |
methods: { | |
stepClasses (index) { | |
return [ | |
'step', | |
{ | |
'--complete': index < this.active, | |
'--current': index === this.active, | |
'--incomplete': index > this.active, | |
'--is-last': index === this.steps.length - 1 | |
} | |
] | |
}, | |
setLineSizes () { | |
if (!this.$refs.steppers) return {} | |
setTimeout(() => { | |
const { width } = this.$refs.steppers.getBoundingClientRect() | |
this.sizes.left = (this.iconSize - 5) + 'px' // 5 = border diff | |
this.sizes.width = ((width / this.steps.length) - this.iconSize) + 'px' | |
}, 800) | |
} | |
}, | |
// future improvement proposal | |
// beforeDestroy () { | |
// this.observer.disconnect() | |
// window.removeEventListener('resize', this.setLineSizes) | |
// this.$refs.steppers.removeEventListener('scroll', this.setLineSizes) | |
// } | |
} | |
</script> | |
<style lang="scss"> | |
.c-steppers { | |
width: 100%; | |
position: relative; | |
display: flex; | |
justify-content: space-between; | |
& > .step { | |
border: 0; | |
outline: none; | |
position: relative; | |
background: transparent; | |
display: flex; | |
align-items: center; | |
flex-direction: column; | |
justify-content: center; | |
& > .icon { | |
position: relative; | |
&:before { background: map-get($text-color, base-10); } | |
&:after { | |
height: 1px; | |
content: ""; | |
top: var(--top); | |
position: absolute; | |
left: calc(var(--left)); | |
width: calc(var(--width)); | |
background: $base-border-color; | |
} | |
} | |
& > .label { | |
font-size: 11px; | |
margin-top: 10px; | |
line-height: 14px; | |
letter-spacing: 0; | |
text-transform: uppercase; | |
font-weight: $title-font-weight; | |
font-family: $title-font-family; | |
-webkit-font-smoothing: antialiased; | |
} | |
&.--current { | |
& > .label { color: map-get($text-color, base-80); } | |
} | |
&.--complete { | |
& > .label { color: map-get($text-color, base-50); } | |
} | |
&.--incomplete { | |
& > .label { color: map-get($text-color, base-30); } | |
& > .icon { background: map-get($text-color, base-10); } | |
} | |
&.--is-last > .icon::after { display: none; } | |
} | |
} | |
</style> |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
<template> | |
<span :class="classes" :style="styles"> | |
<c-icon :size="iconSize" v-bind="$attrs" /> | |
</span> | |
</template> | |
<script> | |
import CIcon from '../CIcon' | |
/** | |
* A very simple component meant to be used similarly to a tag. | |
* Accepts all the same props as CIcon. | |
*/ | |
export default { | |
name: 'CFlag', | |
components: { CIcon }, | |
props: { | |
/** | |
* The size of the flag. | |
*/ | |
size: { | |
type: [String, Number], | |
default: 40, | |
validator: size => typeof +size === 'number' && +size > 0 | |
}, | |
/** | |
* The size of the icon. | |
*/ | |
iconSize: { | |
type: [String, Number], | |
validator: size => typeof +size === 'number' && +size > 0 | |
}, | |
/** | |
* Changes the bg-color to our primary color. | |
*/ | |
primary: Boolean, | |
/** | |
* Changes the bg-color to our success color (usually green). | |
*/ | |
success: Boolean, | |
/** | |
* Changes the bg-color to our error color (usually red). | |
*/ | |
error: Boolean, | |
/** | |
* Changes the bg-color to a gray(ish). | |
*/ | |
grey: Boolean, | |
/** | |
* Changes the bg-color to a white. | |
*/ | |
white: Boolean, | |
/* | |
* Make the button to have a border circled around it | |
*/ | |
circledBorder: Boolean | |
}, | |
computed: { | |
classes () { | |
return ['c-flag', | |
{ | |
'-primary': this.primary, | |
'-success': this.success, | |
'-error': this.error, | |
'-grey': this.grey, | |
'-white': this.white, | |
'-circled-border': this.circledBorder | |
} | |
] | |
}, | |
styles () { | |
const size = this.size + 'px' | |
return { | |
width: size, | |
height: size, | |
minWidth: size, | |
minHeight: size | |
} | |
} | |
} | |
} | |
</script> | |
<style lang="scss"> | |
.c-flag { | |
display: inline-flex; | |
align-items: center; | |
justify-content: center; | |
flex-shrink: 0; | |
padding: 6px; | |
border-radius: 100%; | |
& > .c-icon { | |
fill: #FFF; | |
filter: drop-shadow(0px 1px 2px rgba(0, 0, 0, .3)); | |
} | |
&.-primary { | |
background: set-linear-gradient(125deg); | |
box-shadow: 0 2px 20px -2px rgba($primary-color, .5); | |
} | |
&.-success { | |
background: set-linear-gradient(125deg, $positive-color-map); | |
box-shadow: 0 2px 20px -2px rgba($positive-color, .5); | |
} | |
&.-error { | |
background: set-linear-gradient(125deg, $negative-color-map); | |
box-shadow: 0 2px 20px -2px rgba($negative-color, .5); | |
} | |
&.-grey { | |
z-index: 0; | |
position: relative; | |
background: rgba(18, 30, 72, 0.2); | |
box-shadow: 0 5px 15px -2px map-get($text-color, base-10); | |
&::before { | |
top: 60%; | |
left: 50%; | |
content: ''; | |
z-index: -1; | |
width: 30px; | |
height: 30px; | |
filter: blur(5px); | |
position: absolute; | |
border-radius: 25px; | |
transform: translate(-50%, -50%); | |
background: map-get($text-color, base-05); | |
} | |
& > .c-icon { filter: unset; } | |
} | |
&.-white { | |
box-shadow: unset; | |
background: rgba(255,255,255,0.3); | |
box-shadow: 0 2px 15px 0px map-get($text-color, base-10); | |
} | |
&.-circled-border { | |
border: 5px solid #fff; | |
// height: 50px !important; | |
// min-width: 50px !important; | |
// min-height: 50px !important; | |
// border-radius: 50px !important; | |
box-shadow: 0 0 0 1px rgba(18, 30, 72, 0.1); | |
} | |
} | |
</style> |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment