Skip to content

Instantly share code, notes, and snippets.

@sojohnnysaid
Created March 17, 2024 05:54
Show Gist options
  • Select an option

  • Save sojohnnysaid/a144b18d9a2f612bf2a1c7de40ebf85f to your computer and use it in GitHub Desktop.

Select an option

Save sojohnnysaid/a144b18d9a2f612bf2a1c7de40ebf85f to your computer and use it in GitHub Desktop.
Animation reciting a quote from Pico Iyer
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Quote Animation</title>
<script src="https://cdn.jsdelivr.net/npm/vue@2.6.14/dist/vue.js"></script>
<style>
body {
margin: 0;
padding: 0;
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
}
.background {
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
z-index: 1;
}
.quote-box {
position: relative;
background-color: rgba(255, 255, 255, 0.8);
padding: 30px;
border-radius: 10px;
text-align: center;
max-width: 600px;
box-shadow: 0 4px 6px rgba(0, 0, 0, 0.1);
opacity: 0;
transition: opacity 2s ease;
z-index: 2;
}
.quote-box p {
font-size: 24px;
line-height: 1.5;
margin: 0;
color: #333;
}
.quote-box.hide-quote {
display: none;
}
.replay-button-box {
position: absolute;
bottom: 20px;
left: 50%;
transform: translateX(-50%);
background-color: white;
padding: 10px;
border-radius: 38px;
opacity: 0;
transition: opacity 0.5s ease;
z-index: 3;
}
.replay-button-box.show {
opacity: 1;
}
.replay-button {
padding: 10px 20px;
font-size: 18px;
background-color: #fff;
color: #333;
border: none;
border-radius: 5px;
cursor: pointer;
}
.credit-text {
font-size: 16px;
line-height: 1.5;
margin: 0;
color: #333;
}
.credit-box {
opacity: 0;
transition: opacity 0.5s ease;
}
.credit-box.show {
opacity: 1;
}
.credit-box.fade-out {
opacity: 0;
}
</style>
</head>
<body>
<div id="app">
<div class="background" :style="gradientStyle"></div>
<div class="quote-box" :class="{ 'hide-quote': showReplayButton }" :style="{ opacity: quoteBoxOpacity }">
<transition name="fade" mode="out-in">
<p :key="currentIndex" v-if="quotes[currentIndex]" v-html="quotes[currentIndex].text"></p>
</transition>
</div>
<div class="quote-box credit-box" :class="{ show: showReplayButton,'fade-out': fadeOutCredit }">
<p class="credit-text">― Pico Iyer, The Art of Stillness: Adventures in Going Nowhere</p>
</div>
<div class="replay-button-box" :class="{ show: showReplayButton }">
<button class="replay-button" @click="replayAnimation">Replay</button>
</div>
</div>
<script>
new Vue({
el: '#app',
data: {
fadeOutCredit: false,
quotes: [
{ text: 'In an age of speed, I began to think, nothing could be more invigorating than going slow.', color: '#8BC34A' },
{ text: 'In an age of distraction, nothing can feel more luxurious than paying attention.', color: '#4CAF50' },
{ text: 'And in an age of constant movement, nothing is more urgent than sitting still.', color: '#CDDC39' },
{ text: 'You can go on vacation to Paris or Hawaii or New Orleans three months from now, and you\'ll have a tremendous time, I\'m sure.', color: '#FFC107' },
{ text: 'But if you want to come back feeling new - alive and full of fresh hope and in love with the world - I think the place to visit may be Nowhere.', color: '#9C27B0' }
],
currentIndex: 0,
quoteBoxOpacity: 0,
colorNames: [
'--magic-rainbow-color-0',
'--magic-rainbow-color-1',
'--magic-rainbow-color-2',
],
transitionDelay: 1000,
showReplayButton: false,
},
computed: {
gradientStyle() {
const colorKeys = this.colorNames;
const currentColor = this.quotes[this.currentIndex].color;
return {
[colorKeys[0]]: currentColor,
[colorKeys[1]]: this.lightenColor(currentColor, 20),
[colorKeys[2]]: this.lightenColor(currentColor, 40),
transition: `
${colorKeys[0]} ${this.transitionDelay}ms linear,
${colorKeys[1]} ${this.transitionDelay}ms linear,
${colorKeys[2]} ${this.transitionDelay}ms linear
`,
background: `
radial-gradient(
circle at top left,
var(${colorKeys[2]}) 0%,
var(${colorKeys[1]}) 50%,
var(${colorKeys[0]}) 100%
)
`,
};
},
},
mounted() {
this.registerProperties();
this.startAnimation();
},
methods: {
registerProperties() {
this.colorNames.forEach((name) => {
CSS.registerProperty({
name,
syntax: '<color>',
inherits: false,
initialValue: 'white',
});
});
},
startAnimation() {
this.showReplayButton = false;
this.quoteBoxOpacity = 0;
setTimeout(() => {
this.quoteBoxOpacity = 1;
setTimeout(() => {
this.quoteBoxOpacity = 0;
setTimeout(() => {
this.currentIndex++;
if (this.currentIndex < this.quotes.length) {
setTimeout(() => {
this.startAnimation();
}, this.transitionDelay);
} else {
this.currentIndex = 0;
setTimeout(() => {
this.showReplayButton = true;
}, this.transitionDelay);
}
}, 2000);
}, 5000);
}, 100);
},
replayAnimation() {
this.fadeOutCredit = true;
setTimeout(() => {
this.fadeOutCredit = false;
this.startAnimation();
}, 500);
},
lightenColor(color, amount) {
const parseColor = (color) => parseInt(color.slice(1), 16);
const rgbToHex = (r, g, b) => '#' + [r, g, b].map(x => {
const hex = x.toString(16);
return hex.length === 1 ? '0' + hex : hex;
}).join('');
const r = parseColor(color.slice(0, 3));
const g = parseColor(color.slice(2, 5));
const b = parseColor(color.slice(4, 7));
const lightenChannel = (channel) => Math.min(Math.floor(channel * (1 + amount / 100)), 255);
return rgbToHex(lightenChannel(r), lightenChannel(g), lightenChannel(b));
},
},
});
</script>
</body>
</html>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment