-
Notifications
You must be signed in to change notification settings - Fork 43
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Based on the CodyHouse Framework - SCSS and JS refectoring Co-Authored-By: Sebastiano Guerriero <[email protected]>
- Loading branch information
1 parent
aaa363c
commit ebb0057
Showing
16 changed files
with
434 additions
and
699 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,19 @@ | ||
Multi-Level Accordion Menu | ||
========= | ||
# Multi-Level Accordion Menu | ||
|
||
A simple CSS accordion menu with support for sub level items. | ||
|
||
[Article on CodyHouse](https://codyhouse.co/gem/css-multi-level-accordion-menu) | ||
|
||
[Demo](https://codyhouse.co/demo/multi-level-accordion-menu/index.html) | ||
[Demo](https://codyhouse.co/demo/multi-level-accordion-menu) | ||
|
||
[License](https://codyhouse.co/license) | ||
|
||
## Dependencies | ||
|
||
This experiment is built upon the [CodyHouse Framework](https://github.com/CodyHouse/codyhouse-framework). | ||
|
||
Make sure to include both the _global.scss and util.js files of the framework. | ||
|
||
## Credits | ||
|
||
Icons: [Nucleo](https://nucleoapp.com/) | ||
|
||
[Terms](https://codyhouse.co/terms/) | ||
Icons: [Nucleo Library](https://nucleoapp.com/) |
Large diffs are not rendered by default.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,146 @@ | ||
@import '../../../../codyhouse-framework/main/assets/css/_global.scss'; // ⚠️ make sure to import the CodyHouse framework | ||
@import url('https://fonts.googleapis.com/css?family=Jaldi:400,700'); // custom font | ||
|
||
// -------------------------------- | ||
|
||
// Multi-Level Accordion Menu - by CodyHouse.co | ||
|
||
// -------------------------------- | ||
|
||
:root { | ||
// colors | ||
@include defineColorHSL(--cd-color-1, 218, 7%, 32%); // Abbey | ||
@include defineColorHSL(--cd-color-2, 127, 83%, 80%); // Gossip | ||
|
||
// font | ||
--font-primary: 'Jaldi', sans-serif; | ||
} | ||
|
||
body { | ||
background-color: var(--cd-color-2); | ||
} | ||
|
||
.cd-article-link { | ||
color: rgba(black, 0.5); | ||
} | ||
|
||
h1 { | ||
font-weight: bold; | ||
color: rgba(black, 0.9); | ||
} | ||
|
||
.cd-accordion { | ||
background: var(--cd-color-1); | ||
@include fontSmooth; | ||
box-shadow: var(--shadow-lg); | ||
} | ||
|
||
.cd-accordion--animated .cd-accordion__label::before { | ||
transition: transform .3s; | ||
} | ||
|
||
.cd-accordion__sub { | ||
display: none; // by default hide all sub menus | ||
overflow: hidden; | ||
} | ||
|
||
.cd-accordion__sub--is-visible { | ||
display: block; | ||
} | ||
|
||
.cd-accordion__item { | ||
user-select: none; | ||
} | ||
|
||
.cd-accordion__input { // hide native checkbox | ||
position: absolute; | ||
opacity: 0; | ||
} | ||
|
||
.cd-accordion__label { | ||
position: relative; | ||
display: flex; | ||
align-items: center; | ||
padding: var(--space-sm) var(--space-md); | ||
background: var(--cd-color-1); | ||
--color-shadow: lightness(var(--cd-color-1), 1.2); | ||
box-shadow: inset 0 -1px var(--color-shadow); | ||
color: var(--color-white); | ||
|
||
span { | ||
order: 3; | ||
} | ||
|
||
&:hover { | ||
background: lightness(var(--cd-color-1), 1.1); | ||
} | ||
} | ||
|
||
// icons | ||
.cd-accordion__label::after, .cd-accordion__label--icon-folder::before { | ||
content: ''; | ||
display: block; | ||
width: 16px; | ||
height: 16px; | ||
background-image: url('../img/cd-icons.svg'); | ||
background-repeat: no-repeat; | ||
margin-right: var(--space-xxxs); | ||
} | ||
|
||
.cd-accordion__label--icon-folder::before { | ||
order: 1; | ||
} | ||
|
||
.cd-accordion__label::after { | ||
order: 2; | ||
} | ||
|
||
.cd-accordion__label--icon-folder { | ||
&::before { // arrow icon | ||
background-position: 0 0; | ||
transform: rotate(-90deg); | ||
} | ||
|
||
&::after { // folder icon | ||
background-position: -16px 0; | ||
} | ||
} | ||
|
||
.cd-accordion__label--icon-img::after { // image icon | ||
background-position: -48px 0; | ||
} | ||
|
||
.cd-accordion__input:checked + .cd-accordion__label::before { // rotate arrow | ||
transform: rotate(0); | ||
} | ||
|
||
.cd-accordion__input:checked + .cd-accordion__label::after { // show open folder icon if item is checked | ||
background-position: -32px 0; | ||
} | ||
|
||
.cd-accordion__input:checked ~ .cd-accordion__sub { // show children when item is checked | ||
display: block; | ||
} | ||
|
||
.cd-accordion__sub--l1 .cd-accordion__label { | ||
background: lightness(var(--cd-color-1), 0.65); | ||
--color-shadow: lightness(var(--cd-color-1), 0.85); | ||
box-shadow: inset 0 -1px var(--color-shadow); | ||
padding-left: calc(var(--space-md) + 16px); | ||
|
||
&:hover { | ||
background: lightness(var(--cd-color-1), 0.75); | ||
} | ||
} | ||
|
||
.cd-accordion__item:last-child .cd-accordion__label { | ||
box-shadow: none; | ||
} | ||
|
||
.cd-accordion__sub--l2 .cd-accordion__label { | ||
padding-left: calc(var(--space-md) + var(--space-xxxs) + 32px); | ||
} | ||
|
||
.cd-accordion__sub--l3 .cd-accordion__label { | ||
padding-left: calc(var(--space-md) + var(--space-xxxs) + 48px); | ||
} |
File renamed without changes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,27 @@ | ||
(function() { | ||
// Multi-Level Accordion Menu - by CodyHouse.co | ||
var accordionsMenu = document.getElementsByClassName('cd-accordion--animated'); | ||
|
||
if( accordionsMenu.length > 0 && window.requestAnimationFrame) { | ||
for(var i = 0; i < accordionsMenu.length; i++) {(function(i){ | ||
accordionsMenu[i].addEventListener('change', function(event){ | ||
animateAccordion(event.target); | ||
}); | ||
})(i);} | ||
|
||
function animateAccordion(input) { | ||
var bool = input.checked, | ||
dropdown = input.parentNode.getElementsByClassName('cd-accordion__sub')[0]; | ||
|
||
Util.addClass(dropdown, 'cd-accordion__sub--is-visible'); // make sure subnav is visible while animating height | ||
|
||
var initHeight = !bool ? dropdown.offsetHeight: 0, | ||
finalHeight = !bool ? 0 : dropdown.offsetHeight; | ||
|
||
Util.setHeight(initHeight, finalHeight, dropdown, 200, function(){ | ||
Util.removeClass(dropdown, 'cd-accordion__sub--is-visible'); | ||
dropdown.removeAttribute('style'); | ||
}); | ||
} | ||
} | ||
}()); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,174 @@ | ||
// Utility function | ||
function Util () {}; | ||
|
||
/* | ||
class manipulation functions | ||
*/ | ||
Util.hasClass = function(el, className) { | ||
if (el.classList) return el.classList.contains(className); | ||
else return !!el.className.match(new RegExp('(\\s|^)' + className + '(\\s|$)')); | ||
}; | ||
|
||
Util.addClass = function(el, className) { | ||
var classList = className.split(' '); | ||
if (el.classList) el.classList.add(classList[0]); | ||
else if (!Util.hasClass(el, classList[0])) el.className += " " + classList[0]; | ||
if (classList.length > 1) Util.addClass(el, classList.slice(1).join(' ')); | ||
}; | ||
|
||
Util.removeClass = function(el, className) { | ||
var classList = className.split(' '); | ||
if (el.classList) el.classList.remove(classList[0]); | ||
else if(Util.hasClass(el, classList[0])) { | ||
var reg = new RegExp('(\\s|^)' + classList[0] + '(\\s|$)'); | ||
el.className=el.className.replace(reg, ' '); | ||
} | ||
if (classList.length > 1) Util.removeClass(el, classList.slice(1).join(' ')); | ||
}; | ||
|
||
Util.toggleClass = function(el, className, bool) { | ||
if(bool) Util.addClass(el, className); | ||
else Util.removeClass(el, className); | ||
}; | ||
|
||
Util.setAttributes = function(el, attrs) { | ||
for(var key in attrs) { | ||
el.setAttribute(key, attrs[key]); | ||
} | ||
}; | ||
|
||
/* | ||
DOM manipulation | ||
*/ | ||
Util.getChildrenByClassName = function(el, className) { | ||
var children = el.children, | ||
childrenByClass = []; | ||
for (var i = 0; i < el.children.length; i++) { | ||
if (Util.hasClass(el.children[i], className)) childrenByClass.push(el.children[i]); | ||
} | ||
return childrenByClass; | ||
}; | ||
|
||
/* | ||
Animate height of an element | ||
*/ | ||
Util.setHeight = function(start, to, element, duration, cb) { | ||
var change = to - start, | ||
currentTime = null; | ||
|
||
var animateHeight = function(timestamp){ | ||
if (!currentTime) currentTime = timestamp; | ||
var progress = timestamp - currentTime; | ||
var val = parseInt((progress/duration)*change + start); | ||
element.setAttribute("style", "height:"+val+"px;"); | ||
if(progress < duration) { | ||
window.requestAnimationFrame(animateHeight); | ||
} else { | ||
cb(); | ||
} | ||
}; | ||
|
||
//set the height of the element before starting animation -> fix bug on Safari | ||
element.setAttribute("style", "height:"+start+"px;"); | ||
window.requestAnimationFrame(animateHeight); | ||
}; | ||
|
||
/* | ||
Smooth Scroll | ||
*/ | ||
|
||
Util.scrollTo = function(final, duration, cb) { | ||
var start = window.scrollY || document.documentElement.scrollTop, | ||
currentTime = null; | ||
|
||
var animateScroll = function(timestamp){ | ||
if (!currentTime) currentTime = timestamp; | ||
var progress = timestamp - currentTime; | ||
if(progress > duration) progress = duration; | ||
var val = Math.easeInOutQuad(progress, start, final-start, duration); | ||
window.scrollTo(0, val); | ||
if(progress < duration) { | ||
window.requestAnimationFrame(animateScroll); | ||
} else { | ||
cb && cb(); | ||
} | ||
}; | ||
|
||
window.requestAnimationFrame(animateScroll); | ||
}; | ||
|
||
/* | ||
Focus utility classes | ||
*/ | ||
|
||
//Move focus to an element | ||
Util.moveFocus = function (element) { | ||
if( !element ) element = document.getElementsByTagName("body")[0]; | ||
element.focus(); | ||
if (document.activeElement !== element) { | ||
element.setAttribute('tabindex','-1'); | ||
element.focus(); | ||
} | ||
}; | ||
|
||
/* | ||
Misc | ||
*/ | ||
|
||
Util.getIndexInArray = function(array, el) { | ||
return Array.prototype.indexOf.call(array, el); | ||
}; | ||
|
||
Util.cssSupports = function(property, value) { | ||
if('CSS' in window) { | ||
return CSS.supports(property, value); | ||
} else { | ||
var jsProperty = property.replace(/-([a-z])/g, function (g) { return g[1].toUpperCase();}); | ||
return jsProperty in document.body.style; | ||
} | ||
}; | ||
|
||
/* | ||
Polyfills | ||
*/ | ||
//Closest() method | ||
if (!Element.prototype.matches) { | ||
Element.prototype.matches = Element.prototype.msMatchesSelector || Element.prototype.webkitMatchesSelector; | ||
} | ||
|
||
if (!Element.prototype.closest) { | ||
Element.prototype.closest = function(s) { | ||
var el = this; | ||
if (!document.documentElement.contains(el)) return null; | ||
do { | ||
if (el.matches(s)) return el; | ||
el = el.parentElement || el.parentNode; | ||
} while (el !== null && el.nodeType === 1); | ||
return null; | ||
}; | ||
} | ||
|
||
//Custom Event() constructor | ||
if ( typeof window.CustomEvent !== "function" ) { | ||
|
||
function CustomEvent ( event, params ) { | ||
params = params || { bubbles: false, cancelable: false, detail: undefined }; | ||
var evt = document.createEvent( 'CustomEvent' ); | ||
evt.initCustomEvent( event, params.bubbles, params.cancelable, params.detail ); | ||
return evt; | ||
} | ||
|
||
CustomEvent.prototype = window.Event.prototype; | ||
|
||
window.CustomEvent = CustomEvent; | ||
} | ||
|
||
/* | ||
Animation curves | ||
*/ | ||
Math.easeInOutQuad = function (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; | ||
}; |
Oops, something went wrong.