<div id="app">
<div id='header'>
<h1>
Box Shadow Generator
</h1>
</div>
<div id='info-box' :class="{ show: showInfo}">
<h1>
Info
</h1>
<span class='hide-info' @click="showInfo = false">×</span>
<h3>Tips</h3>
<div class='text'>
<li> Click on the plus button to add a new shadow and change the settings as your like. </li>
<li>Click on any of the boxes next to the add button to access and change particular shadow settings. </li>
<li> Use mousehweel on any of the circular controls for more precise increase/decrease in value.</li>
</div>
<h3>Resources</h3>
<div class='text'>
<a href='https://github.com/xiaokaike/vue-color' target=_blank>Vue Color Picker</a>
<br><a href='https://codepen.io/Brownsugar/pen/NaGPKy' target=_blank>Vue Color Implementation</a>
<br><a href='https://www.npmjs.com/package/vue-circle-slider' target=_blank>Vue Circular Slider</a>
<br>Split Vertical icon By <a href='https://thenounproject.com/term/split-vertical/1268414' target=_blank>Bhima</a>
<br>Spread icon By <a href='https://thenounproject.com/term/spread/1863148' target=_blank>projecthayat</a>
<br>Blur icon By <a href='https://thenounproject.com/term/blur/705680' target=_blank>abderraouf omara</a>
</div>
<h3>Projects</h3>
<div class='text'>
<li>Check my other projects at <a href='https://codepen.io/khr2003/' target=_blank>CodePen</a></li>
</div>
</div>
<div id='controls'>
<div id='reset' @click='resetControls'>
RESET
</div>
<div id='info' @click="showInfo = !showInfo">
🛈
</div>
<div id='box-shadows-container'>
<span v-for='(shadow, index) in boxShadows' :style='{"background-color": shadow.color}' :class='{highlight: (currentShadow == index)}' @click='setShadow(index)'></span>
<span class='add-transform' @click='addShadow'>+</span>
</div>
<box-shadow-control :data='getData' v-if='boxShadows.length > 0' @delete-shadow='deleteShadow'></box-shadow-control>
</div>
<div class='show-effects'>
<div class='transform-box' :style="style"></div>
</div>
<transition name="fade">
<div id='css' v-show='style["box-shadow"] != ""'>
<span v-if='style.transform != ""'>box-shadow: {{style["box-shadow"]}};</span>
</div>
</transition>
</div>
<template id='box-shadow-control'>
<div class='shadow-control'>
<div class="control inset">
<input id='inset-checkbox' type="checkbox" v-model='data.inset'>
<label for='inset-checkbox'>
<span class='switch'></span>
</label>
<span>Inset Shadow</span>
</div>
<div class='control color' ref="colorPicker" v-click-outside="hidePicker">
<input type='text' v-model='data.color' @focus='displayPicker = true' readonly/>
<span class='color-box' :style='{"background-color": data.color}'></span>
<chrome-picker :value="data.color" @input="updatePicker" v-if="displayPicker"/>
</div>
<div class='control circle' @wheel='handleScroll("xoffset", $event)'>
<circle-slider v-model="data.xoffset" :min="-50"
:max="50">data.xoffset</circle-slider>
<span class='icon xoffset'></span>
<span class='amount'>{{data.xoffset}}px
</span>
</div>
<div class='control circle'@wheel='handleScroll("yoffset", $event)'>
<circle-slider v-model="data.yoffset" :min="-50"
:max="50">data.yoffset</circle-slider>
<span class='icon yoffset'></span>
<span class='amount'>{{data.yoffset}}px
</span>
</div>
<div class='control circle'@wheel='handleScroll("blur", $event)'>
<circle-slider v-model="data.blur" :min="0"
:max="100">data.blur</circle-slider>
<span class='icon blur'></span>
<span class='amount'>{{data.blur}}px
</span>
</div>
<div class='control circle'@wheel='handleScroll("spread", $event)'>
<circle-slider v-model="data.spread" :min="-50"
:max="50">data.spread</circle-slider>
<span class='icon spread'></span>
<span class='amount'>{{data.spread}}px
</span>
</div>
<div class='control delete' @click='$emit("delete-shadow")'>
DELETE
</div>
</div>
</template>
@import url("https://fonts.googleapis.com/css?family=Roboto:400,500,900");
@import url("https://fonts.googleapis.com/css?family=Handlee");
body {
background-color: #fafafa;
font-size: 16px;
* {
box-sizing: border-box;
font-family: "Roboto", sans-serif;
}
}
#app > #info-box {
left: 0;
transform: translateX(-100%);
opacity: 0;
background-color: white;
z-index: 5;
color: rgba(180, 180, 180, 1);
font-size: 0.9em;
&.show {
transform: translateX(0);
opacity: 1;
}
h1
{
position: relative;
font-family: "Handlee";
color: #3498db;
&::after {
content: "Info";
position: absolute;
top: 50%;
left: 0%;
font-size: 1.7em;
line-height: 1em;
transform: translate(0%, -50%);
opacity: 0.1;
font-weight: bold;
color: transparentize(#3498db, 0.1);
}
}
.hide-info
{
position: absolute;
top: 1%;
right: 1%;
width: 1em;
height: 1em;
cursor: pointer;
}
h3 {
font-weight: bold;
color: rgba(180, 180, 180, 1);
}
.text {
line-height: 1.5em;
padding: 0 10px;
li {
padding: 10px 0;
list-style: none;
}
a {
font-weight: bold;
color: rgba(180, 180, 180, 1);
}
}
}
#header
{
position: fixed;
top: 0;
left: 0;
height: 150px;
width: 100vw;
text-align: center;
h1 {
position: relative;
padding: 40px 0 60px 0;
color: darken(#3498db, 25%);
font-size: 3em;
font-weight: bold;
line-height: 1.2em;
font-family: "Handlee";
z-index: -2;
text-shadow: 10px 10px 5px rgba(139, 196, 234, 0.58);
}
}
#controls,
#info-box {
position: fixed;
top: 0;
left: 0;
bottom: 0;
width: 300px;
padding: 0 30px;
overflow-y: auto;
overflow: hidden;
display: flex;
flex-direction: column;
z-index: 2;
transition: all 0.2s ease-in;
/* iOS Safari */
touch-callout: none;
/* Safari */
user-select: none;
/* Konqueror HTML */
user-select: none;
/* Firefox */
user-select: none;
/* Internet Explorer/Edge */
user-select: none;
/* Non-prefixed version, currently supported by Chrome and Opera */
user-select: none;
&:hover {
opacity: 1;
}
&.transparent:not(:hover):not(.info):not(.add-transform) {
opacity: 1;
}
#reset {
position: absolute;
bottom: 1%;
left: 5%;
padding: 5px 10px;
font-size: 0.7em;
color: #e74c3c;
border: 1px solid darken(#e74c3c, 5%);
border-radius: 5px;
cursor: pointer;
transition: all 0.2s;
&:hover {
background-color: #e74c3c;
color: white;
}
}
#info {
position: absolute;
top: 1%;
left: 2%;
font-size: 0.7em;
color: #3498db;
height: 1em;
width: 1em;
border-radius: 5px;
cursor: pointer;
transition: all 0.2s;
font-size: 2em;
display: flex;
justify-content: center;
align-items: center;
&:hover {
color: lighten(#3498db, 15%);
}
}
h3 {
width: 100%;
text-align: left;
text-transform: capitalize;
font-size: 1em;
color: rgba(180, 180, 180, 0.5);
text-indent: 5%;
margin-top: 15px;
margin-bottom: 10px;
}
#box-shadows-container {
display: flex;
flex-wrap: wrap;
margin-top: 25vh;
span {
border: 1px solid #3498db;
width: 20%;
display: flex;
justify-content: center;
align-content: center;
color: darken(#3498db, 20%);
margin: 3px;
height: 25px;
cursor: pointer;
transition: all 0.3s;
opacity: 0.5;
&.highlight, &:hover
{
opacity: 1;
}
&.add-transform {
opacity: 1;
&:hover {
background-color: lighten(#3498db, 10%);
}
}
}
}
.shadow-control {
margin: 30px 0;
display: flex;
flex-wrap: wrap;
.control {
margin: 10px 10px 20px 10px;
width: 100px;
height: 100px;
position: relative;
.amount {
width: 20%;
font-size: 0.7em;
text-align: center;
position: absolute;
top: 100%;
width: 100%;
left: 0;
&:hover {
.delete {
opacity: 1;
}
}
}
&.inset {
display: flex;
margin-bottom: 10px;
color: rgba(180, 180, 180, 0.5);
align-items: center;
width: 100%;
height: auto;
input {
display: none;
&:checked+label {
background-color: #3498db;
.switch {
left: 55%;
}
}
}
label {
width: 30px;
height: 15px;
border-radius: 10px;
background-color: gray;
display: inline-block;
margin-right: 10px;
position: relative;
transition: all 0.3s;
cursor: pointer;
span {
background-color: white;
height: 80%;
width: 40%;
position: absolute;
border-radius: 50%;
left: 5%;
top: 9%;
transition: all 0.3s;
}
}
}
&.circle
{
height: 100px;
width: 100px;
z-index: 1;
svg
{
width: 100%;
z-index: 1;
}
.icon
{
position: absolute;
top: 35%;
left: 35%;
width: 30%;
height: 30%;
display: block;
z-index: 5;
&::after
{
content: "";
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
filter: sepia(1);
}
&.xoffset, &.yoffset
{
&::after
{
background-image: url('data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIGRhdGEtbmFtZT0iTGF5ZXIgMSIgdmlld0JveD0iMCAwIDEwMCAxMDAiIHg9IjBweCIgeT0iMHB4Ij48dGl0bGU+MDM8L3RpdGxlPjxwb2x5Z29uIHBvaW50cz0iNzYuOTggNjIuMTIgMjMuMDIgNjIuMTIgMjMuMDIgNjYuMTIgNDggNjYuMTIgNDggODguMDEgMzkuMzcgODEuMyAzNi45MiA4NC40NiA1MCA5NC42MyA2My4wOCA4NC40NiA2MC42MyA4MS4zIDUyIDg4LjAxIDUyIDY2LjEyIDc2Ljk4IDY2LjEyIDc2Ljk4IDYyLjEyIj48L3BvbHlnb24+PHBvbHlnb24gcG9pbnRzPSI3Ni45OCAzMy44OCA1MiAzMy44OCA1MiAxMS45OSA2MC42MyAxOC43IDYzLjA4IDE1LjU0IDUwIDUuMzcgMzYuOTIgMTUuNTQgMzkuMzcgMTguNyA0OCAxMS45OSA0OCAzMy44OCAyMy4wMiAzMy44OCAyMy4wMiAzNy44OCA3Ni45OCAzNy44OCA3Ni45OCAzMy44OCI+PC9wb2x5Z29uPjxyZWN0IHg9IjIzLjAyIiB5PSI0OCIgd2lkdGg9IjUzLjk1IiBoZWlnaHQ9IjQiPjwvcmVjdD48L3N2Zz4=');
}
}
&.xoffset::after
{
transform: rotate(90deg);
}
&.blur::after
{
background-image: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiB4bWxuczpyZGY9Imh0dHA6Ly93d3cudzMub3JnLzE5OTkvMDIvMjItcmRmLXN5bnRheC1ucyMiIHhtbG5zOmRjPSJodHRwOi8vcHVybC5vcmcvZGMvZWxlbWVudHMvMS4xLyIgeG1sbnM6c29kaXBvZGk9Imh0dHA6Ly9zb2RpcG9kaS5zb3VyY2Vmb3JnZS5uZXQvRFREL3NvZGlwb2RpLTAuZHRkIiB4bWxuczpzdmc9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczpjYz0iaHR0cDovL2NyZWF0aXZlY29tbW9ucy5vcmcvbnMjIiB4bWxuczppbmtzY2FwZT0iaHR0cDovL3d3dy5pbmtzY2FwZS5vcmcvbmFtZXNwYWNlcy9pbmtzY2FwZSIgeG1sbnM9Imh0dHA6Ly93d3cudzMub3JnLzIwMDAvc3ZnIiB4bWxuczp4bGluaz0iaHR0cDovL3d3dy53My5vcmcvMTk5OS94bGluayIgdmVyc2lvbj0iMS4xIiB4PSIwcHgiIHk9IjBweCIgdmlld0JveD0iMCAwIDgwMCA4MDAiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDgwMCA4MDAiIHhtbDpzcGFjZT0icHJlc2VydmUiPjxnPjxwYXRoIGZpbGw9IiMwMDAwMDAiIGQ9Ik0zODguMTA0LDM3LjM5NWMtOS4wMjEsMTEuNjkyLTIyMC45OTIsMjg4LjYxMS0yMjAuOTkyLDQ5Ny44NDFjMCwxMzIuNzcxLDEwMC4xMjUsMjMyLjg5NiwyMzIuODk3LDIzMi44OTYgICBjMTMyLjc2OCwwLDIzMi44NzgtMTAwLjEyNSwyMzIuODc4LTIzMi44OTZjMC0yMDkuMjMtMjExLjk2NC00ODYuMTQ5LTIyMC45OTItNDk3Ljg0MSAgIEM0MDYuMTk5LDMwLjAyNiwzOTMuNzk5LDMwLjAyNiwzODguMTA0LDM3LjM5NXogTTQwMC4wMDksNzM4LjA2OWMtMTE3LjUzNSwwLTIwMi44MzQtODUuMjk5LTIwMi44MzQtMjAyLjgzNCAgIGMwLTE3MS4zNzMsMTU3LjczMy00MDEuMjAyLDIwMi44MzQtNDYzLjM5NmM0NS4wOSw2Mi4xOTUsMjAyLjgxNSwyOTIuMDIzLDIwMi44MTUsNDYzLjM5NiAgIEM2MDIuODI0LDY1Mi43NzEsNTE3LjUyNCw3MzguMDY5LDQwMC4wMDksNzM4LjA2OXoiPjwvcGF0aD48cGF0aCBmaWxsPSIjMDAwMDAwIiBkPSJNMzg0Ljk3Nyw2ODkuNTU2YzAsOC4yOTQsNi43MjMsMTUuMDMxLDE1LjAzMiwxNS4wMzFjOTguMTI1LDAsMTY5LjMzMy03MS4yMjMsMTY5LjMzMy0xNjkuMzUyICAgYzAtOC4yOTMtNi43MjQtMTUuMDMxLTE1LjAzMS0xNS4wMzFjLTguMjk0LDAtMTUuMDMxLDYuNzM4LTE1LjAzMSwxNS4wMzFjMCw4MC43MDUtNTguNTY5LDEzOS4yODktMTM5LjI3MSwxMzkuMjg5ICAgQzM5MS43LDY3NC41MjQsMzg0Ljk3Nyw2ODEuMjQ3LDM4NC45NzcsNjg5LjU1NnoiPjwvcGF0aD48L2c+PC9zdmc+");
}
&.spread::after
{
background-image: url("data:image/svg+xml;base64,PHN2ZyBmaWxsPSIjMDAwMDAwIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHhtbG5zOnhsaW5rPSJodHRwOi8vd3d3LnczLm9yZy8xOTk5L3hsaW5rIiB2ZXJzaW9uPSIxLjEiIHg9IjBweCIgeT0iMHB4IiB2aWV3Qm94PSIwIDAgOTYgOTYiIGVuYWJsZS1iYWNrZ3JvdW5kPSJuZXcgMCAwIDk2IDk2IiB4bWw6c3BhY2U9InByZXNlcnZlIj48Zz48cGF0aCBkPSJNMTIuOTc3LDExLjE2MWMzLjIxMiwwLDYuNDI0LDAsOS42MzcsMGMwLjQ0MSwwLDAuNzc3LTAuMTYxLDEuMDE3LTAuNDAyYzAuMDE2LTAuMDEyLDAuMDI4LTAuMDI2LDAuMDQyLTAuMDQgICBzMC4wMjctMC4wMjcsMC4wMzktMC4wNDJjMC4yNDEtMC4yNCwwLjQwMi0wLjU3NiwwLjQwMi0xLjAxN2MwLTAuMzMzLDAtMC42NjcsMC0xYzAtMC44MTgtMC42ODMtMS41LTEuNS0xLjUgICBjLTQuOTg5LDAtOS45NzksMC0xNC45NjYsMGMtMC44MTgsMC0xLjUsMC42ODItMS41LDEuNWMwLDQuOTg4LDAsOS45NzgsMCwxNC45NjdjMCwwLjgxNywwLjY4MiwxLjUsMS41LDEuNWMwLjMzMywwLDAuNjY2LDAsMSwwICAgYzAuODE2LDAsMS41LTAuNjgzLDEuNS0xLjVjMC0zLjIxMywwLTYuNDI2LDAtOS42NGM3LjAwOCw3LjAwOSwxNC4wMTYsMTQuMDE3LDIxLjAyMiwyMS4wMjNjMC41NzcsMC41NzgsMS41NDMsMC41NzgsMi4xMjEsMCAgIGMwLjIzNS0wLjIzNSwwLjQ3My0wLjQ3MSwwLjcwNy0wLjcwN2MwLjU3OC0wLjU3OCwwLjU3OC0xLjU0MywwLTIuMTIxQzI2Ljk5LDI1LjE3NywxOS45ODIsMTguMTY5LDEyLjk3NywxMS4xNjF6Ij48L3BhdGg+PHBhdGggZD0iTTg4LjM1NCw3LjE2MWMtNC45ODgsMC05Ljk3OCwwLTE0Ljk2NywwYy0wLjQ0MSwwLTAuNzc3LDAuMTYtMS4wMTgsMC40MDFjLTAuMDE2LDAuMDEzLTAuMDI3LDAuMDI2LTAuMDQxLDAuMDQgICBjLTAuMDE0LDAuMDE1LTAuMDI3LDAuMDI3LTAuMDM5LDAuMDQyYy0wLjI0MSwwLjI0LTAuNDAyLDAuNTc2LTAuNDAyLDEuMDE4YzAsMC4zMzMsMCwwLjY2NywwLDFjMCwwLjgxNywwLjY4NCwxLjUsMS41LDEuNSAgIGMzLjIxMywwLDYuNDI2LDAsOS42MzksMEM3Ni4wMTgsMTguMTcsNjkuMDEsMjUuMTc4LDYyLjAwMywzMi4xODVjLTAuNTc4LDAuNTc4LTAuNTc4LDEuNTQzLDAsMi4xMjEgICBjMC4yMzUsMC4yMzYsMC40NzIsMC40NzIsMC43MDcsMC43MDdjMC41NzgsMC41NzgsMS41NDMsMC41NzgsMi4xMjEsMGM3LjAwOC03LjAwOCwxNC4wMTctMTQuMDE2LDIxLjAyMi0yMS4wMjMgICBjMCwzLjIxNCwwLDYuNDI3LDAsOS42NGMwLDAuODE3LDAuNjg0LDEuNSwxLjUsMS41YzAuMzM0LDAsMC42NjgsMCwxLDBjMC44MTcsMCwxLjUtMC42ODMsMS41LTEuNWMwLTQuOTg5LDAtOS45NzksMC0xNC45NjcgICBDODkuODU0LDcuODQzLDg5LjE3MSw3LjE2MSw4OC4zNTQsNy4xNjF6Ij48L3BhdGg+PHBhdGggZD0iTTg4LjM1NCw3MC44NzNjLTAuMzMyLDAtMC42NjYsMC0xLDBjLTAuODE2LDAtMS41LDAuNjg0LTEuNSwxLjVjMCwzLjIxMywwLDYuNDI2LDAsOS42MzkgICBjLTcuMDA4LTcuMDA4LTE0LjAxNi0xNC4wMTQtMjEuMDIyLTIxLjAyMWMtMC41NzgtMC41NzgtMS41NDMtMC41NzgtMi4xMjEsMGMtMC4yMzUsMC4yMzQtMC40NzIsMC40NzMtMC43MDcsMC43MDcgICBjLTAuNTc4LDAuNTc4LTAuNTc4LDEuNTQzLDAsMi4xMjFjNy4wMDgsNy4wMDgsMTQuMDE3LDE0LjAxNiwyMS4wMjIsMjEuMDIxYy0zLjIxMywwLTYuNDI2LDAtOS42MzksMGMtMC44MTYsMC0xLjUsMC42ODQtMS41LDEuNSAgIGMwLDAuMzM0LDAsMC42NjgsMCwxYzAsMC44MTgsMC42ODQsMS41LDEuNSwxLjVjNC45ODksMCw5Ljk3OSwwLDE0Ljk2NywwYzAuODE3LDAsMS41LTAuNjgyLDEuNS0xLjVjMC00Ljk4OCwwLTkuOTc5LDAtMTQuOTY3ICAgQzg5Ljg1NCw3MS41NTcsODkuMTcxLDcwLjg3Myw4OC4zNTQsNzAuODczeiI+PC9wYXRoPjxwYXRoIGQ9Ik0zMy4yOTEsNjAuOTljLTAuMzEzLTAuMzEzLTAuNjYyLTAuNDM4LTEuMDAyLTAuNDM4Yy0wLjAyLTAuMDAyLTAuMDM5LDAtMC4wNTktMC4wMDJjLTAuMDIxLDAuMDAyLTAuMDM5LDAtMC4wNiwwLjAwMiAgIGMtMC4zNCwwLTAuNjg5LDAuMTI1LTEuMDAyLDAuNDM4Yy03LjAwOCw3LjAwOC0xNC4wMTYsMTQuMDE0LTIxLjAyMiwyMS4wMjFjMC0zLjIxMywwLTYuNDI2LDAtOS42MzljMC0wLjgxOC0wLjY4NC0xLjUtMS41LTEuNSAgIGMtMC4zMzQsMC0wLjY2NywwLTEsMGMtMC44MTgsMC0xLjUsMC42ODItMS41LDEuNWMwLDQuOTg4LDAsOS45NzcsMCwxNC45NjdjMCwwLjgxNiwwLjY4MiwxLjUsMS41LDEuNWM0Ljk4NywwLDkuOTc3LDAsMTQuOTY2LDAgICBjMC44MTcsMCwxLjUtMC42ODQsMS41LTEuNWMwLTAuMzM0LDAtMC42NjgsMC0xYzAtMC44MTgtMC42ODMtMS41LTEuNS0xLjVjLTMuMjEzLDAtNi40MjUsMC05LjYzNywwICAgYzcuMDA4LTcuMDA4LDE0LjAxNS0xNC4wMTYsMjEuMDIxLTIxLjAyM2MwLjU3OC0wLjU3NiwwLjU3OC0xLjU0MywwLTIuMTIxQzMzLjc2NCw2MS40NjEsMzMuNTI2LDYxLjIyNSwzMy4yOTEsNjAuOTl6Ij48L3BhdGg+PHBhdGggZD0iTTQ4LjQ0OCwzNC44NjdjLTAuMTM3LTAuMDMzLTAuMjgyLTAuMDU0LTAuNDQ4LTAuMDQ1Yy0wLjE2Ni0wLjAwOS0wLjMxMiwwLjAxMy0wLjQ0OSwwLjA0NiAgIEMzMS4wNDIsMzYuMTk3LDMxLjE4Niw2MC4yNzEsNDgsNjEuMThjNy40MzgsMC40MDIsMTIuODExLTYuMzMyLDEzLjE4LTEzLjE3OUM2MS41NzMsNDAuNzI2LDU1LjEzOSwzNS40NDEsNDguNDQ4LDM0Ljg2N3oiPjwvcGF0aD48L2c+PC9zdmc+");
}
}
}
&.color {
height: auto;
position: relative;
flex-grow: 1;
width: 100%;
>input {
width: 100%;
padding: 6px;
border-radius: 5px;
border: 1px solid rgba(0, 0, 0, 0.3);
outline: 0;
}
>span {
position: absolute;
right: 1px;
top: 1px;
height: calc(100% - 2px);
width: 15%;
background: gray;
border-radius: 0 5px 5px 0;
pointer-events: none;
}
.vc-chrome {
position: absolute;
top: 35px;
right: 0;
z-index: 9;
width: 100%;
}
}
&.delete {
margin-top: 30px;
height: auto;
width: 100%;
padding: 5px 10px;
font-size: 0.7em;
color: #e74c3c;
border: 1px solid darken(#e74c3c, 5%);
border-radius: 5px;
cursor: pointer;
transition: all 0.2s;
text-align: center;
&:hover {
background-color: #e74c3c;
color: white;
}
}
}
}
}
.show-effects {
position: fixed;
left: 70%;
z-index: 1;
top: 50%;
transform: translate(-50%, -50%);
width: 30vw;
height: 30vh;
&.transform-3d {
transform-style: preserve-3d;
}
.transform-box {
width: 100%;
left: 0%;
top: 0%;
height: 100%;
background-color: #2980b9;
position: absolute;
color: white;
display: flex;
justify-content: center;
align-items: center;
font-weight: bold;
font-size: 2em;
transition: all 0.2s;
}
}
#css {
position: fixed;
bottom: 1vh;
width: calc(90vw - 235px);
background-color: rgba(255, 255, 255, 0.8);
border-radius: 1vw / 2vh;
right: 5vw;
display: flex;
flex-direction: column;
box-sizing: border-box;
font-size: 1em;
color: black;
z-index: 1;
opacity: 0.3;
transition: all 0.2s;
padding: 10px;
&:hover {
opacity: 1;
}
span {
padding: 5px;
}
}
// Transition
.fade-enter-active,
.fade-leave-active {
transition: opacity 0.2s;
}
.fade-enter,
.fade-leave-to {
opacity: 0;
}
/*
Split Vertical icon designed by Bhima on the @NounProject. https://thenounproject.com/term/split-vertical/1268414
spread icon designed by projecthayat on the @NounProject. https://thenounproject.com/term/spread/1863148
Blur icon designed by abderraouf omara on the @NounProject. https://thenounproject.com/term/blur/705680
*/
View Compiled
// https://stackoverflow.com/a/42389266/529024
Vue.directive('click-outside', {
bind: function(el, binding, vnode) {
this.event = function(event) {
if (!(el == event.target || el.contains(event.target))) {
vnode.context[binding.expression](event);
}
};
document.body.addEventListener('click', this.event)
},
unbind: function(el) {
document.body.removeEventListener('click', this.event)
},
});
var chrome = VueColor.Chrome;
Vue.component("box-shadow-control", {
template: "#box-shadow-control",
props: ["data"],
components: {
'chrome-picker': chrome
},
data() {
return {
displayPicker: false
}
},
methods: {
handleScroll: function(item, e) {
var element = e.target;
var max = (item == 'blur') ? 100 : 50;
var min = (item == 'blur') ? 0 : -50;
var current = this.data[item];
// Scrolling up
if (e.deltaY < 0) {
if (current < max)
this.data[item] = this.data[item] + 1;
}
// Scrolling down
if (e.deltaY > 0) {
if (current > min)
this.data[item] = this.data[item] - 1;
}
},
updatePicker: function(color) {
if (color.rgba.a == 1) {
this.data.color = color.hex;
} else {
this.data.color = "rgba(" + color.rgba.r + ", " + color.rgba.g + ", " + color.rgba.b + ", " + color.rgba.a + ")";
}
},
hidePicker: function() {
this.displayPicker = false;
}
}
});
new Vue({
el: "#app",
data() {
return {
style: {
"box-shadow": ""
},
showInfo: false,
currentShadow: 0,
boxShadows: [{
inset: false,
xoffset: 10,
yoffset: 10,
blur: 0,
spread: 0,
color: "black"
}],
boxShadowTemplate: {
inset: false,
xoffset: 10,
yoffset: 10,
blur: 0,
spread: 0,
color: "black"
}
};
},
computed: {
getData: function() {
return this.boxShadows[this.currentShadow];
}
},
methods: {
resetControls: function(e) {
Object.assign(this.$data, this.$options.data.apply(this));
},
addShadow: function() {
// this code >> JSON.parse(JSON.stringify(transform)) << helps copy object by value not by reference
var newShadow = JSON.parse(JSON.stringify(this.boxShadowTemplate));
//newShadow.id = this.uid();
this.boxShadows.push(newShadow);
this.setShadow(this.boxShadows.length - 1);
},
setShadow: function(shadowIndex) {
this.currentShadow = shadowIndex;
},
deleteShadow: function() {
// First delete element
this.boxShadows.splice(this.currentShadow, 1);
// Second set other elements (if any)
var length = this.boxShadows.length;
if(length > 0)
this.setShadow(length - 1);
},
getStyle: function() {
var final = [];
// Loop through set box shadows and "flatten"
this.boxShadows.forEach(shadow => {
var shadowFinal = [];
// Loop through each box shadow set and format accordingly
for (const item in shadow) {
// if inset is set add the word inset
if (item == 'inset') {
if (shadow[item] == true)
shadowFinal.push("inset");
} else if (item == 'color') {
// Color does not require "px" affix so add as is
shadowFinal.push(shadow[item]);
} else {
// For all other properites add "px"
shadowFinal.push(shadow[item] + "px");
}
}
// Join flatten properties
final.push(
shadowFinal.join(" ")
);
});
// Join everything together and assign
this.style["box-shadow"] = final.join(", ");
}
},
watch: {
boxShadows: {
handler: function(){
this.getStyle();
},
deep: true
}
},
mounted() {
this.getStyle();
}
});
This Pen doesn't use any external CSS resources.