JSFiddle - React, Tailwind, and code Playground
by tlgreg
HTML
<div id="exercise">
<!-- 1) Start the Effect with the Button. The Effect should alternate the "highlight" or "shrink" class on each new setInterval tick (attach respective class to the div with id "effect" below) -->
<div>
<button @click="toggleEffect">Toggle Effect</button>
<div id="effect" :class="{highlight: highlighted, shrink: shrinked}"></div>
</div>
<!-- 2) Create a couple of CSS classes and attach them via the array syntax -->
<div :class="[foo,bar,baz]">I got no class :(</div>
<!-- 3) Let the user enter a class (create some example classes) and attach it -->
<div>
<input type="text" v-model="dynClass">
<div style="min-height: 1rem" :class="dynClass"></div>
</div>
<!-- 4) Let the user enter a class and enter true/ false for another class (create some example classes) and attach the classes -->
<div>
<input type="text" v-model="dynClass">
<input type="checkbox" v-model="isRounded">
<div style="min-height: 1rem" :class="[dynClass, {rounded: isRounded}]"></div>
</div>
<!-- 5) Repeat 3) but now with values for styles (instead of class names). Attach the respective styles. -->
<div>
<input type="text" v-model="dynBg">
<div style="width: 5rem; height: 1rem" :style="{backgroundColor: dynBg}"></div>
</div>
<!-- 6) Create a simple progress bar with setInterval and style bindings. Start it by hitting the below button. -->
<div>
<button @click="startProgress">Start Progress</button>
<div class="progress-bar" :class="{loading: progressLoading, load: progressLoad}"></div>
</div>
</div>
SCSS
#effect {
width: 100px;
height: 100px;
border: 1px solid black;
transition: all .25s ease;
}
#effect.highlight, .highlight {
background-color: red;
width: 200px;
}
#effect.shrink, .shrink {
background-color: gray;
width: 50px;
}
.foo { color: papayawhip }
.bar {
--pad: calc(1em/3);
text-shadow: 0 0 var(\--pad) darkred;
padding: var(\--pad);
}
.baz {
font-weight: bold;
font-family: sans-serif;
}
.rounded {
border-radius: 1rem;
}
.progress-bar {
--duration: 2s;
--outro: .5s;
position: relative;
width: 0rem;
height: 1rem;
background-color: skyblue;
margin: .2rem 0;
border-radius: .2rem;
border-width: 1px;
border-style: none;
border-color: slateblue;
transition: width var(\--duration) linear .01s,
background-color var(\--outro) ease calc(var(\--duration) + var(\--outro));
&::after {
content: "";
display: block;
position: absolute;
left: 0;
top: 0;
width: 100%;
height: 100%;
background-image: repeating-linear-gradient(-45deg, skyblue, skyblue 1rem, slateblue 1rem, slateblue 2rem);
transition: opacity var(\--outro) ease calc(var(\--duration) + var(\--outro));
}
&.loading {
cursor: progress;
}
&.load {
background-color: chartreuse;
width: 30rem;
border-style: solid;
&::after {
opacity: 0;
}
}
}
Babel + JSX
const ONE_SECOND = 1000
new Vue({
el: '#exercise',
timer: null,
data: {
highlighted: true,
shrinked: false,
foo: 'foo',
bar: 'bar',
baz: 'baz',
dynClass: '',
isRounded: false,
dynBg: 'transparent',
progressLoading: false,
progressLoad: false,
},
methods: {
toggleEffect() {
if (!this.timer) {
this.timer = setInterval(() => {
this.highlighted = !this.highlighted
this.shrinked = !this.shrinked
}, ONE_SECOND)
} else {
clearInterval(this.timer)
this.timer = null
}
},
startProgress() {
if (!this.progressLoad) {
this.progressLoading = true
this.progressLoad = true
setTimeout(() => { this.progressLoading = false }, 3010)
}
},
},
});