This commit is contained in:
atomiks
2018-03-03 15:05:35 +10:00
parent 6d9560aad8
commit 01ec0a8a83
46 changed files with 644 additions and 418 deletions

View File

@ -35,6 +35,7 @@
max-height: 378px;
margin-top: 44px;
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 128, 0.2);
padding-bottom: 1rem;
&.is-active {
transform: rotateX(0);
@ -59,6 +60,16 @@
border-color: pink;
}
}
&__section {
padding: 0 0.75rem;
}
&__section-heading {
text-transform: capitalize;
color: #e3f5ff;
margin-bottom: 0.5rem;
}
}
@media (min-width: 992px) {

View File

@ -14,6 +14,10 @@
margin-bottom: 1.25rem;
margin-top: 0;
line-height: 1.3;
span:not(.snippet__tag) {
margin-right: 0.75rem;
}
}
code:not([class*='lang']) {
@ -42,16 +46,20 @@
h4 {
display: inline-block;
margin: 1rem 0 0.5rem;
font-size: 1.1rem;
line-height: 2;
padding: 0 0.5rem;
border-radius: 3px;
font-size: 0.9rem;
text-transform: uppercase;
background: #333;
border: 1px solid #c6d6ea;
border-bottom-color: darken(#c6d6ea, 5);
background: white;
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 64, 0.15);
&[data-type] {
background: #333;
padding: 0 0.5rem;
border-radius: 3px;
font-size: 0.9rem;
text-transform: uppercase;
border: 1px solid #c6d6ea;
border-bottom-color: darken(#c6d6ea, 5);
background: white;
box-shadow: 0 0.25rem 0.5rem -0.1rem rgba(0, 32, 64, 0.15);
}
&[data-type='HTML'] {
color: white;
@ -107,6 +115,9 @@
top: 1rem;
right: 0;
}
&__tag {
}
}
.snippet-demo {

View File

@ -0,0 +1,83 @@
.tags {
position: relative;
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
margin-bottom: 1rem;
&__tag {
display: inline-block;
position: relative;
top: -1px;
font-weight: bold;
font-size: 0.75rem;
text-transform: uppercase;
color: #8385aa;
white-space: nowrap;
border: 1px solid lighten(#8385aa, 15);
border-radius: 2px;
vertical-align: middle;
line-height: 2;
padding: 0 0.5rem;
margin-right: 0.5rem;
transition: all 0.1s ease-out;
outline: 0;
&.is-large {
font-size: 0.95rem;
border-radius: 0.2rem;
.feather {
top: -2px;
width: 18px;
height: 18px;
}
}
.feather {
vertical-align: middle;
margin-right: 0.25rem;
position: relative;
top: -1px;
width: 14px;
height: 14px;
}
}
button.tags__tag {
user-select: none;
cursor: pointer;
margin-bottom: 1rem;
margin-right: 1rem;
&:hover {
background: #8385aa;
border-color: #8385aa;
color: white;
}
&:focus {
box-shadow: 0 0 0 0.25rem transparentize(#8385aa, 0.5);
}
&:active {
box-shadow: inset 0 0.1rem 0.1rem 0.1rem rgba(0, 0, 0, 0.2);
background: darken(#8385aa, 10);
border-color: darken(#8385aa, 10);
}
&.is-active {
background: #7983ff;
border-color: #7983ff;
color: white;
&:focus {
box-shadow: 0 0 0 0.25rem transparentize(#7983ff, 0.5);
}
}
}
}
@media (min-width: 579px) {
}

View File

@ -4,3 +4,4 @@
@import './components/header.scss';
@import './components/snippet.scss';
@import './components/back-to-top-button.scss';
@import './components/tags.scss';

View File

@ -0,0 +1 @@
<button class="back-to-top-button" aria-label="back to top"></button>

View File

@ -0,0 +1 @@
<footer class="footer"></footer>

View File

@ -0,0 +1,10 @@
<header class="header">
<div class="container">
<img class="header__logo" draggable="false" src="./src/img/logo.png">
<h1 class="header__heading">30 Seconds of <strong class="header__css">CSS</strong></h1>
<p class="header__description">
A curated collection of useful CSS snippets you can understand in 30 seconds or less.
</p>
<a class="github-button header__github-button" href="https://github.com/atomiks/30-seconds-of-css" data-icon="octicon-star" data-size="large" data-show-count="true" aria-label="Star atomiks/30-seconds-of-css on GitHub">Star</a>
</div>
</header>

View File

@ -0,0 +1,4 @@
<main class="main" id="main">
<div class="container">
</div>
</main>

View File

@ -0,0 +1,9 @@
<nav class="sidebar" aria-label="Table of Contents">
<button class="hamburger hamburger--spin sidebar__menu" type="button" aria-label="Menu" aria-expanded="false">
<span class="hamburger-box">
<span class="hamburger-inner"></span>
</span>
</button>
<div class="sidebar__links">
</div>
</nav>

View File

@ -0,0 +1 @@
<nav class="tags" aria-label="Filter by tags"></nav>

15
src/html/index.html Normal file
View File

@ -0,0 +1,15 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width,initial-scale=1">
<title>30 Seconds of CSS</title>
<meta name="description" content="A curated collection of useful CSS snippets you can understand in 30 seconds or less. From foundational elements such as clearfix to gradient text color and gradient cursor tracking to CSS easing and far beyond.">
<link rel="icon" type="image/png" sizes="32x32" href="./favicon-32x32.png">
<script src="./src/js/index.js" defer=""></script>
<script async="" defer="" src="https://buttons.github.io/buttons.js"></script>
</head>
<body>
<div class="content-wrapper"></div>
</body>
</html>

View File

@ -1,27 +1,23 @@
import jump from '../deps/jump'
import { select, selectAll, easeOutQuint } from '../deps/utils'
const menu = select('.hamburger')
const links = select('.sidebar__links')
const sections = selectAll('.sidebar__section')
const ACTIVE_CLASS = 'is-active'
const toggle = () => {
const els = [menu, links]
els.forEach(el => el.classList.toggle(ACTIVE_CLASS))
menu.setAttribute('aria-expanded', menu.classList.contains(ACTIVE_CLASS) ? 'true' : 'false')
if (window.innerWidth <= 991) {
const els = [menu, links]
els.forEach(el => el.classList.toggle(ACTIVE_CLASS))
menu.setAttribute('aria-expanded', menu.classList.contains(ACTIVE_CLASS) ? 'true' : 'false')
}
}
menu.addEventListener('click', toggle)
links.addEventListener('click', e => {
setTimeout(toggle, 40)
if (e.target.classList.contains('sidebar__link')) {
e.preventDefault()
jump(e.target.getAttribute('href'), {
duration: 750,
offset: window.innerWidth <= 768 ? -64 : -32,
easing: easeOutQuint
})
setTimeout(toggle, 100)
}
})
@ -35,4 +31,13 @@ document.addEventListener('click', e => {
}
})
EventHub.on('Tag.click', data => {
sections.forEach(section => {
section.style.display = 'block'
if (section.dataset.type !== data.type && data.type !== 'all') {
section.style.display = 'none'
}
})
})
export default { toggle }

View File

@ -0,0 +1,13 @@
import { selectAll } from '../deps/utils'
const snippets = selectAll('.snippet')
EventHub.on('Tag.click', data => {
snippets.forEach(snippet => {
snippet.style.display = 'block'
if (data.type === 'all') return
const tags = selectAll('.tags__tag', snippet)
if (!selectAll('.tags__tag', snippet).some(el => el.dataset.type === data.type)) {
snippet.style.display = 'none'
}
})
})

14
src/js/components/Tag.js Normal file
View File

@ -0,0 +1,14 @@
import { select, selectAll, on } from '../deps/utils'
const tagButtons = selectAll('button.tags__tag')
const onClick = function() {
tagButtons.forEach(button => button.classList.remove('is-active'))
this.classList.add('is-active')
EventHub.emit('Tag.click', {
type: this.dataset.type
})
}
tagButtons.forEach(button => on(button, 'click', onClick))

View File

@ -1,196 +0,0 @@
;(function(global, factory) {
typeof exports === 'object' && typeof module !== 'undefined'
? (module.exports = factory())
: typeof define === 'function' && define.amd ? define(factory) : (global.Jump = factory())
})(this, function() {
'use strict'
// Robert Penner's easeInOutQuad
// find the rest of his easing functions here: http://robertpenner.com/easing/
// find them exported for ES6 consumption here: https://github.com/jaxgeller/ez.js
var easeInOutQuad = function easeInOutQuad(t, b, c, d) {
t /= d / 2
if (t < 1) return c / 2 * t * t + b
t--
return -c / 2 * (t * (t - 2) - 1) + b
}
var _typeof =
typeof Symbol === 'function' && typeof Symbol.iterator === 'symbol'
? function(obj) {
return typeof obj
}
: function(obj) {
return obj &&
typeof Symbol === 'function' &&
obj.constructor === Symbol &&
obj !== Symbol.prototype
? 'symbol'
: typeof obj
}
var jumper = function jumper() {
// private variable cache
// no variables are created during a jump, preventing memory leaks
var element = void 0 // element to scroll to (node)
var start = void 0 // where scroll starts (px)
var stop = void 0 // where scroll stops (px)
var offset = void 0 // adjustment from the stop position (px)
var easing = void 0 // easing function (function)
var a11y = void 0 // accessibility support flag (boolean)
var distance = void 0 // distance of scroll (px)
var duration = void 0 // scroll duration (ms)
var timeStart = void 0 // time scroll started (ms)
var timeElapsed = void 0 // time spent scrolling thus far (ms)
var next = void 0 // next scroll position (px)
var callback = void 0 // to call when done scrolling (function)
// scroll position helper
function location() {
return window.scrollY || window.pageYOffset
}
// element offset helper
function top(element) {
return element.getBoundingClientRect().top + start
}
// rAF loop helper
function loop(timeCurrent) {
// store time scroll started, if not started already
if (!timeStart) {
timeStart = timeCurrent
}
// determine time spent scrolling so far
timeElapsed = timeCurrent - timeStart
// calculate next scroll position
next = easing(timeElapsed, start, distance, duration)
// scroll to it
window.scrollTo(0, next)
// check progress
timeElapsed < duration
? window.requestAnimationFrame(loop) // continue scroll loop
: done() // scrolling is done
}
// scroll finished helper
function done() {
// account for rAF time rounding inaccuracies
window.scrollTo(0, start + distance)
// if scrolling to an element, and accessibility is enabled
if (element && a11y) {
// add tabindex indicating programmatic focus
element.setAttribute('tabindex', '-1')
// focus the element
element.focus()
}
// if it exists, fire the callback
if (typeof callback === 'function') {
callback()
}
// reset time for next jump
timeStart = false
}
// API
function jump(target) {
var options = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : {}
// resolve options, or use defaults
duration = options.duration || 1000
offset = options.offset || 0
callback = options.callback // "undefined" is a suitable default, and won't be called
easing = options.easing || easeInOutQuad
a11y = options.a11y || false
// cache starting position
start = location()
// resolve target
switch (typeof target === 'undefined' ? 'undefined' : _typeof(target)) {
// scroll from current position
case 'number':
element = undefined // no element to scroll to
a11y = false // make sure accessibility is off
stop = start + target
break
// scroll to element (node)
// bounding rect is relative to the viewport
case 'object':
element = target
stop = top(element)
break
// scroll to element (selector)
// bounding rect is relative to the viewport
case 'string':
element = document.querySelector(target)
stop = top(element)
break
}
// resolve scroll distance, accounting for offset
distance = stop - start + offset
// resolve duration
switch (_typeof(options.duration)) {
// number in ms
case 'number':
duration = options.duration
break
// function passed the distance of the scroll
case 'function':
duration = options.duration(distance)
break
}
// start the loop
window.requestAnimationFrame(loop)
}
// expose only the jump method
return jump
}
// export singleton
var singleton = jumper()
return (() => {
let scrolling
const end = () => (scrolling = false)
return (to, options = {}) => {
if (scrolling) return
const scrollY = window.scrollY || window.pageYOffset
if (to !== '.header') location.hash = to
scroll(0, scrollY)
scrolling = true
setTimeout(end, options.duration || 0)
return singleton(to, options)
}
})()
})

View File

@ -1,8 +1,34 @@
export const select = s => document.querySelector(s)
export const selectAll = s => [].slice.call(document.querySelectorAll(s))
export const select = (s, parent = document) => parent.querySelector(s)
export const selectAll = (s, parent = document) => [].slice.call(parent.querySelectorAll(s))
export const scrollY = () => window.scrollY || window.pageYOffset
export const easeOutQuint = (t, b, c, d) => c * ((t = t / d - 1) * t ** 4 + 1) + b
export const on = (el, evt, fn, opts = {}) => {
const delegatorFn = e => e.target.matches(opts.target) && fn.call(e.target, e)
el.addEventListener(evt, opts.target ? delegatorFn : fn, opts.options || false)
if (opts.target) return delegatorFn
}
export const createEventHub = () => ({
hub: Object.create(null),
emit(event, data) {
;(this.hub[event] || []).forEach(handler => handler(data))
},
on(event, handler) {
if (!this.hub[event]) this.hub[event] = []
this.hub[event].push(handler)
},
off(event, handler) {
const i = (this.hub[event] || []).findIndex(h => h === handler)
if (i > -1) this.hub[event].splice(i, 1)
}
})
window.EventHub = createEventHub()
/*
* Make iOS behave normally.
*/

View File

@ -1,6 +1,8 @@
// Deps
import 'normalize.css'
import 'prismjs'
import feather from 'feather-icons'
feather.replace()
// CSS
import '../css/deps/prism.css'
@ -10,5 +12,7 @@ import '../css/index.scss'
import './deps/polyfills'
// Components
import Menu from './components/Menu'
import Sidebar from './components/Sidebar'
import BackToTopButton from './components/BackToTopButton'
import Tag from './components/Tag'
import Snippet from './components/Snippet'