Leaf-Loos Calendar | Calendar html css js







Leaf-Loos Calendar | Calendar html css js

Welcome🎉 to Code With Random blog. In this blog, we learn how we create a Calendar. We use HTML, Css, and javascript for this Custom Calendar. Hope you enjoy our blog so let’s start with a basic HTML structure for a  Calendar.

HTML code

 <div class="wrap">  
<div class="calendar -bevel" id="calendar">
<button type="button" id="reset" class="calendar__reset">Reset</button>
<div class="calendar__scraps" hidden></div>
<div class="calendar__scraps calendar__scraps--1" hidden></div>
<div class="calendar__scraps calendar__scraps--2" hidden></div>
<div class="calendar__scraps calendar__scraps--3" hidden></div>
<div class="calendar__scraps calendar__scraps--4" hidden></div>
<div class="calendar__scraps calendar__scraps--5" hidden></div>
<div class="calendar__scraps-shadow"></div>
<div class="calendar__assist">Click or use keyboard</div>
<div class="calendar__peg">
<div class="calendar__peg-rope -bevel"></div>
<div class="calendar__peg-rope calendar__peg-rope--2 -bevel"></div>
<div class="calendar__peg-nail -bevel"></div>
</div>
</div>
<button type="button" id="tear-all">Tear all</button> <!-- for fun! -->
</div>
<template id="calendar-sheet-tpl">
<time class="leaf">
<div class="leaf__scrap"></div>
<div class="leaf__main">
<h2 class="leaf__year"></h2>
<h3 class="leaf__month"></h3>
<div class="leaf__day"></div>
<div class="leaf__weekday"></div>
</div>
<div class="decor">
<div></div>
<div></div>
</div>
</div>
</template>
<svg version="1.1" class="-removed-from-viewport">
<defs>
<clipPath id="scrap-leaf-path">
<path id="path" transform="scale(3.8)" d="m 70.773536,10.46612 c -0.0014,-0.992822 0.01718,-2.1979764 -0.0046,-2.995332 C 70.784698,6.6977425 70.410061,6.5121183 70.1977,6.0479712 69.346453,5.5907087 69.529988,4.5737036 69.190823,4.6664752 68.335905,5.4059538 68.239865,6.7005368 67.449288,6.4693974 66.851926,6.1584047 66.649285,5.1210255 66.480106,4.7323636 66.1737,4.8456619 65.86506,6.5715683 65.306321,6.8618239 65.011486,6.6517408 64.762642,6.1527579 64.594312,5.8495781 64.545726,5.7612181 63.77227,3.6820407 63.214597,3.8214587 62.648516,3.9629791 60.814739,7.0793723 60.527486,7.4447669 59.323318,7.5928568 59.611072,4.9030576 58.734323,5.46107 58.083157,5.9571423 58.380927,6.3699781 57.472768,6.3699781 56.808051,6.3848178 56.215594,5.4382269 55.706735,5.6842662 55.388214,5.8753797 54.769907,6.5719597 54.316376,6.3443508 53.822968,6.0967288 53.657971,5.4568846 53.298643,5.0377751 53.131305,4.8425978 52.102957,6.08972 51.846864,6.2191502 51.29915,6.4959642 50.932753,5.1763368 50.664079,4.8999547 49.215134,4.884717 49.24005,6.5388349 48.451588,7.2472731 48.142016,6.612005 47.682931,5.9909331 47.174315,5.509574 45.423846,5.2420904 43.886407,7.1402865 42.310238,7.089137 41.050008,6.4751782 41.199961,5.2184063 40.386379,5.0186022 39.783118,5.4119951 39.326218,6.7087878 38.845208,6.703203 38.468647,6.1202967 38.154499,4.7165613 37.825549,4.8179555 36.702927,5.2194785 37.10629,6.9961527 36.10059,6.858809 34.675914,9.1921582 34.720833,6.6113329 34.067561,7.2721908 33.63771,7.7963709 33.160255,8.3038158 32.749841,8.7775959 32.597647,8.9538102 32.408116,9.3985568 32.231935,9.2463227 31.077266,8.3474346 31.104489,7.040133 30.340429,6.0302472 29.09526,4.4455421 28.000671,7.5056253 26.878771,7.278159 26.527408,7.2069197 26.562736,6.2535314 26.343107,5.9701693 25.566524,4.9682308 25.663928,5.610395 24.699969,5.0780849 24.146204,4.7722892 22.828197,6.2630546 22.319946,6.3759992 21.329141,6.5961783 20.740677,5.0209465 20.160806,5.2205201 18.717895,5.8281868 17.767818,7.3116314 16.257066,7.587934 15.24854,6.5629942 14.776612,4.8396606 13.696978,4.2432861 12.295826,4.3635237 11.870544,5.7131572 10.338489,5.6378469 10.110967,5.966869 9.8784647,6.52768 9.5158133,6.7709472 8.4970337,5.9654354 8.3296167,5.604582 7.895868,5.1146611 7.3142791,4.5174888 6.8950101,4.6219852 6.1671189,5.0569491 5.8476567,5.2478494 5.8410474,5.5761719 5.422951,5.5838419 4.7166635,5.5967967 4.3896048,4.991238 3.8809557,4.7724149 1.8862049,6.828618 0.19130199,3.5536941 0.13541012,7.0092989 c 0.0262734,3.3270221 0.0207371,3.4356171 0.0207371,3.4356171 33.68142479,-0.01136 47.07244579,0.03257 70.61738879,0.0212 z" />
</clipPath>
</defs>
</svg>

There is all HTML code for the Calendar. Now, you can see output without CSS, then we write css & javascript for the Calendar.

output

Leaf-Loos Calendar | Calendar html css js

CSS Code

 @import url("https://fonts.googleapis.com/css2?family=Lora&display=swap");  
:root {
--border-radius: 0.125rem;
--calendar-offset: 2rem;
--width: 18.75rem;
--height: 25rem;
--color-paper-dark: #fff19f;
--color-paper-darker: #ffed87;
--color-paper-light: #fffadb;
--color-text: #000; /* todo change */
--color-weekend: #d00; /* todo change */
--color-bg: #1b2531;
--font-size: clamp(1rem, calc(1rem + 1vw), 2rem);
--font-family: "Lora", serif;
--font-text: bold var(--font-size) / 1 var(--font-family);
}
*,
*::before,
*::after {
box-sizing: border-box;
}
html,
body {
width: 100%;
height: 100%;
}
body {
margin: 0;
background-color: var(--color-bg);
-webkit-tap-highlight-color: rgba(0, 0, 0, 0);
outline: 0;
}
.wrap {
position: relative;
width: 100%;
height: 100%;
overflow: hidden;
display: flex;
align-items: center;
justify-content: center;
}
.calendar {
border-radius: var(--border-radius);
width: var(--width);
height: var(--height);
background-color: brown;
position: relative;
}
.calendar__scraps {
position: absolute;
top: calc(var(--calendar-offset) / 2);
left: calc(var(--calendar-offset) / 2);
background-color: var(--color-paper-dark);
height: 2.5rem;
width: calc(100% - var(--calendar-offset));
clip-path: url(#scrap-leaf-path);
transform: scale(-1);
z-index: 6;
}
.calendar__scraps--1 {
background-color: rgba(0, 0, 0, 0.25);
top: calc(var(--calendar-offset) / 2 + 1px);
z-index: 5;
}
.calendar__scraps--2 {
background-color: var(--color-paper-darker);
top: calc(var(--calendar-offset) / 2 + 2px);
transform: scaleY(-1);
z-index: 4;
}
.calendar__scraps--3 {
background-color: rgba(0, 0, 0, 0.25);
top: calc(var(--calendar-offset) / 2 + 3px);
transform: scaleY(-1);
z-index: 3;
}
.calendar__scraps--4 {
background-color: var(--color-paper-darker);
top: calc(var(--calendar-offset) / 2 + 4px);
z-index: 2;
}
.calendar__scraps--5 {
background-color: rgba(0, 0, 0, 0.25);
top: calc(var(--calendar-offset) / 2 + 5px);
z-index: 1;
}
.calendar__assist {
position: absolute;
bottom: -2rem;
color: #fff;
font: bold 1rem/1 Arial, Helvetica, sans-serif;
text-align: center;
width: 100%;
opacity: 0;
animation: blink 0.54s ease-in-out 7 1s alternate;
}
.calendar__peg {
position: absolute;
width: 100%;
height: 3rem;
top: -3rem;
z-index: -1;
}
.calendar__peg-nail {
position: absolute;
width: 1.5rem;
height: 1.5rem;
left: 50%;
transform: translate(-50%);
background-color: #aaa9ad;
border-radius: 50%;
}
.calendar__peg-rope {
position: absolute;
top: 0.6rem;
width: 50%;
height: 0.3rem;
background-color: #5b342e;
transform-origin: center right;
transform: rotate(-20deg);
}
.calendar__peg-rope--2 {
right: 0;
transform-origin: center left;
transform: rotate(20deg);
}
.calendar__reset {
unset: all;
position: absolute;
top: 50%;
left: 50%;
transform: translate(-50%, -50%);
background: none;
border: none;
color: #732222;
font: bold 4rem/1 Georgia, serif;
font-style: italic;
text-shadow: 0.0625rem 0.0625rem 0.0625rem #b34747;
cursor: pointer;
z-index: 1;
}
.calendar__reset:hover {
color: #fc0;
}
.leaf {
border-radius: var(--border-radius);
position: absolute;
top: 0;
left: 0;
margin: 1rem;
width: calc(100% - var(--calendar-offset));
height: calc(100% - var(--calendar-offset));
user-select: none;
cursor: pointer;
text-align: center;
box-shadow: 0.1875rem 0.1875rem 0.25rem rgba(0, 0, 0, 0.45);
transition: transform 0.5s ease-in-out, box-shadow 0.3s ease-in-out 0.1s;
transform-origin: top center;
display: flex;
flex-direction: column;
transform: rotate(var(--rot));
z-index: 2;
}
.leaf:focus-visible {
/* outline: .0625rem dotted gray; */
outline: none;
}
.leaf__main {
background-image: linear-gradient(
155deg,
var(--color-paper-dark),
80%,
var(--color-paper-light)
);
height: 100%;
display: flex;
flex-direction: column;
box-shadow: inset 2rem 0rem 7rem rgba(0, 0, 0, 0.02);
}
.leaf__scrap {
height: 2.5rem;
background-color: var(--color-paper-dark);
transform: translateY(0.0625rem);
}
.leaf.-teared {
transform: translate(var(--xdir), var(--ydir)) rotate(var(--rdir));
box-shadow: 5rem 5rem 1rem rgba(0, 0, 0, 0.55);
}
.leaf.-teared > .leaf__scrap {
clip-path: url(#scrap-leaf-path);
transform: translateY(0.0625rem);
}
.leaf__year {
font: var(--font-text);
margin: 1rem 0 0;
}
.leaf__month {
font: var(--font-text);
margin: 0.1rem 0 0;
}
.leaf__day {
--font-size: clamp(6rem, calc(6rem + 16vw), 12rem);
--font-text: normal var(--font-size) / 1 var(--font-family);
font: var(--font-text);
}
.leaf__weekday {
font: var(--font-text);
}
.-weekend .leaf__day,
.-weekend .leaf__weekday {
color: var(--color-weekend);
}
/* Modifiers */
.-bevel {
box-shadow: inset 0.1rem 0.1rem 0.1rem 0 rgba(255, 255, 255, 0.3),
inset -0.1rem -0.1rem 0.1rem 0 rgba(0, 0, 0, 0.5),
0.4375rem 0.4375rem 0.75rem rgba(0, 0, 0, 0.55);
}
.-hidden {
display: none;
}
.-removed-from-viewport {
position: absolute;
top: -1000rem;
}
#tear-all {
position: absolute;
top: 1rem;
right: 1rem;
}
@keyframes blink {
from {
opacity: 0.2;
}
to {
opacity: 1;
}
}

Here is our updated output CSS.

output

Leaf-Loos Calendar | Calendar html css js

Javascript code 

 /**  
* LoseLeafCalendar.
* @class
*/
class LoseLeafCalendar {
/**
* @param {Date} [date=new Date] - Use start date 'today' is default.
* @param {Date | null} [end] - End is the end of current year.
*/
constructor(date = new Date(), end = null) {
this.currentDate = date;
this.endDate = end || new Date(date.getFullYear(), 11, 31);
this.tearedLeaves = 0;
this._initDate = new Date(this.currentDate);
// We are not interested in time here. So reset it to midnight.
this.currentDate.setHours(0, 0, 0, 0);
this.endDate.setHours(0, 0, 0, 0);
}
/**
* @type {HTMLDivElement}
*/
get calendar() {
return document.getElementById("calendar");
}
/**
* @type {HTMLTemplateElement}
*/
get template() {
return document.getElementById("calendar-sheet-tpl");
}
/**
* @type {NodeList<HTMLTimeElement>}
*/
get leaves() {
return this.calendar.querySelectorAll(".leaf");
}
/**
* @type {NodeList<HTMLTimeElement>}
*/
get calendarScraps() {
return this.calendar.querySelectorAll(".calendar__scraps");
}
/**
* @param {Date} date
* @return {DocumentFragment}
*/
createLeaf(date) {
const leaf = this.template.content.cloneNode(true);
const year = date.getFullYear();
leaf.querySelector(".leaf__year").innerText = year;
const month = date.toLocaleString("default", { month: "long" });
leaf.querySelector(".leaf__month").innerText = month;
const weekday = date.toLocaleString("default", { weekday: "long" });
leaf.querySelector(".leaf__weekday").innerText = weekday;
leaf.querySelector(".leaf__day").innerText = date.getDate();
const timeElem = leaf.querySelector("time");
timeElem.setAttribute("datetime", date.toISOString());
if (date.getDay() === 6 || date.getDay() === 0) {
timeElem.classList.add("-weekend");
}
timeElem.style.setProperty("--rot", Math.random() * 2 - 1 + "deg");
timeElem.style.setProperty("--xdir", Math.random() * 300 - 150 + "%");
timeElem.style.setProperty("--ydir", Math.random() * 100 + 200 + "%");
timeElem.style.setProperty("--rdir", Math.random() * 100 - 50 + "deg");
return leaf;
}
/**
* Builds all leaves for calendar.
*/
buildCalendar() {
while (this.currentDate <= this.endDate) {
const leaf = this.createLeaf(this.currentDate);
this.calendar.prepend(leaf);
this.currentDate.setDate(this.currentDate.getDate() + 1);
}
}
/**
* @param {} leaf
*/
tearLeaf(leaf) {
leaf.classList.add("-teared");
leaf.tabIndex = -1;
if (this.tearedLeaves < this.calendarScraps.length) {
this.calendarScraps[this.tearedLeaves].hidden = false;
}
const prev = leaf.previousElementSibling;
if (prev) {
prev.classList.remove("-hidden");
prev.focus();
}
++this.tearedLeaves;
}
/**
* Add events.
*/
hydrate() {
this.leaves.forEach((l) => {
l.addEventListener("click", () => this.tearLeaf(l));
l.addEventListener("keydown", (e) => {
if (["Enter", "Space", "ArrowDown"].includes(e.code)) {
e.preventDefault();
this.tearLeaf(e.target);
}
});
l.addEventListener("transitionend", (e) => e.target.remove());
});
}
/**
* Setup some accessibility features.
*/
setupAccessibility() {
this.leaves.forEach((leaf) => {
leaf.tabIndex = 0;
leaf.classList.add("-hidden");
leaf.setAttribute("role", "button");
});
this.leaves[this.leaves.length - 1].classList.remove("-hidden");
this.leaves[this.leaves.length - 1].focus();
}
/**
* Resets the calendar and starts from the beginning.
*/
reset() {
this.currentDate = new Date(this._initDate);
this.leaves.forEach((l) => l.remove());
this.initAll();
this.tearedLeaves = 0;
}
/**
* Run all methods to fully init calendar.
*/
initAll() {
this.buildCalendar();
this.hydrate();
this.setupAccessibility();
}
/**
* Tear all leaves automatically.
*/
tearAll() {
let i = this.leaves.length;
const interval = setInterval(() => {
if (i <= 1) {
clearInterval(interval);
}
this.tearLeaf(this.leaves[--i]);
}, 80);
}
}
document.addEventListener("DOMContentLoaded", () => {
const leafLooseCalendar = new LoseLeafCalendar();
const tearAllBtn = document.getElementById("tear-all");
const resetBtn = document.getElementById("reset");
leafLooseCalendar.initAll();
tearAllBtn.addEventListener("click", () => leafLooseCalendar.tearAll());
resetBtn.addEventListener("click", () => leafLooseCalendar.reset());
});

Final output

Leaf-Loos Calendar | Calendar html css js


Now we have completed our javascript section,  Here is our updated output with javascriptHope you like the Calendar. you can see output video and project screenshots. See our other blogs and gain knowledge in front-end development. Thank you 🙏💕!

Share on:

Leave a Comment