Updating scripts and snippets

master
Michael Reber 4 years ago
parent 59d7bb399d
commit 1416242314

@ -0,0 +1,29 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Multi-Button Pill Challenge</title>
<link rel="stylesheet" href="https://use.fontawesome.com/releases/v5.12.0/css/all.css" integrity="sha384-REHJTs1r2ErKBuJB0fCK99gCYsVjwxHrSU0N7I1zl9vZbggVJXRMsv/sLlOAGb4M" crossorigin="anonymous"><link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="multi-button">
<button>
<i class="fas fa-cut"></i>
<div class="animate-normal ">Cut</div>
</button>
<button>
<i class="fas fa-copy"></i>
<div class="animate-normal ">Copy</div>
</button>
<button>
<i class="fas fa-paste"></i>
<div class="animate-normal ">Paste</div>
</button>
</div>
<script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,17 @@
window.onload = () => {
const buttons = document.querySelectorAll(".multi-button button");
buttons.forEach((button, index) => {
button.addEventListener("mouseover", () => {
if (index > 0) {
const prevTooltip = buttons[index - 1].querySelector("div");
prevTooltip.classList.remove("animate-right");
prevTooltip.classList.add("animate-left");
}
if (index < buttons.length - 1) {
const nextTooltip = buttons[index + 1].querySelector("div");
nextTooltip.classList.remove("animate-left");
nextTooltip.classList.add("animate-right");
}
});
});
};

@ -0,0 +1,100 @@
@import url("https://fonts.googleapis.com/css?family=Raleway:400,500,700&display=swap");
body {
height: 100vh;
margin: 0;
display: grid;
place-items: center;
background: rgba(205, 207, 219, 0.2);
}
.multi-button {
padding: 8px 10px;
border-radius: 50px;
background: #fff;
border: 0.5px solid rgba(146, 152, 176, 0.4);
box-shadow: 0 0 10px rgba(146, 152, 176, 0.2), 4px 4px 10px rgba(146, 152, 176, 0.2);
cursor: default;
}
.multi-button button {
border: 0 solid transparent;
background: transparent;
padding: 10px 30px;
margin: 0 -2px;
color: #273043;
font-size: 17px;
border-radius: 12px;
cursor: pointer;
position: relative;
top: 0;
left: 0;
outline: none;
transition: background 0.2s ease-in-out;
}
.multi-button button:first-child {
border-top-left-radius: 40px;
border-bottom-left-radius: 40px;
}
.multi-button button:last-child {
border-top-right-radius: 40px;
border-bottom-right-radius: 40px;
}
.multi-button button div {
position: absolute;
top: -43px;
left: calc(50% - 40px);
width: 80px;
font-size: 13px;
color: #fff;
background: rgba(20, 25, 36, 0.7);
border-radius: 16px;
line-height: 30px;
font-family: 'Raleway', Arial, sans-serif;
text-align: center;
font-weight: 500;
letter-spacing: 1px;
box-shadow: 0 0 5px rgba(39, 48, 68, 0.3), 1px 1px 5px rgba(39, 48, 68, 0.2);
display: none;
cursor: pointer;
}
.multi-button button:hover {
background: #f0f1f4;
}
.multi-button button:hover div {
display: block;
animation: tooltip-animation-normal 0.3s ease-out forwards;
}
.multi-button button:hover div.animate-right {
animation: tooltip-animation-right 0.3s ease-out forwards;
}
.multi-button button:hover div.animate-left {
animation: tooltip-animation-left 0.3s ease-out forwards;
}
.multi-button button:active {
outline: none;
background: #d6d8e1;
}
@keyframes tooltip-animation-right {
0% {
transform: translateX(-75px);
}
100% {
transform: translateX(0);
}
}
@keyframes tooltip-animation-left {
0% {
transform: translateX(75px);
}
100% {
transform: translateX(0);
}
}
@keyframes tooltip-animation-normal {
0% {
transform: translateY(-20px);
}
100% {
transform: translateY(0);
}
}

@ -0,0 +1,2 @@
# 2020 Toggles

@ -0,0 +1,67 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>2020 Toggles</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel='stylesheet' href='https://cdn.jsdelivr.net/npm/inter-ui@3.11.0/inter.min.css'><link rel="stylesheet" href="./style.css">
</head>
<body>
<ul>
<li>
<input id="c1" type="checkbox">
<label for="c1">Checkbox</label>
</li>
<li>
<input id="c2" type="checkbox" checked>
<label for="c2">Checkbox</label>
</li>
<li>
<input id="r1" type="radio" name="radio" value="1">
<label for="r1">Radio</label>
</li>
<li>
<input id="r2" type="radio" name="radio" value="2" checked>
<label for="r2">Radio</label>
</li>
<li>
<input id="s1" type="checkbox" class="switch">
<label for="s1">Switch</label>
</li>
<li>
<input id="s2" type="checkbox" class="switch" checked>
<label for="s2">Switch</label>
</li>
</ul>
<ul>
<li>
<input id="c1d" type="checkbox" disabled>
<label for="c1d">Checkbox</label>
</li>
<li>
<input id="c2d" type="checkbox" checked disabled>
<label for="c2d">Checkbox</label>
</li>
<li>
<input id="r1d" type="radio" name="radiod" value="1" disabled>
<label for="r1d">Radio</label>
</li>
<li>
<input id="r2d" type="radio" name="radiod" value="2" checked disabled>
<label for="r2d">Radio</label>
</li>
<li>
<input id="s1d" type="checkbox" class="switch" disabled>
<label for="s1d">Switch</label>
</li>
<li>
<input id="s2d" type="checkbox" class="switch" checked disabled>
<label for="s2d">Switch</label>
</li>
</ul>
</body>
</html>

@ -0,0 +1,180 @@
@supports (-webkit-appearance: none) or (-moz-appearance: none) {
input[type='checkbox'],
input[type='radio'] {
--active: #275EFE;
--active-inner: #fff;
--focus: 2px rgba(39, 94, 254, .3);
--border: #BBC1E1;
--border-hover: #275EFE;
--background: #fff;
--disabled: #F6F8FF;
--disabled-inner: #E1E6F9;
-webkit-appearance: none;
-moz-appearance: none;
height: 21px;
outline: none;
display: inline-block;
vertical-align: top;
position: relative;
margin: 0;
cursor: pointer;
border: 1px solid var(--bc, var(--border));
background: var(--b, var(--background));
transition: background .3s, border-color .3s, box-shadow .2s;
}
input[type='checkbox']:after,
input[type='radio']:after {
content: '';
display: block;
left: 0;
top: 0;
position: absolute;
transition: opacity var(--d-o, 0.2s), -webkit-transform var(--d-t, 0.3s) var(--d-t-e, ease);
transition: transform var(--d-t, 0.3s) var(--d-t-e, ease), opacity var(--d-o, 0.2s);
transition: transform var(--d-t, 0.3s) var(--d-t-e, ease), opacity var(--d-o, 0.2s), -webkit-transform var(--d-t, 0.3s) var(--d-t-e, ease);
}
input[type='checkbox']:checked,
input[type='radio']:checked {
--b: var(--active);
--bc: var(--active);
--d-o: .3s;
--d-t: .6s;
--d-t-e: cubic-bezier(.2, .85, .32, 1.2);
}
input[type='checkbox']:disabled,
input[type='radio']:disabled {
--b: var(--disabled);
cursor: not-allowed;
opacity: .9;
}
input[type='checkbox']:disabled:checked,
input[type='radio']:disabled:checked {
--b: var(--disabled-inner);
--bc: var(--border);
}
input[type='checkbox']:disabled + label,
input[type='radio']:disabled + label {
cursor: not-allowed;
}
input[type='checkbox']:hover:not(:checked):not(:disabled),
input[type='radio']:hover:not(:checked):not(:disabled) {
--bc: var(--border-hover);
}
input[type='checkbox']:focus,
input[type='radio']:focus {
box-shadow: 0 0 0 var(--focus);
}
input[type='checkbox']:not(.switch),
input[type='radio']:not(.switch) {
width: 21px;
}
input[type='checkbox']:not(.switch):after,
input[type='radio']:not(.switch):after {
opacity: var(--o, 0);
}
input[type='checkbox']:not(.switch):checked,
input[type='radio']:not(.switch):checked {
--o: 1;
}
input[type='checkbox'] + label,
input[type='radio'] + label {
font-size: 14px;
line-height: 21px;
display: inline-block;
vertical-align: top;
cursor: pointer;
margin-left: 4px;
}
input[type='checkbox']:not(.switch) {
border-radius: 7px;
}
input[type='checkbox']:not(.switch):after {
width: 5px;
height: 9px;
border: 2px solid var(--active-inner);
border-top: 0;
border-left: 0;
left: 7px;
top: 4px;
-webkit-transform: rotate(var(--r, 20deg));
transform: rotate(var(--r, 20deg));
}
input[type='checkbox']:not(.switch):checked {
--r: 43deg;
}
input[type='checkbox'].switch {
width: 38px;
border-radius: 11px;
}
input[type='checkbox'].switch:after {
left: 2px;
top: 2px;
border-radius: 50%;
width: 15px;
height: 15px;
background: var(--ab, var(--border));
-webkit-transform: translateX(var(--x, 0));
transform: translateX(var(--x, 0));
}
input[type='checkbox'].switch:checked {
--ab: var(--active-inner);
--x: 17px;
}
input[type='checkbox'].switch:disabled:not(:checked):after {
opacity: .6;
}
input[type='radio'] {
border-radius: 50%;
}
input[type='radio']:after {
width: 19px;
height: 19px;
border-radius: 50%;
background: var(--active-inner);
opacity: 0;
-webkit-transform: scale(var(--s, 0.7));
transform: scale(var(--s, 0.7));
}
input[type='radio']:checked {
--s: .5;
}
}
ul {
margin: 12px;
padding: 0;
list-style: none;
width: 100%;
max-width: 320px;
}
ul li {
margin: 16px 0;
position: relative;
}
html {
box-sizing: border-box;
}
* {
box-sizing: inherit;
}
*:before, *:after {
box-sizing: inherit;
}
body {
min-height: 100vh;
font-family: 'Inter', Arial, sans-serif;
color: #8A91B4;
display: flex;
justify-content: center;
align-items: center;
background: #F6F8FF;
}
@media (max-width: 800px) {
body {
flex-direction: column;
}
}

@ -0,0 +1 @@
# Expanding flex cards

@ -0,0 +1,81 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Expanding flex cards</title>
<link rel='stylesheet' href='https://cdnjs.cloudflare.com/ajax/libs/normalize/8.0.0/normalize.min.css'>
<link rel='stylesheet' href='https://static.fontawesome.com/css/fontawesome-app.css'>
<link rel='stylesheet' href='https://pro.fontawesome.com/releases/v5.2.0/css/all.css'>
<link rel='stylesheet' href='https://fonts.googleapis.com/css?family=Roboto:400,700'><link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="options">
<div class="option active" style="--optionBackground:url(https://66.media.tumblr.com/6fb397d822f4f9f4596dff2085b18f2e/tumblr_nzsvb4p6xS1qho82wo1_1280.jpg);">
<div class="shadow"></div>
<div class="label">
<div class="icon">
<i class="fas fa-walking"></i>
</div>
<div class="info">
<div class="main">Blonkisoaz</div>
<div class="sub">Omuke trughte a otufta</div>
</div>
</div>
</div>
<div class="option" style="--optionBackground:url(https://66.media.tumblr.com/8b69cdde47aa952e4176b4200052abf4/tumblr_o51p7mFFF21qho82wo1_1280.jpg);">
<div class="shadow"></div>
<div class="label">
<div class="icon">
<i class="fas fa-snowflake"></i>
</div>
<div class="info">
<div class="main">Oretemauw</div>
<div class="sub">Omuke trughte a otufta</div>
</div>
</div>
</div>
<div class="option" style="--optionBackground:url(https://66.media.tumblr.com/5af3f8303456e376ceda1517553ba786/tumblr_o4986gakjh1qho82wo1_1280.jpg);">
<div class="shadow"></div>
<div class="label">
<div class="icon">
<i class="fas fa-tree"></i>
</div>
<div class="info">
<div class="main">Iteresuselle</div>
<div class="sub">Omuke trughte a otufta</div>
</div>
</div>
</div>
<div class="option" style="--optionBackground:url(https://66.media.tumblr.com/5516a22e0cdacaa85311ec3f8fd1e9ef/tumblr_o45jwvdsL11qho82wo1_1280.jpg);">
<div class="shadow"></div>
<div class="label">
<div class="icon">
<i class="fas fa-tint"></i>
</div>
<div class="info">
<div class="main">Idiefe</div>
<div class="sub">Omuke trughte a otufta</div>
</div>
</div>
</div>
<div class="option" style="--optionBackground:url(https://66.media.tumblr.com/f19901f50b79604839ca761cd6d74748/tumblr_o65rohhkQL1qho82wo1_1280.jpg);">
<div class="shadow"></div>
<div class="label">
<div class="icon">
<i class="fas fa-sun"></i>
</div>
<div class="info">
<div class="main">Inatethi</div>
<div class="sub">Omuke trughte a otufta</div>
</div>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js'></script>
<script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,5 @@
$(".option").click(function(){
$(".option").removeClass("active");
$(this).addClass("active");
});

@ -0,0 +1,171 @@
body {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
overflow: hidden;
height: 100vh;
font-family: 'Roboto', sans-serif;
}
body .credit {
position: absolute;
bottom: 20px;
left: 20px;
color: #000;
}
body .options {
display: flex;
flex-direction: row;
align-items: stretch;
overflow: hidden;
min-width: 600px;
max-width: 900px;
width: calc(100% - 100px);
height: 400px;
}
@media screen and (max-width: 718px) {
body .options {
min-width: 520px;
}
body .options .option:nth-child(5) {
display: none;
}
}
@media screen and (max-width: 638px) {
body .options {
min-width: 440px;
}
body .options .option:nth-child(4) {
display: none;
}
}
@media screen and (max-width: 558px) {
body .options {
min-width: 360px;
}
body .options .option:nth-child(3) {
display: none;
}
}
@media screen and (max-width: 478px) {
body .options {
min-width: 280px;
}
body .options .option:nth-child(2) {
display: none;
}
}
body .options .option {
position: relative;
overflow: hidden;
min-width: 60px;
margin: 10px;
background: var(--optionBackground, var(--defaultBackground, #E6E9ED));
background-size: auto 120%;
background-position: center;
cursor: pointer;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
body .options .option:nth-child(1) {
--defaultBackground:#ED5565;
}
body .options .option:nth-child(2) {
--defaultBackground:#FC6E51;
}
body .options .option:nth-child(3) {
--defaultBackground:#FFCE54;
}
body .options .option:nth-child(4) {
--defaultBackground:#2ECC71;
}
body .options .option:nth-child(5) {
--defaultBackground:#5D9CEC;
}
body .options .option:nth-child(6) {
--defaultBackground:#AC92EC;
}
body .options .option.active {
flex-grow: 10000;
-webkit-transform: scale(1);
transform: scale(1);
max-width: 600px;
margin: 0px;
border-radius: 40px;
background-size: auto 100%;
/*&:active {
transform:scale(0.9);
}*/
}
body .options .option.active .shadow {
box-shadow: inset 0 -120px 120px -120px black, inset 0 -120px 120px -100px black;
}
body .options .option.active .label {
bottom: 20px;
left: 20px;
}
body .options .option.active .label .info > div {
left: 0px;
opacity: 1;
}
body .options .option:not(.active) {
flex-grow: 1;
border-radius: 30px;
}
body .options .option:not(.active) .shadow {
bottom: -40px;
box-shadow: inset 0 -120px 0px -120px black, inset 0 -120px 0px -100px black;
}
body .options .option:not(.active) .label {
bottom: 10px;
left: 10px;
}
body .options .option:not(.active) .label .info > div {
left: 20px;
opacity: 0;
}
body .options .option .shadow {
position: absolute;
bottom: 0px;
left: 0px;
right: 0px;
height: 120px;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
body .options .option .label {
display: flex;
position: absolute;
right: 0px;
height: 40px;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95);
}
body .options .option .label .icon {
display: flex;
flex-direction: row;
justify-content: center;
align-items: center;
min-width: 40px;
max-width: 40px;
height: 40px;
border-radius: 100%;
background-color: white;
color: var(--defaultBackground);
}
body .options .option .label .info {
display: flex;
flex-direction: column;
justify-content: center;
margin-left: 10px;
color: white;
white-space: pre;
}
body .options .option .label .info > div {
position: relative;
transition: 0.5s cubic-bezier(0.05, 0.61, 0.41, 0.95), opacity 0.5s ease-out;
}
body .options .option .label .info .main {
font-weight: bold;
font-size: 1.2rem;
}
body .options .option .label .info .sub {
transition-delay: .1s;
}

@ -0,0 +1,3 @@
# Horizontal Cards with Fade Animation
Adding fade animation to material design horizontal cards.

@ -0,0 +1,80 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Horizontal Cards with Fade Animation</title>
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/css/materialize.min.css"><link rel="stylesheet" href="./style.css">
</head>
<body>
<body class="grey lighten-2">
<div class="container">
<div class="col s12 m7">
<div class="card horizontal">
<div class="card-image">
<img src="https://unsplash.it/400/300?image=503" class="fadeIn">
</div>
<div class="card-stacked">
<div class="card-content">
<span class="card-title">San Francisco</span>
<p>A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart. I am alone, and feel the charm of existence in this spot, which was created for the bliss of souls like mine.
</p>
</div>
<div class="card-action">
<a href="#">This is a link</a>
</div>
</div>
</div>
</div>
<div class="col s12 m7">
<div class="card horizontal" id="fadedfx">
<div class="card-stacked">
<div class="card-content">
<span class="card-title">New York </span>
<p>A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart. I am alone, and feel the charm of existence in this spot, which was created for the bliss of souls like mine.
</p>
</div>
<div class="card-action">
<a href="#">This is a link</a>
</div>
</div>
<div class="card-image">
<img src="https://unsplash.it/400/300?image=736" class="fadedfx" class="fadedfx">
</div>
</div>
</div>
<div class="col s12 m7">
<div class="card horizontal">
<div class="card-image">
<img src="https://unsplash.it/400/300?image=736" class="fadedfx">
</div>
<div class="card-stacked">
<div class="card-content">
<span class="card-title">London</span>
<p>A wonderful serenity has taken possession of my entire soul, like these sweet mornings of spring which I enjoy with my whole heart. I am alone, and feel the charm of existence in this spot, which was created for the bliss of souls like mine.
</p>
</div>
<div class="card-action">
<a href="#">This is a link</a>
</div>
</div>
</div>
</div>
</div>
</body>
<script src='https://cdnjs.cloudflare.com/ajax/libs/materialize/0.97.7/js/materialize.min.js'></script>
<script src='https://code.jquery.com/jquery-1.10.1.min.js'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,10 @@
$(window).scroll(function() {
$('.fadedfx').each(function(){
var imagePos = $(this).offset().top;
var topOfWindow = $(window).scrollTop();
if (imagePos < topOfWindow+500) {
$(this).addClass("fadeIn");
}
});
});

@ -0,0 +1,32 @@
.fadedfx {
background-color: #fe5652;
visibility: hidden;
}
.fadeIn {
animation-name: fadeIn;
-webkit-animation-name: fadeIn;
animation-duration: 1.5s;
-webkit-animation-duration: 1.5s;
animation-timing-function: ease-in-out;
-webkit-animation-timing-function: ease-in-out;
visibility: visible !important;
}
@keyframes fadeIn {
0% {
opacity: 0.0;
}
100% {
opacity: 1;
}
}
@-webkit-keyframes fadeIn {
0% {
opacity: 0.0;
}
100% {
opacity: 1;
}
}

@ -0,0 +1 @@
# React 0.2.0 - Article Cards

@ -0,0 +1,18 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>React 0.2.0 - Article Cards</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div id="app"></div>
<script src='https://fb.me/react-0.14.7.min.js'></script>
<script src='https://fb.me/react-dom-0.14.7.min.js'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,83 @@
/*
App
<App />
*/
var App = React.createClass({ displayName: "App",
getInitialState: function () {
return {
articles: {
'article': {
"color": "FEC006",
"title": "Snow in Turkey Brings Travel Woes",
"thumbnail": "",
"category": "News",
"excerpt": "Heavy snowstorm in Turkey creates havoc as hundreds of villages left without power, and hundreds of roads closed",
"date": new Date() },
'article-1': {
"color": "2196F3",
"title": "Landslide Leaving Thousands Homeless",
"thumbnail": "",
"category": "News",
"excerpt": "An aburt landslide in the Silcon Valley has left thousands homeless and on the streets.",
"date": new Date() },
'article-2': {
"color": "FE5621",
"title": "Hail the size of baseballs in New York",
"thumbnail": "",
"category": "News",
"excerpt": "A rare and unexpected event occurred today as hail the size of snowball hits New York citizens.",
"date": new Date() },
'article-3': {
"color": "673AB7",
"title": "Earthquake destorying San Fransisco",
"thumbnail": "",
"category": "News",
"excerpt": "A massive earthquake just hit San Fransisco leaving behind a giant crater.",
"date": new Date() } } };
},
renderArticle: function (key) {
return (
React.createElement("div", { className: "column" },
React.createElement(Article, { key: key, index: key, details: this.state.articles[key] })));
},
render: function () {
return (
React.createElement("div", { className: "app" },
React.createElement("div", { className: "container" },
Object.keys(this.state.articles).map(this.renderArticle))));
} });
/*
Article
<Article />
*/
var Article = React.createClass({ displayName: "Article",
render: function () {
var details = this.props.details,
styles = {
backgroundColor: '#' + details.color };
return (
React.createElement("article", { className: "article" },
React.createElement("h3", { className: "article__category", style: styles }, details.category),
React.createElement("h2", { className: "article__title" }, details.title),
React.createElement("p", { className: "article__excerpt" }, details.excerpt)));
} });
ReactDOM.render(React.createElement(App, null), document.querySelector('#app'));

@ -0,0 +1,79 @@
/* Base */
body {
background: #F3F3F3;
padding: 20px;
font-family: "Open Sans", sans-serif;
}
/* Container */
.container {
display: flex;
flex-direction: row;
flex-wrap: wrap;
width: 90%;
max-width: 960px;
margin: 0 auto;
}
/* Column */
.column {
flex-basis: 33.3333333333%;
width: 33.3333333333%;
padding: 0 10px;
box-sizing: border-box;
}
@media (max-width: 900px) {
.column {
flex-basis: 50%;
width: 50%;
}
}
@media (max-width: 600px) {
.column {
flex-basis: 100%;
width: 100%;
}
}
/* Article (Component) */
.article {
background: #FFF;
margin: 0 0 20px;
padding: 20px;
border-radius: 2px;
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2);
cursor: pointer;
transition: 0.3s ease;
}
.article:hover {
box-shadow: 0 2px 4px rgba(0, 0, 0, 0.2), 0 4px 8px rgba(0, 0, 0, 0.2);
}
.article:active {
box-shadow: none;
-webkit-transform-origin: center;
transform-origin: center;
-webkit-transform: scale(0.98);
transform: scale(0.98);
}
.article__category {
display: inline-block;
padding: 8px 10px;
margin: 0 0 10px;
color: #FFF;
font-size: 0.75rem;
font-weight: 600;
letter-spacing: 0.075rem;
text-transform: uppercase;
}
.article__excerpt {
color: #666;
line-height: 1.5rem;
font-size: 0.875rem;
}
.article__title {
margin: 0 0 10px;
color: #444;
font-size: 1.25rem;
font-weight: 600;
line-height: 1.75rem;
}

@ -0,0 +1,4 @@
# Pixel Repulsion
_A Pen created at CodePen.io. Original URL: [https://codepen.io/mendieta/pen/PowaQEm](https://codepen.io/mendieta/pen/PowaQEm).
Image pixel manipulation and repulsion with raw HTML5 canvas made with students at Harbour.Space for module Programming Interactivity of the Interaction Design Master.

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Pixel Repulsion </title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<canvas></canvas>
<img src='https://s3-us-west-2.amazonaws.com/s.cdpn.io/128966/img_repulsion.jpg' alt='' crossorigin="anonymous">
<script src='https://mrdoob.github.io/stats.js/build/stats.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/dat-gui/0.7.3/dat.gui.min.js'></script>
<script src='https://cdnjs.cloudflare.com/ajax/libs/gsap/2.1.3/TweenMax.min.js'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,152 @@
const canvas = document.querySelector("canvas");
const context = canvas.getContext("2d");
const img = document.querySelector("img");
let built = false;
let pixels = [];
const config = {
strength: 2000,
easeFactor: 0.1,
glow: true,
stats: false,
pxSize: 15
};
const mousePosition = { x: 0, y: 0 };
function resize() {
canvas.width = window.innerWidth;
canvas.height = window.innerHeight;
buildPixelData();
}
function draw() {
context.clearRect(0, 0, canvas.width, canvas.height);
stats.begin();
if (!built) {
this.buildPixelData();
}
for (let i = 0; i < pixels.length; i++) {
const pixel = pixels[i];
const deltaX = pixel.x - mousePosition.x;
const deltaY = pixel.y - mousePosition.y;
const angle = Math.atan2(deltaY, deltaX);
let distance =
config.strength / Math.sqrt(deltaX * deltaX + deltaY * deltaY);
if (config.glow) {
pixel.r += distance;
pixel.g += distance;
pixel.b += distance;
pixel.r += (pixel.or - pixel.r) * config.easeFactor;
pixel.g += (pixel.og - pixel.g) * config.easeFactor;
pixel.b += (pixel.ob - pixel.b) * config.easeFactor;
context.fillStyle = `rgb(${pixel.r}, ${pixel.g}, ${pixel.b})`;
} else {
context.fillStyle = `rgb(${pixel.or}, ${pixel.og}, ${pixel.ob})`;
}
pixel.x += Math.cos(angle) * distance;
pixel.y += Math.sin(angle) * distance;
pixel.x += (pixel.ox - pixel.x) * config.easeFactor;
pixel.y += (pixel.oy - pixel.y) * config.easeFactor;
context.beginPath();
context.arc(pixel.x, pixel.y, pixel.size / 2, 0, Math.PI * 2);
context.fill();
}
stats.end();
window.requestAnimationFrame(draw);
}
function getPixels() {
const data = context.getImageData(0, 0, img.width, img.height);
const pxs = [];
for (let x = 0; x < data.width; x += config.pxSize) {
for (let y = 0; y < data.height; y += config.pxSize) {
let index = x * 4 + y * 4 * img.width;
let alpha = data.data[index + 3];
if (alpha > 0) {
pxs.push({
x: canvas.width / 2 - img.width / 2 + x,
y: canvas.height / 2 - img.height / 2 + y,
ox: canvas.width / 2 - img.width / 2 + x,
oy: canvas.height / 2 - img.height / 2 + y,
size: config.pxSize,
oSize: config.pxSize,
r: data.data[index],
g: data.data[index + 1],
b: data.data[index + 2],
or: data.data[index],
og: data.data[index + 1],
ob: data.data[index + 2],
rgb:
"rgb(" +
data.data[index] +
"," +
data.data[index + 1] +
"," +
data.data[index + 2] +
")"
});
}
}
}
return pxs;
}
function buildPixelData() {
if(img.width === 0 || img.height === 0){
return;
}
context.clearRect(0, 0, canvas.width, canvas.height);
context.drawImage(img, 0, 0);
pixels = [];
pixels = getPixels();
context.clearRect(0, 0, canvas.width, canvas.height);
if (pixels.length > 0) {
built = true;
}
}
function buildGUI() {
const gui = new dat.GUI({ closed: true });
gui.closed = true;
gui.add(config, "strength", 0, 7000);
gui.add(config, "easeFactor", 0.05, 0.2);
gui.add(config, "glow");
const sizeController = gui.add(config, "pxSize", 8, 80, 1);
const statsController = gui.add(config, "stats");
sizeController.onFinishChange(() => {
buildPixelData();
});
statsController.onChange(value => {
if (value) {
document.body.appendChild(stats.dom);
} else {
stats.dom.parentNode.removeChild(stats.dom);
}
});
}
function onMouseMove(event) {
mousePosition.x = event.clientX;
mousePosition.y = event.clientY;
}
function touchMoveHandler(event) {
mousePosition.x = event.touches[0].clientX;
mousePosition.y = event.touches[0].clientY;
}
const stats = new Stats();
stats.showPanel(0);
window.addEventListener("DOMContentLoaded", event => {
buildGUI();
resize();
window.addEventListener("mousemove", onMouseMove);
window.addEventListener("touchmove", touchMoveHandler);
window.addEventListener("resize", resize);
window.requestAnimationFrame(draw);
});

@ -0,0 +1,27 @@
canvas,
body {
width: 100%;
height: 100%;
margin: 0;
background-color: black;
overflow: hidden;
}
img {
visibility: hidden;
display: none;
}
footer {
color: white;
position: fixed;
bottom: 0;
left: 0;
padding: 15px;
font-family: "Helvetica", "Roboto", "Sans";
}
footer a {
color: white;
font-family: "Helvetica", "Roboto", "Sans";
}

@ -0,0 +1,3 @@
# Power switch animation - Only CSS
Simple power switch animation

@ -0,0 +1,37 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Power switch animation - Only CSS</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<div class="power-switch">
<input type="checkbox" />
<div class="button">
<svg class="power-off">
<use xlink:href="#line" class="line" />
<use xlink:href="#circle" class="circle" />
</svg>
<svg class="power-on">
<use xlink:href="#line" class="line" />
<use xlink:href="#circle" class="circle" />
</svg>
</div>
</div>
<!-- SVG -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;">
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" id="line">
<line x1="75" y1="34" x2="75" y2="58"/>
</symbol>
<symbol xmlns="http://www.w3.org/2000/svg" viewBox="0 0 150 150" id="circle">
<circle cx="75" cy="80" r="35"/>
</symbol>
</svg>
</body>
</html>

@ -0,0 +1,234 @@
.power-switch {
--color-invert: #ffffff;
--width: 150px;
--height: 150px;
position: relative;
display: flex;
justify-content: center;
align-items: center;
width: var(--width);
height: var(--height);
}
.power-switch .button {
width: 100%;
height: 100%;
display: flex;
justify-content: center;
align-items: center;
position: relative;
}
.power-switch .button:after {
content: "";
width: 100%;
height: 100%;
position: absolute;
background: radial-gradient(circle closest-side, var(--color-invert), transparent);
-webkit-filter: blur(20px);
filter: blur(20px);
opacity: 0;
transition: opacity 1s ease, -webkit-transform 1s ease;
transition: opacity 1s ease, transform 1s ease;
transition: opacity 1s ease, transform 1s ease, -webkit-transform 1s ease;
-webkit-transform: perspective(1px) translateZ(0);
transform: perspective(1px) translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
}
.power-switch .button .power-on,
.power-switch .button .power-off {
height: 100%;
width: 100%;
position: absolute;
z-index: 1;
fill: none;
stroke: var(--color-invert);
stroke-width: 8px;
stroke-linecap: round;
stroke-linejoin: round;
}
.power-switch .button .power-on .line,
.power-switch .button .power-off .line {
opacity: .2;
}
.power-switch .button .power-on .circle,
.power-switch .button .power-off .circle {
opacity: .2;
-webkit-transform: rotate(-58deg);
transform: rotate(-58deg);
-webkit-transform-origin: center 80px;
transform-origin: center 80px;
stroke-dasharray: 220;
stroke-dashoffset: 40;
}
.power-switch .button .power-on {
-webkit-filter: drop-shadow(0px 0px 6px rgba(255, 255, 255, 0.8));
filter: drop-shadow(0px 0px 6px rgba(255, 255, 255, 0.8));
}
.power-switch .button .power-on .line {
opacity: 0;
transition: opacity .3s ease 1s;
}
.power-switch .button .power-on .circle {
opacity: 1;
stroke-dashoffset: 220;
transition: stroke-dashoffset 1s ease 0s, -webkit-transform 0s ease;
transition: transform 0s ease, stroke-dashoffset 1s ease 0s;
transition: transform 0s ease, stroke-dashoffset 1s ease 0s, -webkit-transform 0s ease;
}
.power-switch input {
position: absolute;
height: 100%;
width: 100%;
z-index: 2;
cursor: pointer;
opacity: 0;
}
.power-switch input:checked + .button:after {
opacity: 0.15;
-webkit-transform: scale(2) perspective(1px) translateZ(0);
transform: scale(2) perspective(1px) translateZ(0);
-webkit-backface-visibility: hidden;
backface-visibility: hidden;
transition: opacity .5s ease, -webkit-transform .5s ease;
transition: opacity .5s ease, transform .5s ease;
transition: opacity .5s ease, transform .5s ease, -webkit-transform .5s ease;
}
.power-switch input:checked + .button .power-on,
.power-switch input:checked + .button .power-off {
-webkit-animation: click-animation .3s ease forwards;
animation: click-animation .3s ease forwards;
-webkit-transform: scale(1);
transform: scale(1);
}
.power-switch input:checked + .button .power-on .line,
.power-switch input:checked + .button .power-off .line {
-webkit-animation: line-animation .8s ease-in forwards;
animation: line-animation .8s ease-in forwards;
}
.power-switch input:checked + .button .power-on .circle,
.power-switch input:checked + .button .power-off .circle {
-webkit-transform: rotate(302deg);
transform: rotate(302deg);
}
.power-switch input:checked + .button .power-on .line {
opacity: 1;
transition: opacity .05s ease-in .55s;
}
.power-switch input:checked + .button .power-on .circle {
-webkit-transform: rotate(302deg);
transform: rotate(302deg);
stroke-dashoffset: 40;
transition: stroke-dashoffset .4s ease .2s, -webkit-transform .4s ease .2s;
transition: transform .4s ease .2s, stroke-dashoffset .4s ease .2s;
transition: transform .4s ease .2s, stroke-dashoffset .4s ease .2s, -webkit-transform .4s ease .2s;
}
@-webkit-keyframes line-animation {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
10% {
-webkit-transform: translateY(10px);
transform: translateY(10px);
}
40% {
-webkit-transform: translateY(-25px);
transform: translateY(-25px);
}
60% {
-webkit-transform: translateY(-25px);
transform: translateY(-25px);
}
85% {
-webkit-transform: translateY(10px);
transform: translateY(10px);
}
100% {
-webkit-transform: translateY(0px);
transform: translateY(0px);
}
}
@keyframes line-animation {
0% {
-webkit-transform: translateY(0);
transform: translateY(0);
}
10% {
-webkit-transform: translateY(10px);
transform: translateY(10px);
}
40% {
-webkit-transform: translateY(-25px);
transform: translateY(-25px);
}
60% {
-webkit-transform: translateY(-25px);
transform: translateY(-25px);
}
85% {
-webkit-transform: translateY(10px);
transform: translateY(10px);
}
100% {
-webkit-transform: translateY(0px);
transform: translateY(0px);
}
}
@-webkit-keyframes click-animation {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
@keyframes click-animation {
0% {
-webkit-transform: scale(1);
transform: scale(1);
}
50% {
-webkit-transform: scale(0.9);
transform: scale(0.9);
}
100% {
-webkit-transform: scale(1);
transform: scale(1);
}
}
body {
background: #1B1A23;
height: 100vh;
font: 400 16px 'Poppins', sans-serif;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
body .socials {
position: fixed;
display: block;
left: 20px;
bottom: 20px;
}
body .socials > a {
display: block;
width: 30px;
opacity: .2;
-webkit-transform: scale(var(--scale, 0.8));
transform: scale(var(--scale, 0.8));
transition: -webkit-transform 0.3s cubic-bezier(0.38, -0.12, 0.24, 1.91);
transition: transform 0.3s cubic-bezier(0.38, -0.12, 0.24, 1.91);
transition: transform 0.3s cubic-bezier(0.38, -0.12, 0.24, 1.91), -webkit-transform 0.3s cubic-bezier(0.38, -0.12, 0.24, 1.91);
}
body .socials > a:hover {
--scale: 1;
}

@ -0,0 +1,25 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Rotating Text</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<!-- partial:index.partial.html -->
<div class="rotating-text">
<p>CSS Animation is</p>
<p>
<span class="word alizarin">awesome.</span>
<span class="word wisteria">beautiful.</span>
<span class="word peter-river">creative.</span>
<span class="word emerald">fabulous.</span>
<span class="word sun-flower">interesting.</span>
</p>
</div>
<!-- partial -->
<script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,37 @@
"use strict";
let words = document.querySelectorAll(".word");
words.forEach(word => {
let letters = word.textContent.split("");
word.textContent = "";
letters.forEach(letter => {
let span = document.createElement("span");
span.textContent = letter;
span.className = "letter";
word.append(span);
});
});
let currentWordIndex = 0;
let maxWordIndex = words.length - 1;
words[currentWordIndex].style.opacity = "1";
let rotateText = () => {
let currentWord = words[currentWordIndex];
let nextWord = currentWordIndex === maxWordIndex ? words[0] : words[currentWordIndex + 1];
// rotate out letters of current word
Array.from(currentWord.children).forEach((letter, i) => {
setTimeout(() => {
letter.className = "letter out";
}, i * 80);
});
// reveal and rotate in letters of next word
nextWord.style.opacity = "1";
Array.from(nextWord.children).forEach((letter, i) => {
letter.className = "letter behind";
setTimeout(() => {
letter.className = "letter in";
}, 340 + i * 80);
});
currentWordIndex =
currentWordIndex === maxWordIndex ? 0 : currentWordIndex + 1;
};
rotateText();
setInterval(rotateText, 4000);

@ -0,0 +1,59 @@
@import url(https://fonts.googleapis.com/css?family=Lato:600);
body {
display: flex;
justify-content: center;
align-items: center;
height: 100vh;
background: #222;
}
.rotating-text {
font-family: Lato, sans-serif;
font-weight: 600;
font-size: 36px;
color: white;
transform: translateX(-80px);
}
.rotating-text p {
display: inline-flex;
margin: 0;
vertical-align: top;
}
.rotating-text p .word {
position: absolute;
display: flex;
opacity: 0;
}
.rotating-text p .word .letter {
transform-origin: center center 25px;
}
.rotating-text p .word .letter.out {
transform: rotateX(90deg);
transition: 0.32s cubic-bezier(0.6, 0, 0.7, 0.2);
}
.rotating-text p .word .letter.in {
transition: 0.38s ease;
}
.rotating-text p .word .letter.behind {
transform: rotateX(-90deg);
}
.alizarin {
color: #e74c3c;
}
.wisteria {
color: #8e44ad;
}
.peter-river {
color: #3498db;
}
.emerald {
color: #2ecc71;
}
.sun-flower {
color: #f1c40f;
}

@ -0,0 +1 @@
# Blackboard Contact Form

@ -0,0 +1,46 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Blackboard Contact Form</title>
<link href='https://fonts.googleapis.com/css?family=Permanent+Marker' rel='stylesheet' type='text/css'><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="./style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
</head>
<body>
<div class="shade">
<div class="blackboard">
<div class="form">
<p>
<label>Name: </label>
<input type="text" />
</p>
<p>
<label>Email: </label>
<input type="text" />
</p>
<p>
<label>Phone: </label>
<input type="tel" />
</p>
<p>
<label>Subject: </label>
<input type="text" />
</p>
<p>
<label>Message: </label>
<textarea></textarea>
</p>
<p class="wipeout">
<input type="submit" value="Send" />
</p>
</div>
</div>
</div>
<script src='https://cdnjs.cloudflare.com/ajax/libs/jquery/2.1.3/jquery.min.js'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,108 @@
body {
height: 100%;
background: url(https://s3-us-west-2.amazonaws.com/s.cdpn.io/50598/concrete-wall-background.jpg) center center fixed;
background-size: cover;
}
.shade {
overflow: auto;
position: absolute;
top: 0;
left: 0;
bottom: 0;
right: 0;
background-image: linear-gradient( 150deg, rgba(0, 0, 0, 0.65), transparent);
}
.blackboard {
position: relative;
width: 640px;
margin: 7% auto;
border: tan solid 12px;
border-top: #bda27e solid 12px;
border-left: #b19876 solid 12px;
border-bottom: #c9ad86 solid 12px;
box-shadow: 0px 0px 6px 5px rgba(58, 18, 13, 0), 0px 0px 0px 2px #c2a782, 0px 0px 0px 4px #a58e6f, 3px 4px 8px 5px rgba(0, 0, 0, 0.5);
background-image: radial-gradient( circle at left 30%, rgba(34, 34, 34, 0.3), rgba(34, 34, 34, 0.3) 80px, rgba(34, 34, 34, 0.5) 100px, rgba(51, 51, 51, 0.5) 160px, rgba(51, 51, 51, 0.5)), linear-gradient( 215deg, transparent, transparent 100px, #222 260px, #222 320px, transparent), radial-gradient( circle at right, #111, rgba(51, 51, 51, 1));
background-color: #333;
}
.blackboard:before {
box-sizing: border-box;
display: block;
position: absolute;
width: 100%;
height: 100%;
background-image: linear-gradient( 175deg, transparent, transparent 40px, rgba(120, 120, 120, 0.1) 100px, rgba(120, 120, 120, 0.1) 110px, transparent 220px, transparent), linear-gradient( 200deg, transparent 80%, rgba(50, 50, 50, 0.3)), radial-gradient( ellipse at right bottom, transparent, transparent 200px, rgba(80, 80, 80, 0.1) 260px, rgba(80, 80, 80, 0.1) 320px, transparent 400px, transparent);
border: #2c2c2c solid 2px;
content: "Contact Us";
font-family: 'Permanent Marker', cursive;
font-size: 2.2em;
color: rgba(238, 238, 238, 0.7);
text-align: center;
padding-top: 20px;
}
.form {
padding: 70px 20px 20px;
}
p {
position: relative;
margin-bottom: 1em;
}
label {
vertical-align: middle;
font-family: 'Permanent Marker', cursive;
font-size: 1.6em;
color: rgba(238, 238, 238, 0.7);
}
p:nth-of-type(5) > label {
vertical-align: top;
}
input,
textarea {
vertical-align: middle;
padding-left: 10px;
background: none;
border: none;
font-family: 'Permanent Marker', cursive;
font-size: 1.6em;
color: rgba(238, 238, 238, 0.8);
line-height: .6em;
outline: none;
}
textarea {
height: 120px;
font-size: 1.4em;
line-height: 1em;
resize: none;
}
input[type="submit"] {
cursor: pointer;
color: rgba(238, 238, 238, 0.7);
line-height: 1em;
padding: 0;
}
input[type="submit"]:focus {
background: rgba(238, 238, 238, 0.2);
color: rgba(238, 238, 238, 0.2);
}
::-moz-selection {
background: rgba(238, 238, 238, 0.2);
color: rgba(238, 238, 238, 0.2);
text-shadow: none;
}
::selection {
background: rgba(238, 238, 238, 0.4);
color: rgba(238, 238, 238, 0.3);
text-shadow: none;
}

@ -0,0 +1,36 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Login Form</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<form class='login-form'>
<div class="flex-row">
<label class="lf--label" for="username">
<svg x="0px" y="0px" width="12px" height="13px">
<path fill="#B1B7C4" d="M8.9,7.2C9,6.9,9,6.7,9,6.5v-4C9,1.1,7.9,0,6.5,0h-1C4.1,0,3,1.1,3,2.5v4c0,0.2,0,0.4,0.1,0.7 C1.3,7.8,0,9.5,0,11.5V13h12v-1.5C12,9.5,10.7,7.8,8.9,7.2z M4,2.5C4,1.7,4.7,1,5.5,1h1C7.3,1,8,1.7,8,2.5v4c0,0.2,0,0.4-0.1,0.6 l0.1,0L7.9,7.3C7.6,7.8,7.1,8.2,6.5,8.2h-1c-0.6,0-1.1-0.4-1.4-0.9L4.1,7.1l0.1,0C4,6.9,4,6.7,4,6.5V2.5z M11,12H1v-0.5 c0-1.6,1-2.9,2.4-3.4c0.5,0.7,1.2,1.1,2.1,1.1h1c0.8,0,1.6-0.4,2.1-1.1C10,8.5,11,9.9,11,11.5V12z"/>
</svg>
</label>
<input id="username" class='lf--input' placeholder='Username' type='text'>
</div>
<div class="flex-row">
<label class="lf--label" for="password">
<svg x="0px" y="0px" width="15px" height="5px">
<g>
<path fill="#B1B7C4" d="M6,2L6,2c0-1.1-1-2-2.1-2H2.1C1,0,0,0.9,0,2.1v0.8C0,4.1,1,5,2.1,5h1.7C5,5,6,4.1,6,2.9V3h5v1h1V3h1v2h1V3h1 V2H6z M5.1,2.9c0,0.7-0.6,1.2-1.3,1.2H2.1c-0.7,0-1.3-0.6-1.3-1.2V2.1c0-0.7,0.6-1.2,1.3-1.2h1.7c0.7,0,1.3,0.6,1.3,1.2V2.9z"/>
</g>
</svg>
</label>
<input id="password" class='lf--input' placeholder='Password' type='password'>
</div>
<input class='lf--submit' type='submit' value='LOGIN'>
</form>
<a class='lf--forgot' href='#'>Forgot password?</a>
</body>
</html>

@ -0,0 +1,126 @@
* {
-webkit-font-smoothing: antialiased;
text-rendering: optimizeLegibility;
}
html, body {
height: 100%;
}
body {
display: flex;
align-items: center;
justify-content: center;
flex-direction: column;
position: relative;
background: linear-gradient(135deg, rgba(36, 46, 77, 0.9), rgba(137, 126, 121, 0.9));
font-family: 'Roboto', helvetica, arial, sans-serif;
font-size: 1.5em;
}
body:before {
content: '';
position: absolute;
top: 0;
left: 0;
height: 100%;
width: 100%;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADIAAAAyCAMAAAAp4XiDAAAAUVBMVEWFhYWDg4N3d3dtbW17e3t1dXWBgYGHh4d5eXlzc3OLi4ubm5uVlZWPj4+NjY19fX2JiYl/f39ra2uRkZGZmZlpaWmXl5dvb29xcXGTk5NnZ2c8TV1mAAAAG3RSTlNAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEBAQEAvEOwtAAAFVklEQVR4XpWWB67c2BUFb3g557T/hRo9/WUMZHlgr4Bg8Z4qQgQJlHI4A8SzFVrapvmTF9O7dmYRFZ60YiBhJRCgh1FYhiLAmdvX0CzTOpNE77ME0Zty/nWWzchDtiqrmQDeuv3powQ5ta2eN0FY0InkqDD73lT9c9lEzwUNqgFHs9VQce3TVClFCQrSTfOiYkVJQBmpbq2L6iZavPnAPcoU0dSw0SUTqz/GtrGuXfbyyBniKykOWQWGqwwMA7QiYAxi+IlPdqo+hYHnUt5ZPfnsHJyNiDtnpJyayNBkF6cWoYGAMY92U2hXHF/C1M8uP/ZtYdiuj26UdAdQQSXQErwSOMzt/XWRWAz5GuSBIkwG1H3FabJ2OsUOUhGC6tK4EMtJO0ttC6IBD3kM0ve0tJwMdSfjZo+EEISaeTr9P3wYrGjXqyC1krcKdhMpxEnt5JetoulscpyzhXN5FRpuPHvbeQaKxFAEB6EN+cYN6xD7RYGpXpNndMmZgM5Dcs3YSNFDHUo2LGfZuukSWyUYirJAdYbF3MfqEKmjM+I2EfhA94iG3L7uKrR+GdWD73ydlIB+6hgref1QTlmgmbM3/LeX5GI1Ux1RWpgxpLuZ2+I+IjzZ8wqE4nilvQdkUdfhzI5QDWy+kw5Wgg2pGpeEVeCCA7b85BO3F9DzxB3cdqvBzWcmzbyMiqhzuYqtHRVG2y4x+KOlnyqla8AoWWpuBoYRxzXrfKuILl6SfiWCbjxoZJUaCBj1CjH7GIaDbc9kqBY3W/Rgjda1iqQcOJu2WW+76pZC9QG7M00dffe9hNnseupFL53r8F7YHSwJWUKP2q+k7RdsxyOB11n0xtOvnW4irMMFNV4H0uqwS5ExsmP9AxbDTc9JwgneAT5vTiUSm1E7BSflSt3bfa1tv8Di3R8n3Af7MNWzs49hmauE2wP+ttrq+AsWpFG2awvsuOqbipWHgtuvuaAE+A1Z/7gC9hesnr+7wqCwG8c5yAg3AL1fm8T9AZtp/bbJGwl1pNrE7RuOX7PeMRUERVaPpEs+yqeoSmuOlokqw49pgomjLeh7icHNlG19yjs6XXOMedYm5xH2YxpV2tc0Ro2jJfxC50ApuxGob7lMsxfTbeUv07TyYxpeLucEH1gNd4IKH2LAg5TdVhlCafZvpskfncCfx8pOhJzd76bJWeYFnFciwcYfubRc12Ip/ppIhA1/mSZ/RxjFDrJC5xifFjJpY2Xl5zXdguFqYyTR1zSp1Y9p+tktDYYSNflcxI0iyO4TPBdlRcpeqjK/piF5bklq77VSEaA+z8qmJTFzIWiitbnzR794USKBUaT0NTEsVjZqLaFVqJoPN9ODG70IPbfBHKK+/q/AWR0tJzYHRULOa4MP+W/HfGadZUbfw177G7j/OGbIs8TahLyynl4X4RinF793Oz+BU0saXtUHrVBFT/DnA3ctNPoGbs4hRIjTok8i+algT1lTHi4SxFvONKNrgQFAq2/gFnWMXgwffgYMJpiKYkmW3tTg3ZQ9Jq+f8XN+A5eeUKHWvJWJ2sgJ1Sop+wwhqFVijqWaJhwtD8MNlSBeWNNWTa5Z5kPZw5+LbVT99wqTdx29lMUH4OIG/D86ruKEauBjvH5xy6um/Sfj7ei6UUVk4AIl3MyD4MSSTOFgSwsH/QJWaQ5as7ZcmgBZkzjjU1UrQ74ci1gWBCSGHtuV1H2mhSnO3Wp/3fEV5a+4wz//6qy8JxjZsmxxy5+4w9CDNJY09T072iKG0EnOS0arEYgXqYnXcYHwjTtUNAcMelOd4xpkoqiTYICWFq0JSiPfPDQdnt+4/wuqcXY47QILbgAAAABJRU5ErkJggg==);
opacity: .3;
}
.login-form {
width: 100%;
padding: 2em;
position: relative;
background: rgba(0, 0, 0, 0.15);
}
.login-form:before {
content: '';
position: absolute;
top: -2px;
left: 0;
height: 2px;
width: 100%;
background: linear-gradient(to right, #35c3c1, #00d6b7);
}
@media screen and (min-width: 600px) {
.login-form {
width: 50vw;
max-width: 15em;
}
}
.flex-row {
display: flex;
margin-bottom: 1em;
}
.lf--label {
width: 2em;
display: flex;
align-items: center;
justify-content: center;
background: #f5f6f8;
cursor: pointer;
}
.lf--input {
flex: 1;
padding: 1em;
border: 0;
color: #8f8f8f;
font-size: 1rem;
}
.lf--input:focus {
outline: none;
transition: -webkit-transform .15s ease;
transition: transform .15s ease;
transition: transform .15s ease, -webkit-transform .15s ease;
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
.lf--submit {
display: block;
padding: 1em;
width: 100%;
background: linear-gradient(to right, #35c3c1, #00d6b7);
border: 0;
color: #fff;
cursor: pointer;
font-size: .75em;
font-weight: 600;
text-shadow: 0 1px 0 rgba(0, 0, 0, 0.2);
}
.lf--submit:focus {
outline: none;
transition: -webkit-transform .15s ease;
transition: transform .15s ease;
transition: transform .15s ease, -webkit-transform .15s ease;
-webkit-transform: scale(1.1);
transform: scale(1.1);
}
.lf--forgot {
margin-top: 1em;
color: #00d6b7;
font-size: .65em;
text-align: center;
position: relative;
}
::-webkit-input-placeholder {
color: #8f8f8f;
}
:-ms-input-placeholder {
color: #8f8f8f;
}
::-ms-input-placeholder {
color: #8f8f8f;
}
::placeholder {
color: #8f8f8f;
}

@ -0,0 +1,4 @@
# Less annoying form
_A Pen created at CodePen.io. Original URL: [https://codepen.io/andyfitz/pen/eYmKNEx](https://codepen.io/andyfitz/pen/eYmKNEx).

@ -0,0 +1,121 @@
<!DOCTYPE html>
<html class="no-js" lang="">
<!--
RED HAT SINGLE SIGN ON FORM
`.`` .-..`
://///:--///////:-.`
://///////////////////:-`
./////////////////////////:
`///////////////////////////-
:////////////////////////////`
/////////////////////////////-
`..-::/: `:////////////////////////////
`://////// `-//////////////////////////.
`//////////:` `-://////////////////////-`
`////////////-` `.-:////////////////-`//-`
://///////////:. ``...----...` :////.
-///////////////:-.` -//////:
`://////////////////:--. .-://///////:
`-////////////////////////////////////////////`
`-/////////////////////////////////////////`
`.:////////////////////////////////////.
`.-://///////////////////////////:`
``.-:////////////////////:.`
```-://///////```
-->
<head>
<meta charset="utf-8">
<title>Red Hat Sign-In</title>
<meta name="description" content="sign-in page for Red Hat employees">
<meta name="viewport" content="width=device-width, initial-scale=1">
<meta name="theme-color" content="#cc0000">
<meta name="viewport" content="width=device-width, initial-scale=1">
<link rel="stylesheet" href="./style.css">
<script src="https://cdnjs.cloudflare.com/ajax/libs/prefixfree/1.0.7/prefixfree.min.js"></script>
</head>
<body>
<svg xmlns="http://www.w3.org/2000/svg" class="logo" viewBox="0 0 850 240">
<path id="brim" d="M230.2 110.6c.1-1.6-.1-3.1-.4-4.5l-9.6-41.5c-2.2-9.2-4.2-13.3-20.1-21.4-12.5-6.3-39.6-16.8-47.6-16.8-7.5 0-9.6 9.5-18.6 9.5-9 0-14.9-7-23.1-7-8.1 0-12.7 5.2-16.5 15.9 0 0-10.8 30.4-12.2 34.9a10 10 0 0 0-.3 2.5c0 11.8 45.8 50.7 109 50.7 16 0 39.4-3.2 39.4-22.3zm2.4 7.5a72 72 0 0 1 2.2 13c0 18-20.2 28-46.8 28-60 0-112.4-35.1-112.4-58.4 0-3.3.7-6.5 2-9.6C56.2 92.5 28 96.5 28 121c0 40.4 95.6 90.2 171.5 90.2 58 0 72.7-26.3 72.7-47.1 0-16.3-14-34.8-39.5-45.9"/>
<path id="band" d="M232.7 118.2a58 58 0 0 1 2.2 13c0 18-20.2 28-46.8 28-60 0-112.5-35.1-112.5-58.4 0-3.3.6-6.5 2-9.6l4.6-11.4-.3 2.4c0 12 46.6 50.7 109 50.7 15.9 0 39.3-4.1 39.3-22.3 0-1.6-.1-3.1-.4-4.5z"/>
<path id="type" d="M771.2 144.7c0 15.3 9.2 22.8 26 22.8a68 68 0 0 0 15.3-2.2v-17.7a31.8 31.8 0 0 1-9.9 1.5c-6.9 0-9.4-2.2-9.4-8.7v-27.2h20V95h-20V71.9l-22 4.7V95h-14.4v18.2h14.4v31.5zm-61.8 23c7.7 0 13.9-1.6 19.7-5.5v4.3h21.6v-45.8c0-17.5-11.7-27-31.3-27a79 79 0 0 0-33.4 7.8l7.8 16.1a57 57 0 0 1 21.7-5.7c9 0 13.6 3.5 13.6 10.7v3.5a61 61 0 0 0-16.2-2c-18.4 0-29.5 7.7-29.5 21.5 0 12.5 10 22.1 26 22.1zm-5.2-22.6c0-4.7 4.8-7 11.9-7 4.8 0 9.1.7 13 1.6v9.2c-4 2.3-8.8 3.4-13.6 3.4-7.1 0-11.3-2.7-11.3-7.2zm-112.4 21.4h23.3v-37H654v37h23.3V71.9H654v36.3h-38.9V71.9h-23.3v94.6zm-54.8 0h21.6V67.1L536.7 72v26.9a36.2 36.2 0 0 0-18.2-4.8 36.6 36.6 0 0 0-37.2 36.7 36.4 36.4 0 0 0 36.5 36.8 32 32 0 0 0 19.2-6.3v5.3zm-34.2-35.8a18 18 0 0 1 18.8-18.1c5.9 0 11.3 2 15.1 5.5v25c-3.9 3.8-9 5.7-15.1 5.7a18.1 18.1 0 0 1-18.8-18.1zm-101.3.1c0 20.8 17 37.1 38.9 37.1 12.1 0 20.8-3.3 29.9-10.9l-14.5-12.8a19.1 19.1 0 0 1-14.3 5.4c-8.1 0-14.7-4.5-17.6-11.3h51v-5.5c0-22.7-15.3-39-36.1-39-21 0-37.3 16.2-37.3 37zm36.9-19.2c6.9 0 12.7 4.5 15 11.4h-29.9c2.2-7.2 7.6-11.4 14.9-11.4zm-121 54.9h23.3V132h17.7l17.8 34.5h26l-20.7-37.8a29 29 0 0 0 17.7-26.7c0-17-13.4-30.1-33.4-30.1h-48.4v94.6zm46.3-74.8c7.7 0 12 5 12 10.7 0 5.8-4.3 10.7-12 10.7h-23V91.7h23z"/>
</svg>
<form
id="login_form"
name="login_form"
autocomplete="off"
method="post"
enctype="application/x-www-form-urlencoded"
onsubmit="javascript:stripspaces(this)" >
<input type="text"
id="username"
class="username"
name="username"
size="20"
autocapitalize="off"
autocorrect="off"
autocomplete="on"
autofocus="on"
required />
<label for="username">Username</label> <small>Red Hat ID</small> <svg viewbox="0 0 10 10" ><use xlink:href="#user" /> <use xlink:href="#fed" class="fedora" /> <use xlink:href="#burst" class="flash" /></svg>
<input
id="password"
type="password"
name="password"
autocorrect="off"
autocomplete="off"
autocomplete="new-password"
value=""
size="20"
required>
<label for="password">Password</label> <small>PIN + Token</small> <svg viewbox="0 0 10 10"><use xlink:href="#pad" /><use class="flash" xlink:href="#burst" /><use class="lock" xlink:href="#lock" />
</svg>
<button id="submit" type="submit" name="submit" >Log In</button>
<span class="note" id="note">NOTE: You must close your browser or clear your cookies to completely log out.</span>
<svg xmlns="http://www.w3.org/2000/svg"
class="hbox" viewBox="0 0 200 40">
<rect x=".5" y=".5" ry="3" rx="3" width="199" height="42" />
</svg>
</form>
<svg class="hide">
<defs>
<g id="padlock"> <path id="pad" d="m 3,5.5 5,0 0,4 -5,0 z" /> <path id="lock" d="m 3,5.5 0,-2 c 0,-3 4,-3 4,-0.25 L 7,4 "/> </g>
<path id="fed" d="M7.8 3.8c-.7.6-3.5.6-4.4-.1-.3-.2 4.8-.2 4.4.1zM7 3.5c-.4-.7-.3-2-1.5-1.5-1-.5-1 .7-1.5 1.5" />
<path id="user" d="M5.5 5.8c-2 0-2-3 0-3 2.3 0 2 3 0 3zm.8-.3c1.2 0 2.2 1 2.2 2.3v1.7h-6V7.7c0-1.2 1-2.2 2.3-2.2" />
<path id="burst" d="m 5.47,0 v 2.19 m 4.38,2.19 h -2.2 m -6.55,0 H 3.28 M 2.38,1.28 3.92,2.83 M 8.56,1.28 7.02,2.83" />
</defs>
</svg>
</body>
</html>

@ -0,0 +1,504 @@
:root {
font-size: 1.25rem;
user-select: none;
}
:root {
font-family: "Red Hat Text", sans-serif;
--brand: #e00;
--bg: #fff;
--fg: #000811;
--mid: #999;
outline: none;
}
*, :before, :after {
box-sizing: border-box;
outline: 0;
}
body {
background-color: var(--bg);
background-color: #fafafa;
color: var(--fg);
overscroll-behavior: none;
/* display: flex;*/
flex-direction: column;
overflow: hidden;
width: 100vw;
height: 100vh;
text-align: center;
display: flex;
}
@media (prefers-color-scheme: dark) {
:root {
--bg: #050505;
--fg: #ddd;
--mid: #555;
}
body {
background-color: #050505;
}
#band {
fill: transparent;
}
form:before {
opacity: 0.2 !important;
}
}
body::before,
body::after {
content: "";
/* flex: 1; */
}
form {
position: relative;
display: block;
border-radius: 0.4rem;
box-shadow: 0 0.5rem 0.75rem -0.75rem rgba(0, 0, 0, 0.5);
width: 20rem;
margin: 0 auto;
min-height: 4rem;
}
form:before {
content: "";
position: absolute;
top: 0;
left: 0;
right: 0;
bottom: 0;
background-color: var(--mid);
opacity: 0.085;
z-index: 0;
border-radius: 0.4rem;
}
/* BEGIN GHETTO RESET */
*,
*:before,
*:after {
box-sizing: border-box;
padding: 0;
appearance: none;
font-size: 1rem;
font-weight: 300;
font-family: "Red Hat Text", sans-serif;
border: 0;
box-shadow: 0;
pointer-events: none;
text-rendering: optimizelegibility;
}
input {
appearance: none;
pointer-events: all;
color: currentcolor;
cursor: pointer;
box-shadow: none;
outline: 0 !important;
}
small {
color: var(--mid);
z-index: 1;
}
:valid + label,
:focus + label {
z-index: 4;
transform-origin: 2.5rem 0;
animation: rise 0.45s ease-out forwards;
transform: scale(0.75) translate(0, -1rem);
}
@keyframes rise {
0% {
transform: scale(1) translate(0, -0.5rem);
color: currentcolor;
opacity: 0;
}
100% {
transform: scale(0.75) translate(0, -1rem);
}
}
:valid + label {
color: var(--mid);
}
:focus + label {
color: var(--brand);
}
:focus {
outline: 0;
}
::selection {
color: #fff;
background: rgba(238, 0, 0, 0.99);
}
::-moz-focus-inner {
border: 0;
outline: 0;
}
label {
font-weight: 400;
color: var(--mid);
}
input,
label,
svg,
small {
width: 10rem;
height: 4rem;
line-height: 4.5rem;
position: absolute;
padding: 0;
display: block;
margin: 0 auto;
text-indent: 0;
text-align: left;
}
/* END GHETTO RESET */
[type="submit"] {
background-color: var(--brand);
color: #fff;
border-radius: 0 0 0.4rem 0.4rem;
text-align: center;
background-image: linear-gradient(#f00, #c00);
line-height: 4rem;
width: 100%;
position: relative;
display: block;
transition: all 0.24s ease;
overflow: hidden;
position: absolute;
bottom: -4rem;
}
[type="submit"]:after {
content: "";
display: block;
position: absolute;
height: 4rem;
top: 0;
left: 50%;
margin-left: -4rem;
transform: skew(-45deg) translate(-200%, 0);
background-color: #f00;
width: 8rem;
transition: all .5s ease;
}
[type="submit"]:focus:after {
transform: skew(-45deg) translate(200%, 0);
opacity: 0;
}
/*hide submit button until fields have input*/
:not(:valid) ~ [type="submit"] {
opacity: 0;
transform: translate(0, 0.3rem);
z-index: 0;
}
:valid ~ :valid ~ [type="submit"] {
height: 4rem;
margin-top: 4rem;
opacity: 1;
transform: translate(0, -0.1rem);
box-shadow: 0 0.5rem 0.5rem -0.5rem rgba(0, 0, 0, 0.3);
transition: all 0.5s cubic-bezier(0.3, 0.2, 0.2, 1);
}
[type="submit"]:focus {
box-shadow: 0 0.5rem 0.5rem -0.5rem rgba(0, 0, 0, 0.3) !important;
}
.note {
position: fixed;
bottom: 1em;
left: 0;
color: var(--mid);
width: 100%;
font-size: 0.5em;
z-index: -1;
}
small {
opacity: 0;
font-weight: 200;
}
:focus:not(:valid) + label + small {
opacity: 0.5;
transition: opacity 1s ease 1s;
}
label,
small {
text-indent: 2.75rem;
}
[type="text"],
[type="password"] {
text-indent: 2.75rem;
text-align: left;
background-color: transparent;
line-height: 4rem;
padding-top: 0.5rem;
top: 0;
/*
background-image: linear-gradient(145deg, transparent, rgba(0,0,0,0.035) );*/
}
[type="text"] {
border-radius: 0 0 0;
}
[type="text"]:focus,
[type="password"]:focus {
/* box-shadow: 0 -.15rem var(--brand);*/
transition: box-shadow 0.4s ease;
background-image: none;
background-color: var(--bg);
box-shadow: 0 0.5rem 0.5rem -0.4rem rgba(0, 0, 0, 0.4);
}
[type="password"],
[type="password"] + label,
[type="password"] + label + small {
right: 0;
}
[type="password"] + label + small + svg {
left: 10.75rem;
}
/*
Portrait mode for phones and sidebars
*/
@media screen and (max-width: 440px) {
:root {
font-size: 1rem;
}
form {
min-height: 8rem;
width: 10rem;
}
[type="submit"] {
margin-top: 4rem;
position: relative;
height: 3rem;
line-height: 3rem;
}
:valid ~ :valid ~ [type="submit"] {
height: 3rem;
line-height: 3rem;
}
[type="text"]:focus,
[type="password"]:focus {
box-shadow: 0 0.1em 0 var(--brand);
z-index: 3;
}
[type="password"],
[type="password"] + label,
[type="password"] + label + small,
[type="password"] + label + small + svg {
top: 4rem;
}
[viewbox="0 0 10 10"] {
left: 0.25rem;
}
[type="password"] + label + small + svg {
left: 0.25rem;
top: 5.5rem;
}
}
@media (min-width: 300px) and (orientation: landscape) {
.hbox {
display: block !important;
width: 100%;
height: 4rem;
top: 0;
fill: none;
stroke-width: 1;
stroke: var(--mid);
stroke-dasharray: 0 468;
stroke-dashoffset: -96;
transition: all 0.5s ease;
}
[type="text"]:focus ~ .hbox,
[type="password"]:focus ~ .hbox {
stroke-dasharray: 138 334;
stroke-dashoffset: 42;
stroke: var(--brand);
}
[type="submit"]:focus ~ .hbox {
stroke-dashoffset: -300;
}
[type="password"]:focus ~ .hbox {
stroke-dashoffset: -96;
}
/*field outline*/
}
small + svg {
stroke: var(--mid);
color: var(--mid);
}
input:focus + label + small + svg,
input:focus + label + small + svg use {
stroke: var(--brand);
color: var(--brand);
}
.fedora {
fill: currentcolor !important;
}
/* icons*/
#burst {
stroke: var(--mid);
}
#fed,
#user,
#lock,
#pad,
#burst,
[viewbox="0 0 10 10"] use {
fill: transparent;
stroke-width: 1px;
}
#fed {
fill: currentcolor !important;
}
input + label + small + svg {
text-align: left;
z-index: 3;
height: 1.25rem;
width: 1.25rem;
left: 0.5rem;
top: 1.5rem;
}
.fedora {
transform: translate(0, -1.5px);
opacity: 0;
}
.lock {
transform: translate(0, 0px);
}
[type="password"]:valid ~ svg .lock {
transition: transform 0.5s ease;
transform: translate(0, 1.25px);
}
input[type="text"]:valid ~ svg .fedora {
transform: translate(0, -0.7px);
transition: opacity 0.2s ease, transform 0.35s ease;
opacity: 1;
}
svg use {
fill: none;
}
#fed {
fill: auto !important;
}
.logo {
width: 100%;
position: relative;
margin: 1rem auto;
width: 100%;
}
#brim {
fill: var(--brand);
}
#type {
fill: currentcolor;
}
.flash {
stroke-dasharray: 1 5;
stroke-dashoffset: -4;
stroke-linecap: round;
opacity: 0;
}
:focus + label + small + svg .flash {
stroke-dashoffset: 1;
transition: all 0.6s ease-out;
opacity: 1;
stroke-linecap: round;
}
[type="text"] {
user-select: all;
}
.logo {
height: 2.5rem;
}
/*helper objects */
.hbox {
display: none;
}
@media (max-height: 300px) and (orientation: landscape) {
body {
overflow-y: auto;
}
.hbox {
display: none;
}
form .note,
form .logo {
display: none;
}
}
input:-webkit-autofill,
input:-webkit-autofill:hover,
input:-webkit-autofill:focus {
transition: background-color 50000s ease-in-out 50000s;
font-family: "Red Hat Text", sans-serif !important;
box-shadow: inset 0 0 0 10rem var(--bg);
z-index: 3;
}
input:-webkit-autofill:hover + label + small {
display: none !important;
}

@ -0,0 +1,3 @@
# Loading animation
simple loading animation with SVG and CSS

@ -0,0 +1,33 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Loading animation</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<button></button>
<svg xmlns="http://www.w3.org/2000/svg" id="svg8" version="1.1" viewBox="0 0 40 14">
<rect id="load" stroke-width="0" x="0" y="0" height="9" width="40"/>
<path id="mask" d="M0 0v14h40V0zm9 2.64c.44 0 .84.08 1.2.22.36.15.64.37.86.66.22.3.35.61.39.96.04.34.06.94.06 1.8v1.44c0 .84-.02 1.43-.06 1.78a1.99 1.99 0 01-1.21 1.62c-.36.16-.78.24-1.25.24a3.2 3.2 0 01-1.2-.22 2 2 0 01-1.25-1.62c-.04-.34-.06-.94-.06-1.8V6.28c0-.84.02-1.43.05-1.78a2.02 2.02 0 011.22-1.63c.36-.15.77-.23 1.24-.23zm25.73 0c.63 0 1.16.13 1.58.4.42.26.7.57.83.93.12.36.19.88.19 1.57v.36h-2.18v-.76c0-.48-.02-.78-.06-.9-.04-.12-.14-.18-.3-.18-.13 0-.22.05-.27.15-.05.1-.07.37-.07.8v4.01c0 .38.02.63.07.75.05.11.15.17.29.17.16 0 .27-.06.32-.2.06-.13.09-.4.09-.78v-1h-.44V6.7h2.55v4.5h-1.37l-.2-.6c-.15.25-.34.45-.57.58-.22.13-.49.19-.8.19a2.1 2.1 0 01-1.74-.93 2.09 2.09 0 01-.32-.82 9.97 9.97 0 01-.06-1.3V5.84c0-.8.05-1.38.13-1.74.09-.36.33-.7.74-1 .41-.3.94-.45 1.59-.45zm-32.06.18h2.18V9.5h1.32v1.67h-3.5zm10.27 0h3.14l1.25 8.36H15.1l-.1-1.5h-.79l-.13 1.5h-2.25zm4.76 0h1.63c1.05 0 1.76.05 2.13.14a1.5 1.5 0 011.2 1.21c.05.27.08.8.08 1.6V8.7c0 .75-.04 1.25-.11 1.5-.07.26-.2.46-.37.6-.17.14-.39.24-.65.3s-.65.08-1.17.08H17.7zm5.85 0h2.18v8.36h-2.18zm3.06 0h1.82l1.22 3.76V2.82h1.82v8.36h-1.91l-1.13-3.8v3.8H26.6zM9 4.06a.3.3 0 00-.27.13c-.06.09-.09.35-.09.78v3.9c0 .49.02.79.06.9.04.12.13.17.28.17.15 0 .24-.06.28-.2.04-.12.06-.44.06-.93V4.97c0-.4-.02-.64-.06-.75-.04-.1-.13-.16-.27-.16zm10.87.19v5.5c.3 0 .5-.06.57-.18.08-.13.11-.47.11-1.03V5.29c0-.38 0-.62-.03-.73a.34.34 0 00-.17-.23 1.04 1.04 0 00-.48-.08zm-5.28.44c-.22 1.6-.36 2.77-.41 3.5h.74a98.4 98.4 0 01-.33-3.5z" />
<g id="outline" >
<path d="M4.85 2.82V9.5h1.32v1.67h-3.5V2.82z"/>
<path d="M11.51 7.72q0 1.26-.06 1.78-.06.53-.37.96-.31.43-.85.67-.53.23-1.24.23-.67 0-1.2-.22-.54-.22-.86-.66-.33-.44-.4-.96-.05-.51-.05-1.8V6.28q0-1.26.05-1.78.07-.53.38-.96.31-.43.84-.67.53-.23 1.24-.23.67 0 1.2.22.54.22.87.66.33.44.39.96.06.51.06 1.8zM9.33 4.97q0-.59-.06-.75-.07-.16-.27-.16-.17 0-.26.13t-.09.78v3.9q0 .73.06.9.06.17.28.17.22 0 .28-.2.06-.19.06-.93z"/>
<path d="M16.08 2.82l1.25 8.36H15.1l-.1-1.5h-.79l-.13 1.5h-2.25l1.1-8.36zM14.93 8.2q-.16-1.42-.33-3.51-.33 2.4-.41 3.5z"/>
<path d="M17.7 2.82h1.63q1.57 0 2.13.14.56.15.84.48.3.33.37.74.07.4.07 1.59V8.7q0 1.12-.11 1.5-.1.38-.37.6-.26.21-.65.3-.39.08-1.17.08H17.7zm2.18 1.43v5.5q.47 0 .57-.18.11-.2.11-1.03V5.29q0-.57-.03-.73-.04-.16-.17-.23-.13-.08-.48-.08z"/>
<path d="M25.73 2.82v8.36h-2.18V2.82z"/>
<path d="M31.47 2.82v8.36h-1.91l-1.13-3.8v3.8H26.6V2.82h1.82l1.22 3.76V2.82z"/>
<path d="M37.33 5.9h-2.18v-.76q0-.72-.06-.9-.06-.18-.3-.18-.2 0-.27.15-.07.16-.07.8v4.01q0 .57.07.75.07.17.29.17.24 0 .32-.2.09-.2.09-.78v-1h-.44V6.7h2.55v4.5h-1.37l-.2-.6q-.23.38-.57.58-.33.19-.8.19-.54 0-1.02-.26-.48-.27-.72-.67-.25-.39-.31-.82-.07-.43-.07-1.3V5.84q0-1.2.13-1.74t.74-1q.62-.45 1.59-.45.95 0 1.58.4.63.39.83.93.19.54.19 1.56z"/>
</g>
</svg>
<script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,4 @@
const bdy = document.querySelector('body');
addEventListener('click', e => {
bdy.classList.toggle('invert');
});

@ -0,0 +1,49 @@
body {
background: var( --background-col );
padding: 0;
margin:0;
min-height:100vh;
display: flex;
justify-content:center;
align-items:center;
--foreground-col: #fff;
--background-col: #000;
}
body.invert {
--foreground-col: #000;
--background-col: #fff;
}
button {
position: absolute;
top: 10px;
right:10px;
border-radius: 50%;
width: 40px;
height: 40px;
}
svg {
width: 50vw;
}
#outline {
fill:none;
stroke: var( --foreground-col );
stroke-width: .1px;
}
#load {
fill: var( --foreground-col );
stroke-width: 0px;
animation: loading 6s linear infinite;
}
#mask {
fill: var( --background-col );
stroke-width: 0px;
}
@keyframes loading {
from {
y: 11.5px;
}
to {
y: -6px;
}
}

Before

Width:  |  Height:  |  Size: 106 KiB

After

Width:  |  Height:  |  Size: 106 KiB

@ -0,0 +1,2 @@
# Neumorphism study (change color with dot, best in Chrome)

@ -0,0 +1,20 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Neumorphism study (change color with dot, best in Chrome)</title>
<link rel="stylesheet" href="./style.css">
</head>
<body>
<img src="https://images.unsplash.com/photo-1567911342145-96a7bd51c8dc?ixlib=rb-1.2.1&q=85&fm=jpg&crop=entropy&cs=srgb&ixid=eyJhcHBfaWQiOjE0NTg5fQ" alt=" ">
<card class="neumorphic">
<input type="color" name="color" id="color" value="#45494c" class="neumorphic" oninput="changeColor()">
</card>
<script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,6 @@
const color = document.getElementById('color');
function changeColor() {
console.log(color.value);
document.body.style.setProperty('--color', color.value);
}

@ -0,0 +1,69 @@
body {
--color: hsl(210deg,10%,30%);
background: var(--color);
}
.neumorphic {
border-radius: 1rem;
background: var(--color);
-webkit-animation: 1s -.3s 1 paused opacify;
animation: 1s -.3s 1 paused opacify;
-webkit-backdrop-filter: blur(1.5rem);
backdrop-filter: blur(1.5rem);
border: 1px solid rgba(255, 255, 255, 0.2);
box-shadow: -0.25rem -0.25rem 0.5rem rgba(255, 255, 255, 0.07), 0.25rem 0.25rem 0.5rem rgba(0, 0, 0, 0.12), -0.75rem -0.75rem 1.75rem rgba(255, 255, 255, 0.07), 0.75rem 0.75rem 1.75rem rgba(0, 0, 0, 0.12), inset 8rem 8rem 8rem rgba(0, 0, 0, 0.05), inset -8rem -8rem 8rem rgba(255, 255, 255, 0.05);
}
@-webkit-keyframes opacify {
to {
background: transparent;
}
}
@keyframes opacify {
to {
background: transparent;
}
}
card {
position: absolute;
top: 50vh;
left: 50vw;
width: 400px;
height: 300px;
max-width: 80vw;
max-height: 80vh;
-webkit-transform: translate(-50%, -50%);
transform: translate(-50%, -50%);
box-sizing: border-box;
padding: .5rem;
}
img {
position: absolute;
top: 2rem;
bottom: 2rem;
right: 2rem;
-o-object-fit: cover;
object-fit: cover;
width: calc(50vw - 2rem);
height: calc(100vh - 4rem);
box-shadow: 0 1rem 2rem rgba(0, 0, 0, 0.3);
border-radius: .2rem;
}
input.neumorphic {
width: 1rem;
height: 1rem;
border: 0;
padding: 0;
border-radius: 50%;
display: block;
border: 1px solid rgba(255, 255, 255, 0.5);
cursor: pointer;
overflow: hidden;
}
input[type="color"]::-webkit-color-swatch {
opacity: 0;
}

@ -0,0 +1,21 @@
# Vanilla JS Smooth Scroll
<strong>Pure JavaScript smooth to anchor scrolling</strong>
<p>
Easy to implement and with some great features to enhance flexibility. The script will find all the links on your site that are hash based and linking to the current file, all other links are ignored.
</p>
<p>
Clicking on a hash based link will force your website to scroll smoothly down to the area defined with either the same id or name attribute as the current hash.
</p>
<p>
Feel free to use the script with the latest version from <a href="https://github.com/basticodes/scrollToSmooth" target="_blank">Github</a>
</p>
<strong>Changelog:</strong>
<ul>
<li>1.0.1: </li>
<ul>
<li>Added some vendor Prefixes</li>
<li>Fixed a bug where on some devices the scrolltop was not calculated correctly and so the animation would run forever</li>
<li>Added the ability to let the user cancel the animation by scrolling</li>
</ul>
</ul>

@ -0,0 +1,116 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Vanilla JS Smooth Scroll</title>
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/normalize/5.0.0/normalize.min.css">
<link rel='stylesheet' href='https://highlightjs.org/static/demo/styles/night-owl.css'><link rel="stylesheet" href="./style.css">
</head>
<body>
<nav>
<a href="#section-1">Vanilla JS Smooth Scroll</a>
<a href="#section-2">Easy to use!</a>
<a href="#section-3">Usage</a>
<a href="#section-4">Options</a>
<a href="#section-5">That's it</a>
</nav>
<section id="section-1">
<div>
<strong>Vanilla JS Smooth Scroll</strong>
</div>
</section>
<section id="section-2">
<div>
<strong>Easy to use!</strong>
</div>
</section>
<section id="section-3">
<div>
<span>Usage:</span>
<pre>
<code class="javascript">
let links = document.getElementsByTagName('a');
[].forEach.call(links, (el) => {
el.scrollToSmooth({
speed: 500,
easing: 'easeInOutQuint',
callback: function () { console.log('we reached it!'); },
fixedHeader: null
});
});
</code>
</pre>
</div>
</section>
<section id="section-4">
<div>
<h3>Options:</h3>
<dl class="options">
<dt>speed</dt>
<dd>
Type: <code>Number</code><br>
Default: <code>400</code>
<p>
Scroll time in milliseconds
</p>
</dd>
<dt>easing</dt>
<dd>
Type: <code>string</code><br>
Default: <code>linear</code>
<p>
Easing function used for scrolling.<br>
Available Easings:
<ul>
<li>linear</li>
<li>easeInQuad</li>
<li>easeOutQuad</li>
<li>easeInOutQuad</li>
<li>easeInCubic</li>
<li>easeOutCubic</li>
<li>easeInOutCubic</li>
<li>easeInQuart</li>
<li>easeOutQuart</li>
<li>easeInOutQuart</li>
<li>easeInQuint</li>
<li>easeOutQuint</li>
<li>easeInOutQuint</li>
<li>easeInElastic</li>
<li>easeOutElastic</li>
<li>easeInOutElastic</li>
</ul>
</p>
</dd>
<dt>callback</dt>
<dd>
Type: <code>function</code><br>
Default: <code>null</code>
<p>
Callback to be executed when scrolling is finished
</p>
</dd>
<dt>fixedHeader</dt>
<dd>
Type: <code>string</code><br>
Default: <code>null</code>
<p>
The header element<br>
Example: '#fixed-header'
</p>
</dd>
</dl>
</div>
</section>
<section id="section-5">
<div>
<strong>Here we go!</strong>
</div>
</section>
<script src='https://cdnjs.cloudflare.com/ajax/libs/highlight.js/9.15.10/highlight.min.js'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,176 @@
/**
* Vanilla JS Smooth Scroll
* Author: Bastian Fießinger
* Version: 1.0.1
*/
'use strict';
HTMLAnchorElement.prototype.scrollToSmooth = function (settings) {
if (typeof (settings) == 'undefined') {
settings = {};
}
// Setup Default Settings Object
let defaults = {
speed: 400,
easing: 'linear',
callback: null,
fixedHeader: null
};
/**
* Merge two or more objects together.
* @param {Object} objects The objects to merge together
* @returns {Object} Merged values of defaults and settings
*/
let extend = function () {
var merged = {};
Array.prototype.forEach.call(arguments, (obj) => {
for (var key in obj) {
if (!obj.hasOwnProperty(key)) return;
merged[key] = obj[key];
}
});
return merged;
};
// Available Easing Functions
const easings = {
linear(t) { return t; },
easeInQuad(t) { return t * t; },
easeOutQuad(t) { return t * (2 - t); },
easeInOutQuad(t) { return t < 0.5 ? 2 * t * t : -1 + (4 - 2 * t) * t; },
easeInCubic(t) { return t * t * t; },
easeOutCubic(t) { return (--t) * t * t + 1; },
easeInOutCubic(t) { return t < 0.5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; },
easeInQuart(t) { return t * t * t * t; },
easeOutQuart(t) { return 1 - (--t) * t * t * t; },
easeInOutQuart(t) { return t < 0.5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t; },
easeInQuint(t) { return t * t * t * t * t; },
easeOutQuint(t) { return 1 + (--t) * t * t * t * t; },
easeInOutQuint(t) { return t < 0.5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; },
easeInElastic: function (t) { return (.04 - .04 / t) * Math.sin(25 * t) + 1 },
easeOutElastic: function (t) { return .04 * t / (--t) * Math.sin(25 * t) },
easeInOutElastic: function (t) { return (t -= .5) < 0 ? (.02 + .01 / t) * Math.sin(50 * t) : (.02 - .01 / t) * Math.sin(50 * t) + 1 }
};
// Build the Settings Object from Defaults and user defined settings
settings = extend(defaults, settings || {});
const reqAnimFrame = window.requestAnimationFrame || window.mozRequestAnimationFrame || window.webkitRequestAnimationFrame || window.msRequestAnimationFrame;
const cancelAnimFrame = window.cancelAnimationFrame || window.mozCancelAnimationFrame;
// Get All Links with hashes based on the current URI
const findHashLinks = () => {
// Make sure to only apply to hash links
if (this.href.indexOf(this.baseURI.replace(/\/+$/, '')) != -1 && this.href.indexOf('#') != -1 && this.hash != '') {
this.addEventListener('click', clickHandler);
}
}
const clickHandler = (e) => {
// Prevent Default Behaviour of how the browser would treat the click event
e.preventDefault();
// Evaluate the current Target Element
const currentTargetIdSliced = this.hash.slice(1);
let currentTarget = document.getElementById(currentTargetIdSliced);
// If no ID for the current target is present try to find an element with it's name attribute.
currentTarget = currentTarget ? currentTarget : document.querySelector('[name="' + currentTargetIdSliced + '"]');
if (!currentTarget) return;
const windowStartPos = window.pageYOffset;
const startTime = 'now' in window.performance ? performance.now() : new Date().getTime();
const docHeight = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
const winHeight = window.innerHeight || document.documentElement.clientHeight || document.getElementsByTagName('body')[0].clientHeight;
const targetOffset = currentTarget.offsetTop;
let distToScroll = Math.round(docHeight - targetOffset < winHeight ? docHeight - winHeight : targetOffset);
if (settings.fixedHeader !== null) {
const fixedHeader = document.querySelector(settings.fixedHeader);
if (fixedHeader.tagName) {
distToScroll -= Math.round(fixedHeader.getBoundingClientRect().height);
}
}
// Distance can't be negative
distToScroll = (distToScroll < 0) ? 0 : distToScroll;
scrollToTarget(0, distToScroll, windowStartPos, startTime);
}
// Animate the ScrollTop
const scrollToTarget = (timestamp, distToScroll, startPos, startTime) => {
const now = 'now' in window.performance ? performance.now() : new Date().getTime();
const time = Math.min(1, ((now - startTime) / settings.speed));
const timeFunction = easings[settings.easing](time);
let curScrollPosition = window.pageYOffset || document.body.scrollTop || document.documentElement.scrollTop;
window.scroll(0, Math.ceil((timeFunction * (distToScroll - startPos)) + startPos));
if (Math.ceil(curScrollPosition) === distToScroll) {
if (settings.callback) {
settings.callback();
}
// Stop when the element is reached
return;
}
let scrollAnimationFrame = reqAnimFrame((timestamp) => {
scrollToTarget(timestamp, distToScroll, startPos, startTime);
});
// Cancel Animation on User Scroll Interaction
let cancelAnimationOnEvents = ['mousewheel', 'wheel', 'touchstart'];
cancelAnimationOnEvents.forEach((ev) => {
window.addEventListener(ev, () => {
cancelAnimationFrame( scrollAnimationFrame );
});
});
}
const BindEvents = () => {
window.addEventListener('load', findHashLinks);
}
this.init = () => {
// Bind Events
BindEvents.call(this);
};
this.init();
}
document.addEventListener('DOMContentLoaded', function () {
let links = document.getElementsByTagName('a');
[].forEach.call(links, (el) => {
el.scrollToSmooth({
speed: 500,
easing: 'easeInOutQuint',
callback: function () { console.log('we reached it!'); },
fixedHeader: null
});
});
// Init Highlight JS
hljs.initHighlightingOnLoad();
});

@ -0,0 +1,114 @@
@import url("https://fonts.googleapis.com/css?family=Montserrat:400,900&display=swap");
* {
box-sizing: border-box;
}
body {
font-family: 'Montserrat', sans-serif;
}
nav {
position: fixed;
right: 20px;
top: 50%;
-webkit-transform: translateY(-50%);
transform: translateY(-50%);
}
nav a {
font-size: 0px;
line-height: 0px;
display: block;
width: 20px;
height: 20px;
background: transparent;
border: 4px solid #FFF;
border-radius: 50%;
margin: 10px 0;
-webkit-filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
filter: drop-shadow(0 0 4px rgba(0, 0, 0, 0.5));
}
section {
width: 100%;
min-height: 100vh;
display: flex;
align-items: center;
justify-content: center;
color: #FFF;
padding: 5rem;
}
section#section-1 {
background-color: #e67e22;
}
section#section-2 {
background-color: #2980b9;
}
section#section-3 {
background-color: #8e44ad;
}
section#section-4 {
color: #000;
}
section#section-5 {
background-color: #c0392b;
}
section > div {
width: 80%;
}
strong {
font-size: 80px;
text-align: center;
display: block;
}
.hljs, code {
font-family: 'Space Mono', monospace;
}
.hljs {
font-size: 14px;
padding: 0 26px;
border-radius: 4px;
flex: 1;
overflow: auto;
line-height: 1.6;
}
pre {
margin: 1rem 0;
display: flex;
}
.options dt {
margin-bottom: 10px;
}
.options dd {
line-height: 24px;
margin-left: 0;
border-bottom: 1px solid #000;
margin-bottom: 20px;
}
.options dd:last-child {
margin-bottom: 0;
border-bottom: 0;
}
.options code {
font-weight: bold;
background: #f7f7f7;
font-size: 90%;
font-weight: normal;
padding: 1px 5px;
border-radius: 2px;
color: #000;
}
@media (max-width: 840px) {
strong {
font-size: 40px;
}
section {
padding: 2rem;
}
}

@ -0,0 +1,2 @@
# Section Navigation Menu
An experiment with a navigation menu for page sections. The active anchor link updates based on the current page section as the user scrolls. When the menu overflows, it will automatically scroll an active link into view if it spills outside the viewport.

@ -0,0 +1,84 @@
<!DOCTYPE html>
<html lang="en" >
<head>
<meta charset="UTF-8">
<title>Section Navigation Menu</title>
<meta name="viewport" content="width=device-width, initial-scale=1"><link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/meyer-reset/2.0/reset.min.css">
<link rel="stylesheet" href="./style.css">
</head>
<body>
<header class="placeholder-section">
<h1>Horizontal Section Navigation</h1>
</header>
<nav class="nav-sections">
<ul class="menu">
<li class="menu-item"><a class="menu-item-link active" href="#about">About</a></li>
<li class="menu-item"><a class="menu-item-link" href="#documentation">Documentation</a></li>
<li class="menu-item"><a class="menu-item-link" href="#showcase">Showcase</a></li>
<li class="menu-item"><a class="menu-item-link" href="#latest-news">Latest News</a></li>
<li class="menu-item"><a class="menu-item-link" href="#contact-us">Contact Us</a></li>
<div class="active-line"></div>
</ul>
</nav>
<main id="main-content" class="page-sections">
<section class="page-section">
<h2 class="section-title" id="about">About</h2>
<p>As you scroll through each section, the horizontal navigation will update its active state to the correlating anchor link. The menu overflows horizontally and allows the user to scroll left and right. If an anchor link is outside of the viewport, the menu will automatically scroll the active item into view.</p>
<p>And now... placeholder text: Lorem ipsum dolor sit amet consectetur, adipisicing elit. Consequatur corporis, placeat eaque iure ex possimus ab exercitationem atque sed culpa eos vel, ipsa porro corrupti omnis tempore, fuga quos explicabo.</p>
<p>Velit eos maxime veritatis sunt provident accusantium vitae, aperiam consectetur, laboriosam consequatur beatae quam recusandae, corporis iste laudantium illo praesentium amet ratione aliquid modi. Officia similique incidunt magni doloremque aperiam!</p>
<p>Cupiditate odio exercitationem dolorem explicabo numquam natus, cum a omnis incidunt ipsam quibusdam eligendi odit consectetur? Laboriosam magni labore, nobis, facilis aliquid delectus ad molestiae quo iusto a, consectetur molestias?</p>
<p>Minus ratione quae, quibusdam ab atque obcaecati. Necessitatibus perferendis quibusdam, placeat ipsa expedita recusandae culpa labore? Aut quaerat animi culpa minima illo, odio tempore corporis, quidem nisi eius iure fugit! Id, earum reprehenderit. Placeat voluptate aut, provident aspernatur consequuntur praesentium ullam, magni deserunt repellendus dicta eos odio modi aliquid quasi tempora saepe adipisci itaque? Unde distinctio aut perferendis delectus quam?</p>
<h3>Lorem ipsum dolor</h3>
<ul>
<li>Lorem ipsum dolor, sit amet consectetur adipisicing elit. Debitis, quasi temporibus laborum quidem praesentium et vero incidunt itaque. Hic, aliquid odio non atque exercitationem ipsa? A repudiandae dolores blanditiis voluptatem.</li>
<li>Dolore dolorem velit impedit libero non. Deserunt optio rerum earum quas recusandae. Praesentium, voluptates ipsa temporibus. Nisi, qui autem. Aliquid?</li>
<li>Ea facilis corporis enim tempora tenetur consectetur quam asperiores, porro reprehenderit expedita! Esse laboriosam suscipit illo. Quasi numquam tempora aperiam corrupti alias? Amet provident esse tenetur eveniet voluptatum modi iure.</li>
<li>Provident labore iusto, voluptatibus incidunt cumque cum quisquam, asperiores accusamus velit repellat mollitia facilis. Sit, voluptas tempore. Placeat quas, corporis enim ratione accusamus repellendus quos repellat quo voluptatum, eos rerum.</li>
</ul>
</section>
<section class="page-section">
<h2 class="section-title" id="documentation">Documentation</h2>
<ul>
<li>Lorem ipsum dolor sit, amet consectetur adipisicing elit. Aut delectus, fuga tempore, recusandae vel ut aliquam reprehenderit dolorum odio ratione unde accusantium dolore, modi mollitia sapiente ipsa autem quibusdam. Qui?</li>
<li>Iste facilis perspiciatis veritatis minima totam modi autem quaerat natus ullam at, qui similique asperiores laboriosam, voluptas quos blanditiis tempora illum et. Ea commodi facere tempora, officiis minus in odio.</li>
<li>Ratione molestias, temporibus perferendis aspernatur voluptatem optio, necessitatibus distinctio cum doloremque, deserunt cumque deleniti a quos beatae magni in ab. Ipsa libero ullam minima repellat sit molestiae, maxime accusamus dicta?</li>
<li>Ipsa dolor eveniet explicabo.</li>
<li>Molestiae nobis quasi unde rerum cum laboriosam voluptatum id dolores autem fugiat aliquam, vitae error iure. Totam nesciunt earum dolorum facilis doloremque fuga asperiores fugiat, dicta nostrum, debitis harum veritatis.</li>
</ul>
</section>
<section class="page-section">
<h2 class="section-title" id="showcase">Showcase</h2>
<p>Lorem, ipsum dolor sit amet consectetur adipisicing elit. Ea voluptatem perferendis quaerat neque voluptatibus vel unde, nostrum saepe voluptate voluptates iure veniam. Soluta possimus deserunt earum, itaque porro quam praesentium.</p>
<p>Vel itaque quae nostrum, blanditiis doloribus mollitia delectus unde rerum ab dignissimos voluptatum repellendus odit sint necessitatibus totam possimus cum voluptatem ipsa ex corrupti sit veritatis libero expedita laboriosam? Quas?</p>
<p>Illum repellendus modi at, nostrum harum iste. Natus animi corporis corrupti suscipit dicta magni distinctio a exercitationem ut. Saepe cum sequi asperiores? Quos, nemo corporis animi porro odit iure? Itaque?</p>
<p>Nesciunt in quibusdam, esse tempore sequi earum illum exercitationem praesentium reprehenderit aliquam asperiores sint impedit dolor? Sapiente, asperiores atque ipsam voluptatem molestiae repudiandae. In, optio! Quidem rem rerum perferendis pariatur.</p>
<p>Ipsam asperiores voluptas porro commodi? Consequuntur magni ipsum facere officiis fugit nesciunt itaque officia accusamus, cum tempore sed velit vero praesentium quod, hic blanditiis ducimus quis. Aperiam, sed! Deleniti, dolorum.</p>
</section>
<section class="page-section">
<h2 class="section-title" id="latest-news">Latest News</h2>
<p>Lorem ipsum dolor sit amet consectetur, adipisicing elit.</p>
<p>Atque iste repellendus accusantium vitae nam eaque dolorem consequuntur laborum impedit ex nesciunt quod, aliquid pariatur nihil dolor deserunt animi ad earum voluptatibus ullam fugit id? Ex, nihil dolorum. Corporis? Maxime nemo amet iste itaque obcaecati dolor non ea, quae hic ducimus saepe, fugiat vitae voluptatem veniam reprehenderit minima sint! Atque dolor, mollitia doloremque id reiciendis debitis vel aspernatur facilis?</p>
<p>Itaque blanditiis soluta magni obcaecati maxime iure similique esse quibusdam fuga inventore. Sapiente pariatur quas delectus rerum, repellendus fugit possimus eligendi vel sit ipsum saepe nihil, accusamus obcaecati vitae atque!</p>
<p>Quibusdam accusamus, architecto obcaecati amet quasi fuga soluta quaerat tenetur. Omnis harum eos cum sed officiis rerum dignissimos nemo. Laboriosam illum vero pariatur ea consequuntur, autem cupiditate rerum eaque iste!</p>
</section>
<section class="page-section">
<h2 class="section-title" id="contact-us">Contact Us</h2>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit provident necessitatibus laudantium, illo blanditiis inventore minima ipsam distinctio incidunt odio, itaque officiis vel facere unde. Ratione ex doloribus minus eius.</p>
<p>Quibusdam accusamus, architecto obcaecati amet quasi fuga soluta quaerat tenetur. Omnis harum eos cum sed officiis rerum dignissimos nemo. Laboriosam illum vero pariatur ea consequuntur, autem cupiditate rerum eaque iste!</p>
<p>Lorem ipsum dolor sit amet, consectetur adipisicing elit. Velit provident necessitatibus laudantium, illo blanditiis inventore minima ipsam distinctio incidunt odio, itaque officiis vel facere unde. Ratione ex doloribus minus eius.</p>
<p>Quibusdam accusamus, architecto obcaecati amet quasi fuga soluta quaerat tenetur. Omnis harum eos cum sed officiis rerum dignissimos nemo. Laboriosam illum vero pariatur ea consequuntur, autem cupiditate rerum eaque iste!</p>
</section>
</main>
<footer class="placeholder-section">
<p>Footer section</p>
</footer>
<script src='https://unpkg.com/smoothscroll-polyfill/dist/smoothscroll.min.js'></script>
<script src='https://unpkg.com/smoothscroll-anchor-polyfill'></script><script src="./script.js"></script>
</body>
</html>

@ -0,0 +1,79 @@
const sectionsContainer = document.querySelector('.page-sections');
const sections = document.querySelectorAll('.page-section');
const nav = document.querySelector('.nav-sections');
const menu = nav.querySelector('.menu');
const links = nav.querySelectorAll('.menu-item-link');
const activeLine = nav.querySelector('.active-line');
const sectionOffset = nav.offsetHeight + 24;
const activeClass = 'active';
let activeIndex = 0;
let isScrolling = true;
let userScroll = true;
const setActiveClass = () => {
links[activeIndex].classList.add(activeClass);
};
const removeActiveClass = () => {
links[activeIndex].classList.remove(activeClass);
};
const moveActiveLine = () => {
const link = links[activeIndex];
const linkX = link.getBoundingClientRect().x;
const menuX = menu.getBoundingClientRect().x;
activeLine.style.transform = `translateX(${menu.scrollLeft - menuX + linkX}px)`;
activeLine.style.width = `${link.offsetWidth}px`;
};
const setMenuLeftPosition = position => {
menu.scrollTo({
left: position,
behavior: 'smooth' });
};
const checkMenuOverflow = () => {
const activeLink = links[activeIndex].getBoundingClientRect();
const offset = 30;
if (Math.floor(activeLink.right) > window.innerWidth) {
setMenuLeftPosition(menu.scrollLeft + activeLink.right - window.innerWidth + offset);
} else if (activeLink.left < 0) {
setMenuLeftPosition(menu.scrollLeft + activeLink.left - offset);
}
};
const handleActiveLinkUpdate = current => {
removeActiveClass();
activeIndex = current;
checkMenuOverflow();
setActiveClass();
moveActiveLine();
};
const init = () => {
moveActiveLine(links[0]);
document.documentElement.style.setProperty('--section-offset', sectionOffset);
};
links.forEach((link, index) => link.addEventListener('click', () => {
userScroll = false;
handleActiveLinkUpdate(index);
}));
window.addEventListener("scroll", () => {
const currentIndex = sectionsContainer.getBoundingClientRect().top < 0 ?
sections.length - 1 - [...sections].reverse().findIndex(section => window.scrollY >= section.offsetTop - sectionOffset * 2) :
0;
if (userScroll && activeIndex !== currentIndex) {
handleActiveLinkUpdate(currentIndex);
} else {
window.clearTimeout(isScrolling);
isScrolling = setTimeout(() => userScroll = true, 100);
}
});
init();

@ -0,0 +1,141 @@
:root {
--space: 1rem;
--border: 4px;
--page-width: 80ch;
--font-family: 'Helvetica', sans-serif;
--color-link: black;
--color-active: royalblue;
--ease: cubic-bezier(0.23, 1, 0.32, 1);
--duration: 350ms;
--section-offset: 0;
}
* {
box-sizing: border-box;
}
html {
--scroll-behavior: smooth;
scroll-behavior: var(--scroll-behavior);
}
@media (prefers-reduced-motion: reduce) {
html {
--scroll-behavior: auto;
}
}
body {
font-family: var(--font-family);
line-height: 1.5;
}
h1, h2, h3 {
font-weight: bold;
line-height: 1.25;
}
h1 {
font-size: 2.75rem;
}
h2 {
font-size: 2.25rem;
}
h3 {
font-size: 1.5rem;
}
ul:not(.menu) {
list-style-type: disc;
margin-left: var(--space);
}
ul:not(.menu) > li + li {
margin-top: var(--space);
}
.nav-sections {
position: -webkit-sticky;
position: sticky;
top: 0;
width: 100%;
background-color: white;
box-shadow: inset lightgray 0 -1px 0, rgba(0, 0, 0, 0.15) 0 3px 10px 0;
z-index: 100;
}
.nav-sections .menu {
position: relative;
display: flex;
flex-wrap: nowrap;
overflow: scroll;
-ms-scroll-chaining: none;
overscroll-behavior: none;
scrollbar-width: none;
-ms-overflow-style: none;
margin: 0 auto;
max-width: var(--page-width);
-webkit-transform: translateZ(0);
transform: translateZ(0);
transition: -webkit-transform var(--ease) var(--duration);
transition: transform var(--ease) var(--duration);
transition: transform var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
}
.nav-sections .menu::-webkit-scrollbar {
display: none;
}
.nav-sections .menu-item-link {
display: block;
padding: calc(var(--space) * 1.5) var(--space);
text-decoration: none;
white-space: nowrap;
color: var(--color-link);
transition: color var(--ease) var(--duration);
}
.nav-sections .menu-item-link.active {
color: var(--color-active);
}
.active-line {
position: absolute;
bottom: 0;
left: 0;
height: 4px;
background-color: var(--color-active);
transition: width var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
transition: width var(--ease) var(--duration), transform var(--ease) var(--duration);
transition: width var(--ease) var(--duration), transform var(--ease) var(--duration), -webkit-transform var(--ease) var(--duration);
}
.placeholder-section {
display: flex;
align-items: center;
justify-content: center;
text-align: center;
height: 50vh;
background-color: lightgray;
}
.page-sections {
margin: 0 auto;
max-width: var(--page-width);
}
.page-section {
margin: calc(var(--space) * 2) 0;
padding: calc(var(--space) * 2) var(--space);
}
.page-section > * + * {
margin-top: calc(var(--space) * 1.5);
}
.section-title {
outline: none;
}
.section-title:before {
content: "";
display: block;
visibility: hidden;
pointer-events: none;
margin-top: calc(var(--section-offset) * -1px);
height: calc(var(--section-offset) * 1px);
}
Loading…
Cancel
Save