.calendar
.indicator
.overlay
ol.round-list.years
ol.round-list.months
ol.round-list.days
.details
h1 Events
ul.events-container
li.event.current(data-date="June 2, 2019")
h2.event-title Rooftop Cinema: Trouble Makers
p.event-date at 9:00 PM
li.event(data-date="September 21, 2030")
h2.event-title Rooftop Cinema: Trouble Makers
p.event-date at 9:00 PM
li.event(data-date="February 28, 2025")
h2.event-title Rooftop Cinema: Trouble Makers
p.event-date at 9:00 PM
a(href="#") Go To Event
ul.dots
li.current
li
li
View Compiled
/** Mixin Definitions **/
center-children() {
display: flex;
justify-content: center;
align-items: center;
}
set-position(position, top, right=top, bottom=top, left=right) {
position: position;
top: top;
left: left;
right: right;
bottom: bottom;
}
/** Base Styles **/
*,
*::before,
*::after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
html {
font-size: 62.5%;
}
body {
center-children();
height: 100vh;
font-family: "Roboto", sans-serif;
font-weight: 100;
-webkit-font-smoothing: antialiased;
line-height: 1;
}
ol,
ul {
list-style: none;
}
/** Base Calendar Styles **/
.calendar {
flex-shrink: 0;
width: 71rem;
height: 71rem;
padding: 3rem;
position: relative;
border-radius: 50%;
background-color: #000;
background-clip: content-box;
overflow: hidden;
&::before {
content: "";
set-position(absolute, 3rem);
border-radius: 50%;
background: #000 url("https://cdn.arnellebalane.com/images/codepen-day11/background.jpg") center center no-repeat;
opacity: 0.05;
}
}
.calendar * {
flex-shrink: 0;
}
/** Round List Styles **/
.round-list {
border-radius: 50%;
color: #545247;
transition: transform 500ms ease-out;
&.years {
set-position(absolute, 1.25rem);
}
&.months {
set-position(absolute, 7rem);
}
&.days {
set-position(absolute, 13.5rem);
}
}
.round-list li {
position: absolute;
text-align: center;
transition: color 500ms ease-out;
&.current {
color: #000;
}
}
.round-list.days li {
width: 1.8rem;
top: calc(50% - 0.8rem);
left: calc(50% - 0.9rem);
font-size: 1.5rem;
}
.round-list.months li {
width: 5rem;
top: calc(50% - 0.8rem);
left: calc(50% - 2.5rem);
font-size: 1.6rem;
text-indent: 0.5rem;
letter-spacing: 0.5rem;
text-transform: uppercase;
}
.round-list.years li {
width: 8.6rem;
top: calc(50% - 1rem);
left: calc(50% - 4.3rem);
font-size: 2rem;
text-indent: 0.5rem;
letter-spacing: 1rem;
}
/** Event Details Styles **/
.details {
center-children();
set-position(absolute, 20.5rem);
flex-direction: column;
border: 2px solid #6e6424;
border-radius: 50%;
font-size: 1.4rem;
}
.details h1 {
margin-bottom: 2.4rem;
font-weight: 100;
text-transform: uppercase;
font-size: 1.4rem;
letter-spacing: 0.8rem;
color: #fff;
opacity: 0.2;
}
.details a {
display: inline-block;
margin-top: 2rem;
color: #dbbf32;
}
.events-container {
width: 100%;
height: 5rem;
position: relative;
overflow: hidden;
}
.events-container .event {
set-position(absolute, 0);
text-align: center;
visibility: hidden;
opacity: 0;
transform: translateX(100%);
transition: transform 500ms ease-out,
visibility 300ms ease-out,
opacity 300ms ease-out;
&.current {
visibility: visible;
opacity: 1;
transform: translateX(0);
}
&.move-left {
transform: translateX(-100%);
}
}
.event .event-title {
padding: 0 5rem;
margin-bottom: 0.3rem;
font-size: 1.5rem;
text-transform: uppercase;
color: #fff;
}
.event .event-date {
color: #fff;
}
.dots {
display: flex;
margin-top: 2rem;
}
.dots li {
width: 0.5rem;
height: 0.5rem;
margin: 0 0.25rem;
border-radius: 50%;
background-color: #fff;
opacity: 0.2;
cursor: pointer;
&.current {
background-color: #e6cf59;
opacity: 1;
}
}
/** Indicator Styles **/
.indicator {
set-position(absolute, 2.9rem);
border-radius: 50%;
overflow: hidden;
pointer-events: none;
&::before,
&::after {
content: "";
position: absolute;
}
&::before {
border-top: 14.5rem solid #e5e91e;
border-left: 6.5rem solid transparent;
border-right: 6.5rem solid transparent;
top: 0
left: calc(50% - 6.5rem);
}
&::after {
height: 3.6rem;
border-left: 2px solid #e5e91e;
top: 14rem;
left: calc(50% - 1px);
}
}
/** Overlay Styles **/
.overlay {
set-position(absolute, 3rem);
border-radius: 50%;
&::before,
&::after {
content: "";
set-position(absolute, 0);
border-radius: 50%;
}
&::before {
background-image: linear-gradient(top left, #ff671b, transparent 40%, transparent)
opacity: 0.15;
}
&::after {
background-image: linear-gradient(bottom left, #5eade4, transparent 50%, transparent);
opacity: 0.15;
}
}
View Compiled
var $days = $('.round-list.days');
var $months = $('.round-list.months');
var $years = $('.round-list.years');
var $events = $('.events-container');
var $dots = $('.dots');
populateCalendar();
positionDigits();
showEvent(0);
$dots.on('click', 'li', function() {
showEvent($(this).index());
});
function showEvent(index) {
var $event = $events.children().eq(index);
$events.children().removeClass('current move-left');
$event.addClass('current').prevAll().addClass('move-left');
$dots.children().removeClass('current').eq(index).addClass('current');
var date = new Date($event.data('date'));
rotateListToDigit($days, date.getDate());
rotateListToDigit($months, date.getMonth());
rotateListToDigit($years, date.getFullYear());
}
function rotateListToDigit(list, digit) {
var current = list.children(`[data-value="${digit}"]`).addClass('current');
var angleDelta = 360 / list.children().length;
var rotation = -angleDelta * current.index();
current.siblings().removeClass('current');
list.css('transform', `rotate(${rotation}deg)`);
}
function populateCalendar() {
// populate days
for (let i = 1; i <= 31; i++) {
$days.append(`<li data-value="${i}">${i}</li>`);
}
// populate months
'Jan Feb Mar Apr May Jun Jul Aug Sep Oct Nov Dec'.split(' ')
.forEach((month, i) =>
$months.append(`<li data-value="${i}">${month}</li>`));
// populate years
var year = (new Date()).getFullYear();
for (let i = 0; i < 18; i++) {
$years.append(`<li data-value="${year + i}">${year + i}</li>`);
}
}
function positionDigits() {
// position days digits
positionDigitsOf($days);
positionDigitsOf($months);
positionDigitsOf($years);
}
function positionDigitsOf(list) {
var angleDelta = 360 / list.children().length;
list.children().each(function(i) {
var angle = 180 - angleDelta * i;
var position = getPointAtAngle(angle, list.width() / 2);
positionDigitAt($(this), position, angle);
});
}
function positionDigitAt(digit, position, angle) {
var transform = [
`translate(${position.x}px, ${position.y}px)`,
`rotate(${180 - angle}deg)`
];
digit.css('transform', transform.join(' '));
}
function getPointAtAngle(angle, distance) {
angle = deg2rad(angle);
return { x: Math.sin(angle) * distance, y: Math.cos(angle) * distance };
}
function deg2rad(angle) {
return angle * (Math.PI / 180);
}
function rad2deg(angle) {
return angle * (180 / Math.PI);
}
View Compiled
This Pen doesn't use any external CSS resources.