Skip to content

Instantly share code, notes, and snippets.

@INDIAN2020
Created December 14, 2020 05:03
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save INDIAN2020/fdaf864b267bba4bf99cc5fa3951f5b1 to your computer and use it in GitHub Desktop.
Save INDIAN2020/fdaf864b267bba4bf99cc5fa3951f5b1 to your computer and use it in GitHub Desktop.
Advent Calendar Magic Drawers

Advent Calendar Magic Drawers

Inspired by the most common type of Advent Calendar, for the CodePen Christmas challenge, I've created a magical version of it. It's dedicated completely to Christmas festivities. Hope you like it!

A Pen by Eduardo Allegrini on CodePen.

License.

import React, {
Component,
useState
} from "https://cdn.skypack.dev/react@17.0.1";
import ReactDOM from "https://cdn.skypack.dev/react-dom@17.0.1";
class Calendar extends Component {
constructor(props) {
super(props);
this.state = {
time: "--:--",
box: undefined,
content: {}
};
}
componentDidMount() {
this.tick();
this.clock = setInterval(() => this.tick(), 1000);
}
componentWillUnmount() {
clearInterval(this.clock);
}
tick() {
const date = new Date();
let hours = 23 - date.getHours();
let minutes = 60 - date.getMinutes();
let seconds = 60 - date.getSeconds();
if (hours === 0 && minutes === 0 && seconds === 0) {
window.location.reload();
}
if (minutes < 10) {
minutes = "0" + minutes;
}
if (seconds < 10) {
seconds = "0" + seconds;
}
this.setState({
time: hours + ":" + minutes + ":" + seconds
});
}
handleClick(i) {
if (this.state.box !== undefined) {
this.setState({ box: undefined });
} else if (i < today) {
this.setState({
box: i,
content: contentSelected[i]
});
}
}
render() {
const box = this.state.box;
const content = this.state.content;
const calendar = box !== undefined;
const boxes = contentSelected.map((item, i) => {
const ready = i < today;
const active = box === i;
return (
<a
key={i}
className={
"calendar-box" + (ready ? " ready" : "") + (active ? " active" : "")
}
href={"#box-" + i}
onClick={() => this.handleClick(i)}
>
<div
className="face"
style={ready ? { backgroundImage: "url(" + item.image + ")" } : {}}
>
{i === today ? (<span>{this.state.time}</span>) : i + 1}
</div>
</a>
);
});
return (
<div className={"calendar" + (calendar ? " active" : "")}>
<div
className="calendar-bg"
style={{ backgroundImage: "url(" + content.image + ")" }}
></div>
<div className="calendar-boxes">{boxes}</div>
<h3 className="calendar-text" style={content.style}>
{content.quote}
<span>{content.author}</span>
</h3>
</div>
);
}
}
ReactDOM.render(<Calendar />, document.getElementById("root"));
<script src="https://assets.codepen.io/5356857/advent-calendar-content.js"></script>
$inner: lighten(black, 20);
$size: 80px;
.calendar {
padding: 1rem;
min-height: calc(100vh - 2rem);
overflow: auto;
color: white;
background: linear-gradient(45deg, #ff5f6d, #ffc371);
}
.calendar-bg {
position: fixed;
top: 0;
right: 0;
bottom: 0;
left: 0;
background-size: cover;
transition: all 300ms ease-in-out;
opacity: 0;
transition-property: opacity;
will-change: opacity;
&:before {
//content: "";
position: absolute;
top: 0;
right: 0;
bottom: 0;
left: 0;
background: linear-gradient(
15deg,
rgba(black, .7) 15%,
transparent 25%,
);
}
.active & {
//transition-delay: 300ms;
opacity: 1;
}
}
.calendar-text {
position: absolute;
bottom: 1rem;
right: 1rem;
max-width: 250px;
margin: 0;
font-size: 2rem;
font-weight: 100;
font-family: 'Caveat', cursive;
background: linear-gradient(45deg, #000000, #434343);
padding: 1rem;
box-shadow: 0 10px 10px -5px rgba(black, .8);
/**/
transform: translateX(20px);
opacity: 0;
transition: all 300ms ease-in-out;
transition-property: opacity, transform;
will-change: opacity, transform;
span {
font-size: 1rem;
position: absolute;
bottom: 0;
right: .3rem;
&:before {
content: "– "
}
}
.active & {
z-index: 1;
transition-delay: 1000ms;
opacity: 1;
transform: translate(0);
}
}
.calendar-boxes {
display: grid;
grid-template-columns: repeat(7, 1fr);
grid-template-rows: repeat(7, 1fr);
gap: 1rem;
}
.calendar-box {
position: relative;
z-index: 1;
min-width: $size;
min-height: $size;
box-sizing: border-box;
text-decoration: none;
perspective: 1000px;
color: inherit;
.face {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
display: flex;
//flex-wrap: wrap;
align-items: center;
justify-content: center;
font-size: 2rem;
border: 1px dashed;
}
&.ready {
background-color: $inner;
transition: all 300ms ease-in-out;
transition-property: box-shadow, opacity, z-index;
will-change: box-shadow, opacity, z-index;
transition-delay: 0, 0, 300ms;
.face {
padding-top: 1rem;
border-style: solid;
box-shadow: 0 5px 15px rgba(black, 0.5);
background-size: cover;
background-attachment: fixed;
background-position-y: -20px;
transition: all 300ms ease-in-out;
transition-property: transform, box-shadow;
will-change: transform, box-shadow;
perspective: 1000px;
//cursor: grab;
&:before {
content: "";
position: absolute;
top: -1px;
left: 50%;
width: $size / 2;
height: $size / 5;
margin-left: -$size / 4;
background-color: $inner;
border-bottom-left-radius: $size / 5;
border-bottom-right-radius: $size / 5;
border: 1px solid white;
border-top: none;
transition: all 300ms ease-in-out;
transition-property: background-color;
will-change: background-color;
}
&:after {
content: '';
position: absolute;
left: -1px;
right: -1px;
background-color: $inner;
//top: -13px;
//height: 13px;
//clip-path: polygon(4% 0%, 96% 0%, 100% 100%, 0% 100%);
//transform: scaleY(0);
bottom: 100%;
height: 110px;
transform-origin: bottom;
transform: rotateX(80deg) scaleY(0);
transition: all 300ms ease-in-out;
transition-property: transform, background-color;
will-change: transform, background-color;
}
}
}
&:not(.ready) {
cursor: not-allowed;
span {
font-size: 1.2rem;
}
}
.active & {
opacity: 0;
}
&.active {
transition-delay: 0, 0, 0;
opacity: 1;
box-shadow: 0 0 15px 5px rgba(white, 1);
.face {
transform: translatey(15px) translateZ($size);
box-shadow: 0 10px 10px rgba(black, 0.7);
&:before {
background-color: white;
}
&:after {
//transform: scaleY(1);
transform: rotateX(80deg) scaleY(1);
background-color: white;
}
}
}
/* Sizes & positions */
&:nth-child(1) {
grid-row-start: 1;
grid-row-end: 3;
}
&:nth-child(3) {
grid-column-start: 3;
grid-column-end: 5;
}
&:nth-child(4) {
grid-row-start: 1;
grid-row-end: 3;
grid-column-start: 5;
grid-column-end: 7;
}
&:nth-child(5) {
grid-row-start: 1;
grid-row-end: 3;
grid-column-start: 7;
grid-column-end: 8;
}
&:nth-child(6) {
grid-row-start: 3;
grid-row-end: 4;
grid-column-start: 1;
grid-column-end: 2;
}
&:nth-child(7) {
grid-row-start: 2;
grid-row-end: 4;
grid-column-start: 2;
grid-column-end: 4;
}
&:nth-child(8) {
grid-row-start: 2;
grid-row-end: 4;
}
&:nth-child(10) {
grid-column-start: 6;
grid-column-end: 8;
}
&:nth-child(11) {
grid-column-start: 1;
grid-column-end: 2;
grid-row-start: 4;
grid-row-end: 6;
}
&:nth-child(12) {
grid-column-start: 2;
grid-column-end: 4;
}
&:nth-child(13) {
grid-column-start: 4;
grid-column-end: 6;
}
&:nth-child(16) {
grid-row-start: 6;
grid-row-end: 7;
}
&:nth-child(17) {
grid-row-start: 5;
grid-row-end: 7;
}
&:nth-child(18) {
grid-column-start: 3;
grid-column-end: 5;
grid-row-start: 5;
grid-row-end: 7;
}
&:nth-child(20) {
grid-column-start: 6;
grid-column-end: 8;
}
&:nth-child(21) {
grid-column-start: 1;
grid-column-end: 3;
}
&:nth-child(24) {
grid-row-start: 6;
grid-row-end: 8;
}
&:nth-child(25) {
grid-column-start: 6;
grid-column-end: 8;
grid-row-start: 6;
grid-row-end: 8;
}
}
<link href="https://fonts.googleapis.com/css2?family=Caveat" rel="stylesheet" />
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment