Skip to content

Instantly share code, notes, and snippets.

@toomanyredirects
Created December 6, 2021 09:26
Show Gist options
  • Save toomanyredirects/905b4c16e088aa9908ae1bb3b33364a4 to your computer and use it in GitHub Desktop.
Save toomanyredirects/905b4c16e088aa9908ae1bb3b33364a4 to your computer and use it in GitHub Desktop.
Responsive & Accessible App UI/UX Framework
<!-- Loadind Splash Screen -->
<script>
var html = document.getElementsByTagName('html')[0];
html.setAttribute('loading', '');
document.addEventListener('DOMContentLoaded', function(e) {
var img = html.querySelector('#logo svg').cloneNode(true);
img.id = 'loading-logo';
html.querySelector('body').appendChild(img);
}, false);
window.addEventListener('load', function(e) {
setTimeout(function(){
html.removeAttribute('loading');
html.querySelector('body').removeChild(html.querySelector('#loading-logo'));
}, 1500);
}, false);
</script>
<style>
body > * { opacity: 1; transition: opacity .3s linear;}
[loading] body > * { opacity: 0; }
[loading] body { background: transparent; overflow: hidden; }
[loading] body:after, [loading] > body:before {
content: '';
position: absolute;
width: 100%;
color: white;
text-align: center;
}
[loading] body:before {
top:0; left:0;
height: .2em;
background-repeat: no-repeat;
background-attachment: fixed;
background-image: linear-gradient(90deg, #FFF, #FFF);
background-size: 100% 100%;
background-position: left center;
background-color: rgba(255,255,255,0.5);
animation: gradient 2s ease-in-out 1 0s;
-webkit-animation: gradient 2s ease-in-out 1 0s;
}
@keyframes gradient {
0% {background-size: 10% 100% }
10% {background-size: 20% 100% }
75% {background-size: 85% 100% }
100% {background-size: 100% 100% }
}
@-webkit-keyframes gradient {
0% {background-size: 10% 100% }
10% {background-size: 20% 100% }
75% {background-size: 85% 100% }
100% {background-size: 100% 100% }
}
[loading] body:after {
content: attr(data-loading);
top: calc(50% + 2em); left: 50%;
transform: translate(-50%, -50%);
font-weight: bold;
font-size: 1.2em;
opacity: 1;
animation: fadein 0.2s ease-in;
-webkit-animation: fadein 0.2s ease-in 0s;
}
#loading-logo {
position: absolute;
opacity: 1;
top: calc(50% - 2em); left: 50%;
transform: translate(-50%, -50%);
color: #FFF;
width: 4em; height: auto;
animation: fadein 0.4s ease-in;
-webkit-animation: fadein 0.4s ease-in;
}
@keyframes fadein { from { opacity: 0; } to { opacity: 1 !important; } }
@-webkit-keyframes fadein { from { opacity: 0; } to { opacity: 1 !important; } }
</style>
<body id="app" role="application" data-scheme="auto" data-loading="UX Framework">
<!-- Drawer -->
<aside id="sidebar" class="drawer shadow">
<div class="drawer-header">
<h4>Profile</h4>
<a class="close" href="#!" data-dismiss="drawer">Close</a>
</div>
<div class="drawer-body">
Body
</div>
<div class="drawer-footer">
Footer
</div>
</aside>
<!-- Header -->
<header id="header">
<div class="container-fluid container-sm">
<!-- Logo -->
<a href="#tab-icons" id="logo" class="float-left" accesskey="h">
<figure aria-label="Logo UX Framework">
<svg viewBox="0 0 9 9" role="presentation">
<use xlink:href="#ui-icon"/>
</svg>
<figcaption>UX</figcaption>
</figure>
</a>
<!-- Mobile Navigation trigger-->
<input type="checkbox" id="navigation-toggle" class="hamburger-toggler" hidden/>
<!-- Main Navigation -->
<nav id="navigation" class="mobile-menu d-none d-sm-inline-block">
<h4 id="navigationH4" class="d-sm-none">Main Navigation</h4>
<ul role="menubar" class="menubar menubar-mobile float-left" aria-labelledby="navigationH4">
<li role="none" class="dropdown">
<a href="#!components" class="current" role="menuitem" aria-haspopup="true" aria-expanded="false" tabindex="0">Components</a>
<ul role="menu" class="dropdown-menu" aria-label="Components">
<li class="current" role="none"><a href="#tab-layout" role="menuitem" tabindex"-1">Layout</a></li>
<li role="none"><a href="#tab-colors" role="menuitem" tabindex"-1">Colors <i class="visually-hidden">(current)</i><i class="caret" aria-hidden="true"></i></a>
<ul role="menu" class="dropdown-menu" aria-label="Components">
<li role="none"><a href="#tab-colors?section=#colors-theme" role="menuitem" tabindex"-1">Theme Colors</a></li>
<li role="none"><a href="#tab-colors?section=#colors-shades" role="menuitem" tabindex"-1">Shades of Primary &amp; Gray</a></li>
</ul>
</li>
<li role="none"><a href="#tab-typography" role="menuitem" tabindex"-1">Typography</a></li>
<li role="none"><a href="#tab-cards" role="menuitem" tabindex"-1">Cards</a></li>
<li role="none"><a href="#tab-forms" role="menuitem" tabindex"-1">Forms <i class="caret" aria-hidden="true"></i></a>
<ul role="menu" class="dropdown-menu" aria-label="Components">
<li role="none"><a href="#tab-forms?section=#forms-floating-labels" role="menuitem" tabindex"-1">Floating Labels</a></li>
<li role="none"><a href="#tab-forms?section=#forms-standard-labels" role="menuitem" tabindex"-1">Standard Labels</a></li>
<li role="none"><a href="#tab-forms?section=#forms-input-sizing" role="menuitem" tabindex"-1">Input Sizing</a></li>
</ul>
</li>
<li role="none"><a href="#tab-multistep" role="menuitem" tabindex"-1">Multistep Form</a></li>
</ul>
</li>
<li class="dropdown" role="none"><a href="#!download" role="menuitem" aria-haspopup="true" aria-expanded="false" tabindex="0">Download</a>
<ul class="dropdown-menu" role="menu" aria-label="Download">
<li role="none"><a href="#download&type=scss" id="download-scss" role="menuitem" tabindex"-1">SCSS File <small>Download the uncompiled SCSS file</small></a></li>
<li role="none"><a href="#download&type=css" id="download-css" role="menuitem" tabindex"-1">CSS File <small>Download the compiled CSS file</small></a></li>
<li role="none"><a href="#download&type=js" id="download-js" role="menuitem" tabindex"-1">JS File <small>Download the the JavaScript file</small></a></li>
<li role="none"><a href="#download&type=rar" id="download-rar" role="menuitem" tabindex"-1">RAR Archive <small>A compressed archive of all files</small></a></li>
</ul>
</li>
<li role="none">
<a href="#about-ux-framework" role="menuitem" tabindex="0">About</a>
</li>
</ul>
<div class="d-sm-none d-md-inline-block float-right">
<form id="login-register-buttons">
<button type="button" class="btn btn-outline-primary">Login</button>
<button type="button" class="btn btn-primary">Register</button>
</form>
</div>
</nav>
<!-- Header Site Search -->
<form id="header-search" class="form-group float-right dropdown d-none" role="search" action="#header-search">
<input type="search" class="form-control" id="header-search-input" placeholder="Search..." minlength="3" maxlength="32" aria-haspopup="true" aria-label="Search the site's content" incremental required/>
<output id="header-search-results" class="dropdown-menu" for="header-search-input" aria-label="Search Results">
<span id="header-search-results-placeholder" role="alert" aria-live="assertive">
<i class="loading-spinner loading-spinner-sm" role="status" aria-hidden="true"></i>
<span class="loading-ellipsis">Loading results</span>
</span>
</output>
</form>
<!-- Dropdown More Menu -->
<div class="dropdown float-right">
<a href="#more-dropdown" id="more" class="ripple" type="button" data-toggle="dropdown" data-align="right" data-offset="5" data-persist="true" aria-haspopup="true" aria-expanded="false" aria-label="more">
<svg viewBox="0 0 9 9" role="img">
<use xlink:href="#dots-icon"/>
</svg>
</a>
<div class="dropdown-menu" id="more-dropdown" aria-labelledby="more">
<h6 >Account</h6>
<a role="menuitem" href="#login-register-popup?register" data-toggle="modal">Register</a>
<a role="menuitem" href="#login-register-popup" data-toggle="modal">Login</a>
<a role="menuitem" href="#sidebar" data-toggle="collapse" aria-controls="sidebar" aria-expanded="false" data-expanded="Close Profile">Open Profile</a>
<h6>Settings</h6>
<fieldset role="menuitem" class="form-switch">
<input type="checkbox" id="scheme-switch" />
<label for="scheme-switch">Switch Scheme</label>
</fieldset>
</div>
</div>
<!-- Mobile Navigation Hamburger-->
<label id="hamburger" class="float-right hamburger d-sm-none" for="navigation-toggle" role="button" tabindex="0" accesskey="n" aria-controls="navigation">
Open Navigation
<i aria-hidden="true"></i>
</label>
</div>
</header>
<!--Tab List / Subnavigation -->
<nav id="nav" class="nav tab-list" role="tablist" aria-label="Tab Navigation" data-scroll="true">
<a href="#tab-layout" id="layout" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-layout">Layout</a>
<a href="#tab-colors" class="active" id="colors" role="tab" data-toggle="tab" aria-selected="true" aria-controls="tab-colors" tabindex="0">Colors</a>
<a href="#tab-typography" id="typography" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-typography">Typography</a>
<a href="#tab-cards" id="cards" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-cards">Cards</a>
<a href="#tab-forms" id="forms" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-forms">Forms</a>
<a href="#tab-multistep" id="multistep" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-multistep">Multistep Form</a>
<a href="#tab-buttons" id="buttons" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-buttons">Buttons</a>
<a href="#tab-icons" id="icons" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-icons">Icons</a>
<a href="#tab-native-ui" id="native-ui" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-native-uib">Native UI</a>
<a href="#tab-dropdowns" id="dropdowns" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-dropdowns">Dropdowns</a>
<a href="#tab-tooltips" id="tooltips" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-tooltips">Tooltips</a>
<a href="#tab-notifications" id="notifications" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-notifications">Notifications</a>
<a href="#tab-toasts" id="toasts" role="tab" data-toggle="tab" aria-selected="false" aria-controls="tab-toasts">Toasts</a>
<i class="indicator">current tab</i>
</nav>
<!-- Tabs -->
<main id="main" class="tab-panels" data-swipe="horizontal" data-indicate="true">
<!--Tab Grid -->
<section id="tab-layout" class="tab-panel slide"role="tabpanel" aria-labelledby="layout" tabindex="-1" >
<div class="container-fluid container-sm">
<h2>Layout</h2>
<h3>Grid</h3>
<p>A responsive grid system based on bootstrap logic.</p>
<style>
#tab-layout .col {background-color: rgba(127,127,127,0.1); padding: 1em 0; border: 1px dotted #ccc; text-align: center; margin-bottom:0.5em}
</style>
<div class="row">
<div class="col">1 of 2</div>
<div class="col">2 of 2</div>
</div>
<div class="row">
<div class="col">1 of 3</div>
<div class="col">2 of 3</div>
<div class="col">3 of 3</div>
</div>
<div class="row">
<div class="col">1 of 4</div>
<div class="col">2 of 4</div>
<div class="col">3 of 4</div>
<div class="col">4 of 4</div>
</div>
</div>
</section>
<!-- Tab Colors -->
<section id="tab-colors" class="tab-panel slide show active" role="tabpanel" aria-labelledby="colors" tabindex="0">
<div class="container-fluid container-sm">
<h2>Colors Swatches</h2>
<p>Support for a design color system that themes styles and component.This enables more comprehensive customization and extension for any project.</p>
<h3 id="colors-theme">Theme Colors</h3>
<p>
<style>
.swatches div {height: 4em; line-height: 4em; text-align: center; }
</style>
<div class="swatches row g-2 g-md-3 g-lg-3">
<div class="col-3 bg-primary shadow-md text-center" title="Primary Theme Color">Primary</div>
<div class="col-3 bg-secondary shadow-md text-center" title="Secondary Theme Color">Secondary</div>
<div class="col-3 bg-success shadow-md text-center" title="Success Theme Color">Success</div>
<div class="col-3 bg-danger shadow-md text-center" title="Danger Theme Color">Danger</div>
<div class="col-3 bg-warning shadow-md text-center" title="Warning Theme Color">Warning</div>
<div class="col-3 bg-info shadow-md text-center" title="Info Theme Color">Info</div>
<div class="col-3 bg-light shadow-md text-center" title="Ligh Theme Colort">Light</div>
<div class="col-3 bg-dark shadow-md text-center" title="Dark Theme Color">Dark</div>
</div>
</p>
<h3 id="colors-shades">Shades of Colors and Gray</h3>
<style>
.swatches-row div div {height: 1.75em; line-height: 1.75em; text-align: center; }
.swatches-row .first {position: relative; height: 3.5em; line-height: 3.5em; text-align: left; padding: 0 1em; }
.swatches-row .first:before, .swatches-row .first:after {
content: '';
position: absolute;
right: 1rem; top: 1rem;
display: inline-block;
width: 0.5rem; height: 0.5rem;
border-radius: .1rem;
background: black;
overflow: visible;
text-indent: -3.5em;
text-align: left;
font-size: 0.6em;
line-height: 0.5rem;
outline: 1px solid lightgray;
outline-offset: 0;
}
.swatches-row .first:before { content: attr(data-white) ' '; background: white; }
.swatches-row .first:after { content: attr(data-black) ' '; bottom: 1rem; top: auto;}
</style>
<div class="swatches-row">
<div class="row g-2 g-md-3 g-lg-3">
<div class="col-4 shadow-md">
<div class="col bg-primary first" title="Primary Color 100%" data-white="White" data-black="Black">Primary</div>
<div class="col bg-primary-100" title="Primary Color 10%">Primary-100</div>
<div class="col bg-primary-200" title="Primary Color 20%">Primary-200</div>
<div class="col bg-primary-300" title="Primary Color 30%">Primary-300</div>
<div class="col bg-primary-400" title="Primary Color 40%">Primary-400</div>
<div class="col bg-primary-500" title="Primary Color 50%">Primary-500</div>
<div class="col bg-primary-600" title="Primary Color 60%">Primary-600</div>
<div class="col bg-primary-700" title="Primary Color 70%">Primary-700</div>
<div class="col bg-primary-800" title="Primary Color 80%">Primary-800</div>
<div class="col bg-primary-900" title="Primary Color 90%">Primary-900</div>
</div>
<div class="col-4 shadow-md">
<div class="col bg-secondary first" title="Secondary Color 100%" data-white="White" data-black="Black">Secondary</div>
<div class="col bg-secondary-100" title="Secondary Color 10%">Secondary-100</div>
<div class="col bg-secondary-200" title="Secondary Color 20%">Secondary-200</div>
<div class="col bg-secondary-300" title="Secondary Color 30%">Secondary-300</div>
<div class="col bg-secondary-400" title="Secondary Color 40%">Secondary-400</div>
<div class="col bg-secondary-500" title="Secondary Color 50%">Secondary-500</div>
<div class="col bg-secondary-600" title="Secondary Color 60%">Secondary-600</div>
<div class="col bg-secondary-700" title="Secondary Color 70%">Secondary-700</div>
<div class="col bg-secondary-800" title="Secondary Color 80%">Secondary-800</div>
<div class="col bg-secondary-900" title="Secondary Color 90%">Secondary-900</div>
</div>
<div class="col-4 shadow-md">
<div class="col bg-black first" title="Black 100%" data-white="White" data-black="Black">Black</div>
<div class="col bg-gray-100" title="Gray 10%">Gray-100</div>
<div class="col bg-gray-200" title="Gray 20%">Gray-200</div>
<div class="col bg-gray-300" title="Gray 30%">Gray-300</div>
<div class="col bg-gray-400" title="Gray 40%">Gray-400</div>
<div class="col bg-gray-500" title="Gray 50%">Gray-500</div>
<div class="col bg-gray-600" title="Gray 60%">Gray-600</div>
<div class="col bg-gray-700" title="Gray 70%">Gray-700</div>
<div class="col bg-gray-800" title="Gray 80%">Gray-800</div>
<div class="col bg-gray-900" title="Gray 90%">Gray-900</div>
</div>
</div>
</div>
</div>
</section>
<!-- Tab Typography -->
<section id="tab-typography" class="tab-panel slide" role="tabpanel" aria-labelledby="typography" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Typography and Text</h2>
<h3>Text Elements</h3>
<p>Text elements, lists, tables.</p>
<h3>Inline Messages</h3>
<p>Text elements, lists, tables.</p>
<h3>List Types</h3>
<p>Text elements, lists, tables.</p>
<h3>Tables</h3>
<p>Text elements, lists, tables.</p>
</div>
</section>
</section>
<!--Tab Cards -->
<section id="tab-cards" class="tab-panel slide" role="tabpanel" aria-labelledby="cards">
<div class="container-fluid container-sm" tabindex="-1">
<h2>Cards</h2>
<h3>Cards Grid</h3>
<div class="card-columns">
<div class="card">
<svg class="card-img-top" width="100%" height="10rem" role="img" aria-label="Placeholder: Image cap">
<rect width="100%" height="100%" fill="#868e96"/>
</svg>
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<div class="card">
<svg class="card-img-top" width="100%" height="10rem" role="img" aria-label="Placeholder: Image cap">
<rect width="100%" height="100%" fill="#868e96"/>
</svg>
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<div class="card">
<svg class="card-img-top" width="100%" height="10rem" role="img" aria-label="Placeholder: Image cap">
<rect width="100%" height="100%" fill="#868e96"/>
</svg>
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
<div class="card">
<svg class="card-img-top" width="100%" height="10rem" role="img" aria-label="Placeholder: Image cap">
<rect width="100%" height="100%" fill="#868e96"/>
</svg>
<div class="card-body">
<h5 class="card-title">Card title</h5>
<p class="card-text">Some quick example text to build on the card title and make up the bulk of the card's content.</p>
<a href="#" class="btn btn-primary">Go somewhere</a>
</div>
</div>
</div>
</div>
</section>
<!--Tab Forms -->
<section id="tab-forms" class="tab-panel slide" role="tabpanel" aria-labelledby="forms" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Forms</h2>
<p>Native UI &amp; Form Submission</p>
<form lang="en" data-validate="true" id="forms-form" novalidate>
<h3>Floating Labels</h3>
<div class="row form-row">
<fieldset class="form-group form-float-label col-md-6">
<input class="form-control" id="float-name" name="name" type="text" placeholder="Change name here" autocomplete="name" required/>
<label for="float-name" class="form-label">Name</label>
</fieldset>
<fieldset class="form-group form-float-label col-md-6">
<input class="form-control" id="float-password" type="password" placeholder="Type password here" inputmode="password" autocomplete="new-password" min="4" max="32" data-error="Password must contain at least one number and one uppercase and lowercase letter, and at least 6 or more characters." pattern="(?=.*\d)(?=.*[a-z])(?=.*[A-Z]).{6,}" required/>
<label for="float-password" class="form-label">Password</label>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group form-float-label col-md-6">
<select id="float-select" class="form-control" type="text" placeholder="Please select" required>
<option value="" selected disabled>Please select</option>
<optgroup label="Group">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
<option value="Option 4" disabled>Option 4</option>
</optgroup>
</select>
<label for="float-select" class="form-label">Select</label>
</fieldset>
<fieldset class="form-group form-float-label col-md-4 col-8">
<input class="form-control" id="float-date" type="date" placeholder="Change date here" inputmode="date" required/>
<label for="float-date" class="form-label">Date</label>
</fieldset>
<fieldset class="form-group form-float-label col-md-2 col-4">
<input class="form-control" id="float-time" type="time" placeholder="Change time here" inputmode="time" required/>
<label for="float-time" class="form-label">Time</label>
</fieldset>
</div>
<fieldset class="form-group form-float-label">
<input id="float-disabled" class="form-control" type="text" placeholder="Disabled input" disabled/>
<label for="float-disabled" class="form-label">Text disabled</label>
</fieldset>
<fieldset class="form-group form-float-label">
<textarea class="form-control" id="float-textarea" type="text" placeholder="Change text here" data-error="Text can not be empty." min="16" required></textarea>
<label for="float-textarea" class="form-label">Textarea</label>
</fieldset>
<!--- Standard labels -->
<h3>Standard Labels</h3>
<div class="row form-row">
<fieldset class="form-group col-md-6">
<label for="input-name" class="form-label">Name</label>
<input class="form-control" id="input-name" name="name" type="text" placeholder="Change name here" autocomplete="name" required/>
</fieldset>
<fieldset class="form-group col-md-6">
<label for="input-password" class="form-label">Password</label>
<input class="form-control" id="input-password" type="password" placeholder="Type password here" inputmode="password" autocomplete="new-password" min="4" max="32" data-error="Provide a valid secure password (min. 4 charcters)." required/>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col-10">
<label for="input-street" class="form-label">Street</label>
<input class="form-control" id="input-street" name="street" type="text" placeholder="Change street here" autocomplete="street-address" required/>
</fieldset>
<fieldset class="form-group col-2">
<label for="street-number" class="form-label">No.</label>
<input class="form-control" id="street-number" type="text" autocomplete="street-number"/>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col-md-6">
<label for="input-email" class="form-label">Email</label>
<input class="form-control" id="input-email" name="email" type="email" placeholder="Change email here" autocomplete="email" data-error="Provide a valid email address." required/>
</fieldset>
<fieldset class="form-group col-md-6">
<label for="input-phone" class="form-label">Phone</label>
<input class="form-control" id="input-phone" type="tel" placeholder="Change number here" inputmode="numeric" autocomplete="tel" data-error="Provide a valid phone number." required/>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col">
<label for="input-url" class="form-label">Website</label>
<input class="form-control" id="input-url" name="url" type="email" placeholder="Input site here" autocomplete="url" data-error="Innvalid URL format." required/>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col-md-4 col-8">
<label for="input-date" class="form-label">Date</label>
<input class="form-control" id="input-date" type="date" placeholder="Change date here" inputmode="date" required/>
</fieldset>
<fieldset class="form-group col-md-2 col-4">
<label for="input-time" class="form-label">Time</label>
<input class="form-control" id="input-time" type="time" placeholder="Change time here" inputmode="time" required/>
</fieldset>
<fieldset class="form-group col-md-6">
<label for="input-select" class="form-label">Select</label>
<select id="input-select" class="form-control" type="text" placeholder="Please select" required>
<option value="" selected disabled>Please select</option>
<optgroup label="Group">
<option value="Option 1">Option 1</option>
<option value="Option 2">Option 2</option>
<option value="Option 3">Option 3</option>
<option value="Option 4" disabled>Option 4</option>
</optgroup>
</select>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col-md-6">
<label for="input-range" class="form-label">Range slider</label>
<input id="input-range" class="form-range" type="range" value="33" min="0" max="100" step="1" data-unit="%" minlength="34" required/>
</fieldset>
<fieldset class="form-group col-md-6">
<label for="input-disabled" class="form-label">Text disabled</label>
<input id="input-disabled" class="form-control" type="text" placeholder="Disabled input" disabled/>
</fieldset>
</div>
<fieldset class="form-group">
<label for="input-textarea" class="form-label">Textarea</label>
<textarea class="form-control" id="input-textarea" type="text" placeholder="Change text here" data-error="Text can not be empty." required></textarea>
</fieldset>
<div class="row form-row">
<fieldset class="form-group col-4">
<legend class="form-label">Checkboxes</legend>
<div class="form-check">
<input type="checkbox" id="checkbox-1" name="checkboxes" indeterminate="true"/>
<label for="checkbox-1">Option 1</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check" id="checkbox-2" name="checkboxes"/>
<label for="checkbox-2">Option 2</label>
</div>
<div class="form-check">
<input type="checkbox" class="form-check" id="checkbox-3" name="checkboxes" disabled/>
<label for="checkbox-3">Option 3</label>
</div>
</fieldset>
<fieldset class="form-group col-4">
<legend class="form-label">Radios</legend>
<div class="form-radio">
<input type="radio" id="radio-1" name="radios" value="Radio 1"/>
<label for="radio-1">Radio 1</label>
</div>
<div class="form-radio">
<input type="radio" id="radio-2" name="radios" value="Radio 2"/>
<label for="radio-2">Radio 2</label>
</div>
<div class="form-radio">
<input type="radio" id="radio-3" name="radios" value="Radio 3" disabled/>
<label for="radio-3">Radio 3</label>
</div>
</fieldset>
<fieldset class="form-group col-4">
<legend class="form-label">Switches</legend>
<div class="form-switch">
<input type="checkbox" id="switch-1" name="switches" value="Switch 1"/>
<label for="switch-1">Switch 1</label>
</div>
<div class="form-switch">
<input type="checkbox" id="switch-2" name="switches" value="Switch 2"/>
<label for="switch-2">Switch 2</label>
</div>
<div class="form-switch">
<input type="checkbox" id="switch-3" name="switches" value="Switchh 3" disabled/>
<label for="switch-3">Switch 3</label>
</div>
</fieldset>
</div>
<div class="row form-row">
<fieldset class="form-group col-4 col-sm-2">
<label for="color" class="form-label">Color</label>
<input id="color" class="form-control form-control-color" type="color" inputmode="color" value="" list="swatches" required/>
<datalist id="swatches">
<option>#cc0000</option>
<option>#00cc00</option>
<option>#0000cc</option>
<option>#cc00cc</option>
</datalist>
</fieldset>
<fieldset class="form-group col-8 col-sm-4">
<label for="number-input" class="form-label">Number</label>
<input type="number" id="number-input" class="form-control" placeholder="0" min="1" max="99" step="1" inputmode="numeric" required/>
</fieldset>
<fieldset class="form-group col-12 col-sm-6">
<label for="search-input" class="form-label">Search</label>
<input type="search" id="search-input" class="form-control" placeholder="Search" required/>
</fieldset>
</div>
<fieldset class="form-group">
<label for="file-input" class="form-label">Pick a File</label>
<div class="input-group">
<input type="file" id="file-input" class="form-control" placeholder="No file selected" required/>
<div class="input-group-append">
<label role="button" class="btn btn-primary" for="file-input">Browse</label>
</div>
</div>
</fieldset>
<fieldset>
<button type="reset" class="btn float-left" disabled>Reset</button>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</fieldset>
</form>
</div>
</section>
<!-- Tab Multistep -->
<section id="tab-multistep" class="tab-panel slide" role="tabpanel" aria-labelledby="multistep" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Multistep Form</h2>
<p>Native UI &amp; Form Submission</p>
<h3>Please Complete the Steps Below</h3>
<form lang="en" novalidate data-validate="true">
<nav role="tablist" id="multistep-list" class="step-list" aria-label="Step Navigation" data-current="current step">
<ol>
<li><a href="#tab-step-start" id="step-start" role="tab" aria-selected="true" aria-controls="tab-step-start" class="active">Personal</a></li>
<li><a href="#tab-step-2" id="step-2" role="tab" aria-selected="false" aria-controls="tab-step-2" tabindex="-1">Location</a></li>
<li><a href="#tab-step-3" id="step-3" role="tab" aria-selected="false" aria-controls="tab-step-3" tabindex="-1">Credit Card</a></li>
<li><a href="#tab-step-end" id="step-end" role="tab" aria-selected="false" aria-controls="tab-step-end" tabindex="-1">Finish</a></li>
</ol>
</nav>
<div class="tabs">
<section class="tab-panel slide fade active show" id="tab-step-start" role="tabpanel" aria-labelledby="step-start" tabindex="0">
<fieldset>
<legend>Step 1</legend>
<div class="form-group form-float-label">
<input type="text" id="step-name" class="form-control" placeholder="Full Name" required/>
<label class="form-label" for="step-name">Name</label>
</div>
<div class="form-group form-float-label">
<input type="email" id="step-email" class="form-control" placeholder="E-Mail Address" required/>
<label class="form-label" for="step-email">Email</label>
</div>
</fieldset>
</section>
<section class="tab-panel slide fade" id="tab-step-2" role="tabpanel" aria-labelledby="step-2" tabindex="-1">
<fieldset>
<legend>Step 2</legend>
</fieldset>
</section>
<section class="tab-panel slide fade" id="tab-step-3" role="tabpanel" aria-labelledby="step-3" tabindex="-1">
<fieldset>
<legend>Step 3</legend>
</fieldset>
</section>
<section class="tab-panel slide fade" id="tab-step-end" role="tabpanel" aria-labelledby="step-end" tabindex="-1">
<legend>Form Complete</legend>
<p>Form successfully completed!</p>
</section>
</div>
<nav data-steplist="multistep-list">
<button type="button" class="btn btn-primary float-left" disabled hidden>Previous Step</button>
<button type="button" class="btn btn-primary float-right">Next Step</button>
</nav>
</form>
</div>
</section>
<!--Tab buttons -->
<section id="tab-buttons" class="tab-panel slide" role="tabpanel" aria-labelledby="forms" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Buttons</h2>
<h3>Theme colored:</p>
<form>
<fieldset>
<button type="button" class="btn">default</button>
<button type="button" class="btn btn-primary">primary</button>
<button type="button" class="btn btn-secondary">secondary</button>
<button type="button" class="btn btn-success">success</button>
</fieldset>
<fieldset>
<button type="button" class="btn btn-danger">danger</button>
<button type="button" class="btn btn-warning">warning</button>
<button type="button" class="btn btn-info">info</button>
<button type="button" class="btn btn-dark">dark</button>
<button type="button" class="btn btn-light">light</button>
</fieldset>
</form>
<h3>With SVG icons:</h3>
<form>
<fieldset>
<button type="button" class="btn">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#home-icon"/></svg> Default
</button>
<button type="button" class="btn btn-primary">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#ui-icon"/></svg> Primary
</button>
<button type="button" class="btn btn-secondary">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#dots-icon"/></svg> Secondary
</button>
<button type="button" class="btn btn-success">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#check-icon"/></svg> Success
</button>
</fieldset>
<fieldset>
<button type="button" class="btn btn-danger">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#delete-icon"/></svg> Danger
</button>
<button type="button" class="btn btn-warning">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#warning-icon"/></svg> Warning
</button>
<button type="button" class="btn btn-info">
<svg viewBox="0 0 9 9" role="img"><use xlink:href="#star-icon"/></svg> Info
</button>
<button type="button" class="btn btn-dark"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#refresh-icon"/></svg> Dark</button>
<button type="button" class="btn btn-light"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#dots-icon"/></svg></button>
</fieldset>
</form>
<h3>Outlined:</h3>
<form>
<fieldset>
<button type="button" class="btn"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#home-icon"/></svg> Default</button>
<button type="button" class="btn btn-outline-primary"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#star-outline-icon"/></svg> Primary</button>
<button type="button" class="btn btn-outline-secondary"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#refresh-outline-icon"/></svg> Secondary</button>
<button type="button" class="btn btn-outline-success"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#fader-icon"/></svg> Success</button>
</fieldset>
<fieldset>
<button type="button" class="btn btn-outline-danger"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#pdf-icon"/></svg> Danger</button>
<button type="button" class="btn btn-outline-warning"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#settings-icon"/></svg> Warning</button>
<button type="button" class="btn btn-outline-info"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#copy-outline-icon"/></svg> Info</button>
<button type="button" class="btn btn-outline-dark"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#copy-icon"/></svg> Dark</button>
<button type="button" class="btn btn-outline-light">light</button>
</fieldset>
</form>
<h2>Variations:</h2>
<form>
<fieldset>
<button type="button" class="btn rounded-pill"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#home-icon"/></svg> Default</button>
<button type="button" class="btn btn-outline-primary rounded-pill"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#star-outline-icon"/></svg> Primary</button>
<button type="button" class="btn btn-secondary rounded-circle"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#refresh-outline-icon"/></svg> </button>
<button type="button" class="btn btn-success shadow-elevated rounded-circle"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#plus-outline-icon"/></svg> </button>
<button type="button" class="btn btn-outline-danger rounded-circle"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#pdf-outline-icon"/></svg></button>
<button type="button" class="btn btn-outline-warning"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#settings-icon"/></svg></button>
<button type="button" class="btn btn-info"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#copy-icon"/></svg></button>
<button type="button" class="btn btn-outline-dark"><svg viewBox="0 0 9 9" role="img"><use xlink:href="#copy-outline-icon"/></svg></button>
<button type="button" class="btn btn-outline-light">light</button>
</fieldset>
</form>
</div>
</section>
<!--Tab Icons -->
<section id="tab-icons" class="tab-panel slide" role="tabpanel" aria-labelledby="icons" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Icons</h2>
<p>Available SVG icons:</p>
<div id='icons-wrapper'>
<form class="form-group">
<div class="input-group">
<input type="search" class="form-control" id="search-icons" placeholder="Search icon" autocomplete="search" required/>
<div class="input-group-append">
<button type="button" class="btn btn-primary">Search</button>
</div>
</div>
</form>
</div>
</div>
</section>
<!--Tab Native UI -->
<section id="tab-native-ui" class="tab-panel slide" role="tabpanel" aria-labelledby="native-ui" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Native UI and Custon Dialogs</h2>
<h3>UI Alert Dialog</h3>
<p>Open a user agent alert warning with the Javascript <code>alert();</code> command.</p>
<code data-language="Javascript" class="code-block">
<pre>prompt('Prompt text', value [, options, callback]);</pre>
</code>
<p>
<button type="button" onclick="alert('Something just happened!')" title="alert('text' [ , options, callback ]);" class="btn block-sm">Trigger an Alert</button>
</p>
<h3>UI Confirm Dialog</h3>
<p>Open a user agent confirmation dialog with the Javascript <code>confirm();</code> command.</p>
<code data-language="Javascript" class="code-block">
<pre>confirm('Prompt text', value [, options, callback]);</pre>
</code>
<p>
<button type="submit" onclick="confirm('Do you really want to do this?')" title="confirm('text' [ , options, callback ]);" class="btn block-sm">Trigger a Confirmation</button>
</p>
<h3>UI Prompt Dialog</h3>
<p>Open a user agent prompt dialog with the Javascript <code>prompt();</code> command.</p>
<code data-language="Javascript" class="code-block">
<pre>prompt('Prompt text', value [, options, callback]);</pre>
</code>
<p>
<button type="button" onclick="prompt('Type something. Just do it.', 'something')" title="prompt('text', value [, options, callback]);" class="btn btn-block-sm">Trigger a Prompt</button>
</p>
<h3>Custom Dialog</h3>
<p>Open a <a href="#customModal" data-toggle="modal" data-target="customModal" title="Custom modal dialog">Custom Modal Dialog</a> which is inline the page's HTML code.</p>
<code data-language="Javascript" class="code-block">
<pre>prompt('Prompt text', value [, options, callback]);</pre>
</code>
<p>
<button type="button" onclick="prompt('Type something. Just do it.', 'something')" title="prompt('text', value [, options, callback]);" class="btn block-sm">Trigger a Dialog</button>
</p>
<h3>Native UI &amp; Form Submission</h3>
<p>Use native user agent javascript dialogs in form validation and submission.</p>
<form onsubmit="alert('submitted form!')" id="native-ui-form" class="clearfix">
<fieldset class="form-group form-float-label">
<input class="form-control" type="text" placeholder="Type your name" value="John Richard Doe" required/>
<label class="form-label">Full Namen</label>
</fieldset>
<fieldset class="form-group form-float-label" required>
<select class="form-control form-select">
<optgroup label="Group">
<option>Option 1</option>
<option>Option 2</option>
</optgroup>
</select>
<label class="form-label">Select Option</label>
</fieldset>
<button type="reset" class="btn float-left">Reset Form</button>
<button type="submit" class="btn float-right">Send Data</button>
</form>
</div>
</section>
<!--Tab Dropdowns -->
<section id="tab-dropdowns" class="tab-panel slide" role="tabpanel" aria-labelledby="dropdowns" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Dropdowns</h2>
<p>Dropdowns are absolute positioned to their parent element.</p>
<form id="dropdowns-form">
<fieldset class="dropdown">
<button class="btn ripple" type="button" id="dropdownLink" data-toggle="dropdown" data-offset="7" aria-haspopup="true" aria-expanded="false">Drop down <i class="caret" aria-hidden="true"></i></button>
<div class="dropdown-menu" aria-labelledby="dropdownLink">
<h6>Dropdown header</h6>
<a class="disabled" role="menuitem" href="#!" tabindex="-1" aria-disabled="true">Action</a>
<a role="menuitem" href="#!">Another action</a>
<a role="menuitem" href="#!">Something else here</a>
<div class="divider"></div>
<a role="menuitem" href="#!">Separated link</a>
</div>
</fieldset>
<fieldset class="dropdown dropup">
<button class="btn ripple" type="button" id="dropupLink" data-toggle="dropdown" data-offset="7" data-align="right top" aria-haspopup="true" aria-expanded="false">Drop up <i class="caret" aria-hidden="true"></i></button>
<div class="dropdown-menu" aria-labelledby="dropupLink">
<h6>Dropup header</h6>
<a role="menuitem" href="#!" class="disabled" tabindex="-1" aria-disabled="true">Action</a>
<a role="menuitem" href="#!">Another action</a>
<a role="menuitem" href="#!">Something else here</a>
<div class="divider"></div>
<a role="menuitem" href="#!">Separated link</a>
<i class="indicator"></i>
</div>
</fieldset>
</form>
</div>
</section>
<!--Tab Tooltips -->
<section id="tab-tooltips" class="tab-panel slide" role="tabpanel" aria-labelledby="tooltips" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Tooltips</h2>
<p>Tooltips for the HTML title property are single elements for descriptive user interface feedbacks or descriptions.</p>
<form id="tooltips-form">
<fieldset>
<button type="button" class="btn ripple" title="Tooltip top" data-tooltip="top">Top</button><br>
<button type="button" class="btn" title="Tooltip left" data-tooltip="left">Left</button>
<button type="button" class="btn" title="Tooltip right" data-tooltip="right">Right</button><br>
<button type="button" class="btn" title="Tooltip right" data-tooltip="right">Right</button>
<button type="button" class="btn" title="Tooltip left" data-tooltip="left">Left</button><br>
<button type="button" class="btn" title="Tooltip bottom" data-tooltip="bottom">Bottom</button>
</fieldset>
</form>
</div>
</section>
<!--Tab Notifications -->
<section id="tab-notifications" class="tab-panel slide" role="tabpanel" aria-labelledby="notifications" tabindex="-1">
<div class="container-fluid container-sm">
<h2>Notifications</h2>
<p>Notifications and browser notifications with or without the Notification API The browser Notification API is only triggered when the window / tab is not active or in the actual view of the user..</p>
<form id="notifications-form">
<button class="btn" type="button" onclick="notify('Something just happened!')" title="notify('text', type [ , options, callback ]);">Notify</button>
<button class="btn" type="button" onclick="notify('Something just happened with an image!', 'image', {image:'https://pixy.org/src2/614/thumbs350/6147553.jpg'})" title="notify('text', type [ , options, callback ]);">with Image</button>
<button class="btn" type="button" onclick="notify('Error just happened!', 'error')" title="notify('text', type [ , options, callback ]);">an Error</button>
<button class="btn" type="button" onclick="notify('Warning just happened!', 'warning')" title="notify('text', type [ , options, callback ]);">a Warning</button>
<button class="btn" type="button" onclick="notify('Success just happened!', 'Success')" title="notify('text', type [ , options, callback ]);">a Success</button>
</form>
</div>
</section>
<!--Tab Toasts -->
<section id="tab-toasts" class="tab-panel slide" role="tabpanel" aria-labelledby="toasts" tabindex="-1">
<div class="container-fluid container-sm">
<h2>System Toasts</h2>
<p>Toast messages are single elements for user interface feedbacks for the user and can not be stacked.</p>
<form id="Toaster">
<button class="btn" type="button" onclick="toast('Something just happened!')" title="notify('text' [ , type, options ]);">Toast</button>
<button class="btn" type="button" onclick="toast('Error just happened!', 'error')" title="toast('text' [ , type, options ]);">an Error</button>
<button class="btn" type="button" onclick="toast('Success just happened!', 'success')" title="toast('text' [ , type, options ]);">a Success</button>
<button class="btn" type="button" onclick="toast('Warning just happened!', 'warning')" title="toast('text' [ , type, options ]);">a
Warning</button>
</form>
</div>
</section>
</main>
<footer>
<div class="container-fluid container-md"></div>
</footer>
<!-- Modal Dialog Template -->
<template>
</template>
<!-- Inline Modal Dialog -->
<div class="modal ui-modal" id="customModal" tabindex="-1" role="dialog" aria-hidden="true" aria-describedby="title-customModal">
<div class="modal-dialog" role="document">
<div class="modal-content">
<div class="modal-header">
<h3 id="title-customModal">Custom</h3>
<button href="#!" class="close" data-dismiss="modal">Close</button>
</div>
<div class="modal-body">
<p>Custom modal content</p>
</div>
<div class="modal-footer">
<button class="btn btn-secondary" data-dismiss="modal">Cancel</button>
<button class="btn btn-primary">Yes</button>
</div>
</div>
</div>
</div>
<!-- SVG Icon system -->
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;" id="ui-icons">
<symbol id="ui-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8 7h.5v.4c0 .3-.3.6-.6.6H1.1c-.3 0-.6-.3-.6-.6V7H1V3.1c0-.3.3-.6.6-.6H3v.8H1.8V7h2c0 .1.1.2.2.2h1c.1 0 .2-.1.2-.2h2V5H8v2zM6.1 3.7v-.5H4.5v.5h1.6zM4.6 2.4v.5h2.9v-.5M4.1 4.6c-.4-.1-.6-.4-.6-.7V1.7c0-.4.3-.7.7-.7h3.6c.4 0 .7.3.7.7v2.2c0 .4-.3.7-.7.7H5.3L4.1 5.8V4.6zm1.1-3.1c0 .1.1.2.2.2s.2-.1.2-.2-.1-.2-.2-.2-.2.1-.2.2zm-.6 0c0 .1.1.2.2.2s.2-.1.2-.2-.1-.2-.2-.2-.2.1-.2.2zm-.5 0c0 .1.1.2.2.2s.2-.1.2-.2-.1-.2-.2-.2c-.2 0-.2.1-.2.2zm.1 2.6h.4v.6l.6-.6h2.6c.1 0 .2-.1.2-.2V2H4v1.9c0 .1.1.2.2.2z"/>
</symbol>
<symbol id="search-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M.5 3.7C.5 5.6 2 7 3.8 7c.7 0 1.4-.2 1.9-.6l2 2c.1.1.2.1.3.1.1 0 .2 0 .3-.1.2-.2.2-.5 0-.6l-2-2c.5-.6.7-1.3.7-2.1C7 1.9 5.5.4 3.7.4 2 .4.5 1.9.5 3.7zm.7 0c0-1.4 1.2-2.6 2.6-2.6s2.6 1.2 2.6 2.6-1.2 2.6-2.6 2.6-2.6-1.1-2.6-2.6z"/>
</symbol>
<symbol id="dots-icon" viewBox="0 0 9 9" fill="currentColor">
<circle cx="4.5" cy="1.5" r="1"/><circle cx="4.5" cy="4.5" r="1"/><circle cx="4.5" cy="7.5" r="1"/>
</symbol>
<symbol id="check-icon" viewBox="0 0 9 9" fill="currentColor">
<path fill="none" stroke="currentColor" stroke-width="1.5" d="M8 2L3 7 1 5"/>
</symbol>
<symbol id="reveal-eye-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5,4.2c-0.7,0-1.4,0.6-1.4,1.4S3.7,7,4.5,7s1.4-0.6,1.4-1.4S5.2,4.2,4.5,4.2z M4.5,2C2,2,0,3.6,0,5.6h1C1,4.1,2.5,3,4.5,3C6.4,3,8,4.1,8,5.6h1C9,3.6,7,2,4.5,2z"/>
</symbol>
<symbol id="hide-eye-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="m7.4 2.9-.7.7C7.5 4 8 4.8 8 5.6h1c0-1.1-.6-2.1-1.6-2.7zM3.6 6.7c.2.2.5.3.9.3.8 0 1.4-.6 1.4-1.4 0-.3-.1-.6-.3-.9l-2 2zM4.5 3h.2l.9-.9C5.3 2 4.9 2 4.5 2 2 2 0 3.6 0 5.6h1C1 4.1 2.5 3 4.5 3zM.68 7.75 7.75.68l.57.57-7.07 7.07z"/>
</symbol>
<symbol id="not-allowed-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="m2.2 5.9 3.7-3.7c-.4-.2-.9-.4-1.4-.4C3 1.8 1.8 3 1.8 4.5c0 .5.2 1 .4 1.4zm4.6-2.8L3.1 6.8c.4.2.9.4 1.4.4C6 7.2 7.2 6 7.2 4.5c0-.5-.2-1-.4-1.4zM4.5.5c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4 1.8-4 4-4z"/>
</symbol>
<symbol id="warning-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5,0.5L0,8.5h9L4.5,0.5z M5,7.5H4V6.7h1V7.5z M4,6V3h1v3H4z"/>
</symbol>
<symbol id="time-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5.5c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm1.8 5.2l-.4.1-.2-.1-1.4-1-.1-.1v-.1-.1-.1-.1L5 1.3c0-.2.2-.3.4-.2.2.1.3.3.3.5L5 4.3l1.2.8c.1.2.2.4.1.6z"/>
</symbol>
<symbol id="calendar-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M1.8.5v.8h-.7c-.2 0-.4.2-.4.4v6.5c0 .2.2.4.4.4H8c.2 0 .4-.2.4-.4V1.6c0-.2-.2-.4-.4-.4h-.8V.5H6v.8H3V.5H1.8zm-.3 3h6.1v4.2H1.5V3.5zm.3.4v1.5h1.5V3.9H1.8zm1.9 0v1.5h1.5V3.9H3.7zm1.9 0v1.5h1.5V3.9H5.6zM1.8 5.8v1.5h1.5V5.8H1.8zm1.9 0v1.5h1.5V5.8H3.7z"/>
</symbol>
<symbol id="select-icon" viewBox="0 0 9 9">
<path d="M4.5,1L2,3.8h5L4.5,1z M4.5,8L2,5.3h5L4.5,8" fill="currentColor"/>
</symbol>
<symbol id="bell-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5 8.5c-.5 0-.7-.4-.7-.9h1.5c0 .5-.4.9-.8.9zM7 6l.8 1v.3H1.3V7L2 6V4c0-1.3.8-2.2 2-2.5V1c0-.3.2-.5.5-.5s.5.2.5.5v.5c1.2.3 2 1.3 2 2.5v2z"/>
</symbol>
<symbol id="close-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8.4 1.4L7.6.6 4.5 3.8 1.4.6l-.8.8 3.2 3.1L.6 7.6l.8.8 3.1-3.2 3.1 3.2.8-.8-3.2-3.1z"/>
</symbol>
<symbol id="home-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.7 8.5c.3 0 .5-.2.5-.5V3.5c0-.1-.1-.3-.2-.4L4.8.6c-.2-.1-.5-.1-.7 0L1 3.1c-.1.1-.2.3-.2.4V8c0 .3.2.5.5.5h6.4zm-4.8-1h-1V3.8l2.6-2.1 2.6 2.1v3.7H2.9z"/>
</symbol>
<symbol id="favorites-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.2 8.4C3.8 8 .5 5.2.5 3 .5 1.6 1.6.5 2.9.5c.6 0 1.2.3 1.6.6.4-.4 1-.6 1.6-.6C7.4.5 8.5 1.6 8.5 3c0 2.2-3.3 5-3.7 5.3-.2.2-.5.2-.6.1zM2.9 1.5c-.7 0-1.4.7-1.4 1.5 0 1.1 1.8 3.1 3 4.3 1.1-1 3-3 3-4.3 0-.8-.6-1.5-1.4-1.5-.5 0-.9.3-1.2.7-.2.3-.6.3-.8 0-.3-.4-.7-.7-1.2-.7z"/>
</symbol>
<symbol id="star-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5,7L2,8.5l0.7-3l-2.2-2l2.9-0.3l1.1-2.8l1.1,2.8l2.9,0.3l-2.2,2l0.7,3L4.5,7z"/>
</symbol>
<symbol id="star-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5,1.8l0.8,1.9l2.1,0.2L5.8,5.4l0.5,2.1L4.5,6.4L2.7,7.5l0.5-2.1L1.7,3.9l2.1-0.2L4.5,1.8 M4.5,0.5L3.4,3.3L0.5,3.5l2.2,2
L2,8.5L4.5,7L7,8.5l-0.7-3l2.2-2L5.6,3.3L4.5,0.5L4.5,0.5z"/>
</symbol>
<symbol id="refresh-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.3 1.7L8.5.5V4H5l1.6-1.6c-.6-.6-1.3-.9-2.1-.9-1.7 0-3 1.3-3 3s1.3 3 3 3c1.3 0 2.4-.8 2.8-2h1c-.4 1.8-2 3-3.9 3-2.2 0-4-1.8-4-4s1.8-4 4-4c1.2 0 2.2.4 2.9 1.2z"/>
</symbol>
<symbol id="refresh-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.6 5.5c-.1.4-.4.8-.7 1.1a2.9 2.9 0 01-4.2 0 2.9 2.9 0 010-4.2 3 3 0 014.1-.1H5.5V3h2.1c.2 0 .4-.2.4-.4V.5h-.8v1.1a3.8 3.8 0 00-5.2.5 3.6 3.6 0 00.4 5.2C4 8.6 6.3 8.5 7.6 6.9c.3-.3.5-.7.7-1.2l-.7-.2z"/>
</symbol>
<symbol id="settings-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8.2 5.5l-.7-.4c.1-.4.1-.8 0-1.1l.7-.4c.1 0 .1-.1.1-.2-.2-.7-.5-1.2-.9-1.6-.1-.1-.2-.1-.2 0l-.7.3c-.3-.2-.6-.4-1-.6V.8c0-.1-.1-.2-.2-.2C4.7.5 4.1.5 3.5.6c-.1 0-.2.1-.2.2v.8c-.4.1-.7.3-1 .6l-.5-.5h-.2c-.4.5-.7 1-.9 1.6 0 .1 0 .2.1.2l.7.4c-.1.4-.1.8 0 1.1l-.7.5c-.1 0-.1.1-.1.2.2.6.5 1.1.9 1.5.1.1.2.1.2 0l.7-.4c.3.2.6.4 1 .6v.8c0 .1.1.2.2.2.6.1 1.2.1 1.8 0 .1 0 .2-.1.2-.2v-.8c.4-.1.7-.3 1-.6l.7.4h.2c.4-.4.7-.9.9-1.5-.2-.1-.2-.2-.3-.2zm-3.7.3c-.7 0-1.3-.6-1.3-1.3s.6-1.3 1.3-1.3 1.3.6 1.3 1.3-.6 1.3-1.3 1.3z"/>
</symbol>
<symbol id="store-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5 7.2V5.4H1.8v1.8h2.7zm4-1.8h-.4v3.1h-.9V5.4H5.4v3.1H.9V5.4H.5v-.9L1 2.3h7l.5 2.2v.9zM8 .9v1H1v-1h7z"/>
</symbol>
<symbol id="parcel-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M.5 6.6l3.9 1.9V4.3L.5 2.5v4.1zm1.2-2.5l1.5.7v.6l-1.5-.7v-.6zm2.9.2v4.2l3.9-1.9V2.5L4.6 4.3zM4.5.5l-4 1.8 4 1.7 4-1.8-4-1.7z"/>
</symbol>
<symbol id="parcel-open-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M.7 5l3.2 1.6.6-1.6-3.2-1.5L.7 5zm3.9 0l.6 1.6L8.4 5l-.6-1.5L4.6 5zM.2 2.2l1.1 1.3 3.2-1.6-1-1.3L.2 2.2zm8.6 0L5.6.5 4.5 1.8l3.2 1.6c.1 0 1.1-1.2 1.1-1.2zM1.1 5.4v1.5l3.4 1.5V5.6L4 6.8 1.1 5.4zm3.5.2v2.9L8 6.9V5.4L5 6.8l-.4-1.2z"/>
</symbol>
<symbol id="stop-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8.1 2.3v4.8c0 .7-.6 1.3-1.3 1.3H4.4c-.4.1-.7 0-.9-.3L.8 5.4l.4-.4h.5l1.5.8v-4c0-.3.2-.5.5-.5s.5.2.5.5v2.3h.3V1c0-.3.2-.5.5-.5s.5.2.5.5v3.2h.3V1.4c0-.3.2-.5.5-.5s.5.2.5.5v2.8h.4V2.4c0-.3.2-.5.5-.5.2-.1.5.2.4.4z"/>
</symbol>
<symbol id="key-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6 .5C4.6.5 3.5 1.6 3.5 3c0 .3.1.6.1.9L.5 7v1.5H2v-.9h.9v-.9h.9l1.3-1.3c.3.1.6.2.9.2 1.4 0 2.5-1.1 2.5-2.5C8.5 1.6 7.4.5 6 .5zM1.4 7.1L1.3 7l1.4-1.4.1.1-1.4 1.4zm1.7-1.7L3 5.3l.3-.3.1.1-.3.3zm3.6-2.5c-.3 0-.6-.3-.6-.6s.3-.6.6-.6.6.3.6.6-.3.6-.6.6z"/>
</symbol>
<symbol id="view-grid-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M5,0.5h3.5V4H5V0.5z M0.5,4V0.5H4V4H0.5z M5,5h3.5v3.5H5V5z M0.5,8.5V5H4v3.5H0.5z"/>
</symbol>
<symbol id="view-list-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M0.5,0.5h8v2h-8V0.5z M0.5,8.5v-2h8v2H0.5z M0.5,5.5v-2h8v2H0.5z"/>
</symbol>
<symbol id="delete-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8,1v0.7H1V1h1.9l0.5-0.5h2.2L6.1,1H8z M1.8,2.5h5.5v5.1c0,0.5-0.4,0.9-0.9,0.9H2.7c-0.5,0-0.9-0.4-0.9-0.9L1.8,2.5z"/>
</symbol>
<symbol id="plus-circle-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.9 2.5h-.8v1.6H2.5v.8h1.6v1.6h.8V4.9h1.6v-.8H4.9V2.5zm-.4-2c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm0 7.2c-1.8 0-3.2-1.4-3.2-3.2s1.4-3.2 3.2-3.2 3.2 1.4 3.2 3.2-1.4 3.2-3.2 3.2z"/>
</symbol>
<symbol id="share-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.5 5.9a1 1 0 00-.7.3L3.4 4.5l.1-.4v-.2l2.4-1.2c.2.3.5.4.9.4.7 0 1.2-.6 1.2-1.3S7.5.6 6.8.6s-1.3.6-1.3 1.3v.2L3.1 3.3c-.2-.2-.5-.4-.9-.4-.7 0-1.2.6-1.2 1.3s.6 1.3 1.3 1.3c.3 0 .5-.1.7-.3l2.3 1.7-.1.4c0 .7.6 1.3 1.3 1.3S7.8 8 7.8 7.3c-.1-.8-.7-1.4-1.3-1.4z"/>
</symbol>
<symbol id="print-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7 4V.6H2V4H1c-.3 0-.5.2-.5.5V7H2v.9l5 .6V7h1.5V4.5c0-.3-.2-.5-.5-.5H7zm-.5 4l-4-.5V6h4v2zm0-4h-4V1.1h4V4zm1 1.3c-.1-.1-.3-.2-.2-.3 0-.1.1-.2.3-.2.1 0 .2.1.2.3 0 0-.2.1-.3.2z"/>
</symbol>
<symbol id="bookmark-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M2 .5v.8h5V.5H2zm0 8l2.5-2 2.5 2V1.8H2v6.7zm1.9-5l.5-1 .6 1 1 .1-.8.7.2 1.2-.9-.7-1 .7.2-1.2-.7-.7.9-.1z"/>
</symbol>
<symbol id="fader-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M2.5 6.7h-.7v1.8h-.6V6.7H.5V5.6h2v1.1zM1.8.5h-.6v4.4h.7V.5zM5.5 3h-2v1.1h.7v4.4h.7V4.1h.7V3zM4.8.5h-.6v1.8h.7V.5zm3.7 5.1h-2v1.1h.7v1.8h.7V6.7h.7V5.6zM7.8.5h-.6v4.4h.7V.5z"/>
</symbol>
<symbol id="pdf-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.3 1.5c-.1-.1-.2 0-.2 0-.2.3-.1 1 .1 1.4.1-.5.2-1.2.1-1.4zm.2 2.7L4 5.4c.2-.1.6-.2 1.2-.3-.3-.3-.5-.6-.7-.9zM1.6 7.1l.1.1c.1.1.3 0 .5-.2.3-.2.5-.6.6-.8-1 .5-1.2.8-1.2.9zm3-3.3c0-.1 0-.1 0 0zM.5.5v8h8v-8h-8zm6.7 5.7c-.3 0-1-.2-1.7-.8-.7.1-1.3.3-1.8.5h.1c-.1.2-1 1.8-1.9 1.8-.4 0-.6-.2-.6-.5 0-.2.1-.8 1.9-1.5.1-.2.5-1 1-2.2-.2-.2-.5-.9-.5-1.5 0-.7.4-.8.6-.8.1 0 .3 0 .4.2s.3.4.2.8c0 .6-.1 1.1-.3 1.5 0 .1.3.5.9 1.3.5 0 .8-.1 1.2-.1.6 0 1.2.2 1.2.7 0 .6-.5.6-.7.6zm-.5-1c-.3 0-.6 0-.7.1.4.3.8.4 1 .4.3 0 .3-.2.3-.2 0-.1-.2-.3-.6-.3z"/>
</symbol>
<symbol id="pdf-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.1 5.1c-.5 0-.9 0-1.4.1-.8-.9-1.1-1.4-1.1-1.5.2-.6.3-1.2.4-1.9 0-.5-.1-.8-.3-1-.3-.3-.5-.3-.6-.3-.3 0-.7.1-.7 1 0 .8.4 1.6.5 1.8-.6 1.5-1.1 2.6-1.2 2.8C.5 6.9.4 7.7.4 7.9c0 .4.3.6.8.6 1.1 0 2.2-1.9 2.3-2.2h-.1c.7-.3 1.4-.5 2.2-.6.8.8 1.7 1 2 1 .3 0 1 0 1-.7s-.8-.9-1.5-.9zM1.5 7.7c-.2.2-.4.3-.5.3 0 0-.1 0-.2-.1v-.1c0-.1.2-.6 1.5-1.2-.2.4-.5.8-.8 1.1zM3.9 1L4 .9s.1 0 .1.1c.2.2 0 1-.1 1.7-.2-.6-.3-1.4-.1-1.7zm-.1 4.7l.6-1.5c.2.4.5.7.8 1-.6.2-1.1.4-1.4.5zm3.7.4c-.3 0-.8-.1-1.3-.5.2 0 .5-.1.9-.1.6 0 .8.2.8.3-.1.1-.1.3-.4.3z"/>
</symbol>
<symbol id="mail-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M.5 3v4.3h8V3l-4 2.5L.5 3zm0-1v.5l4 2.5 4-2.5V2h-8z"/>
</symbol>
<symbol id="mail-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M.5 2.9v3.9l2.4-2.4L.5 2.9zm4 2.5l-1.2-.7L.8 7.2h7.3L5.7 4.7l-1.2.7zm4 1.5v-4L6.1 4.5l2.4 2.4zM.5 2v.4l4 2.5 4-2.5V2h-8z"/>
</symbol>
<symbol id="swatches-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4 1.1c0-.3-.3-.6-.6-.6H1.1C.8.5.5.8.5 1.1v5.6c0 1 .8 1.8 1.7 1.8 1 0 1.8-.8 1.8-1.7V1.1zM2.2 7.5c-.4 0-.7-.3-.7-.8 0-.4.3-.7.7-.7s.8.3.8.8c0 .4-.3.7-.8.7zm6.3-1.9v2.3c0 .3-.3.6-.6.6H4L7.5 5h.4c.3 0 .6.3.6.6zM5.8 1.5l1.6 1.6c.2.2.2.6 0 .8L4.7 6.8V1.9l.3-.4c.2-.2.6-.2.8 0z"/>
</symbol>
<symbol id="eyedropper-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M2.2 6.27l-.42.95.95-.42.93-.93-.53-.53-.93.93zM8.06.94C7.48.36 6.53.35 5.94.94l-.91.89-.39-.39c-.22-.22-.57-.22-.79 0-.22.22-.22.58 0 .79l.42.4L1.38 5.5S.64 7.41.51 8.15c-.04.2.14.38.34.35.73-.13 2.62-.85 2.62-.85l2.91-2.89.38.39c.22.22.57.22.79 0 .22-.22.22-.58 0-.79l-.41-.4.91-.9c.59-.59.6-1.54.01-2.12zM2.97 7.09c-.04.04-1.71.65-1.71.65s.61-1.67.65-1.71l2.9-2.9 1.06 1.06-2.9 2.9z"/>
</symbol>
<symbol id="location-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5.5C2.9.5 1.6 1.8 1.6 3.4s2.9 5.1 2.9 5.1S7.4 5 7.4 3.4 6.1.5 4.5.5zm0 4.2c-.7 0-1.3-.6-1.3-1.3S3.8 2 4.5 2s1.3.6 1.3 1.3-.6 1.4-1.3 1.4z"/>
</symbol>
<symbol id="copy-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.3 3V.8H.8v5.5H3v2h5.3V3h-2zm-.5 2.8H1.3V1.3h4.5v4.5z"/>
</symbol>
<symbol id="copy-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.8 6.8V3.5h1.5v4.8H3.5V6.8h3.3zm-1-1V1.3H1.3v4.5h4.5zm.5.5H.8V.8h5.5v5.5z"/>
</symbol>
<symbol id="code-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.4 2l.1.1zM3 2.7l-.6-.5L.5 4.5l2 2.4.5-.5-1.5-1.9zM6.5 2.1l-.5.6 1.5 1.8L6 6.4l.5.5 2-2.4zM3.4 7.9l.8.1 1.4-6.9-.8-.1z"/>
</symbol>
<symbol id="plus-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.1.5v3.6H.5V5h3.6v3.6H5V4.9h3.6v-.8H4.9V.5h-.8z"></path>
</symbol>
<symbol id="minus-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.1.5v3.6H.5V5h3.6v3.6H5V4.9h3.6v-.8H4.9V.5h-.8z"></path>
</symbol>
<symbol id="bookmark-simple-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M2.3.5h4.4c.5 0 .9.4.9.9v7.1L4.5 7.2 1.4 8.5V1.4c0-.5.4-.9.9-.9zm2.2 5.7l2.2 1V1.4H2.3v5.8l2.2-1z"/>
</symbol>
<symbol id="user-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M5.9 5.3c-.4 0-.7.3-1.4.3s-1-.3-1.4-.3c-1.2 0-2.1.9-2.1 2v.4c0 .4.3.8.8.8h5.5c.4 0 .7-.3.7-.7v-.5c0-1.1-.9-2-2.1-2zm1.4 2.5H1.8v-.5c0-.7.6-1.3 1.3-1.3.2 0 .6.3 1.4.3.8 0 1.2-.3 1.4-.3.7 0 1.3.6 1.3 1.3v.5zM4.5 5c1.2 0 2.3-1 2.3-2.3S5.8.4 4.5.4s-2.3 1-2.3 2.3S3.3 5 4.5 5zm0-3.7c.8 0 1.5.6 1.5 1.5s-.7 1.5-1.5 1.5S3 3.6 3 2.8s.7-1.5 1.5-1.5z"/>
</symbol>
<symbol id="camera-photo-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5,3.8c-0.7,0-1.3,0.6-1.3,1.3s0.6,1.3,1.3,1.3c0.7,0,1.3-0.6,1.3-1.3S5.2,3.8,4.5,3.8z M7.9,2H6.4L6.3,1.5 C6.2,1.2,6,1,5.7,1H3.3C3,1,2.8,1.2,2.7,1.5L2.6,2H1.1C0.8,2,0.5,2.2,0.5,2.5v5C0.5,7.8,0.8,8,1.1,8h6.8c0.3,0,0.6-0.2,0.6-0.5V2.6 C8.5,2.3,8.2,2,7.9,2z M4.5,7C3.4,7,2.6,6.1,2.6,5.1s0.9-1.9,1.9-1.9c1.1,0,1.9,0.9,1.9,1.9S5.6,7,4.5,7z"/>
</symbol>
<symbol id="camera-video-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.1,2.6C6.1,2.2,5.9,2,5.5,2H1.1C0.8,2,0.5,2.2,0.5,2.6v3.8C0.5,6.8,0.8,7,1.1,7h4.4c0.4,0,0.7-0.2,0.6-0.6V2.6z"/>
<path d="M8.3,2.5l-1.7,1v2l1.7,1c0.1,0,0.2,0,0.2-0.1V2.6C8.5,2.5,8.4,2.5,8.3,2.5z"/>
</symbol>
<symbol id="colorscheme-dark-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8 1H1c-.3 0-.5.2-.5.5v1.3h8V1.5c0-.3-.2-.5-.5-.5zM1.5 2.3c-.2 0-.3-.1-.3-.3 0-.2.1-.3.3-.3s.3.1.3.3c0 .1-.1.3-.3.3zm1 0c-.2 0-.3-.1-.3-.3 0-.2.1-.3.3-.3.2 0 .3.1.3.3 0 .1-.1.3-.3.3zm.9 0c-.2 0-.3-.1-.3-.3 0-.2.1-.3.3-.3s.3.1.3.3c.1.1-.1.3-.3.3zM.5 3.3v4.2c0 .4.1.5.5.5h7c.4 0 .5-.1.5-.5V3.3h-8zm5.1 3.3c-.3.3-.8.4-1.3.3-.7-.2-1.1-1-.9-1.7.1-.5.5-.8 1-1 0 0 .1 0 .1.1v.1c-.1.2-.2.3-.3.5-.2.6.2 1.3.8 1.5.2.1.4.1.5 0 0 0 .1 0 .1.1.1 0 .1 0 0 .1z"/>
</symbol>
<symbol id="colorscheme-light-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8 1H1c-.3 0-.5.2-.5.5v6c0 .3.2.5.5.5h7c.3 0 .5-.2.5-.5v-6c0-.3-.2-.5-.5-.5zm-4.6.6c.2 0 .3.1.3.3s-.1.4-.3.4c-.1 0-.3-.2-.3-.3 0-.2.2-.4.3-.4zm-.9 0c.2 0 .3.1.3.3s-.1.4-.3.4-.3-.2-.3-.3c0-.2.1-.4.3-.4zm-1 0c.2 0 .3.1.3.3s-.1.4-.3.4-.3-.2-.3-.3c0-.2.1-.4.3-.4zM8 7.2c0 .2-.1.3-.3.3H1.2c-.1 0-.2-.1-.2-.2V2.8h7v4.4z"/>
<path d="M4.5 5.9c.4 0 .8-.3.8-.8s-.4-.8-.8-.8-.8.4-.8.8.4.8.8.8zM4.5 4c.1 0 .2-.1.2-.2v-.3c0-.1-.1-.2-.2-.2s-.2.1-.2.2v.3c0 .1.1.2.2.2zM3.5 4.3l.1.1s.1 0 .1-.1c.1-.1.1-.2 0-.3l-.2-.2c-.1-.1-.2-.1-.3 0v.3l.3.2zM2.9 5.3h.3c.1 0 .2-.1.2-.2s-.1-.2-.2-.2h-.3c-.1 0-.2.1-.2.2s.1.2.2.2zM3.5 5.8l-.3.3c-.1.1-.1.2 0 .3l.1.1s.1 0 .1-.1l.2-.2c.1-.1.1-.2 0-.3.1-.1-.1-.1-.1-.1zM4.5 6.2c-.1 0-.2.1-.2.2v.3c0 .1.1.2.2.2s.2-.1.2-.2v-.3c0-.2-.1-.2-.2-.2zM5.5 5.8c-.1-.1-.2-.1-.3 0-.1.1-.1.2 0 .3l.2.2.1.1c.1 0 .1 0 .1-.1.1-.1.1-.2 0-.3l-.1-.2zM5.6 5.1c0 .1.1.2.2.2h.3c.1 0 .2-.1.2-.2s-.1-.2-.2-.2h-.3c-.1 0-.2.1-.2.2zM5.4 4.4c.1 0 .1 0 .1-.1l.2-.2c.1-.1.1-.2 0-.3s-.2-.1-.3 0l-.1.3c-.1.1-.1.2 0 .3h.1z"/>
</symbol>
<symbol id="upload-cloud-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5 1.4c.6 0 1.3.2 1.7.7.5.5.7 1 .8 1.5a2 2 0 011.8 2 2 2 0 01-2 2H1.9C1 7.6.3 6.8.3 5.9c0-.9.7-1.7 1.6-1.7H2c0-.7.2-1.5.8-2 .4-.5 1.1-.8 1.7-.8zm0 1.7L3 4.5l.3.4 1-.9v2.6h.5V4l.9.8.3-.3-1.5-1.4z"/>
</symbol>
<symbol id="microphone-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5 5.5C5.3 5.5 6 4.8 6 4V2C6 1.2 5.3.5 4.5.5S3 1.2 3 2v2c0 .8.7 1.5 1.5 1.5zM6.8 4c0 1.2-1 2.3-2.3 2.3S2.3 5.2 2.3 4h-.8c0 1.5 1.2 2.8 2.6 3v1.5h.8V7a3.1 3.1 0 002.6-3h-.7z"/>
</symbol>
<symbol id="type-keyboard-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M8 .5H1L.5 1v7l.5.5h7l.5-.5V1L8 .5zm-.2 7.3H1.2V1.2h6.7v6.6zM3 2.5h1.3v4h-.8V7h2v-.5h-.7v-4H6V3h.5V2h-4v1H3v-.5z"/>
</symbol>
<symbol id="rename-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M5,2H0.5v5H5V2z M7,2v5h1.5V2H7z M6.3,1h1V0.5H4.8V1h1v7h-1v0.5h2.5V8h-1V1z"/>
</symbol>
<symbol id="preview-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6 .5v2h2l-2-2zM3.1 5.1c0 .5.4 1 1 1s1-.4 1-1-.4-1-1-1-1 .4-1 1zM5.5.5H1v8h7V3H5.5V.5zm.2 4.6l-.3.9 1 1.1-.5.4L5 6.4a3 3 0 01-.9.2c-.9 0-1.5-.7-1.5-1.5 0-.9.7-1.5 1.5-1.5s1.6.6 1.6 1.5z"/>
</symbol>
<symbol id="fullscreen-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.3 7.3H5.5v1h2.8V5.5h-1v1.8zM.8 3.5h1V1.8h1.8v-1H.8v2.7zm1 2h-1v2.8h2.8v-1H1.8V5.5zM8.3.8v2.8h-1V1.8H5.5v-1h2.8z"/>
</symbol>
<symbol id="fullscreen-exit-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M6.5 6.5h1.8v-1H5.5v2.8h1V6.5zM3.6.8h-1v1.7H.8v1h2.8V.8zm-1 7.5h1V5.5H.8v1h1.8v1.8zm2.9-4.7V.8h1v1.8h1.8v1H5.5z"/>
</symbol>
<symbol id="speaker-mute-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M1.8,2.8H0.5v3.4h1.3l2.7,2.3V0.6L1.8,2.8z"/>
<path d="M8.5 3.2L8 2.7 6.7 4 5.4 2.7l-.4.5 1.3 1.3L5 5.8l.5.5L6.8 5 8 6.2l.5-.5-1.3-1.2 1.3-1.3z"/>
</symbol>
<symbol id="speaker-volume-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M1.8,2.8H0.5v3.4h1.3l2.7,2.3V0.6L1.8,2.8z"/>
<path d="M5.6 2.6l-.5.6c.7.7.7 1.9 0 2.6l.6.6c1-1.1 1-2.8-.1-3.8z"/>
<path d="M7.4 1.8l-.6.6a3 3 0 010 4.2l.6.6a3.8 3.8 0 000-5.4z"/>
</symbol>
<symbol id="play-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M3 2v5l4-2.5z"/>
</symbol>
<symbol id="pause-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M2 7h2V2H2v5zm3-5v5h2V2H5z"/>
</symbol>
<symbol id="download-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M7.7 3.5L7 2.9 5 5V.8H4V5L2 2.9l-.7.6 3.2 3.2 3.2-3.2zm-6.2 5h6v-.9h-6v.9z"/>
</symbol>
<symbol id="offline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.9 1.8c-.2 0-.3-.1-.5-.1-1 0-1.9.6-2.3 1.6C1.2 3.3.5 4.1.5 5s.7 1.7 1.7 1.7h.4c0 .1 2.3-4.9 2.3-4.9zm1.5 1.1c-.1-.2-.3-.4-.4-.5L6.7 1 6.1.7 2.6 7.9l.6.3.7-1.6h2.7c1 0 1.9-.8 1.9-1.9 0-1-1-1.9-2.1-1.8z"/>
</symbol>
<symbol id="offline-outline-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M1.1 5.1c0-.5.4-1 1-1h.1c.2 0 .3-.1.4-.2.2-.8.9-1.4 1.8-1.4h.2l.3-.6c-.2 0-.3-.1-.5-.1-1 0-1.9.6-2.3 1.6-.9 0-1.6.8-1.6 1.7s.7 1.7 1.7 1.7h.4l.3-.6h-.7c-.6-.1-1.1-.5-1.1-1.1zM6.4 3c-.1-.2-.3-.4-.4-.5L6.7 1 6.1.7 2.6 8l.6.3.8-1.6h2.7c1 0 1.9-.8 1.9-1.9-.1-1-1.1-1.9-2.2-1.8zm.2 3.1H4.2l1.4-3c.2.1.3.3.4.4 0 .2.2.2.3.2h.3c.7 0 1.2.6 1.2 1.2 0 .7-.5 1.2-1.2 1.2z"/>
</symbol>
</svg>
<!-- CSS inline (to be removed) -->
<style type="text/css">
/* Layout*/
#app {padding-top: 7.25rem; overflow: hidden;}
#sidebar { left: 0; top: 0; bottom: 0; width: 20vw; min-width: 20rem; }
#header, #nav { position: absolute; display: inline-block; }
#nav { width: 100%; top: 4rem; text-align: center; z-index:1;}
#nav a .badge{ margin-left: 0.75em;}
#header, #main { padding: 0; margin:0; width: 100%;}
#main { padding: 2rem 0.5rem 0 0.5rem; display: flex; overflow-y: auto; height: calc(100vh - 7.25rem); z-index: 0; }
#header { padding: 0.75rem 0.5rem; top:0; line-break: no-wrap; }
#header-search { display: inline-block; width: auto; margin:0 1rem; float: right; }
#header-search .dropdown-menu { width:100%; top: 2.5rem; }
#header-search-results-placeholder { padding: 1em; display: inline-block; }
#header-search-results-placeholder .loading-ellipsis { margin-left: 1em; float: right; }
#navigation { display: inline-block; margin-left: 1rem; width: calc(100% - 9rem) }
#navigation > ul > li > a { font-weight: 600; }
#more, #logo, #hamburger, #navigation { margin-top: 0.2rem;}
#more { float:right; vertical-align: middle; width: 2em; height: 2em; line-height: 2.5; text-align: center; }
#more svg { height: 1.35em; }
#logo { height: 2em; line-height: 2em; position: relative; overflow: hidden; }
#logo svg { height: 2em;}
#logo figure { text-align: left; margin:0; padding:0; display: inline-block; position: relative; }
#logo figcaption { margin: 0 0 0 0.35rem; font-size: 2em; font-weight: bold; display: inline-block; vertical-align: top;}
#icons-wrapper .icons { text-align: center;}
#icons-wrapper .icons figure { display: none; margin:0;}
#icons-wrapper .icons figure.show { display: inline-block; }
#icons-wrapper .icons figcaption { display: block; margin:0; overflow: hidden; text-overflow: ellipsis; padding: .5em 1em; white-space: nowrap; }
#icons-wrapper .icon { height: 3em; margin: 0.5em; padding: 0.5em; color: currentColor; border-radius: 0.5em; cursor: pointer; transition: all 0.15s; -webkit-transition: all 0.15s; outline: 0; }
#icons-wrapper .icon:hover, #icons-wrapper .icon:focus { color: white; background-color: #333; transform-origin: center center; transform: scale(1.5); }
#icons-wrapper .icon::after { content: attr(data-content); display: inline-block; position: absolute; z-index: 1; bottom: .25em; }
#tab-tooltips fieldset { text-align: center; }
#tab-tooltips button { display: inline; min-width: 6em; margin: 0.5rem 0;}
#tab-tooltips button:first-of-type, #tab-tooltips button:last-of-type { float: none; clear: right; }
#tab-tooltips button:nth-of-type(2), #tab-tooltips button:nth-of-type(4) {float: none; max-width: 47.5%; margin-right:6em; margin-left: 0;}
#tab-tooltips button:nth-of-type(3), #tab-tooltips button:nth-of-type(5) {float: none; max-width: 47.5%; margin-left: 0; margin-right: 0; }
@media (max-width: 567.98px) { #tab-tooltips button:nth-of-type(2), #tab-tooltips button:nth-of-type(4) {float: left;} #tab-tooltips button:nth-of-type(3), #tab-tooltips button:nth-of-type(5) {float: right;} }
#tab-dropdowns form { clear: both; display: inline-block; width: 100%;}
#tab-dropdowns fieldset { width: 45%; display:block; float: left; }
#tab-dropdowns fieldset:last-child { float: right;}
#tab-dropdowns fieldset:last-child button { float: right;}
.tab-panels section h2 { font-weight: 200; font-size: 1.75em; }
</style>
<!-- Ui / App initialisation -->
<script type="text/javascript">
document.addEventListener('DOMContentLoaded', function(e){
// Build i18n object for ui
var lang = {
ok: 'ok',
cancel: 'abbrechen',
close: 'schliessen',
dismiss: 'ablehnen',
warning: 'Warnung',
alert: 'Hinweis',
confirm: 'Bestätigung',
prompt: 'Eingabe',
permission: 'Berechtigung',
error: 'Fehler',
errors: 'Fehler',
success: 'Alles klar',
permisssion: 'Berechtigung',
unload: 'Diese Seite verlassen?',
willnotbesaved: 'Änderungen werden möglicherweise nicht gespeichert.',
plus: 'plus',
minus: 'minus',
reveal: 'anzeigen',
hide: 'verstecken',
clear: 'löschen',
offline: 'Das Netzwerk ist nicht erreichbar. Daten werden zwischengespeichert.',
online: 'Das Netzwerk ist wieder erreichbar.',
dateformat: 'MM.DD.YYY H:m:s'
}
// Class initialization
var ui = new UI(lang);
// Trigger delayed notification
// setTimeout(function (){ notify('Do you really want to do this?', 'alert'); }, 5000)
// Scheme switch
switchScheme('#scheme-switch');
// Icon display
Icons('#ui-icons', '#icons-wrapper');
// Header search
Search();
// Download
var aJS = '#download-js', dataJS = '[href*="pen.js-52d862a5-3975-c7d8-e3ff-9bfa49b45d02"]',
aSCSS = '#download-scss', dataSCSS = '',
aCSS = '#download-css', dataCSS = '.INLINE_PEN_STYLESHEET_ID';
setDownload(aJS, dataJS, 'ux-framework', 'js');
// setDownload(aSCSS, dataJS, 'ux-framework', 'scss');
setDownload(aCSS, dataJS, 'ux-framework', 'css');
}, false);
// Functions
// Header search
function Search (){
var d = document,
input = d.getElementById('header-search-input'),
output = d.getElementById('header-search-results'),
placeholder = d.getElementById('header-search-results-placeholder'),
hasresults = false;
// Listeners:
input.addEventListener('input', show, false);
// input.addEventListener('focusin', show, false);
// input.addEventListener('focusout', hide, false);
// Methods:
function search (key) {
var q = new RegExp(key, 'gi'),
els = d.querySelectorAll('section.tab-panel');
clear();
[].slice.call(els).forEach(function(el) {
if (el.textContent.match(q)) {
var a = d.createElement('a'),
txt = d.querySelector('.tab-list a[href="#'+ el.id +'"]').textContent;
a.href = '#'+ el.id;
a.setAttribute('role', 'menuitem');
a.innerHTML = txt;
output.insertBefore(a, placeholder);
hasresults = true;
}
});
if(hasresults) {
placeholder.className += ' hidden';
} else clear;
}
function show () {
if(this.value.length < this.minLength) return clear;
output.className += ' show';
setTimeout(function(){search(this.value);}, 2000);
}
function hide () {
if(!hasresults) return clear;
output.className = output.className.replace(/\bshow\b/gi, '').trim();
}
function clear () {
var previous = output.querySelectorAll('a');
if(previous) {
[].slice.call(previous).forEach(function(p){ output.removeChild(p); });
placeholder.className = placeholder.className.replace(/\bhidden\b/gi,'');
}
hasresults = false;
}
}
// Display SVG icons in a wrapper
function Icons (svg, wrap) {
var d = document;
wrap = typeof wrap === 'string' ? d.querySelector(wrap) : wrap;
svg = d.querySelector(svg);
var svgurl = svg ? false : true,
container = wrap.querySelector('.icons'),
search = wrap.querySelector('#search-icons');
if(!container) {
container = d.createElement('div');
wrap.appendChild(container);
}
container.className += ' icons';
container.innerHTML = ''; // Clean-up
if(svgurl){
var xhr = new XMLHttpRequest();
xhr.onreadystatechange = function() {
if (xhr.readyState === 4) {
svg = xhr.response;
console.log(svg);
}
};
xhr.open('GET', svgurl, true);
xhr.url = svgurl;
xhr.send();
}
var symbols = svg.querySelectorAll('symbol');
[].slice.call(symbols).forEach( function(symbol){
var icon = d.createElementNS('http://www.w3.org/2000/svg', 'svg'),
figure = d.createElement('figure'),
caption = d.createElement('figcaption'),
id = symbol.getAttribute('id'),
keywords = id.replace(/-/gi,' ');
icon.innerHTML = symbol.innerHTML;
icon.setAttribute('viewBox', symbol.getAttribute('viewBox'));
icon.id = 'icon-'+ id;
icon.setAttribute('tabindex', 0);
icon.setAttribute('class', 'icon');
icon.setAttribute('fill', 'currentColor');
figure.className = 'show';
figure.setAttribute('data-offset', 16);
figure.setAttribute('title', 'ID: #'+ id);
figure.setAttribute('data-keywords', keywords);
caption.innerHTML = keywords.replace(/icon/gi,'').trim();
figure.appendChild(icon);
figure.appendChild(caption);
figure.addEventListener('click', function(e){ smoothUIScroll(container); },false);
container.appendChild(figure);
});
// Icon search function
if(search) {
search.addEventListener('keyup', function (){
var query = this.value.toLowerCase().replace(/\s+/g, ' ');
[].slice.call(container.querySelectorAll('figure')).forEach(function(fig){
var keywords = fig.getAttribute('data-keywords'),
match = (keywords.toLowerCase().replace(/\s+/g, '').indexOf(query) != -1);
if(match) fig.className += ' show';
else fig.className = fig.className.replace(/\bshow\b/g, '').trim();
});
}, false);
search.focus();
}
}
// Set download data URL and link
function setDownload (a, data, name, type) {
a = a instanceof Element ? a : document.querySelector(a);
data = data instanceof Element ? data : document.querySelector(data);
if(!a || !data) return;
a.href = 'data:text/'+ type +';charset=utf-8,' + encodeURIComponent(data.innerHTML);
a.download = name +'.'+ type;
}
</script>
</body>

Responsive & Accessible App UI/UX Framework

UI: Title, inputs, dialogs, notifications, dropdowns, swipe / drag actions

Compatibility: FF, Chrome, IE 9+, WAI ARIA W3C (a11ya) rich internet applications recommendations for maximum accessibility. No dependencies whatsoever.

Language: Internationalization (i18n) with language object Last change: 2021.11.13, 21:20h Note: Adapted Bootstrap 3/4 CSS selectors to run without Bootstrap files.

A Pen by Dan on CodePen.

License.

// Responsive & Accessible App UI/UX Framework
// -------------------------------------------
// UI: Title, inputs, dialogs, notifications, dropdowns, swipe / drag actions
// Compatibility: FF, Chrome, IE 9+, WAI ARIA W3C (a11ya) rich internet applications
// recommendations for maximum accessibility. No dependencies whatsoever.
// Language: Internationalisation (i18n) with language object
// Last change: 2021.11.13, 21:20h
// Note: Adapted Bootstrap 3/4 css selectors to run without it's own css
function UI(i18n, icons) {
'use strict';
// Monkey patching / adding some functions to Element prototypes
var w = window, d = w.document, n = navigator;
var raf = w.requestAnimationFrame || w.webkitRequestAnimationFrame || w.mozRequestAnimationFrame || function(c){ setTimeout(c, 16, Date.now()); return true;};
var ep = Element.prototype;
if(!ep.matches) ep.matches = ep.matchesSelector || ep.msMatchesSelector || ep.webkitMatchesSelector || ep.mozMatchesSelector;
if(!ep.closest) ep.closest = function(s){ var el = this; while (el.matches && !el.matches(s)) el = el.parentElement; return el.matches ? el : null; };
if(!ep.setAttributes) ep.setAttributes = function(o) { for(var key in o) this.setAttribute(key, o[key]); };
// Passive listener feature detection
var hasPassive = false
try { w.addEventListener('test', null, Object.defineProperty({}, 'passive', { get: function() { hasPassive = { passive: true }; } })); }
catch(err) {}
// UI class settings / i18n / SVGs
i18n = i18n ? i18n : {
ok: 'ok',
cancel: 'cancel',
close: 'close',
dismiss: 'dismiss',
alert: 'alert',
warning: 'warning',
confirm: 'confirm',
prompt: 'prompt',
error: 'error',
errors: 'errors',
success: 'success',
permisssion: 'permmission',
unload: 'Leave this page?',
willnotbesaved: 'Changes will not be saved.',
plus: 'plus',
minus: 'minus',
reveal: 'reveal',
hide: 'hide',
clear: 'clear',
offline: 'The network is not reachable. Your data will be cached.',
online: 'The network connection was re-established.'
};
icons = icons ? icons : {
ok: '<path fill="none" stroke="currentColor" d="M8 1L4 8 1 6"/>',
warn: '<path d="M4.5,0.5L0.3,8h8.5L4.5,0.5z M5,7.3H4V6.5h1V7.3z M4,6V3h1v3H4z"/>',
note: '<path d="M4.5 8.5c-.5 0-.7-.4-.7-.9h1.5c0 .5-.4.9-.8.9zM7 6l.8 1v.3H1.3V7L2 6V4c0-1.3.8-2.2 2-2.5V1c0-.3.2-.5.5-.5s.5.2.5.5v.5c1.2.3 2 1.3 2 2.5v2z"/>',
close: '<path d="M8.4 1.4L7.6.6 4.5 3.8 1.4.6l-.8.8 3.2 3.1L.6 7.6l.8.8 3.1-3.2 3.1 3.2.8-.8-3.2-3.1z"/>',
reveal: '<path d="M4.5,4.2c-0.7,0-1.4,0.6-1.4,1.4S3.7,7,4.5,7s1.4-0.6,1.4-1.4S5.2,4.2,4.5,4.2z M4.5,2C2,2,0,3.6,0,5.6h1C1,4.1,2.5,3,4.5,3C6.4,3,8,4.1,8,5.6h1C9,3.6,7,2,4.5,2z"/>',
hide: '<path d="m7.4 2.9-.7.7C7.5 4 8 4.8 8 5.6h1c0-1.1-.6-2.1-1.6-2.7zM3.6 6.7c.2.2.5.3.9.3.8 0 1.4-.6 1.4-1.4 0-.3-.1-.6-.3-.9l-2 2zM4.5 3h.2l.9-.9C5.3 2 4.9 2 4.5 2 2 2 0 3.6 0 5.6h1C1 4.1 2.5 3 4.5 3zM.68 7.75 7.75.68l.57.57-7.07 7.07z"/>',
copy: '<path d="M6.8 6.8V3.5h1.5v4.8H3.5V6.8h3.3zm-1-1V1.3H1.3v4.5h4.5zm.5.5H.8V.8h5.5v5.5z"/>',
offline: '<path d="M6.8 6.8V3.5h1.5v4.8H3.5V6.8h3.3zm-1-1V1.3H1.3v4.5h4.5zm.5.5H.8V.8h5.5v5.5z"/>',
notallow: '<path d="m2.2 5.9 3.7-3.7c-.4-.2-.9-.4-1.4-.4C3 1.8 1.8 3 1.8 4.5c0 .5.2 1 .4 1.4zm4.6-2.8L3.1 6.8c.4.2.9.4 1.4.4C6 7.2 7.2 6 7.2 4.5c0-.5-.2-1-.4-1.4zM4.5.5c2.2 0 4 1.8 4 4s-1.8 4-4 4-4-1.8-4-4 1.8-4 4-4z"/>'
};
// Keyboard Key Codes
var keys = { backspace:8, tab:9, return:13, shift:16, pause:19, esc:27, space:32, pgup:33, pgdown:34, end:35, home:36, left:37, up:38, right:39, down:40, add:107, substract:109 };
// Register changes in document inputs
var hasChanged = changed(d, 'hasChanged');
// Global audio setting
var allowAudio = true;
var allowVibration = true;
var allowNotifications = false;
// Make UI functions available in window namespace
w.allowUIAudio = function(s){ allowAudio = s || allowAudio; return allowAudio; };
w.allowUIVibration = function(s){ allowVibration = s || allowVibration; return allowVibration; };
w.allowUINotifications = function(s){ allowNotifications = s || allowNotifications; return allowNotifications; };
w.smoothUIScroll = function(l, r, ms){ smoothScroll(l, r, ms); };
w.switchScheme = function(el){ Scheme(el); }
// Check for duplicate IDs
checkDuplicateIds();
// Native UI overwrites
w.alert = function(m, o, c) { new Alert(m, o, c); };
w.confirm = function(m, o, c) {new Confirm(m, o, c); };
w.prompt = function(m, v, o, c) { new Prompt(m, v, o, c); };
w.dialog = function(m, v, o, c) { new Dialog(m, v, o, c); };
w.notify = function(m, t, o, c) { new Notify(m, t, o, c); };
w.toast = function(m, t, o) { new Toast(m, t, o); };
// On unload message
w.addEventListener('beforeunload', Unload, true);
// Try hiding address bar
w.addEventListener('load', function(e) {
setTimeout(function(){ w.scrollTo(0, 1); }, 0);
}, hasPassive);
// Check DOM for ui element / add functionality to inline trigger
w.addEventListener('DOMContentLoaded', function(e) {
// Mobile viewport hack
setViewport(e);
// Native title Overwrite
Tooltips(e);
// Inline modal dialog triggers
[].slice.call(d.querySelectorAll('[data-toggle="modal"]')).forEach(function(mt){
var mo = mt.hash ? d.getElementById(mt.hash.substring(1)) : d.getElementById(mt.getAttribute('data-target'));
if (mo) mt.addEventListener('click', function(e){ new Modal(mo, {}); }, false);
});
// Dropdown togglers
[].slice.call(d.querySelectorAll('[data-toggle="dropdown"]')).forEach(function(dd){
dd.addEventListener('click', function(e){ new Dropdown(e); }, false);
});
// Tabs
[].slice.call(d.querySelectorAll('[role="tablist"]')).forEach(function(tl){
new Tabs(tl);
});
// Ripples
[].slice.call(d.querySelectorAll('.ripple')).forEach(function(rp){
rp.addEventListener('click', function(e){ new Ripple(e); }, false);
});
// Collapse togglers
[].slice.call(d.querySelectorAll('[data-toggle="collapse"]')).forEach(function(cl){
cl.addEventListener('click', function(e){ new Collapse(e); }, false);
});
// Range inputs
[].slice.call(d.querySelectorAll('[type="range"]')).forEach(function(ri){
new rangeInput(ri);
});
// Number inputs
[].slice.call(d.querySelectorAll('[type="number"]')).forEach(function(ni){
new numberInput(ni);
});
// Password inputs
[].slice.call(d.querySelectorAll('[type="password"]')).forEach(function(pi){
new passwordInput(pi);
});
// Search inputs
[].slice.call(d.querySelectorAll('[type="search"]')).forEach(function(si){
new searchInput(si);
});
// Form validation
[].slice.call(d.querySelectorAll('form[data-validate="true"]')).forEach(function(fm){
new Validation(fm);
});
// Tests
// Toast(getRootVar('--ui-font'));
}, false);
// Public Methods:
// Alert modal dialog
function Alert(message, options, callback) {
new Modal('alert', options, message, null, callback);
}
// Confirm modal dialog
function Confirm(message, options, callback) {
new Modal('confirm', options, message, null, callback);
}
// Prompt modal dialog
function Prompt(message, value, options, callback) {
new Modal('prompt', options, message, value, callback);
}
// Generic modal dialog
function Dialog(content, value, options, callback) {
new Modal('dialog', options, content, null, callback);
}
// Notifications
function Notify(message, type, options, callback) {
new Note(type, message, options, callback);
}
// Before unload modal dialog
function Unload(e) {
if (hasChanged) {
new Modal('confirm unload', null, i18n.willnotbesaved, null);
w.removeEventListener('beforeunload', Unload, true);
}
}
// UI Methods:
// Modal dialogs
function Modal (type, options, message, value, callback) {
// Constructor
var TYPE = typeof type !== 'string' ? 'custom' : type,
MODAL = typeof type === 'string' ? create(type, options, message, value) : type,
CALLBACK = typeof callback === 'function' ? callback : null,
EVENT = w.event || d.event,
TRIGGER = EVENT ? EVENT.target : null,
isStatic = (MODAL.getAttribute('data-backdrop') === 'static') || !TYPE.match(/(custom|alert)/gi);
if (EVENT) EVENT.preventDefault();
open();
// Methods:
// Create ui modal dialog
function create(type, options, message, value) {
switch(type) {
case 'alert': i18n.title = 'alert'; break;
case 'confirm': i18n.title = 'confirm'; break;
case 'prompt': i18n.title = 'prompt'; break;
case 'confirm unload': i18n.title = i18n.unload; break;
default: i18n.title = 'notification';
}
i18n = options ? merge(i18n, options) : i18n;
var tpl = [
'<div class="modal-dialog ui-dialog '+ type +'" role="document">',
'<div class="modal-content"><div class="modal-header">',
'<h3 id="'+ type +'Title">'+ i18n.title +'</h3></div><div class="modal-body">',
(type.match(/prompt/gi)) ? '<label for="'+ type +'Input">'+ message +'</label>' : message,
(type.match(/prompt/gi)) ? '<input type="text" class="form-control" id="'+ type +'Input" value="'+ value +'" autofocus/>' : '',
'</div><div class="modal-footer">',
(type.match(/alert|info/gi)) ? '' : '<button type="button" class="btn btn-secondary" data-dismiss="modal">'+ i18n.cancel +'</button>',
'<button type="button" class="btn btn-primary">'+ i18n.ok +'</button>',
'</div></div></div>'
].join('');
var modal = d.createElement('div');
modal.id = 'ui-'+ type;
modal.className = 'modal ui-modal';
modal.setAttributes({
'tabindex': '-1',
'aria-hidden': true,
'aria-labelledby': type +'Title'
});
modal.innerHTML = tpl;
d.body.appendChild(modal);
return modal;
}
// Open modal
function open() {
scrollbar();
MODAL.removeAttribute('aria-hidden');
MODAL.setAttribute('aria-modal', true);
MODAL.setAttribute('open', '');
// Event listeners
if (isStatic) MODAL.addEventListener('click', makestatic, false);
else MODAL.addEventListener('click', closeclick, false)
MODAL.addEventListener('blur', trapFocus, true);
var cls = MODAL.querySelectorAll('[data-dismiss="modal"], .modal-footer button, [type="submit"]');
[].slice.call(cls).forEach(function(cl) {
cl.addEventListener('click', function(e){ close(MODAL, EVENT, CALLBACK); }, false);
})
MODAL.firstChild.addEventListener('click', nopropagate, false);
w.addEventListener('keydown', keylistener, false);
// Timeout needed for smooth CSS transitions & effects
setTimeout(function() {
if(!TYPE.match(/(prompt)/gi)) cls[cls.length - 1].focus();
else MODAL.querySelector('input').select();
setTimeout(function() { sound(); }, 160);
MODAL.className += ' show';
dispatchEvent('ui.modal.open', MODAL);
}, 1);
}
// Methods:
// Close / hide modal dialog
function close () {
MODAL.removeAttribute('aria-modal');
MODAL.removeAttribute('open');
MODAL.setAttribute('aria-hidden', true);
MODAL.className = MODAL.className.replace(/\bshow\b/g, '').trim();
w.removeEventListener('keydown', keylistener, false);
scrollbar();
// Dispatcher ?
dispatchEvent('ui.modal.close', MODAL);
if (CALLBACK) CALLBACK.call();
if (MODAL.id.match(/confirm/gi)) {
CALLBACK = TRIGGER.getAttribute('onclick') || TRIGGER.onclick;
if (typeof CALLBACK === 'function') TRIGGER.onclick = false;
else TRIGGER.removeAttribute('onclick');
TRIGGER.click();
if (typeof CALLBACK === 'function') TRIGGER.onclick = CALLBACK;
else TRIGGER.setAttribute('onclick', CALLBACK);
}
smoothScroll(TRIGGER);
if ('focus' in TRIGGER) TRIGGER.focus();
if (!TYPE.match(/custom/gi)) remove(MODAL);
}
// Remove Modal from DOM
function remove (el) {
setTimeout(function(){
el.parentNode.removeChild(el);
dispatchEvent('ui.modal.destroy', el);
}, 500);
}
// Hide / disable scrollbars if any
function scrollbar() {
var width = parseInt(w.innerWidth - d.documentElement.clientWidth, 10);
if(width > 0) {
d.body.style.paddingRight = width +'px';
d.body.className = d.body.className + ' modal-open'.trim()
} else if (d.body.className.match(/(modal-open)/gi)) {
d.body.style.paddingRight = '';
d.body.className = d.body.className.replace('modal-open','').trim();
}
}
// Make modal static
function makestatic (e){
var el = this;
el.className += ' modal-static';
vibration([500]);
setTimeout(function(){
el.className = el.className.replace(/\b(modal-static)\b/g, '').trim();
el.querySelector('button:first-of-type').focus();
}, 500);
}
// Click on modal only closes dialog
function closeclick (e){
if(!isTarget(e, MODAL.firstChild)) close();
}
}
// Notifications:
function Note (type, message, options, callback) {
var WRAP = d.getElementById('ui-notifications') ? d.getElementById('ui-notifications') : wrap(),
TYPE = type ? type.toLowerCase() : '',
IMG = options ? (options.image ? options.image : null) : null,
MSG = message,
NOTE = create();
show();
// Methods:
// Create wrapper
function wrap () {
var el = d.createElement('div');
el.id = 'ui-notifications';
el.className = 'ui-notifications';
el.setAttributes({'tabindex': '-1', 'aria-live': 'polite', 'aria-relevant': 'additions removals'});
el.innerHTML = '<a href="#!" class="counter" role="region" aria-live="polite"></a>'
d.body.appendChild(el);
return el;
}
// Create notification
function create () {
i18n.title = TYPE.match(/(error)/gi) ? 'error' : TYPE.match(/(warn)/gi) ? 'warning' : TYPE.match(/(success)/gi) ? 'success' : 'notification';
var ico = icons[TYPE.match(/(error)/gi) ? 'close' : TYPE.match(/(warning)/gi) ? 'warn' : TYPE.match(/(success)/gi) ? 'ok' : 'note'] ;
var fig = IMG ? '<img src="'+ IMG +'"/>' : '<svg viewbox="0 0 9 9">'+ ico +'</svg>';
var tpl = [
'<figure aria-label="icon '+ TYPE +'">'+ fig +'</figure>',
'<p><b>'+ i18n.title +'</b> '+ MSG +'</p>',
'<a href="#!" class="close" role="button">'+ i18n.close +'</a>',
'<time timestamp="'+ Date.now() +'"></time>',
'<div class="progress"><i role="progressbar" aria-valuemin="0" aria-valuemax="1"></i></div>'
].join(''),
note = d.createElement('div');
note.id = 'note-'+ Math.random().toString(36).substr(2, 8);
note.className = 'note' + (TYPE ? ' note-'+ TYPE : '');
note.setAttributes({
'role': 'alert',
'aria-live': 'assertive',
'aria-atomic': true,
'tabindex': 0,
'draggable': ''
});
note.innerHTML = tpl;
return note;
}
// Show notification
function show () {
var progress = NOTE.querySelector('.progress i'),
close = NOTE.querySelector('.close'),
timed = TYPE.match(/(timed)/gi),
time = NOTE.querySelector('time'),
img = NOTE.querySelector('figure svg, figure img');
ago(time);
close.addEventListener('click', remove, false);
if(timed) {
NOTE.className += ' timed';
addPrefixedListener(progress, 'AnimationEnd', remove);
}
WRAP.insertAdjacentElement('afterbegin', NOTE);
// Timeout needed for smoootth CSS transitions & effects
setTimeout(function() {
NOTE.className += ' show';
NOTE.focus();
sound();
new Swipe(NOTE, 'x', WRAP, function(gesture){
if(gesture === 'left') remove();
if(gesture === 'right') hide();
}, true);
// vibration([400]);
if (!d.hasFocus()) notification(TYPE, MSG, img ? (img.src ? img.src : png64(img)) : null, null, audiopool.pop );
dispatchEvent('ui.notification.show', NOTE);
}, 1);
}
// Hide notification after timeout
function hide () {
WRAP.className = NOTE.className.replace(/\bshow\b/g, '').trim();
dispatchEvent('ui.notification.hide', NOTE);
}
// Delete notification
function remove () {
NOTE.className = NOTE.className.replace(/\bshow\b/g, '').trim();
setTimeout(function() {
WRAP.removeChild(NOTE);
dispatchEvent('ui.notification.destroy', NOTE);
}, 500);
}
}
// Dropdown
function Dropdown(e) {
var TRIGGER = e.target || w.event.target,
PARENT = getClosest(TRIGGER, '.dropdown'),
MENU = d.querySelector('[aria-labelledby="'+ TRIGGER.id +'"]'),
isPersistent = TRIGGER.getAttribute('data-persist') === 'true',
isExpanded = TRIGGER.getAttribute('aria-expanded') === 'true';
if(MENU){
prevent(e);
d.addEventListener('scroll', position, hasPassive);
w.addEventListener('resize', position, false);
w.addEventListener('orientationchange', position, false);
if(!isPersistent) d.addEventListener('click', hide, true);
if(!isPersistent) MENU.addEventListener('click', hide, false);
toggle(e);
}
// Methods:
function toggle (e) {
isExpanded ? hide(e) : show(e);
}
function show (e) {
TRIGGER.setAttribute('aria-expanded', true);
PARENT.className += ' show';
MENU.className += ' show';
position(e);
dispatchEvent('ui.dropdown.show', MENU);
}
function hide (e) {
d.removeEventListener('scroll', position, hasPassive);
w.removeEventListener('resize', position, false);
w.removeEventListener('orientationchange', position, false);
if(!isPersistent) d.removeEventListener('click', hide, true);
TRIGGER.setAttribute('aria-expanded', false);
PARENT.className = PARENT.className.replace('show','').trim()
MENU.className = MENU.className.replace('show','').trim();
dispatchEvent('ui.dropdown.hide', MENU);
}
function position (e) {
var s = w.getComputedStyle(TRIGGER),
align = TRIGGER.getAttribute('data-align') || '',
offset = parseInt(TRIGGER.getAttribute('data-offset'),10) || 5,
margin = {
top: parseInt(s.marginTop,10),
right: parseInt(s.marginRight,10),
bottom: parseInt(s.marginBottom,10),
left: parseInt(s.marginLeft,10)
},
vh = d.documentElement.clientHeight, vw = d.body.clientWidth,
tH = TRIGGER.offsetHeight, tT = TRIGGER.offsetTop, tL = TRIGGER.offsetLeft,
mH = MENU.offsetHeight, mW = MENU.offsetWidth,
hT, hR, hB, hL;
MENU.style.top = tH + margin.top + offset +'px';
MENU.style.right = 'auto';
MENU.style.left = 0;
if(!align || align.match(/(top|bottom)/gi)) {
if(align.match(/top/gi)) MENU.style.top = -(mH + offset - margin.top) +'px';
}
if(align && align.match(/(right|left)/gi)) {
if(align.match(/left/gi)) MENU.style.left = tL - offset +'px';
if(align.match(/right/gi)) {MENU.style.left = 'auto'; MENU.style.right = 0}
}
}
}
/// Collapse
function Collapse(e) {
var TRIGGER = e.target || w.event.target,
TARGETS = [],
BACKDROP = d.getElementById('backdrop'),
TEXT = TRIGGER.getAttribute('data-expanded'),
isExpanded = TRIGGER.getAttribute('aria-expanded') === 'true';
if(TEXT && !TRIGGER.hasAttribute('data-original-text')) TRIGGER.setAttribute('data-original-text', TRIGGER.textContent);
if(BACKDROP) BACKDROP.addEventListener('click', hide, false);
if(TRIGGER.hash) TARGETS.push(d.getElementById(TRIGGER.hash.substr(1)));
if(TRIGGER.getAttribute('aria-controls') !== null) {
var ctrls = TRIGGER.getAttribute('aria-controls').trim().replace(' ',',').split(',');
for(var i = 0; i < ctrls.length; i++) {
if(d.getElementById(ctrls[i])) TARGETS.push(d.getElementById(ctrls[i]));
}
}
prevent(e);
if (isExpanded) hide();
else {
if(TEXT) TRIGGER.textContent = TEXT;
for(var i = 0; i < TARGETS.length; i++) show(TARGETS[i]);
}
// Methods:
function show (el){
var dismiss = el.querySelectorAll('[data-dismiss="drawer"]');
TRIGGER.setAttribute('aria-expanded', true);
el.className += el.className.match(/\bshow\b/gi) ? '' : ' show';
if(dismiss) {
for(var i = 0; i < dismiss.length; i++) dismiss[i].addEventListener('click', hide, false);
}
dispatchEvent('ui.collapse.show', el);
}
function hide (){
if(TEXT) TRIGGER.textContent = TRIGGER.getAttribute('data-original-text');
for(var i = 0; i < TARGETS.length; i++){
TARGETS[i].className = TARGETS[i].className.replace(/\bshow\b/gi,'').trim();
dispatchEvent('ui.collapse.hide', TARGETS[i]);
}
TRIGGER.setAttribute('aria-expanded', false);
}
}
/// Tabs
function Tabs (el) {
var LIST = el,
TABS = LIST.querySelectorAll('[aria-controls]'),
CURR = LIST.hasAttribute('data-current') ? current(LIST.getAttribute('data-current')) : false,
STEPS = LIST.className.match(/\bstep-list\b/gi) && d.querySelector('[data-steplist="'+ LIST.id +'"]'),
SCROLL = LIST.hasAttribute('data-scroll'),
TIND = LIST.querySelector('.indicator'),
PANELS = [], SWIPE = false, PIND = false;
if(TABS) getPanels(TABS);
if(SCROLL) mousescroll();
// Global Listeners:
if(TIND) d.addEventListener('scroll', indicateTab, hasPassive);
if(TIND) w.addEventListener('resize', indicateTab, false);
if(TIND) w.addEventListener('orientationchange', indicateTab, false);
w.addEventListener('hashchange', init, false);
w.addEventListener('DOMContentLoaded', init, false);
// Methods:
function init () {
var tab = LIST.querySelector('[href="'+ w.location.hash +'"]'),
active = tab ? !tab.className.match(/\bactive\b/ig) && tab.getAttribute('aria-selected') != 'true' : false;
if(active) tab.click();
}
function getPanels (tabs) {
if(!tabs) return;
[].slice.call(tabs).forEach(function(tab){
var panel = tab.hash ? d.getElementById(tab.hash.substr(1)) : d.querySelector('[aria-labelledby="'+ tab.getAttribute('aria-controls') +'"]');
if(!panel) return;
PANELS.push(panel);
if(!SWIPE) SWIPE = panel.closest('.tab-panels').hasAttribute('data-swipe');
set(tab, panel);
});
PIND = PANELS[0] && PANELS[0].closest('.tab-panels').getAttribute('data-indicate') === 'true' ? indicator() : false;
}
function set (tab, panel) {
tab.addEventListener('click', function(e){ e.preventDefault(); show(tab, panel); }, false);
if(!STEPS) {
var i = [].indexOf.call(TABS, tab),
first = TABS[0],
last = TABS[TABS.length-1],
prev = i === 0 ? last : TABS[i-1],
next = i < TABS.length-1 ? TABS[i+1] : first;
onKey('right', tab, function(){ next.click(); next.focus(); });
onKey('left', tab, function(){ prev.click(); prev.focus(); });
onKey('space', tab, function(){ tab.click(); });
onKey('home', tab, function(){ first.click(); first.focus(); });
onKey('end', tab, function(){ last.click(); last.focus(); });
}
if(tab.getAttribute('aria-selected') === 'true') tab.click();
}
function show (tab, panel) {
// Reset all tabs and panels
reset();
if(!STEPS) {
var i = [].indexOf.call(PANELS, panel),
next = i < PANELS.length-1 ? PANELS[i+1] : PANELS[0],
prev = i === 0 ? PANELS[PANELS.length - 1] : PANELS[i-1];
prev.className += ' previous';
next.className += ' next';
if(SWIPE) new Swipe(panel, panel.parentElement.getAttribute('data-swipe'), panel, function(swipe) {
var i = [].indexOf.call(TABS, tab),
prev = i === 0 ? TABS[TABS.length - 1] : TABS[i-1],
next = i < TABS.length-1 ? TABS[i+1] : TABS[0];
if(swipe.direction === 'right') { prev.click(); return; }
else if(swipe.direction === 'left') { next.click(); return; }
}, true); // false = do not remove listeners after swipe is completed.
}
else navigation(tab, panel);
// Set tab & panel active
tab.className += ' active';
tab.setAttribute('aria-selected', true);
tab.setAttribute('tabindex', '-1');
panel.className += ' active';
panel.setAttribute('tabindex', 0);
setTimeout(function(){ panel.className += ' show'; }, 10);
// Set hash / history /**/
if (w.history.pushState) w.history.pushState({}, d.title +' - '+ tab.textContent, '#'+ panel.id);
else w.location.hash = '#' + panel.id;
if(SCROLL) position(tab);
if(CURR) tab.appendChild(CURR);
if(TIND) indicateTab();
if(PIND && !STEPS) indicatePanel(panel.id);
dispatchEvent('ui.tabs.show', panel);
}
function reset () {
PANELS.forEach(function(p){
p.setAttribute('tabindex', '-1');
p.className = p.className.replace(/\bactive|show|previous|next\b/gi,'').trim();
dispatchEvent('ui.tabs.hide', p);
});
[].slice.call(TABS).forEach(function(t){
t.setAttribute('aria-selected', false);
t.setAttribute('tabindex', 0);
t.setAttribute('draggable', false);
t.className = t.className.replace(/\bactive\b/gi,'').trim();
});
}
function validate (tab, panel, next) {
panel.className = panel.className.replace(/\bvalid\b/gi,'').trim();
tab.className = tab.className.replace(/\bdone\b/gi,'').trim();
if (Validation(panel)) {
panel.className += ' valid';
tab.className += ' done';
next.click();
}
}
function navigation (tab, panel) {
var i = [].indexOf.call(TABS, tab),
next = i < (TABS.length-1) ? TABS[i+1] : false,
prev = i === 0 ? false : TABS[i-1],
v = panel.closest('form').contains(panel) && panel.closest('form').matches('[data-validate="true"]'),
done = tab.className.match(/\bdone\b/gi) && panel.className.match(/\bvalid\b/gi),
btnPrev = STEPS.querySelector('button:first-child'),
btnNext = STEPS.querySelector('button:last-child');
btnPrev.disabled = true;
btnPrev.hidden = true;
btnNext.type = 'button';
if(!prev) {
btnNext.onclick = function(e){
if(v && !done) validate(tab, panel, next);
else { tab.className += ' done'; next.click(); }
};
}
else if (!next) {
btnPrev.disabled = false;
btnPrev.hidden = false;
btnNext.type = 'submit';
btnPrev.onclick = function(e){ prev.click(); };
}
else {
btnPrev.disabled = false;
btnPrev.hidden = false;
btnPrev.onclick = function(e){ prev.click(); };
btnNext.onclick = function(e){
if(v && !done) validate(tab, panel, next);
else { tab.className += ' done'; next.click(); }
};
}
}
function position (tab) {
LIST.setAttribute('scrolling','');
LIST.scrollLeft = tab.offsetLeft;
LIST.removeAttribute('scrolling');
}
function current (string) {
var i = d.createElement('i');
i.innerHTML = string;
i.className = 'visually-hidden';
return i;
}
function indicateTab () {
var active = LIST.querySelector('[aria-selected="true"]');
TIND.style.width = active.offsetWidth +'px';
TIND.style.left = active.offsetLeft +'px';
}
function indicatePanel (id) {
var all = PIND.querySelectorAll('a'),
active = PIND.querySelector('[href="#'+ id +'"]');
[].slice.call(all).forEach(function(a){ a.className = ''; });
active.className = 'active';
(active.previousElementSibling || all[all.length-1]).className = 'previous';
(active.nextElementSibling || all[0]).className = 'next';
}
function indicator () {
var wrap = d.createElement('div');
wrap.className = 'tab-panel-indicator';
PANELS[0].parentElement.appendChild(wrap);
PANELS.forEach(function(p){
var a = d.createElement('a'),
active = p.className.match(/\bactive\b/gi);
a.setAttributes({
'href': '#'+ p.id,
'id': p.id +'-indicator',
'aria-controls': p.id,
'aria-selected': active ? true : false,
'tabindex': '-1'
});
wrap.appendChild(a);
});
return wrap;
}
function mousescroll () {
var x, left, down = false;
// Event listeners:
LIST.addEventListener('mousedown', start, false);
LIST.addEventListener('mousemove', move, false);
LIST.addEventListener('mouseup', stop, false);
LIST.addEventListener('mouseleave', stop, false);
// Methods:
function start (e) {
LIST.setAttribute('drag', '');
down = true;
x = e.pageX - LIST.offsetLeft;
left = LIST.scrollLeft;
};
function stop (e) {
prevent(e);
LIST.removeAttribute('drag');
LIST.removeAttribute('dragging');
LIST.removeAttribute('dragging-horizontal');
down = false;
};
function move (e) {
if(!down) return;
prevent(e);
LIST.removeAttribute('drag');
LIST.setAttribute('dragging', '');
LIST.setAttribute('dragging-horizontal', '');
var pX = e.pageX - LIST.offsetLeft,
scroll = pX - x;
LIST.scrollLeft = left - scroll;
}
}
}
// Tooltips
function Tooltips (options) {
var TIPS = d.querySelectorAll('[title]'),
OFFSET = 9;
[].slice.call(TIPS).forEach(function(tip){
if (tip.getAttribute('title') !== null) {
tip.addEventListener('mouseenter', show, false);
tip.addEventListener('mouseleave', hide, false);
tip.addEventListener('focus', show, false);
tip.addEventListener('blur', hide, false);
}
});
// Methods:
function remove(e){
var trigger = this || (e || w.event).target,
tip = d.getElementById(trigger.getAttribute('aria-describedby'));
if(tip){
d.body.removeChild(tip);
d.removeEventListener('scroll', function(){ position(trigger, tip); }, hasPassive);
d.removeEventListener('resize', function(){ position(trigger, tip); }, false);
d.removeEventListener('orientationchange', function(){ position(trigger, tip); }, false);
trigger.setAttribute('title', trigger.getAttribute('data-original-title'));
trigger.removeAttribute('data-original-title');
dispatchEvent('ui.tooltip.destroy', tip);
}
}
function hide (e){
var trigger = this || (e || w.event).target,
tip = d.getElementById(trigger.getAttribute('aria-describedby'));
if(tip) tip.setAttribute('aria-hidden', true);
dispatchEvent('ui.tooltip.hide', tip);
}
function show (e){
var trigger = this || (e || w.event).target,
tip = d.getElementById(trigger.getAttribute('aria-describedby'));
if(!tip) tip = create(trigger);
position(trigger, tip);
tip.setAttribute('aria-hidden', false);
d.addEventListener('scroll', function(){ position(trigger, tip); }, hasPassive);
w.addEventListener('resize', function(){ position(trigger, tip); }, false);
w.addEventListener('orientationchange', function(){ position(trigger, tip); }, false);
dispatchEvent('ui.tooltip.show', tip);
}
// Helper methods
function position(trigger, tip){
var align = trigger.getAttribute('data-tooltip'),
offset = trigger.hasAttribute('data-tooltip-offset') ? trigger.getAttribute('data-tooltip-offset') : OFFSET,
vh = d.documentElement.clientHeight, vw = d.body.clientWidth,
sY = w.scrollY || w.pageYOffset, sX = w.scrollX || w.pageXOffset,
rect = trigger.getBoundingClientRect(),
tW = rect.width, tH = rect.height,
tL = rect.left + sX, tT = rect.top + sY,
X = tL + tW/2, Y = tT + tH/2,
W = tip.offsetWidth, H = tip.offsetHeight;
var css = tip.style, icss = tip.querySelector('.indicator').style;
var hT, hB, hR, hL;
tip.className = 'ui-tooltip'+ ((align) ? ' '+ align : '');
css.top = (tT - H - offset) +'px';
css.left = (X - W/2) +'px';
if(!align || align.match(/(top|bottom)/gi)) {
hT = (tT - sY) - H <= 0;
hB = (tT - sY) + (tH + offset + H) >= vh;
hR = (X + W/2) >= vw;
hL = (X - W/2) <= 0;
if(align === 'bottom') { css.top = (tT + tH + offset) +'px'; }
if((hT && hB) || (hL && hR)) return;
if(hT) { tip.className = 'ui-tooltip bottom'; css.top = (tT + tH + offset) +'px'; }
if(hB) { tip.className = 'ui-tooltip'; css.top = (tT - tH - offset) +'px'; }
if(hL) { css.left = offset +'px'; icss.left = tW/2 +'px'; }
if(hR) { css.left = vw - (offset + W) +'px'; icss.left = 'auto'; icss.right = tW/2 + offset +'px'; }
}
if(align && align.match(/(right|left)/gi)) {
hR = (tL + tW + W + offset) >= vw ;
hL = tL - (W + offset) <= 0;
if((hL && hR)) return tip.className = 'ui-tooltip';
css.top = (Y - H/2) +'px';
if(align === 'right') css.left = (tL + tW + offset) +'px';
if(align === 'left') css.left = (tL - W - offset) +'px';
if(hR) { tip.className = 'ui-tooltip left'; css.left = (tL - W - offset) +'px'; }
if(hL) { tip.className = 'ui-tooltip right'; css.left = (tL + tW + offset) +'px'; }
}
}
function create (trigger){
var tip = d.createElement('div'),
content = trigger.getAttribute('title'),
sanitized = d.createTextNode(content);
tip.id = 'tooltip-'+ Math.random().toString(36).substr(2, 8);
tip.setAttribute('role', 'tooltip');
tip.className = 'ui-tooltip';
tip.innerHTML = '<i class="indicator" aria-hidden="true"></i>';
tip.appendChild(sanitized);
tip.setAttribute('aria-hidden', true);
trigger.setAttribute('aria-describedby', tip.id);
trigger.removeAttribute('title');
trigger.setAttribute('data-original-title', sanitized.textContent);
d.body.insertAdjacentElement('beforeend', tip);
return tip;
}
}
// Toasts
function Toast(message, type, ms) {
var MS = ms ? parseInt(ms, 10) : 10000,
TOAST = d.getElementById('ui-toast'),
TYPE = type ? type : '',
TXT = message ? message.message || message.toString() : i18n.unknown;
if(!TOAST) { TOAST = d.createElement('div'); TOAST.id = 'ui-toast'; }
clearTimeout(w.toastTimeout);
TOAST.className = TYPE;
TOAST.innerHTML = TXT;
TOAST.addEventListener('click', close, false);
d.body.appendChild(TOAST);
TOAST.className += ' visible';
dispatchEvent('ui.toast.show', TOAST);
// Autohide error / success toast
if(TYPE.match(/(error|success)/gi)) w.toastTimeout = setTimeout(close, MS);
// Method:
// Close Toast
function close (e){
TOAST.className += ' closing';
dispatchEvent('ui.toast.hide', TOAST);
setTimeout(function() { TOAST.removeAttribute('class'); }, 500);
clearTimeout(w.toastTimeout);
}
}
// Password Reveal Input
function passwordInput(el) {
var reveal = d.createElement('button'),
wrap = d.createElement('div'),
label = el.parentNode.querySelector('label'),
float = el.parentNode.className.match(/form-float-label/gi);
wrap.className = 'form-password';
el.setAttribute('tabindex', 0);
reveal.setAttributes({'class':'btn-reveal', 'type':'button', 'tabindex':-1, 'aria-label':i18n.reveal});
reveal.innerHTML = '<svg viewBox="0 0 9 9">'+ icons.reveal +'</svg>';
el.parentNode.insertBefore(wrap, el);
wrap.appendChild(el);
wrap.insertBefore(reveal, el.nextSibling);
if(label && float) wrap.insertBefore(label, reveal.nextSibling);
reveal.onclick = toggle;
// Check for changes
observe(el, set, {attributes: true});
// Methods:
function toggle () {
if(el.type != 'password') {
el.type = 'password';
reveal.innerHTML = '<svg viewBox="0 0 9 9">'+ icons.reveal +'</svg>';
reveal.setAttribute('aria-label', i18n.reveal);
} else {
el.type ='text';
reveal.innerHTML = '<svg viewBox="0 0 9 9">'+ icons.hide +'</svg>';
reveal.setAttribute('aria-label', i18n.hide);
}
el.focus();
}
function set () {
el.disabled ? reveal.setAttribute('disabled', true) : reveal.removeAttribute('disabled');
}
}
// Search Clear Input
function searchInput(el) {
var clear = d.createElement('button'),
wrap = d.createElement('div'),
label = el.parentNode.querySelector('label'),
float = el.parentNode.className.match(/form-float-label/gi);
wrap.className = 'form-search';
el.setAttribute('tabindex', 0);
clear.setAttributes({'class':'btn-clear', 'type':'button', 'tabindex':-1, 'aria-label':i18n.clear});
clear.innerHTML = '<svg viewBox="0 0 9 9">'+ icons.close +'</svg>';
el.parentNode.insertBefore(wrap, el);
wrap.appendChild(el);
wrap.insertBefore(clear, el.nextSibling);
if(label && float) wrap.insertBefore(label, clear.nextSibling);
clear.onclick = function(){ el.value = ''; el.focus(); };
// Check for changes
observe(el, set, {attributes: true});
// Method:
function set(){
el.disabled ? clear.setAttribute('disabled', true) : clear.removeAttribute('disabled');
}
}
// Input Number Spinner
function numberInput(el) {
var wrap = d.createElement('div'),
plus = d.createElement('button'),
minus = d.createElement('button'),
step = parseFloat(el.getAttribute('step'));
plus.innerHTML = '&plus;';
minus.innerHTML = '&minus;';
wrap.className = 'form-number';
el.setAttribute('tabindex', 0);
plus.setAttributes({'class':'btn', 'type':'button', 'tabindex':-1, 'aria-label':i18n.plus});
minus.setAttributes({'class':'btn', 'type':'button', 'tabindex':-1, 'aria-label':i18n.minus});
plus.onclick = function(){ el.stepUp(step); };
minus.onclick = function(){ el.stepDown(step); };
el.parentNode.insertBefore(wrap, el);
wrap.appendChild(el);
wrap.insertBefore(minus, el);
wrap.insertBefore(plus, el.nextSibling);
// Check for changes
observe(el, set, {attributes: true});
// Method:
function set(){
if (el.disabled) {
plus.disabled = true;
minus.disabled = true;
wrap.setAttribute('disabled', true);
}
else {
plus.disabled = false;
minus.disabled = false;
wrap.removeAttribute('disabled');
}
}
}
// Range Input
function rangeInput(el) {
var output = el.parentNode.querySelector('output'),
unit = el.getAttribute('data-unit'),
ini = el.defaultValue || el.value || 0;
if(!output) {
output = d.createElement('output');
el.parentNode.appendChild(output);
};
el.addEventListener('input', set, false);
el.form.addEventListener('reset', set, false);
set();
// Method:
function set(){
var min = parseFloat(el.min) || 0,
max = parseFloat(el.max) || 1,
value = el.value || ini,
r = 100/(max-min);
el.style.setProperty('--rangeValue', (value-min)*r);
output.setAttribute('aria-live', 'assertive');
output.innerHTML = (value-min)*r + (unit ? unit : '');
}
}
// Swipe
function Swipe (target, axis, zone, callback, remove, minPx) {
if(!target) return alert('No swipe target defined. Aborting...');
var self = this, root = d.documentElement;
remove = remove ? remove : false; // Remove initial listener from target?
axis = axis.match(/(x|h|hor|horiz|horizontal)/gi) ? 'h' : 'v';
zone = zone ? zone : target;
var ratio = w.devicePixelRatio || 1;
var x, y, sX = 0, sY = 0, eX = 0, eY = 0, dX, dY, deg, degV = 70, degH = 30,
minPx = minPx ? minPx*ratio : 35*ratio, minMs = 200, sT = null, eT = null,
distance, direction, duration, dragging = false;
target.removeAttribute('style');
// Event listeners
zone.addEventListener('mousedown', start, false);
zone.addEventListener('touchstart', start, hasPassive);
// Methods:
function start(e) {
if(e.target.tagName.match(/(input|textarea|select|button)/gi)) return;
if(dragging) end(e);
e.preventDefault();
var touches = e.changedTouches || e.touches;
sX = touches ? touches[0].screenX : e.clientX;
sY = touches ? touches[0].screenY : e.clientY;
eT = null; sT = e.timeStamp;
target.style = '';
dragging = true;
zone.setAttribute(axis === 'h' ? 'pan-x' : 'pan-y', '');
// zone.setAttribute('swiping', '');
// root.setAttribute('manipulating', '');
// target.setAttribute('noanimate', '');
// Event mouse listeners
zone.addEventListener('mousemove', move, false);
root.addEventListener('mouseup', end, false);
zone.addEventListener('mouseleave', end, false);
// Event touch listeners
zone.addEventListener('touchmove', move, hasPassive);
root.addEventListener('touchend', end, false);
zone.addEventListener('touchcancel', end, false);
}
function move(e) {
if(!dragging || !sT) return;
var touches = e.changedTouches || e.touches;
eX = touches ? touches[0].screenX : e.clientX;
eY = touches ? touches[0].screenY : e.clientY;
x = eX - sX;
y = eY - sY;
dX = Math.abs(x);
dY = Math.abs(y);
deg = Math.atan2(dY, dX)*(180/Math.PI);
if (axis === 'h' && deg > degH) return;
else if (axis === 'v' && deg < degV) return;
else raf(transform);
}
function end(e) {
e.preventDefault();
dragging = false;
eT = e.timeStamp;
dispatch(e);
target.removeAttribute('style');
zone.removeAttribute('swiping');
root.removeAttribute('manipulating');//
zone.removeAttribute(axis === 'h' ? 'pan-x' : 'pan-y');
// target.removeAttribute('noanimate');
sT = null; eT = null; deg = null;
distance = 0, direction = null;
// Remove mouse event listener
zone.removeEventListener('mousemove', move, false);
root.removeEventListener('mouseup', end, false);
zone.removeEventListener('mouseleave', end, false);
// Remove touch event listener
zone.removeEventListener('touchmove', move, hasPassive);
root.removeEventListener('touchend', end, false);
zone.removeEventListener('touchcancel', end, false);
}
function dispatch (e) {
duration = eT - sT;
var xy = Math.abs(x/y), yx = Math.abs(y/x);
if(Math.abs(x) + Math.abs(y) <= minPx/3) {
if(duration < minMs) callback({direction: 'tab', distance: 0, duration: duration});
else callback({direction: 'press', distance: 0, duration: duration});
return;
}
if(axis === 'h') {
if (eX <= sX && deg < degH) { distance = sX - eX; direction = 'left'; }
if (eX >= sX && deg < degH) { distance = eX - sX; direction = 'right'; }
} else {
if (eY <= sY && deg > degV) { distance = sY - eY; direction = 'up'; }
if (eY >= sY && deg > degV) { distance = eY - sY; direction = 'down'; }
}
if (distance > minPx && duration > minMs && direction) {
act(direction, distance, duration, e);
}
}
function act (direction, distance, duration, e) {
callback({ direction: direction, distance: distance, duration: duration });
if (remove) {
zone.removeEventListener('mousedown', start, false);
zone.removeEventListener('touchstart', start, hasPassive);
}
}
function transform() {
axis === 'h' ? y = 0 : x = 0;
target.style.webkitTransform = 'translate('+ x +'px,'+ y +'px)';
target.style.mozTransform = 'translate('+ x +'px,'+ y +'px)';
target.style.msTransform = 'translate('+ x +'px,'+ y +'px)';
target.style.oTransform = 'translate('+ x +'px,'+ y +'px)';
target.style.transform = 'translate('+ x +'px,'+ y +'px)';
}
}
// Form validation
function Validation (el){
var ERRORS = [],
RX = {
email: /^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/,
url: '[(http(s)?):\/\/(www\.)?a-zA-Z0-9@:%._\+~#=]{2,256}\.[a-z]{2,6}\b([-a-zA-Z0-9@:%_\+.~#?&//=]*)',
date: '\d{2,4}(\.|-|\/)\d{2}(\.|-|\/)\d{2,4}$',
time: '^((([0-1]?[0-9])|([2][0-3])):)?(([0-5][0-9]):)?([0-5][0-9])(\.\d{1,3})?$|^\d+(\.\d{1,3})?$',
datetime: '(0?[1-9]|[12][0-9]|3[01])[\/\-](0?[1-9]|1[012])[\/\-]\d{4}(\s\d{1,2}[:-]\d{2}([:-]\d{2,3})*)?',
number: '(^\d{1,10}$)',
password: '',
tel: '([+(\d]{1})(([\d+() -.]){5,20})([+(\d]{1})',
color: '^((rgb|hsl)(a?)\(([\d\.\-\s,]{5,})\)$)|^((#)(([0-9A-F]{3})$|([0-9A-F]{6})$))',
clearhtml: '(<script(\s|\S)*?<\/script>)|(<style(\s|\S)*?<\/style>)|(<!--(\s|\S)*?-->)|(<\/?(\s|\S)*?>)'
},
FORM = el.tagName.match(/form/gi),
SET = el instanceof Element ? el : d.querySelector(el);
if(FORM) {
SET.setAttribute('novalidate', true);
SET.addEventListener('submit', function(e) { e.preventDefault(); validate(SET); }, false);
}
else return validate(SET);
// Methods:
// Validate form / sets / form parts
function validate (set) {
var inputs = set.querySelectorAll('[required]:not(:disabled), [pattern]:not(:disabled)');
[].slice.call(inputs).forEach(function(i){ checkInput(i, set); });
if(ERRORS.length) scrollToError(set);
else if(FORM) set.submit();
else return true;
}
// Input validation
function checkInput(input, set) {
var group = input.closest('.form-group') || set,
label = input.closest('label') ? input.closest('label').innerText : input.getAttribute('placeholder') || input.id,
type = input.type.split('-')[0].toLowerCase(),
value = input.value.trim(),
error = input.getAttribute('data-error') || i18n.error +': '+ label,
pattern = input.getAttribute('pattern'),
min = input.getAttribute('min') || input.getAttribute('minlength'),
max = input.getAttribute('max') || input.getAttribute('maxlength'),
len = input.getAttribute('type') === ('number' || 'range') ? input.value : input.value.length;
if (value === '') setError(input, error, group, set);
else if (pattern && !RegExp(pattern, 'g').test(value)) setError(input, error, group, set);
else if (!pattern && !RegExp(RX[type] || '', 'g').test(value)) setError(input, error, group, set);
else if (min && min > len) setError(input, error, group, set);
else if (max && max < len) setError(input, error, group, set);
else removeError(input, group, set);
}
// Set error
function setError (input, error, group, set) {
var hasError = group.className.match(/\bhas-error\b/gi),
hasHint = group.querySelector('.hint');
if (!hasError) {
group.className += ' has-error';
group.setAttribute('title', error);
}
input.setAttribute('aria-invalid', true);
if(hasHint) input.setAttribute('aria-describedby', hasHint.id);
ERRORS.push({
'set': '#'+ set.id,
'input': '#'+ input.id,
'message': error
});
input.addEventListener('change', function(){ checkInput(input, set); }, hasPassive);
// input.addEventListener('keyup', function(){ checkInput(input, set); }, hasPassive);
if(FORM) group.form.addEventListener('reset', function(e) { removeError(input, group, set); }, false);
setTimeout(function(){ displayErrorBadge(set); }, 5);
}
// Remove error
function removeError(input, group, set) {
ERRORS.splice(ERRORS.indexOf('#'+ input.id), 1);
group.className = group.className.replace(/\bhas-error\b/gi,'').trim();
group.removeAttribute('title');
input.removeAttribute('aria-invalid');
input.className = input.className.replace(/is-error/gi,'').trim();
input.removeEventListener('change', function(){ checkInput(input, set); }, hasPassive);
// input.removeEventListener('keyup', function(){ checkInput(input, set); }, hasPassive);
if(FORM) group.form.removeEventListener('reset', function(e){ removeError(input, group, set); }, false);
setTimeout(function(){ displayErrorBadge(set); }, 5);
}
// Scroll to first error in set
function scrollToError (set){
var first = set.querySelector('.has-error'),
scroll = scrollParent(first.parentNode); // Scroll to label
if(scroll) smoothScroll(first, scroll);
first.querySelector('input, select, textarea').focus();
}
// Display badge in tab
function displayErrorBadge (set){
var isTabbed = set.closest('[role="tabpanel"]').contains(el);
if (!isTabbed) return;
var count = 0;
ERRORS.forEach(function(e){ if(e.set === '#'+set.id) count++; });
var panel = set.closest('[role="tabpanel"]'),
tab = d.querySelector('a[href="#'+ panel.id +'"]'),
badge = tab.querySelector('.badge');
if(tab) {
if(count <= 0) {
if(badge) tab.removeChild(badge);
return;
}
else if(!badge) {
badge = d.createElement('b');
tab.appendChild(badge);
}
badge.setAttributes({
'class': 'badge badge-circle badge-danger scale',
'aria-live': 'assertive',
'title': count +' '+ (count > 1 ? i18n.errors : i18n.error),
'data-tooltip': 'top'
});
badge.innerHTML = count;
}
}
}
// Backdrop
function Backdrop (el, color) {
var DROP = d.getElementById('backdrop');
if(!DROP) { DROP = d.createElement('div'); DROP.id = 'backdrop'; }
DROP.className = 'visible';
theme(w.getComputedStyle(DROP).backgroundColor);
// Methods:
function theme (bgcolor) {
var metas = ['theme-color', 'msapplication-navbutton-color', 'apple-mobile-web-app-status-bar-style'],
head = d.getElementByTagName('head')[0],
icon = head.querySelector('link[rel*=icon]'),
color = head.querySelector('meta["'+ metas[0] +'"]').getAttribute('content'),
style = head.querySelector('meta["'+ metas[2] +'"]').getAttribute('content'),
black = bgcolor.replace(' ','').match(/(#000|#000000|0,0,0)/gi) || style.match(/(black)/gi);
function set () {
metas.forEach(function(meta){
var entry = head.querySelector('meta["'+ meta +'"]');
if(!entry) head.insertAdjacentElement('beforeend', d.createElement('meta'));
entry.setAttribute('name', meta);
if(meta.match(/(status-bar)/gi)) entry.setAttribute('content', 'translucent' + black ? '-black' : '');
else entry.setAttribute('content', bgcolor);
});
}
function reset(e){
metas.forEach(function(meta){
var entry = head.querySelector('meta["'+ meta +'"]');
if(meta.match(/(status-bar)/gi)) entry.setAttribute('content', style);
else entry.setAttribute('content', color);
});
}
}
}
// Sccroll reveal when in viewport
function scrollReveal(selectors, reverse) {
var items = d.querySelectorAll(selectors);
// Listeners
w.addEventListener('orientationchange', set);
w.addEventListener('resize', set);
w.addEventListener('scroll', set);
set();
// Method
function set() {
[].slice.call(items).forEach(function(item){
var cn = item.className.replace(/(is-hidden|in-view)/g,'').trim();
if (inViewport(item)) item.className = (cn +' in-view').trim();
else item.className = (cn +' is-hidden').trim();
});
}
}
// Smooth scrolling
function smoothScroll(selectors, root, ms){
var MS = ms ? ms : 500,
ROOT = root && isElement(root) ? root : d.documentElement,
qubicFn = function (t) { return t*t*t; },
isNative = 'scroll-behavior' in ROOT.style,
isSingle = isElement(selectors);
if(!isSingle) {
[].slice.call(d.querySelectorAll(selectors)).forEach(function(el) {
ROOT = scrollParent(el);
el.addEventListener('click', isNative ? native : scroll, false);
});
}
else {
ROOT = scrollParent(selectors);
selectors.addEventListener('click', isNative ? native : scroll, false);
}
// API method, requires css scroll-behavior support
function native (e) {
var hash = this.hash || this.getAttribute('aria-controls') || this.getAttribute('data-target'),
target = hash ? d.getElementById(hash.replace(/#/g,'').trim()) : null,
offset = this.getAttribute('data-scrolloffset') || (target ? w.getComputedStyle(target, null).scrollMarginTop : 0);
if(target) {
e.preventDefault();
ROOT.style.scrollPadding = parseInt(offset, 10) +'px';
ROOT.setAttribute('scrolling','');
setTimeout(function(){
ROOT.removeAttribute('scrolling');
// Trigger scroll eventlistener
w.scroll(0, w.scrollY + 1);
w.scroll(0, w.scrollY - 1);
}, MS);
}
if(hash) w.location.hash = hash;
}
// Native scroll method, interval frame ease animation
function scroll (e) {
var hash = this.hash || this.getAttribute('aria-controls') || this.getAttribute('data-target'),
target = hash ? d.getElementById(hash.replace(/#/g,'').trim()) : null,
offset = this.getAttribute('data-scrolloffset') || (target ? w.getComputedStyle(target, null).scrollMarginTop : 0);
if(target) {
e.preventDefault();
raf(function () {
var T = new Date().getTime(), sT = T, sY = w.pageYOffset,
top = target.getBoundingClientRect().top - parseInt(offset, 10);
frame(sT, T, MS, top, sY, hash);
});
}
}
function frame (sT, T, ms, top, sY, hash) {
var time = T - sT, ease = qubicFn(time/ms);
w.scroll(0, sY + (top * ease));
if(time < ms) raf(function() { frame(sT, new Date().getTime(), ms, top, sY, hash); });
else if(hash) w.location.hash = hash;
}
}
// Notifications API: Send notification (IE 11 and lower isn't supported.)
function notification (title, body, icon, img, sound) {
if (!('Notification' in w) || !allowNotifications) return false;
var title = title || 'Undefined title',
badge = d.querySelector('link[rel="mask-icon"]'),
options = {
body: body || 'Undefined content',
icon: icon ? icon : null,
badge: badge ? badge.href : null,
image: img ? img : null,
vibrate: [400],
sound: audiopool.pop
};
if (Notification.permission === 'granted') return new Notification(title, options);
else { Notification.requestPermission(permission => {
if (permission === 'granted') return new Notification(title, options);
else return alert('Permission '+ permission +'.', {title: 'Notification API'});
});
}
}
// Color scheme
function Scheme (toggler) {
var ROOT = d.documentElement,
HEAD = d.querySelector('head'),
BODY = d.body || ROOT.body,
userPrefers, mediaQuery, darkScheme, saved;
saved = w.localStorage.getItem('UiColorScheme');
userPrefers = saved || w.getComputedStyle(ROOT, null).getPropertyValue('color-scheme').replace(/"/g, '');
darkScheme = BODY.getAttribute('data-scheme') === 'dark';
if(w.matchMedia) mediaQuery = w.matchMedia('(prefers-color-scheme: light)');
if(mediaQuery) mediaQuery.onchange = toggle;
if(userPrefers === 'light' && darkScheme) toggle;
// Init Scheme or Element Listeners:
toggler = toggler instanceof Element ? toggler : d.querySelector(toggler);
if(toggler) {
toggler.onchange = toggle;
toggler.checked = darkScheme ? true : false;
}
else toggle;
// Methods:
function toggle (e) {
darkScheme = toggler ? toggler.checked : !darkScheme;
BODY.setAttribute('data-scheme', darkScheme ? 'dark' : 'light');
// Wait for transitions to end.
BODY.addEventListener('transitionend', set, false);
}
function set () {
var theme = HEAD.querySelector('meta[name="theme-color"]'),
iosbar = HEAD.querySelector('meta[name="apple-mobile-web-app-status-bar-style"]'),
scheme = HEAD.querySelector('meta[name="color-scheme"]'),
color = w.getComputedStyle(BODY).getPropertyValue('background-color');
if(!theme) theme = createMeta('theme-color');
if(!scheme) scheme = createMeta('color-scheme');
if(!iosbar) iosbar = createMeta('apple-mobile-web-app-status-bar-style');
BODY.removeEventListener('transitionend', set, false);
ROOT.style.setProperty('color-scheme', darkScheme ? 'dark' : 'light');
scheme.content = darkScheme ? 'dark' : 'light';
iosbar.content = darkScheme ? 'black-translucent' : 'default';
theme.content = color;
ROOT.offsetWidth; // force reflow, resolves scrollbar style bug?
// Save preference and clean-up
w.localStorage.setItem('UIColorScheme', darkScheme ? 'dark' : 'light');
BODY.removeEventListener('transitionend', set, false);
// Method: Create and append <meta/>
function createMeta (name) {
var m = d.createElement('meta');
m.name = name; HEAD.appendChild(m);
return m;
}
}
}
// Ripple effects
function Ripple (e) {
var trigger = e.target || w.event.target,
touch = e.changedTouches || e.touches,
ink = trigger.querySelector('.ink'), x, y;
if(!ink) {
ink = d.createElement('i');
trigger.appendChild(ink);
ink.setAttribute('aria-hidden', true);
}
ink.className = 'ink';
if(!ink.offsetHeight && !ink.offsetWidth) {
var dia = Math.max(trigger.offsetWidth, trigger.offsetHeight);
ink.style.cssText = 'height:'+ dia +'px; width:'+ dia +'px;';
}
x = (touch ? touch[0].screenX : e.clientX) - trigger.offsetLeft - ink.offsetWidth/2;
y = (touch ? touch[0].screenY : e.clientY) - trigger.offsetTop - ink.offsetHeight/2;
ink.style.cssText = 'top:'+ y +'px; left:'+ x +'px;';
ink.className += ' animating';
setTimeout(function(){
ink.className = 'ink';
ink.removeAttribute('style');
}, 20000);
}
// Network Status
function Online () {
var msg = d.createElement('div'),
status = check;
msg.id = 'network-status';
msg.className = 'network-status';
msg.setAttributes({
'role': 'alert',
'aria-live': 'assertive',
'aria-atomic': true,
'tabindex': '-1',
'draggable': ''
});
// Listeners
w.addEventListener('ui.online', update, false);
// Methods;
function update () {
status = check;
if(!status) {
}
}
function check () {
var xhr = new XMLHttpRequest();
xhr.open('HEAD', '//'+ w.location.hostname +'/?r='+ Date.now(), false);
try { xhr.send(); return (xhr.status >= 200) && (xhr.status < 300 || xhr.status === 304); }
catch (error) { return false; }
}
}
// Helpers:
// Get closest element with specific selector
function getClosest (el, selector) {
for ( ; el && el !== d; el = el.parentNode ) {
if (el.matches(selector)) return el; // Need el.matches() support
}
return null;
};
// Set global viewport height CSS variable
function setViewport (){
w.addEventListener('resize', set, false);
w.addEventListener('orientationchange', set, false);
set();
function set(){
d.documentElement.style.setProperty('--vh', (w.innerHeight * 0.01) +'px');
}
}
// Check if element is partially in viewport
function inViewport(el) {
var r = el.getBoundingClientRect(),
x = r.left, y = r.top,
W = el.clientWidth, H = el.clientHeight,
vW = Math.max(d.documentElement.clientWidth, w.innerWidth || 0),
vH = Math.max(d.documentElement.clientHeight, w.innerHeight || 0);
return (y < vH && y+H > 0) && (x < vW && x+W > 0);
}
// Focus trap
function trapFocus (e) {
if (!e.relatedTarget || !this.contains(e.relatedTarget)) {
var f = this.querySelectorAll('button,[href],input,select,textarea,[tabindex]:not([tabindex="-1"])');
if(f) setTimeout(function() { f[0].focus(); }, 1);
}
}
// Check if event happens inside an element
function isTarget (e, el) {
var target = e.target;
do { if (target == el) return true; target = target.parentNode; }
while (target);
return false;
}
// Get next overflow scroll parent
function scrollParent(node) {
if (!node || node.nodeType != 1) return null;
var oY = w.getComputedStyle(node).overflowY,
isScroll = oY !== 'visible' && oY !== 'hidden';
if (isScroll && node.scrollHeight > node.clientHeight) return node;
else return scrollParent(node.parentNode);
}
// Url parts
function urlVars() {
var vars = {};
w.location.href.replace(/[?&]+([^=&]+)=([^&]*)/gi, function(m, k, v) { vars[k] = v; } );
return vars;
}
// Create and append or modify <meta/>
function setMeta (name, content) {
var exists = d.querySelector('meta[name='+name+']'),
m = exists ? exists : d.createElement('meta');
m.name = name; m.content = content;
if(!exists) d.querySelector('head').appendChild(m);
}
// Get value of css var
function rootVar(name){
var root = d.querySelector(':root');
return w.getComputedStyle(root).getPropertyValue(name);
}
// Format bytes
function formatBytes (bytes, dec) {
var s = ['Bytes','KB','MB','GB','TB','PB','EB','ZB','YB'],
dec = dec ? dec : 2;
for(var i = 0, r = bytes, b = 1024; r > b; i++) r /= b;
return parseFloat(r.toFixed(dec)) +' '+ s[i];
}
// Color conversion
function rgb2hex(string) {
var parts = (string || '').match(/\d+/g);
return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).slice(1);
}
// First letter upper case
function ucFirst(string) {
return string.charAt(0).toUpperCase() + string.slice(1);
}
// Color contrast
function contrast(color) {
var r, g, b, hsp, threshold = 127.5;
if (color.match(/^rgb/)) {
color = color.match(/^rgba?\((\d+),\s*(\d+),\s*(\d+)(?:,\s*(\d+(?:\.\d+)?))?\)$/);
r = color[1];
g = color[2];
b = color[3];
} else {
color = +('0x' + color.slice(1).replace(color.length < 5 && /./g, '$&$&'));
r = color >> 16;
g = color >> 8 & 255;
b = color & 255;
}
hsp = Math.sqrt(0.299 * (r * r) + 0.587 * (g * g) + 0.114 * (b * b));
if (hsp > threshold) return 'light';
else return 'dark';
}
function contrast4hex(hex){
var r = parseInt(hex.substr(0,2),16), g = parseInt(hex.substr(2,2),16), b = parseInt(hex.substr(4,2),16),
yiq = ((r*299)+(g*587)+(b*114))/1000;
return (yiq >= 128) ? 'dark' : 'light';
}
// Add multiple event listeners to element
function addListeners (el, events, fn) {
var evts = events.split(' ');
for (var i = 0; i < evts.length; i++) {
el.addEventListener(evts[i], fn, false);
}
}
// Remove listenners from element by type
function removeListeners (el, event){
var evts = getEventListeners(el)[event];
for(var i = 0; i < evts.length; i++){
el.removeEventListener(event, evts[i].listener);
}
}
// Prefixed JS CSS event listener
function addPrefixedListener (el, type, callback) {
var prefix = ['webkit', 'moz', 'MS', 'o', ''];
for (var p = 0; p < prefix.length; p++) {
if (!prefix[p]) type = type.toLowerCase();
el.addEventListener(prefix[p]+type, callback, false);
}
}
// Replace / refresh / update listenner
function replaceListener (event, fn, passive, el) {
el.removeEventListener(event, fn, passive);
el.addEventListener(event, fn, passive);
}
// Observe changes in DOM Elements
function observe (el, call, opts){
var MutationObserver = w.MutationObserver || w.WebKitMutationObserver;
if( !el || el.nodeType != 1 ) return; // validation
if( MutationObserver ){
var o = new MutationObserver(call);
o.observe( el, opts || {attributes: true, childList: true, subtree: true});
return o;
}
else if( w.addEventListener ){
el.addEventListener('DOMNodeInserted', call, false);
el.addEventListener('DOMNodeRemoved', call, false);
}
}
// Add event observe
function dispatchEvent(name, el, data) {
var e = d.createEvent('Event');
e.initEvent(name, true, true);
e.data = data || {};
if(el.nodeType === 1) e.data.target = el;
w.dispatchEvent(e);
}
// Check if object is a dom node element
function isElement (o) {
return (o instanceof Element || o instanceof HTMLDocument) && o instanceof Node;
}
// Prevent event bubbling
function prevent (e) {
e = (e) ? e : w.event;
e.preventDefault();
e.stopPropagation();
}
// Prevent event propagation
function nopropagate (e) {
e = (e) ? e : w.event;
e.stopPropagation();
}
// Merge
function merge (o1, o2) {
for (var key in o2) o1[key] = o2[key];
return o1;
}
function mergeArr (a1, a2) {
return a1.concat(a2.filter(function (m) { return a1.indexOf(m) === -1; }));
}
// Listen to changes in element / document
function changed (el, val){
var inputs = el.querySelectorAll('input, select, [contenteditable], textarea'),
value = val ? [val] : false;
for(var i = 0; i < inputs; i++){
inputs[i].addEventListener('change', function(e){ [value] = true; }, false);
};
return value;
}
// Fullscreen
function toggleFullScreen(e) {
var dc = w.document, dEl = dc.documentElement,
rFS = dEl.requestFullscreen || dEl.mozRequestFullScreen || dEl.webkitRequestFullScreen || dEl.msRequestFullscreen,
cFS = d.exitFullscreen || dc.mozCancelFullScreen || dc.webkitExitFullscreen || dc.msExitFullscreen;
if(!dc.fullscreenElement && !dc.mozFullScreenElement && !dc.webkitFullscreenElement && !dc.msFullscreenElement) rFS.call(dEl);
else cFS.call(dc);
}
// Create SVG
function svg (paths, viewbox, label) {
var el = d.createElementNS('http://www.w3.org/2000/svg','svg');
el.setAttribute('viewBox', viewbox ? viewbox : '0 0 9 9');
if(paths instanceof Array) paths.forEach(function(p){ el.innerHTML += '<path d="'+ p +'"/>'; });
else if(paths) el.innerHTML = '<path d="'+ paths +'"/>';
if(!label) el.setAttribute('aria-hidden', true);
else el.setAttribute('aria-label', label);
return el;
}
// SVG to PNG
function png64(svg) {
var fill = w.getComputedStyle(svg).fill || null,
stroke = w.getComputedStyle(svg).stroke || null;
if(fill) svg.setAttribute('fill', fill);
if(stroke) svg.setAttribute('stroke', stroke);
var data = new XMLSerializer().serializeToString(svg),
canvas = d.createElement('canvas'),
ratio = w.devicePixelRatio,
size = svg.getBoundingClientRect(),
ctx = canvas.getContext('2d'),
img = new Image();
canvas.width = size.width * ratio;
canvas.height = size.height * ratio;
ctx.scale(ratio, ratio);
var dataurl = 'data:image/svg+xml,'+ encodeURIComponent(svg);
img.setAttribute('src', dataurl);
img.onload = function() {
setTimeout(function(){
ctx.drawImage(img, 0, 0);
},5)
};
return canvas.toDataURL('image/png');
}
// IE 9 fix
/MSIE|Trident/.test(n.userAgent) && d.addEventListener('DOMContentLoaded', function(){
[].forEach.call(d.querySelectorAll('svg'), function (svg) {
var use = svg.querySelector('use');
if (use) {
var obj = d.createElement('object');
obj.data = use.getAttribute('xlink:href');
obj.className = svg.getAttribute('class');
svg.parentNode.replaceChild(obj, svg);
}
});
});
// Key listener
function onKey (name, el, callback, once) {
if(!el || !name || !callback) return;
var fn = function(e) {
var key = e.keyCode ? e.keyCode : e.which;
if (key === keys[name]) {
e.preventDefault();
callback();
}
if(once) el.removeEventListener('keyup', fn, false);
};
el.addEventListener('keyup', fn, false);
}
// Keyboard listener
function keylistener (e) {
// console.log(e.target)
var target = e.target || w.event.target;
// if(!target) return;
nopropagate(e);
var key = e.keyCode ? e.keyCode : e.which;
if (key === 13) { // Enter
console.log(key)
}
else if (key === 27) { // Esc
console.log(key)
}
}
// Format milliseconds to hours, minutes and seconds
// Note: Hours display needs to be tested...
function formatMs (n) {
var h = Math.floor(n/3600),
m = Math.floor((n-(h*3600))/60),
s = Math.floor(n-(h*3600)-(m*60));
if (h >= 1) h = h +':'; else h = '';
if (m < 10) m = '0'+ m;
if (s < 10) s = '0'+ s;
return h + m +':'+ s;
}
// Format dates
function formatDate(date, format) {
var z = { M: date.getMonth() + 1, d: date.getDate(), h: date.getHours(), m: date.getMinutes(), s: date.getSeconds() };
format = date.replace(/(M+|d+|h+|m+|s+)/g, function(v) {
return ((v.length > 1 ? '0' : '') + z[v.slice(-1)]).slice(-2);
});
return format.replace(/(format+)/g, function(v) {
return date.getFullYear().toString().slice(-v.length)
});
}
// Display human readable n time ago
function ago(el, int) {
var instance, interval = int ? int : 10000,
timestamp = parseInt(el.getAttribute('timestamp'), 10),
units = i18n.ago ? i18n.ago : [
{sec: 0, text: 'just now'},
{sec: 1, text: '%n second%s ago'},
{sec: 60, text: '%n minute%s ago'},
{sec: 3600, text: '%n hour%s ago'},
{sec: 86400, text: '%n day%s ago'},
{sec: 604800, text: '%n week%s ago'},
{sec: 2592000, text: '%n month%s ago'},
{sec: 31536000, text: '%n year%s ago'},
{sec: 315360000, text: '%n decade%s ago'}
];
// Clear previous interval on element;
clearInterval(instance); // if(instance)
instance = setInterval(timer, interval);
timer();
// Refresh date / time
function timer () {
var delta = Math.floor((new Date().getTime() - timestamp)/1000);
for (var i = 0; i < units.length; i++) {
if (delta < units[i].sec) {
if (i === 0) el.innerHTML = units[0].text;
else {
var dif = Math.round(delta/units[i-1].sec);
el.innerHTML = units[i-1].text.replace('%n', dif).replace(/%(\w+)/g, (dif <= 1 ? '' : '$1') );
}
return;
}
}
}
}
// Check for duplicate ids
function checkDuplicateIds () {
var ids = {}, dp = {}, str,
nodes = d.querySelectorAll('[id]');
for(var i = 0; i < nodes.length; i++) {
var c = nodes[i].id ? nodes[i].id : 'undefined';
if(isNaN(ids[c])) ids[c] = 0;
ids[c]++;
}
for (var key in ids) if (ids[key] > 1) dp[key] = ids[key];
str = Object.keys(dp).map(function(k){ return '#'+k+": "+(dp[k]-1)+' Duplicate(s)';}).join("\n");
if(Object.keys(dp).length > 0) console.log('Non-unique IDs in the document: \n'+str+'\n');
}
// Vibrate
function vibration (pattern) {
pattern = pattern ? pattern : [300, 100, 300];
w.navigator.vibrate(pattern);
}
// Play sound via HTML element (IE9 support)
function sound(url){
if(!allowAudio) return;
url = url ? url : audiopool.pop;
var audio = d.createElement('audio');
audio.style.display = 'none';
audio.src = url;
audio.autoplay = true;
audio.onended = function(){ d.body.removeChild(audio);};
d.body.appendChild(audio);
}
// Mp3 audiopool for ui
var audiopool = { pop: 'data:audio/mpeg;base64,SUQzBAAAAAABAlRYWFgAAAAKAAAAAENPTU1FTlRTVFNTRQAAAA4AAABMYXZmNTguMTIuMTAwVERSQwAAAAUAAAAyMDEzAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAD/80hkAAaQNRYvoYgBBvgR8AFDEAABlG23ePr8RKhOBvESoVd4EEAA5Uc4PvKBjwxlAQ4gd4gdE7yH/Lv9Rz/8H3w//rB9+XP5BECAAYE4eBAEHdYPl4g///8pBwEAx///4gOFAwrdzrgXqaWQgt2h3mYZtQ4CCGedJDIthbIIEBUAhQAoJEIQ+QDBjCILwNz/80hkKgxBE14AzFAADNBy9l+YKQIWAYACdCLAJFAZk4ACRDGN+TpbKzKIVel+gnrUpJX/3QZJkf//UtbJuzv///6BoT6CTGKFf//KmpdlKGwIAAwOAMABgAAOdZ4hQQlZpLGSU+8954f/PQovOnA5xNYS+j/PFjX/zd////rLCGpRpKENtvuABSVbLO1TmbX/80hEDweoU2Ef4xgBDcCqrV/GYAJc4jD5bV6hvV8rzJxIBAJLlSzTCziwCuLFTsSkvUQ9A85U+Y56CygobGU1pN3aLlbYBAAAUAkY056ONRamOw5HPmwkdTclj6BCtVaVgbADAGH7eJAqUeDk+0WnhLQj///8kRDq+mpSNtA9tvsAO3lA7Uy3RJE1LILCI9D/80hkFQlwe1MfGEaRCtBysl4IwFIHCjmOwq8N80c1bxBqfcy8yDJfsloNIa5hl73AAHR4BDTHmcNBwyF1jKSIMblyoaoa++NGaHanJW0wbtv+ABcaVsTiqzGuepZlQijwlBXPEn89rG/1b5up7bfZs7NZ4WIUJmvkQpJJbZxGpxrk7RcX4KReAxwlEzSyBwn/80hkGQgIW0LfCSYFCHiiTABj0uANlUxLj5gok1qyVoIE5h6o7Qv79Viv/o2c6olRYGzLFERIj6H7//oGq63Fix+3dMLvfClPUqk5iZJJoYjgaIxVD07oaA11E2WF1T1abdsj4IyfqoVCryqciUk+c7cOJdwWK9WiHAMaqyWzJeg0JH+g89ditUJNFoVo+rr/80hkMQboRzR/BSYRCKCSNABJnjDdX9/X//rImy05CIdZaWuyTFEi6Slrp1xzVXDCMaErs9hZWgotlH6noQG79t8BhURBUi9KQ1IhpYCERIjU9CStHLHsjfU0ke87rcrtqPfyX/zv/4a8t6JaZPjckk4IkssVAp1DIafW1/iL0VEtaCP2fU//qPfEO3//PFX/80hkUgW4BxQrCCMBCngGNZ4IRgLZXfK8j0Iv+A7TTT////TTTRVVVf//6KqqqqaaaaKqqqrdppo+qqq1NNNFVVVX///yqqqmmmGIf//9NNNv5UqH////4qLCws3+oWFxUVFRX/6hakxBTUUzLjk5LjW=',
click: 'data:audio/mpeg;base64,//NIZAAFEADy36CIAAiA1bgBQRAAJKTlzcrT4Bxcgp0H8ufEBmIJcMQffy8P7S/f/+GCnkKw+Xfzn+c/+Q+Yx8gTGOMf//nyZ3qc7oQAIUOF3///+GCn///8Pl//+oEF/SA/DLk1Qt5Evm78et8/Q3hviABfB2jxHd2CoDAhVxLTIex0y9wkZUCRiOAoB8kR//NIZDAMfX9iAMe0AA0K/uI/gSgCihzQrn+BLx8HIbGkBmhOTy2V/b////1v///9rWW6bmht/X1//8kCUNiUNEGTZ72qJIxNVAkOBMMAEACASgQKADouaELHYf9P///5f7///o3///3Rs7f1T///+un5f//ZyN/5QkAoqmtu2fwKgs0R+XgVwg1PyaGmW46u//NIZBMKeO1iAMfAAAqYmtWVgRAAF1A+Q9chw5xSbh7gr4j8AsIwNXCNgvT1sI8KjoMKKrmT+///9BqDK+l/6EuFw0K6CDqSUZDLEyau/IDnBj6v/6IgwAgAAAAjDwA8YfF+XRsxvIToGO+V////6gG/U538+kgFnf/1OuKHPg0qLktrRl2k24CwqRBpr/3J//NIZA8KiFdlL+SMAQmoAq4/wRgCE01K1UKHbVQ55IkRRmPqgLMfQokY4GgaBo9wVPKDqgqGsGv8GgVdER4GgaUDR07/4iPFjxUFQa8GnwaiI8VcGoKgqeWGiABAgolUsAKu/EX6j1T/xE3+DR3+VxLVwa//6j2CriwMnSoKu/w7KcSbjdt1uvBPStKh6WhR//NIRA8FpAMZLwQjAQpwBh2eCEYC8ZQFYr1C0t1pliPan14Td+r1ixr8Z/rKpQz/GN/0lXdnJGpJwc69TJEYLzISNICuKYs2kBCzdIS9nH+v/FPxZEf/F///+pnUTEFNRTMuMTAwqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq//NIZDMAAAGkAAAAAAAAA0gAAAAAqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqqq'};
}
@charset "UTF-8";
/*! UI v0.1 - SCSS - Responsive & Accessible App UI/UX Framework */
/// Variables
// Font stacks
$font-stack: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, "Helvetica Neue", Arial, "Noto Sans", sans-serif !default;
$font-stack-monospace: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace !default;
// Font size
$font-size: 1rem !default; // 16px ua standard
$font-size-sm: .875rem !default;
$font-size-lg: 1.125rem !default;
$font-size-sub-sup: .75rem !default;
// Font weight
$font-weight-lighter: lighter !default;
$font-weight-light: 300 !default;
$font-weight-normal: 400 !default;
$font-weight-bold: 700 !default;
$font-weight-bolder: bolder !default;
// Font line height
$font-line-height: 1.5;
// Gray color system
$white: #fff !default;
$gray-100: #f8f9fa !default;
$gray-200: #e9ecef !default;
$gray-300: #dee2e6 !default;
$gray-400: #ced4da !default;
$gray-500: #adb5bd !default;
$gray-600: #6c757d !default;
$gray-700: #495057 !default;
$gray-800: #343a40 !default;
$gray-900: #212529 !default;
$black: #000 !default;
// Grays map
$grays: ( "100": $gray-100, "200": $gray-200, "300": $gray-300, "400": $gray-400,"500": $gray-500, "600": $gray-600, "700": $gray-700, "800": $gray-800, "900": $gray-900) !default;
// Theme colors
$primary: #007bff !default;
$secondary: $gray-600 !default;
$success: #43A047 !default;
$info: #5C6BC0 !default;
$warning: #FFA000 !default;
$danger: #E53935 !default;
$light: $gray-100 !default;
$dark: $gray-800 !default;
// Theme colors map
$theme-colors: ( "primary": $primary, "secondary": $secondary, "success": $success,"info": $info, "warning": $warning, "danger": $danger, "light": $light, "dark":$dark ) !default;
// Customize the light and dark text colors for use in our color contrast function.
$color-contrast-dark: $gray-900 !default;
$color-contrast-light: $white !default;
// Color scheme auto detection via media query
$scheme-detection: true !default;
// Layout sizing
// Breakpoints
$breakpoints: (
xs: 0,
sm: 576px,
md: 768px,
lg: 992px,
xl: 1200px,
xxl: 1400px
) !default;
$breakpoints-down: (
xs: 384px - 0.02px, // New logic for breakpoint-down
sm: map-get($breakpoints, "sm") - 0.02px,
md: map-get($breakpoints, "md") - 0.02px,
lg: map-get($breakpoints, "lg") - 0.02px,
xl: map-get($breakpoints, "xl") - 0.02px,
xxl: map-get($breakpoints, "xxl") - 0.02px
) !default;
// Display
$displays: (none inline inline-block block table table-row table-cell flex inline-flex) !default;
// Positions
$positions: (static relative absolute fixed sticky) !default;
// Container
$container-max-widths: (
xs: 384px,
sm: 540px,
md: 720px,
lg: 960px,
xl: 1140px,
xxl: 1320px
) !default;
$container-padding-x: 1rem !default;
// Spacing
$spacer: 1rem !default;
// Spacing map
$spacers: (
0: 0,
1: $spacer * .25,
2: $spacer * .5,
3: $spacer,
4: $spacer * 1.5,
5: $spacer * 3
) !default;
// Grid
$enable-grid: true !default; // enable / disable
$grid-columns: 12 !default;
$grid-gutter-width: 0 !default;
$grid-row-columns: 6 !default;
$gutters: $spacers !default;
// Z-indexes
$zindex-app: 0 !default;
$zindex-main: 1 !default;
$zindex-backdrop: 1010 !default;
$zindex-sticky: 1020 !default;
$zindex-fixed: 1030 !default;
$zindex-dropdown: 1040 !default;
$zindex-tooltip: 1050 !default;
$zindex-drawer: 1060 !default;
$zindex-note: 1080 !default;
$zindex-toast: 1090 !default;
$zindex-modal: 1100 !default;
// App / root element HTML
$root-bg: $primary !default;
// Dark Scheme
$root-dark-bg: $primary !default;
// Body
$body-bg: $white !default;
$body-color: $gray-900 !default;
$body-text-align: null !default;
// Dark Scheme
$body-dark-bg: $gray-900 !default;
$body-dark-color: $gray-200 !default;
// Text
$text-muted: $gray-600 !default;
// Border
$border-width: 1px !default;
$border-color: $gray-300 !default;
$border-radius: .25rem !default;
$border-radius-sm: .2rem !default;
$border-radius-lg: .3rem !default;
// Global Pointer style
$cursor-pointer: true !default;
$cursor: if($cursor-pointer, pointer, default) !default;
// Shadows
$shadow: 0 0.5rem 1rem rgba($black, 0.15) !default;
$shadow-lg: 0 1rem 3rem rgba($black, 0.175) !default;
$shadow-sm: 0 .125rem .25rem rgba($black, 0.075) !default;
$shadow-inset: inset 0 1px 2px rgba($black, .075) !default;
$shadow-elevated: 0px 5px 5px -3px rgba($black, 0.2),
0px 8px 10px 1px rgba($black, 0.07),
0px 3px 14px 2px rgba($black, 0.06) !default;
// Transition
$enable-transitions: true !default;
$enable-reduced-motion: true !default;
$transition-base: all .2s ease-in-out !default;
$transition-fade: opacity .15s linear !default;
$transition-collapse: height .35s ease !default;
$transition-dropscale: opacity .1s linear, scale .2s ease-in !default;
// SVGs: Characters which are escaped by the escape-svg function
$escaped-characters: ( ("<","%3c"), (">","%3e"), ("#","%23"), ("(","%28"), (")","%29") ) !default;
/// Functions
// String replace
@function str-replace($string, $search, $replace: "") {
$index: str-index($string, $search);
@if $index {
@return str-slice($string, 1, $index - 1) + $replace + str-replace(str-slice($string, $index + str-length($search)), $search, $replace);
}
@return $string;
}
// Escape SVG. See https://codepen.io/kevinweber/pen/dXWoRw
@function escape-svg($string) {
@if str-index($string, "data:image/svg+xml") {
@each $char, $encoded in $escaped-characters {
// Do not escape the url brackets
@if str-index($string, "url(") == 1 {
$string: url("#{str-replace(str-slice($string, 6, -3), $char, $encoded)}");
} @else {
$string: str-replace($string, $char, $encoded);
}
}
}
@return $string;
}
// The contrast ratio to reach against white
@function contrast-color($color) {
@if (lightness($color) < 60) { @return $color-contrast-light; }
@else { @return $color-contrast-dark; }
}
// Return valid calc
@function add($value1, $value2, $return-calc: true) {
@if $value1 == null { @return $value2; }
@if $value2 == null { @return $value1; }
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 + $value2;
}
@return if($return-calc == true, calc(#{$value1} + #{$value2}), $value1 + unquote(" + ") + $value2);
}
@function substract($value1, $value2, $return-calc: true) {
@if $value1 == null and $value2 == null { @return null; }
@if $value1 == null { @return -$value2; }
@if $value2 == null { @return $value1; }
@if type-of($value1) == number and type-of($value2) == number and comparable($value1, $value2) {
@return $value1 - $value2;
}
@return if($return-calc == true, calc(#{$value1} - #{$value2}), $value1 + unquote(" - ") + $value2);
}
// Border radius
@function valid-radius($radius) {
$return: ();
@each $value in $radius {
@if type-of($value) == number { $return: append($return, max($value, 0)); }
@else { $return: append($return, $value); }
}
@return $return;
}
// Transparent grid
$transparency-bg: transparent url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 2 2'%3e%3cpath fill='%23eee' d='M0,0v1h1V0H0z M1,1v1h1V1H1z'/%3e%3c/svg%3e") repeat right top/12px 12px !default;
/// Components
$component-active-color: $white !default;
$component-active-bg: $primary !default;
$component-inactive-bg: $gray-500 !default;
// Links
$link-color: currentColor !default;
$link-decoration: underline !default;
$link-hover-color: $primary !default;
$link-hover-decoration: null !default;
$link-active-color: darken($primary, 15%) !default;
// Backdrop
$backdrop-bg: rgba($black, 0.6) !default;
// Form control / input & button
$input-padding-y: .375rem !default;
$input-padding-x: .75rem !default;
$input-padding-y-sm: .375rem !default;
$input-padding-x-sm: .75rem !default;
$input-padding-y-lg: .375rem !default;
$input-padding-x-lg: .75rem !default;
$input-bg: $white !default;
$input-dark-bg: $gray-900 !default;
$input-disabled-bg: $gray-200 !default;
$input-disabled-border-color: null !default;
$input-focus-bg: $body-bg !default;
$input-dark-focus-bg: $body-dark-bg !default;
$input-color: $gray-800 !default;
$input-autofill-color: $gray-800 !default;
$input-dark-color: $gray-400 !default;
$input-plaintext-color: $body-color !default;
$input-focus-color: $primary !default;
$input-hover-color: $gray-800 !default;
$input-dark-hover-color:$gray-300 !default;
$input-font-family: $font-stack !default;
$input-font-size: $font-size !default;
$input-font-size-sm: $font-size-sm !default;
$input-font-size-lg: $font-size-lg !default;
$input-font-weight: $font-weight-normal !default;
$input-placeholder-color: $gray-600 !default;
$input-line-height: $font-line-height !default;
$input-border-width: $border-width !default;
$input-border-color: $border-color !default;
$input-focus-border-color: $primary!default;
$input-hover-border-color: $gray-500!default;
$input-dark-hover-border-color: $gray-200!default;
$input-border-radius: $border-radius !default;
$input-border-radius-sm:$border-radius-sm !default;
$input-border-radius-lg:$border-radius-lg !default;
$input-box-shadow: none !default;
$input-focus-box-shadow:0 0 0 .25rem rgba($primary, 0.2) !default;
$input-error-box-shadow:0 0 0 .25rem rgba($danger, 0.2) !default;
$input-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, letter-spacing .15s ease-in-out !default;
$input-label-uppercase: false !default;
$input-label-focus-color: $input-focus-color !default;
$input-height: add($input-line-height * 1em, add($input-padding-y * 2, $input-border-width * 2, false)) !default;
$input-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2, $input-border-width * 2, false)) !default;
$input-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2, $input-border-width * 2, false)) !default;
// Floating input labela
$input-float-label-font-size: $font-size/1.45 !default;
$input-float-label-font-size-sm: $font-size-sm/1.45 !default;
$input-float-label-font-size-lg: $font-size-lg/1.45 !default;
$input-float-label-height: add($input-line-height * 1em, add($input-padding-y * 2 + $input-float-label-font-size, $input-border-width * 2, false)) !default;
$input-float-label-height-sm: add($input-line-height * 1em, add($input-padding-y-sm * 2 + $input-float-label-font-size-sm, $input-border-width * 2, false)) !default;
$input-float-label-height-lg: add($input-line-height * 1em, add($input-padding-y-lg * 2 + $input-float-label-font-size-lg, $input-border-width * 2, false)) !default;
$input-float-label-transition: padding-top .1s ease-out, color .15s ease-in-out, font-size .1s ease-out !default;
// Icons backgrounds
$input-autofill-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5,7L2,8.5l0.7-3l-2.2-2l2.9-0.3l1.1-2.8l1.1,2.8l2.9,0.3l-2.2,2l0.7,3L4.5,7z' fill='#{$input-autofill-color}'/></svg>") !default;
$input-autofill-active-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5,7L2,8.5l0.7-3l-2.2-2l2.9-0.3l1.1-2.8l1.1,2.8l2.9,0.3l-2.2,2l0.7,3L4.5,7z' fill='#{$input-focus-color}'/></svg>") !default;
$input-search-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M.5 3.7C.5 5.6 2 7 3.8 7c.7 0 1.4-.2 1.9-.6l2 2c.1.1.2.1.3.1.1 0 .2 0 .3-.1.2-.2.2-.5 0-.6l-2-2c.5-.6.7-1.3.7-2.1C7 1.9 5.5.4 3.7.4 2 .4.5 1.9.5 3.7zm.7 0c0-1.4 1.2-2.6 2.6-2.6s2.6 1.2 2.6 2.6-1.2 2.6-2.6 2.6-2.6-1.1-2.6-2.6z' fill='#{$input-placeholder-color}'/></svg>") !default;
$input-search-icon-bg-focus: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M.5 3.7C.5 5.6 2 7 3.8 7c.7 0 1.4-.2 1.9-.6l2 2c.1.1.2.1.3.1.1 0 .2 0 .3-.1.2-.2.2-.5 0-.6l-2-2c.5-.6.7-1.3.7-2.1C7 1.9 5.5.4 3.7.4 2 .4.5 1.9.5 3.7zm.7 0c0-1.4 1.2-2.6 2.6-2.6s2.6 1.2 2.6 2.6-1.2 2.6-2.6 2.6-2.6-1.1-2.6-2.6z' fill='#{$primary}'/></svg>") !default;
$input-search-icon-bg-error: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M.5 3.7C.5 5.6 2 7 3.8 7c.7 0 1.4-.2 1.9-.6l2 2c.1.1.2.1.3.1.1 0 .2 0 .3-.1.2-.2.2-.5 0-.6l-2-2c.5-.6.7-1.3.7-2.1C7 1.9 5.5.4 3.7.4 2 .4.5 1.9.5 3.7zm.7 0c0-1.4 1.2-2.6 2.6-2.6s2.6 1.2 2.6 2.6-1.2 2.6-2.6 2.6-2.6-1.1-2.6-2.6z' fill='#{$danger}'/></svg>") !default;
$input-date-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M1.8.5v.8h-.7c-.2 0-.4.2-.4.4v6.5c0 .2.2.4.4.4H8c.2 0 .4-.2.4-.4V1.6c0-.2-.2-.4-.4-.4h-.8V.5H6v.8H3V.5H1.8zm-.3 3h6.1v4.2H1.5V3.5zm.3.4v1.5h1.5V3.9H1.8zm1.9 0v1.5h1.5V3.9H3.7zm1.9 0v1.5h1.5V3.9H5.6zM1.8 5.8v1.5h1.5V5.8H1.8zm1.9 0v1.5h1.5V5.8H3.7z' fill='#{$input-placeholder-color}'/></svg>") !default;
$input-date-icon-bg-focus: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M1.8.5v.8h-.7c-.2 0-.4.2-.4.4v6.5c0 .2.2.4.4.4H8c.2 0 .4-.2.4-.4V1.6c0-.2-.2-.4-.4-.4h-.8V.5H6v.8H3V.5H1.8zm-.3 3h6.1v4.2H1.5V3.5zm.3.4v1.5h1.5V3.9H1.8zm1.9 0v1.5h1.5V3.9H3.7zm1.9 0v1.5h1.5V3.9H5.6zM1.8 5.8v1.5h1.5V5.8H1.8zm1.9 0v1.5h1.5V5.8H3.7z' fill='#{$primary}'/></svg>") !default;
$input-date-icon-bg-error: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M1.8.5v.8h-.7c-.2 0-.4.2-.4.4v6.5c0 .2.2.4.4.4H8c.2 0 .4-.2.4-.4V1.6c0-.2-.2-.4-.4-.4h-.8V.5H6v.8H3V.5H1.8zm-.3 3h6.1v4.2H1.5V3.5zm.3.4v1.5h1.5V3.9H1.8zm1.9 0v1.5h1.5V3.9H3.7zm1.9 0v1.5h1.5V3.9H5.6zM1.8 5.8v1.5h1.5V5.8H1.8zm1.9 0v1.5h1.5V5.8H3.7z' fill='#{$danger}'/></svg>") !default;
$input-time-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5.5c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm1.8 5.2l-.4.1-.2-.1-1.4-1-.1-.1v-.1-.1-.1-.1L5 1.3c0-.2.2-.3.4-.2.2.1.3.3.3.5L5 4.3l1.2.8c.1.2.2.4.1.6z' fill='#{$input-placeholder-color}'/></svg>") !default;
$input-time-icon-bg-focus: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5.5c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm1.8 5.2l-.4.1-.2-.1-1.4-1-.1-.1v-.1-.1-.1-.1L5 1.3c0-.2.2-.3.4-.2.2.1.3.3.3.5L5 4.3l1.2.8c.1.2.2.4.1.6z' fill='#{$primary}'/></svg>") !default;
$input-time-icon-bg-error: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5.5c-2.2 0-4 1.8-4 4s1.8 4 4 4 4-1.8 4-4-1.8-4-4-4zm1.8 5.2l-.4.1-.2-.1-1.4-1-.1-.1v-.1-.1-.1-.1L5 1.3c0-.2.2-.3.4-.2.2.1.3.3.3.5L5 4.3l1.2.8c.1.2.2.4.1.6z' fill='#{$danger}'/></svg>") !default;
$input-select-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5,1L2,3.8h5L4.5,1z M4.5,8L2,5.3h5L4.5,8' fill='#{$input-placeholder-color}'/></svg>") !default;
$input-select-icon-bg-focus: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5,1L2,3.8h5L4.5,1z M4.5,8L2,5.3h5L4.5,8' fill='#{$primary}'/></svg>") !default;
$input-select-icon-bg-error: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 9 9'><path d='M4.5,1L2,3.8h5L4.5,1z M4.5,8L2,5.3h5L4.5,8' fill='#{$danger}'/></svg>") !default;
// Checkbox, radio, switch
$form-check-icon-bg: url("data:image/svg+xml,<svg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 8 8'><path d='M6.564.75l-3.59 3.612-1.538-1.55L0 4.26l2.974 2.99L8 2.193z' fill='#{$white}'/></svg>") !default;
$form-check-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, transform .15s ease-in-out, opacity .1s linear !default;
$form-radio-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, transform .15s ease-in-out, opacity .1s linear !default;
$form-switch-transition: border-color .15s ease-in-out, box-shadow .15s ease-in-out, transform .15s ease-in-out, opacity .1s linear !default;
// Range
$form-range-track-width: 100% !default;
$form-range-track-height: .5rem !default;
$form-range-track-cursor: pointer !default;
$form-range-track-bg: $gray-200 !default;
$form-range-track-border-radius: 1rem !default;
$form-range-track-box-shadow: $shadow-inset !default;
$form-range-track-fill-bg: $component-inactive-bg !default;
$form-range-track-active-fill-bg: $component-active-bg !default;
$form-range-thumb-width: 1rem !default;
$form-range-thumb-height: $form-range-thumb-width !default;
$form-range-thumb-bg: $component-inactive-bg !default;
$form-range-thumb-active-bg: $component-active-bg !default;
$form-range-thumb-border: 0 !default;
$form-range-thumb-border-radius: 1rem !default;
$form-range-thumb-box-shadow: 0 .1rem .25rem rgba($black, .1) !default;
$form-range-thumb-focus-box-shadow: 0 0 0 1px $body-bg, $input-focus-box-shadow !default;
$form-range-thumb-focus-box-shadow-width: .2rem !default; // For focus box shadow issue in Edge
$form-range-thumb-active-bg: darken($component-active-bg, 15%) !default;
$form-range-thumb-disabled-bg: $gray-500 !default;
$form-range-thumb-transition: background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;
// Input group
$input-group-addon-color: $gray-500 !default;
$input-group-addon-bg: $gray-200 !default;
// Label
$form-label-color: currentColor !default;
$form-label-margin-bottom:.75rem !default;
$form-label-font-size: 1em !default;
$form-label-font-style: normal !default;
$form-label-font-weight:400 !default;
// Form group
$form-group-margin-bottom: $spacer*.75 !default;
$form-grid-gutter-width: $spacer/2 !default;
// Button
$btn-transition: color .15s ease-in-out, background-color .15s ease-in-out, border-color .15s ease-in-out, box-shadow .15s ease-in-out !default;
$btn-uppercase: false !default;
// Dropdown
$dropdown-bg: $white !default;
$dropdown-dark-bg: $gray-900 !default;
// Modal
$modal-bg: $white !default;
$modal-dark-bg: $gray-900 !default;
$modal-sm: 300px !default;
$modal-md: 500px !default;
$modal-lg: 800px !default;
$modal-xl: 1140px !default;
$modal-fade-transform: translate(0, -50px) !default;
$modal-show-transform: none !default;
$modal-transition: transform .3s ease-out !default;
$modal-scale-transform: scale(1.02) !default;
// Drawer
$drawer-bg: $white !default;
$drawer-dark-bg: $gray-900 !default;
$drawer-width: 25rem !default;
// Sheet
$sheet-bg: $white !default;
$sheet-dark-bg: $gray-900 !default;
// Card
$card-bg: $white !default;
$card-dark-bg: $gray-900 !default;
// Toast
$toast-bg: rgba($black, 0.7) !default;
// Tooltip
$tooltip-bg: rgba($black, 0.7) !default;
$tooltip-dark-bg: $gray-900 !default;
// Notification
$note-bg: $white !default;
$note-dark-bg: $gray-900 !default;
/// Mixins
// Border radius
@mixin border-radius($radius: $border-radius) {
border-radius: valid-radius($radius);
}
// Breakpoint media queries
@mixin breakpoint-up($name, $points: $breakpoints) {
$min: map-get($points, $name);
@if $min { @media (min-width: $min) { @content; } }
@else { @content; }
}
@mixin breakpoint-down($name, $points: $breakpoints-down) {
$max: map-get($points, $name);
@if $max { @media (max-width: $max) { @content; } }
@else { @content; }
}
@mixin breakpoint-between($namemin, $namemax, $points: $breakpoints, $pointsdown: $breakpoints-down) {
$min: map-get($points, $namemin);
$max: map-get($pointsdown, $namemax);
@if $min != null and $max != null {
@media (min-width: $min) and (max-width: $max) { @content; }
} @else if $max == null {
@include breakpoint-up($namemin) { @content; }
} @else if $min == null {
@include breakpoint-down($namemax) { @content; }
}
}
// Dark scheme property / media query
@mixin dark-scheme($root:false) {
@if $scheme-detection == true {
@media (prefers-dark-interface), (prefers-color-scheme: dark) { @content; }
}
@if $root == true { &[data-scheme="dark"] { @content; } }
@else { [data-scheme="dark"] & { @content; } }
}
// Grid system
@mixin make-row($gutter: $grid-gutter-width) {
display: flex;
flex-wrap: wrap;
margin-top: 0*-1; // logical only
margin-right: $gutter/-2;
margin-left: $gutter/-2;
}
@mixin make-col-ready($gutter: $grid-gutter-width) {
flex-shrink: 0;
width: 100%;
max-width: 100%;
padding-right: $gutter/2;
padding-left: $gutter/2;
margin-top: 0;
}
@mixin make-col($size, $columns: $grid-columns) {
flex: 0 0 auto;
width: percentage($size / $columns);
}
@mixin make-col-auto() {
flex: 0 0 auto;
width: auto;
}
@mixin make-col-offset($size, $columns: $grid-columns) {
$num: $size / $columns;
margin-left: if($num == 0, 0, percentage($num));
}
@mixin make-col-gutter($size, $columns: $grid-columns, $gutter: $grid-gutter-width) {
$num: $size / $columns;
margin-left: $gutter;
width: calc(#{percentage($num)} - #{$gutter});
}
@mixin row-cols($count) {
& > * {
flex: 0 0 auto;
width: 100% / $count;
}
}
@mixin make-grid-columns($columns: $grid-columns, $gutter: $grid-gutter-width, $points: $breakpoints) {
@each $breakpoint in map-keys($points) {
$infix: breakpoint-infix($breakpoint, $points);
@include breakpoint-up($breakpoint, $points) {
.col#{$infix} {
flex: 1 0 0%; // Flexbugs #4: https://github.com/philipwalton/flexbugs#flexbug-4
min-width: 0; // See https://github.com/twbs/bootstrap/issues/25410
}
.row-cols#{$infix}-auto > * {
@include make-col-auto();
}
@if $grid-row-columns > 0 {
@for $i from 1 through $grid-row-columns {
.row-cols#{$infix}-#{$i} {
@include row-cols($i);
}
}
}
.col#{$infix}-auto {
@include make-col-auto();
}
@if $columns > 0 {
@for $i from 1 through $columns {
.col#{$infix}-#{$i} {
@include make-col($i, $columns);
}
}
@for $i from 0 through ($columns - 1) {
@if not ($infix == "" and $i == 0) {
.offset#{$infix}-#{$i} {
@include make-col-offset($i, $columns);
}
}
}
}
// Gutters
@each $key, $value in $gutters {
.g#{$infix}-#{$key},
.gx#{$infix}-#{$key} {
// --ui-gutter-x: #{$value};
margin-left: -#{$value};
@for $i from 0 through ($columns - 1) {
.col-#{$i} {
@include make-col-gutter($i, $columns, $value);
}
}
}
.g#{$infix}-#{$key},
.gy#{$infix}-#{$key} {
// --ui-gutter-y: #{$value};
margin-top: -#{$value};
& > .col, & > [class*="col-"] {
margin-top: #{$value};
}
}
}
}
}
}
// Responsive image
@mixin img-fluid {
max-width: 100%;
height: auto;
}
// Transition
@mixin transition($transition...) {
@if length($transition) == 0 { $transition: $transition-base; }
@if length($transition) > 1 {
@each $value in $transition {
@if $value == null or $value == none {
@warn "The keyword 'none' or 'null' must be used as a single argument.";
}
}
}
@if $enable-transitions {
@if nth($transition, 1) != null { transition: $transition; }
@if $enable-reduced-motion and nth($transition, 1) != null and nth($transition, 1) != none {
@media (prefers-reduced-motion: reduce) {
transition: none;
}
}
}
}
/// Start CSS
// Password dot font face
@font-face {
font-family: 'Dots';
font-style: normal;
font-weight: 400;
src: url(data:application/font-woff;charset=utf-8;base64,d09GRgABAAAAAATsAA8AAAAAB2QAAQAAAAAAAAAAAAAAAAAAAAAAAAAAAABGRlRNAAABWAAAABwAAAAcg9+z70dERUYAAAF0AAAAHAAAAB4AJwANT1MvMgAAAZAAAAA/AAAAYH7AkBhjbWFwAAAB0AAAAFkAAAFqZowMx2N2dCAAAAIsAAAABAAAAAQAIgKIZ2FzcAAAAjAAAAAIAAAACAAAABBnbHlmAAACOAAAALkAAAE0MwNYJ2hlYWQAAAL0AAAAMAAAADYPA2KgaGhlYQAAAyQAAAAeAAAAJAU+ATJobXR4AAADRAAAABwAAAAcCPoA6mxvY2EAAANgAAAAEAAAABAA5gFMbWF4cAAAA3AAAAAaAAAAIAAKAE9uYW1lAAADjAAAARYAAAIgB4hZ03Bvc3QAAASkAAAAPgAAAE5Ojr8ld2ViZgAABOQAAAAGAAAABuK7WtIAAAABAAAAANXulPUAAAAA1viLwQAAAADW+JM4eNpjYGRgYOABYjEgZmJgBEI2IGYB8xgAA+AANXjaY2BifMg4gYGVgYVBAwOeYEAFjMgcp8yiFAYHBl7VP8wx/94wpDDHMIoo2DP8B8kx2TLHACkFBkYA8/IL3QB42mNgYGBmgGAZBkYGEEgB8hjBfBYGDyDNx8DBwMTABmTxMigoKKmeV/3z/z9YJTKf8f/X/4/vP7pldosLag4SYATqhgkyMgEJJnQFECcMOGChndEAfOwRuAAAAAAiAogAAQAB//8AD3jaY2BiUGJgYDRiWsXAzMDOoLeRkUHfZhM7C8Nbo41srHdsNjEzAZkMG5lBwqwg4U3sbIx/bDYxgsSNBRUF1Y0FlZUYBd6dOcO06m+YElMa0DiGJIZUxjuM9xjkGRhU2djZlJXU1UDQ1MTcDASNjcTFQFBUBGjYEkkVMJCU4gcCKRTeHCk+fn4+KSllsJiUJEhMUgrMUQbZk8bgz/iA8SRR9qzAY087FjEYD2QPDDAzMFgyAwC39TCRAAAAeNpjYGRgYADid/fqneL5bb4yyLMwgMC1H90HIfRkCxDN+IBpFZDiYGAC8QBbSwuceNpjYGRgYI7594aBgcmOAQgYHzAwMqACdgBbWQN0AAABdgAiAAAAAAAAAAABFAAAAj4AYgI+AGYB9AAAAAAAKgAqACoAKgBeAJIAmnjaY2BkYGBgZ1BgYGIAAUYGBNADEQAFQQBaAAB42o2PwUrDQBCGvzVV9GAQDx485exBY1CU3PQgVgIFI9prlVqDwcZNC/oSPoKP4HNUfQLfxYN/NytCe5GwO9/88+/MBAh5I8C0VoAtnYYNa8oaXpAn9RxIP/XcIqLreZENnjwvyfPieVVdXj2H7DHxPJH/2/M7sVn3/MGyOfb8SWjOGv4K2DRdctpkmtqhos+D6ISh4kiUUXDj1Fr3Bc/Oc0vPqec6A8aUyu1cdTaPZvyXyqz6Fm5axC7bxHOv/r/dnbSRXCk7+mpVrOqVtFqdp3NKxaHUgeod9cm40rtrzfrt2OyQa8fppCO9tk7d1x0rpiQcuDuRkjjtkHt16ctbuf/radZY52/PnEcphXpZOcofiEZNcQAAeNpjYGIAg///GBgZsAF2BgZGJkZmBmaGdkYWRla29JzKggxD9tK8TAMDAxc2D0MLU2NjENfI1M0ZACUXCrsAAAABWtLiugAA) format('woff');
}
/// CSS root variables
:root {
@each $color, $value in $theme-colors {
--ui-#{$color}: #{$value};
}
@each $gray, $value in $grays {
--ui-gray-#{$gray}: #{$value};
}
@each $breakpoint, $value in $breakpoints {
--ui-breakpoint-#{$breakpoint}: #{$value};
}
--ui-font: #{$font-stack};
--ui-font-monospace: #{$font-stack-monospace};
}
/// Minimal reset
*, *::before, *::after {
box-sizing: border-box;
}
/// HTML
html {
font-size: $font-size;
background-color: $root-bg;
text-rendering: optimizeLegibility;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
-webkit-font-smoothing: antialiased;
-moz-osx-font-smoothing: grayscale;
}
@include breakpoint-up("sm") { html { font-size: 1.0625rem; } }
@include breakpoint-up("md") { html { font-size: 1.125rem; } }
@include breakpoint-up("lg") { html { font-size: 1.1875rem; } }
@include breakpoint-up("xl") { html { font-size: 1.225rem; } }
// Body
body {
margin: 0;
font-family: $font-stack;
font-size: $font-size;
font-weight: $font-weight-normal;
line-height: $font-line-height;
color: $body-color;
text-align: left;
background-color: $body-bg;
overflow-x: hidden;
overscroll-behavior-y: none; // remove overscrolling in Chrome 63+, Firefox 59+ and Opera 50+
-webkit-overflow-scrolling: touch;
@include dark-scheme (true){
background-color: $body-dark-bg;
color: $body-dark-color;
}
}
// Viewport mobile hack
.vh {
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
}
// Outline normalization
* {
outline-color: $primary;
outline-offset: 0.125rem;
}
/// Scrollbars
// Firefox
* {
scrollbar-width: thin;
scrollbar-color: $body-bg transparent;
transition: scrollbar-color .25s ease-in-out;
@include dark-scheme (){
scrollbar-color: $body-dark-bg transparent;
}
&:hover {
scrollbar-color: $body-bg $gray-400;
@include dark-scheme (){
scrollbar-color: $body-dark-bg $gray-600;
}
}
&:active {
scrollbar-color: $body-bg $link-hover-color;
@include dark-scheme (){
scrollbar-color: $body-dark-bg $link-hover-color;
}
}
}
*:hover {
scrollbar-color: $body-bg $gray-500;
@include dark-scheme (){
scrollbar-color: $body-dark-bg $gray-800;
}
}
// IE
* {
scrollbar-face-color: $gray-400;
scrollbar-track-color: $body-bg;
-ms-overflow-style: -ms-autohiding-scrollbar;
@include dark-scheme (){
scrollbar-track-color: $body-dark-bg;
scrollbar-face-color: $gray-800;
}
&:hover {
scrollbar-face-color: $gray-500;
@include dark-scheme (){
scrollbar-face-color: $gray-600;
}
}
&:active {
scrollbar-face-color: $link-hover-color;
}
}
// Chrome, Edge, and Safari (Chromium)
::-webkit-scrollbar {
width: 12px;
}
::-webkit-scrollbar-track {
background: $body-bg;
@include dark-scheme (){
background: $body-dark-bg;
}
}
::-webkit-scrollbar-thumb {
background-color: rgba($gray-400, 1);
border-radius: 6px;
border: 3px solid $body-bg;
visibility: hidden;
will-change: background, visibility;
transition: background-color .25s ease-in-out, visibility .5s ease-in-out;
@include dark-scheme (){
border: 3px solid $body-dark-bg;
background-color: $gray-800;
}
// Hover, active, window inactive states
&:hover {
background-color: $gray-500;
@include dark-scheme (){
background-color: $gray-600;
}
}
&:active {
background-color: $link-hover-color;
}
&:window-inactive {
visibility: hidden;
}
}
// Show on hover / focus
*:hover::-webkit-scrollbar-thumb,
*:focus::-webkit-scrollbar-thumb,
*:focus-within::-webkit-scrollbar-thumb {
visibility: visible;
}
// Links
a {
color: currentColor;
text-decoration: $link-decoration;
background-color: transparent;
cursor: $cursor;
transition: color .15s ease;
&:hover {
color: $link-hover-color;
text-decoration: $link-hover-decoration;
}
&:active {
color: $link-active-color;
text-decoration: $link-decoration;
}
}
// SVGs
svg {
fill: currentColor;
display: inline-block;
a &, button & {
pointer-events: none;
z-index: -1;
}
}
// Responsive image
.responsive-img {
@include img-fluid;
}
/// Typography
legend, p, h1, h2, h3, h4, h5, h6 {
margin: 0 0 $spacer 0;
}
p {
display: block;
}
h1 {
font-size: 1.5rem;
font-weight: 200;
font-weight: lighter;
}
legend, h2 {
font-size: 1.25rem;
font-weight: bold;
}
h3, h4, h5, h6 {
font-size: 1.05rem;
font-weight: bold;
}
kbd {
}
/// Text classes
.text-hide {
font: 0/0;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.text-mute {
}
/// Screenreaders & Hidden Text
.sr-only,
.sr-only-focusable:not(:focus):not(:focus-within),
.visually-hidden,
.visually-hidden-focusable:not(:focus):not(:focus-within) {
position: absolute !important;
width: 1px !important;
height: 1px !important;
padding: 0 !important;
margin: -1px !important;
overflow: hidden !important;
clip: rect(0, 0, 0, 0) !important;
white-space: nowrap !important;
border: 0 !important;
}
/// Code Block
.code-block {
position: relative;
display: inline-block;
width: 100%;
border-radius: .5rem;
background-color: rgba($gray-500, 0.1);
padding: .5rem .75rem;
margin-bottom: 1.5rem;
&:before {
position: absolute;
left: .5rem; top: .25rem;
content: attr(data-language);
color: $gray-500;
font-size: .75em;
}
pre {
width: 100%;
overflow: hidden;
white-space: nowrap;
overflow-style: ellipsis;
}
}
/// Icon class
.icon {
height: 1.5em;
width: auto;
}
/// Float classes
.float-left {
float: left !important;
}
.float-right {
float: right !important;
}
.float-none {
float: none !important;
}
.clearfix::after {
display: block;
clear: both;
content: '';
}
/// Background mixin
@mixin bg-variant($parent, $color) {
#{$parent} {
background-color: $color !important;
}
a#{$parent},
button#{$parent} {
&:hover, &focus, &:target {
background-color: darken($color, 15%) !important;
}
}
}
// Generete backgrounds
@each $name, $color in $theme-colors {
.bg-#{$name} {
color: contrast-color($color);
background-color: $color;
}
}
@each $name, $color in $grays {
.bg-gray-#{$name} {
color: contrast-color($color);
background-color: $color;
}
}
/// Inline alerts
// Alert mixin
@mixin alert-variant($background, $border, $color) {
color: $color;
background-color: $background;
border-color: $border;
a {
color: currentColor;
&:hover, &:focus {
color: darken($color, 10%);
}
&:active {
color: lighten($color, 7%);
}
}
}
// Generate alerts
@each $name, $color in $theme-colors {
.alert-#{$name} {
@include alert-variant($color, 0, contrast-color($color));
}
}
/// Shadow classes
.shadow-sm { box-shadow: $shadow-sm; }
.shadow { box-shadow: $shadow; }
.shadow-lg { box-shadow: $shadow-lg; }
.shadow-none { box-shadow: none !important; }
.shadow-elevated { box-shadow: $shadow-elevated; }
/// Rounded classes
.rounded-0 { border-radius: 0!important; }
.rounded-sm { border-radius: $border-radius/2 !important; }
.rounded { border-radius: $border-radius !important; }
.rounded-lg { border-radius: $border-radius*2 !important; }
.rounded-circle { border-radius: 50% !important; }
.rounded-pill { border-radius: 50rem !important; }
/// Grid system
// Container
@mixin make-container($gutter: $container-padding-x) {
width: 100%;
padding-right: $gutter / 2;
padding-left: $gutter / 2;
margin-right: auto;
margin-left: auto;
}
// For each breakpoint, define the maximum width of the container in a media query
@mixin make-container-max-widths($max-widths: $container-max-widths, $points: $breakpoints) {
@each $breakpoint, $container-max-width in $max-widths {
@include breakpoint-up($breakpoint) {
max-width: $container-max-width;
}
}
}
// Minimum breakpoint width. Null for the smallest (first) breakpoint.
@function breakpoint-min($name, $points: $breakpoints) {
$min: map-get($points, $name);
@return if($min != 0, $min, null);
}
// Returns a blank string if smallest breakpoint, otherwise returns the name with a dash in front.
@function breakpoint-infix($name, $points: $breakpoints) {
@return if(breakpoint-min($name, $points) == null, "", "-#{$name}");
}
// Single container class with breakpoint max-widths
.container {
@include make-container();
@include make-container-max-widths();
}
// 100% wide container at all breakpoints
.container-fluid {
@include make-container();
}
// Responsive containers that are 100% wide until a breakpoint
@each $breakpoint, $container-max-width in $container-max-widths {
.container-#{$breakpoint} {
@extend .container-fluid;
}
@include breakpoint-up($breakpoint, $breakpoints) {
%responsive-container-#{$breakpoint} {
max-width: $container-max-width;
}
@each $name, $width in $breakpoints {
@if ($container-max-width > $width or $breakpoint == $name) {
.container#{breakpoint-infix($name)} {
@extend %responsive-container-#{$breakpoint};
}
}
}
}
}
// Grid Row
@if $enable-grid {
.row {
@include make-row();
> * {
@include make-col-ready();
}
}
}
// Grid Columns
@if $enable-grid {
@include make-grid-columns();
}
/// Display
@each $breakpoint in map-keys($breakpoints) {
@include breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $breakpoints);
@each $value in $displays {
.d#{$infix}-#{$value} { display: $value !important; }
}
}
}
// Print
@media print {
@each $value in $displays {
.d-print-#{$value} { display: $value !important; }
}
}
/// Position
.fixed-top {
position: fixed;
top: 0;
right: 0;
left: 0;
z-index: $zindex-fixed;
}
.fixed-bottom {
position: fixed;
right: 0;
bottom: 0;
left: 0;
z-index: $zindex-fixed;
}
// Responsive sticky top
@each $breakpoint in map-keys($breakpoints) {
@include breakpoint-up($breakpoint) {
$infix: breakpoint-infix($breakpoint, $breakpoints);
.sticky#{$infix}-top {
position: sticky;
top: 0;
z-index: $zindex-sticky;
}
}
}
/// Global Close:
// Used in notifications, inlinr alerts, popups and dialogs, etc.
.close {
display: inline-block;
overflow: hidden;
position: relative;
font-size: 1rem;
width: 2em;
height: 2em;
border-radius: 1em;
border: 0;
text-indent: -9999rem;
background-color: rgba($white, 0);
cursor: $cursor;
pointer-events: all;
&::before, &::after {
content: '';
position: absolute;
top: calc(50%);
left: 20%;
display: inline-block;
height: 0.15em;
width: 60%;
background-color: currentColor;
transform-origin: center center;
transform: rotate(45deg);
pointer-events: none;
}
&::after {
transform: rotate(-45deg);
}
@include breakpoint-down("xs") {
&::before, &::after {
transform-origin: right center;
width: 40%;
right: 30%;
}
&::before {
top: auto;
bottom: 20%;
}
&::after {
top: 20%;
}
}
}
/// Global Caret:
// Used for the collaps class, dropdowns etc.
.caret {
position: relative;
display: inline-block;
width: 1em;
height: 1em;
line-height: 1;
margin: 0 0 0 .25em;
vertical-align: middle;
text-align: center;
pointer-events: none;
&:empty::before {
content: '';
display: inline-block;
position: absolute;
top: 0;
left: .15em;
width: .6em;
height: .6em;
border: 0px solid currentColor;
border-width: 0 .1em .1em 0;
transform: rotate(45deg);
}
}
/// Global Hamburger:
// Mobile menu label button from hamburger to centered list to x and back.
$hamburger-transition-transform: transform .45s cubic-bezier(.9, -.6, .3, 1.6) .1s;
$hamburger-transition-width: width .2s ease;
.hamburger {
appearance: button;
position: relative;
display: inline-block;
overflow: hidden;
width: 2em;
height: 2em;
margin:0; padding:.5em;
text-indent: -9999rem;
font-size: 1rem; // Hamburger sizing
color: currentColor;
// border-radius: 50%;
cursor: pointer;
i {
overflow: visible;
top: calc(50% - .1em);
width: calc(100% - .5em);
left: .25em; right: .25em;
height: .2em;
&,
&:before,
&:after {
position: absolute;
display: block;
border-radius: .1em;
background: currentColor;
transform: translate(0,0);
// transform-origin: center center;
will-change: transform, width;
transition: $hamburger-transition-transform, $hamburger-transition-width .2s;
}
&:before,
&:after {
content: '';
height: 100%;
}
&:before {
top: -0.5em;
right: 0;
width: 50%;
}
&:after {
bottom: -0.5em;
right: 0;
width: 75%;
}
}
&:hover, &:focus, &:active {
i {
color: $link-hover-color;
&:before, &:after {
width:75%;
transform: translateX(-12.5%);
}
}
}
&:active i {
color: $link-active-color;
}
// Toggle Checkbox
&-toggler {
display: none;
&:checked ~ .hamburger i {
transform: translateX(-150%);
background-color: transparent;
transition: $hamburger-transition-transform, background 0.5s ease-in-out;
&:before {
width: 100%;
transform: translate(150%, 0.5em) rotate(-45deg);
transition: $hamburger-transition-transform, $hamburger-transition-width;
}
&:after {
width: 100%;
transform: translate(150%, -0.5em) rotate(45deg);
transition: $hamburger-transition-transform, $hamburger-transition-width;
}
}
&:checked ~ nav,
&:checked ~ .mobile-menu {
display: inline-block !important; // !Hack is unavoidable here.
visibility: visible;
}
}
}
/// Loading Indicators:
// Spinner
.loading-spinner {
position: relative;
display: inline-block;
font-size: inherit;
width: 2em;
height: 2em;
border-radius: 50%;
border: .175em solid rgba(0, 0, 0, 0.15);
border-left-color: currentColor;
transform: translateY(50%);
animation: loading-rotate 1s infinite linear;
will-change: transform;
cursor: progress;
// Sizes
&-sm {
font-size: .7em;
}
&-lg {
font-size: 1.5em;
}
}
@keyframes loading-rotate {
0% { transform: rotate(360deg); }
100% { transform: rotate(0deg); }
}
// Ellipsis
.loading-ellipsis {
&:after {
overflow: hidden;
content: '\2026'; // Ascii code for the ellipsis character.
width: 0;
display: inline-block;
vertical-align: bottom;
animation: loading-ellipsis steps(4,end) 1.5s infinite;
}
}
@keyframes loading-ellipsis {
to { width: 1em; }
}
// Progress bar
.loading-progress {
padding-bottom: 0.15em;
&:after {
content: '';
position: absolute;
bottom: 0; left: 0;
width: 100%;
height: .15em;
background-repeat: no-repeat;
background-attachment: fixed;
background-image: linear-gradient(90deg, currentColor, currentColor);
background-size: 0% 100%;
background-position: left center;
background-color: $gray-300;
animation: loading-progress 2s ease-in-out infinite 0s;
transition: background-size .1s ease-in-out;
}
// Not animated
&.loading-progress-noanimate {
&:after {
animation-play-state: paused;
}
}
// Colors
&.loading-progress-primary {
&:after {
color: $primary;
}
}
}
@keyframes loading-progress {
to { background-size: 100% 100%; }
}
/// Document States:
// Loading
[loading], .loading {
cursor: progress;
& * {
pointer-events: none;
}
}
// Disabled property / pseudo / class
[disabled], :disabled, .disabled {
cursor: not-allowed!important; // !Hack to make [disabled]
filter: grayscale(1);
opacity: 0.5;
&:before {
content: '';
display: block;
position: absolute;
width: 100%; height: 100%;
pointer-events: none;
}
}
// Hidden property / pseudo / class
:hidden, [hidden], .hidden {
display: none!important;
visibility: hidden;
}
// UI interaction / manipulation properties
[scrolling] {
scroll-behavior: smooth;
@media screen and (prefers-reduced-motion: reduce) { scroll-behavior: auto; }
}
[swiping], [dragging] {
overscroll-behavior: contain;
-webkit-overflow-scrolling: touch;
-ms-scroll-chaining: none;
/* autoprefixer: off */
-ms-touch-action: none;
touch-action: none;
&, & > * {
user-select: none;
}
}
[pan-x] {
touch-action: pan-x;
}
[pan-y] {
touch-action: pan-y;
}
[drag] {
cursor: grab;
}
[dragging] {
cursor: grabbing;
& > * {
pointer-events: none;
}
& [dragging-horizontal] {
cursor: e-resize!important;
}
& [dragging-vertical] {
cursor: n-resize!important;
}
}
[manipulating] {
user-select: none;
/* autoprefixer: off */
-ms-touch-action: manipulation;
touch-action: manipulation;
}
[noanimate] {
transition: none;
animation: none;
}
@media screen and (prefers-reduced-motion: reduce) {
[scrolling], [dragging], [paning] {
scroll-behavior: auto;
}
}
/// Transitions:
.fade {
@include transition($transition-fade);
&:not(.show) { opacity: 0; }
}
.collapse {
&:not(.show) { display: none; }
}
.collapsing {
height: 0;
overflow: hidden;
@include transition($transition-collapse);
}
.dropping {
height: 0;
overflow: hidden;
@include transition($transition-dropscale);
}
/// Forms:
// Form normalization
form, fieldset {
padding: 0;
margin: 0;
border: 0;
}
form, .form {
width: 100%;
}
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
.form-check {
width: 100%;
}
}
// Form grid
.form-row {
display: flex;
flex-wrap: wrap;
margin-right: -$form-grid-gutter-width*.75;
margin-left: -$form-grid-gutter-width*.75;
> .col,
> [class*="col-"] {
padding-right: $form-grid-gutter-width*.75;
padding-left: $form-grid-gutter-width*.75;
}
}
// Form group
.form-group {
position: relative;
margin-bottom: $form-group-margin-bottom;
}
// Form group with floating labels
@mixin form-float-label-up($font-size: $input-float-label-font-size, $padding-y: $input-padding-y) {
padding-top: $padding-y;
font-size: $font-size;
min-height: auto;
line-height: 1;
}
.form-float-label {
.form-control, .form-label {
padding-left: $input-padding-x;
min-height: $input-float-label-height;
}
.form-label {
position: absolute;
top: 0;
display: block;
@include form-float-label-up();
font-weight: $input-font-weight;
font-family: $input-font-family;
color: $input-placeholder-color;
background-color: transparent;
will-change: padding-top, font-size, color;
pointer-events: none;
order: 1; // Screenreader order
@include transition($input-float-label-transition);
@include dark-scheme (){
color: $input-dark-color;
}
// Validation states
@at-root .has-error #{&} {
font-weight: $font-weight-normal;
}
}
.form-control {
padding-top: $input-padding-y + $input-float-label-font-size/1.15;
order: 2; // Screenreader order
&:not(textarea):not(:disabled):not(:read-only) {
&::placeholder {
opacity: 0;
}
&[type="text"], &[type="password"], &[type="url"], &[type="phone"], &[type="email"] {
& ~ .form-label {
padding-top: $input-padding-y + $input-float-label-font-size/2;
min-height: $input-height;
font-size: $input-font-size;
line-height: $input-line-height;
}
}
&:focus, &:active, &:focus-within, &:not(:placeholder-shown) {
& ~ .form-label {
@include form-float-label-up();
}
}
}
&:focus, &:active, &:focus-within {
& ~ .form-label {
color: $input-label-focus-color;
}
}
}
}
/// Labels
.form-label {
margin-bottom: $form-label-margin-bottom;
font-size: inherit;
font-style: $form-label-font-style;
font-weight: $form-label-font-weight!important;
color: $form-label-color;
// Validation states
@at-root .has-error #{&} {
color: $danger;
font-weight: $font-weight-bold;
}
}
// Inputs
// Hide spam honey pot & possible token fields
input[id*='spam'], label[for*='spam'] {display: none!important; visibility: hidden;}
input[id*='token'], label[for*='token'] {display: none!important; visibility: hidden;}
// Form control
.form-control {
display: block;
width: 100%;
min-height: $input-height;
padding: $input-padding-y $input-padding-x;
font-family: $input-font-family;
font-size: $input-font-size;
font-weight: $input-font-weight;
line-height: $input-line-height;
letter-spacing: normal;
color: $input-color;
caret-color: currentColor;
background-color: $input-bg;
background-clip: padding-box;
border: $input-border-width solid $input-border-color;
appearance: none;
@include border-radius($input-border-radius);
box-shadow: $input-box-shadow;
cursor: default;
will-change: border, background, box-shadow, letter-spacing;
@include transition($input-transition);
@include dark-scheme (){
background-color: $input-dark-bg;
color: $input-dark-color;
}
&:hover:not(:disabled):not(:focus) {
color: $input-hover-color;
border-color: $input-hover-border-color;
&::placeholder, & ~ label {
color: $input-hover-color;
}
// Validation error
@at-root .has-error #{&} {
color: $danger;
border-color: $danger;
&::placeholder, & ~ label {
color: $danger;
}
}
}
&:focus {
color: $input-focus-color;
background-color: $input-focus-bg;
border-color: $input-focus-border-color;
outline: 0;
box-shadow: $input-focus-box-shadow;
cursor: text;
@include dark-scheme (){
background-color: $input-dark-focus-bg;
}
}
// Remove select outline from select box in FF
&:-moz-focusring {
color: transparent;
text-shadow: 0 0 0 $input-color;
}
// Unstyle the caret on `<select>`s in IE10+.
&::-ms-expand {
background-color: transparent;
border: 0;
}
&::-ms-clear {
display:none;
}
// Placeholder
&::placeholder {
font-family: $input-font-family;
color: $input-placeholder-color;
letter-spacing: normal;
opacity: 1;
}
// Disabled and read-only inputs
&:disabled, &:readonly {
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
opacity: 1;
}
// Readonly controls as plain text
#{&}-plaintext {
display: block;
width: 100%;
padding: $input-padding-y 0;
margin-bottom: 0; // match inputs if this class comes on inputs with default margins
line-height: $input-line-height;
color: $input-plaintext-color;
background-color: transparent;
border: solid transparent;
border-width: $input-border-width 0;
&.form-control-sm,
&.form-control-lg {
padding-right: 0;
padding-left: 0;
}
}
// Form control sizing
&-sm {
min-height: $input-height-sm;
padding: $input-padding-y-sm $input-padding-x-sm;
font-size: $input-font-size-sm;
@include border-radius($input-border-radius-sm);
}
&-lg {
min-height: $input-height-lg;
padding: $input-padding-y-lg $input-padding-x-lg;
font-size: $input-font-size-lg;
@include border-radius($input-border-radius-lg);
}
// Textarea
@at-root textarea#{&} {
height: auto;
resize: vertical;
}
// Color input
&[type*="color"] {
max-width: 3rem;
padding: $input-padding-y;
&:focus {
cursor: default;
}
&:invalid {
&::-moz-color-swatch { background: $transparency-bg; }
&::-webkit-color-swatch { background: $transparency-bg; }
}
&::-webkit-color-swatch-wrapper { // remove datalist ui [list="id"]
padding:0;
}
&::-moz-color-swatch {
border:0;
@include border-radius(0);
}
&::-webkit-color-swatch {
border:0;
@include border-radius(0);
}
}
// Range / file input
&[type*="file"],
&[type*="range"]{
display: block;
width: 100%;
}
&::file-selector-button {
display: none
}
&::-webkit-file-upload-button {
display: none
}
&::-ms-browse {
display: none
}
// Select
@at-root select#{&} {
background-image: escape-svg($input-select-icon-bg);
background-repeat: no-repeat;
background-size: 1em 1em;
background-position: substract(100%, $input-padding-x, true) center;
&[multiple],
&[size]:not([size="1"]) {
height: auto;
background-image: none;
}
&:focus {
cursor: default;
background-image: escape-svg($input-select-icon-bg-focus);
&::-ms-value {
color: $input-focus-color;
background-color: $input-focus-bg;
}
}
optgroup, option {
font-style: normal;
color: $input-color;
&[label], &[label] { // W3C recos, Firefox label display
content: attr(label);
}
}
optgroup[label]{
font-weight: 400!important;
}
option {
&:hover {
color: $input-focus-color;
background-color: rgba($gray-500, 0.1)!important;
}
&:focus, &:active,
&:selected:not(:disabled),
&:checked:not(:disabled) {
color: $input-focus-bg;
background-color: $input-focus-color;
}
&:selected, &:checked {
&::before{
display: inline;
content: check;
}
}
&:invalid, &:not(:valid) {
color: $input-placeholder-color;
}
&[value=""][disabled], &[default] {
display: none;
}
}
// Error
@at-root .has-error #{&} {
background-image: escape-svg($input-select-icon-bg-error);
}
}
// Number
&[type*="number"]{
-moz-appearance: textfield;
&::-webkit-inner-spin-button {
display: none;
}
&::-webkit-clear-button {
display: none;
}
&::-ms-clear {
display: none;
}
}
// Date / time / datetime-local / datetime
&[type*="date"], &[type="time"], &[type="week"], &[type="month"] {
appearance: listbox;
-webkit-appearance: none;
background-repeat: no-repeat;
background-size: 1em 1em;
background-position: substract(100%, $input-padding-x, true) center;
&::-webkit-spin-button,
&::-webkit-outer-spin-button,
&::-webkit-inner-spin-button {
display: none;
}
&::-webkit-clear-button {
display: none;
}
&::-ms-clear {
display: none;
}
&::-webkit-calendar-picker-indicator {
position: absolute;
right: $input-padding-x;
width: 1em;
opacity: 0;
cursor: $cursor;
margin:0;
}
}
&[type*="date"], &[type="week"], &[type="month"] {
background-image: escape-svg($input-date-icon-bg);
&:focus {
background-image: escape-svg($input-date-icon-bg-focus);
}
}
&[type="time"] {
background-image: escape-svg($input-time-icon-bg);
&:focus {
background-image: escape-svg($input-time-icon-bg-focus);
}
}
// Search
&[type="search"] {
padding-left: add(1.5em, 2*$input-padding-x, true);
background-repeat: no-repeat;
background-size: 1.5em 1.5em;
background-position: $input-padding-x center;
background-image: escape-svg($input-search-icon-bg);
&:focus {
background-image: escape-svg($input-search-icon-bg-focus);
}
}
// Password
&[type*="password"]{
font-family: 'Dots', $input-font-family;
letter-spacing: .1em;
}
// Autofill
@mixin input-autofill ($font-size: $input-font-size) {
font: inherit !important;
color: $input-color !important;
-webkit-text-fill-color: $input-color !important; // Non-standard
background: escape-svg($input-autofill-icon-bg) !important;
background-image: escape-svg($input-autofill-icon-bg) !important;
background-repeat: no-repeat;
background-size: 1em 1em;
background-position: substract(100%, $input-padding-x, true) center;
@include dark-scheme (){
background-color: $input-dark-bg;
}
@include transition($input-transition, font 0s linear, background-image .15s linear, background-color 99999s linear 99999s);
&:focus, &:active {
font: inherit !important;
color: $primary !important;
-webkit-text-fill-color: $primary !important; // Non-standard
background-image: escape-svg($input-autofill-active-icon-bg) !important;
}
}
&:autofill {
@include input-autofill ();
}
&:-webkit-autofill {
@include input-autofill ();
}
&:-internal-autofill-selected,
&:-internal-autofill-previewed,
&:-internal-input-suggested {
@include input-autofill ();
}
// Validation states
&.is-validated:invalid {
color: $danger;
border-color: $danger;
&:focus {
box-shadow: $input-error-box-shadow;
}
}
&.is-validated:valid {
}
// Validation states
@at-root .has-error #{&} {
color: $danger;
border-color: $danger;
& ~ * {
color: $danger!important; // !Hack.
}
&:focus {
box-shadow: $input-error-box-shadow;
}
&::placeholder {
color: $danger;
}
&[type*="date"], &[type="month"] {
background-image: escape-svg($input-date-icon-bg-error);
&:focus {
background-image: escape-svg($input-date-icon-bg-error);
}
}
&[type*="time"] {
background-image: escape-svg($input-time-icon-bg-error);
&:focus {
background-image: escape-svg($input-time-icon-bg-error);
}
}
&[type*="search"] {
background-image: escape-svg($input-search-icon-bg-error);
&:focus {
background-image: escape-svg($input-search-icon-bg-error);
}
}
}
@at-root .is-valid #{&} {
}
}
// Custom inputs (enhanced wrap with JS).
// Password & Search UI buttons
.form-password, .form-search {
position: relative;
input {
padding-right: add(2.5em, $input-padding-x/2, true);
&:not(:placeholder-shown), &:not(:placeholder-shown):focus {
& ~ .btn-reveal, & ~ .btn-clear {
opacity: 1;
pointer-events: all;
}
}
&:focus {
& ~ .btn-reveal, & ~ .btn-clear {
color: $input-focus-color;
}
}
// Search input
&[type="search"] {
&::-ms-clear {
display: none; width : 0; height: 0;
}
&::-webkit-search-decoration,
&::-webkit-search-cancel-button,
&::-webkit-search-results-button,
&::-webkit-search-results-decoration {
-webkit-appearance: none;
display: none;
}
}
// Password
&[type="password"] {
&::-ms-reveal {
display:none;
}
}
}
button {
position: absolute;
border: 0;
top: 0;
right: 0;
background: transparent;
opacity: 0;
pointer-events: none;
outline: none;
text-align: center;
line-height: 0;
height: 100%;
padding: $input-padding-y $input-padding-x;
color: $input-placeholder-color;
&:hover, &:focus, &:active {
opacity: 1;
pointer-events: all;
color: currentColor;
}
svg {
width: 1.15em; height: auto;
fill: currentColor;
}
}
}
// Number input
.form-number {
white-space: nowrap;
button {
position: relative;
width: 2.5em;
max-height: $input-height;
min-height: unset;
z-index: 1;
&:focus, &:active {
z-index: 3;
}
&:first-of-type {
float: left;
border-top-right-radius: 0;
border-bottom-right-radius:0;
}
&:last-of-type {
float: right;
border-top-left-radius: 0;
border-bottom-left-radius:0;
}
}
input{
position: relative;
float: left;
width: calc(100% - 5em);
text-align: center;
border-radius:0;
z-index:2;
}
&[disabled], &.disabled {
button {
pointer-events: none;
}
}
}
// Custom checkboxes, radios, switches: Apply class on wrapper.
.form-check, .form-radio, .form-switch {
position: relative;
margin-bottom: $form-label-margin-bottom/2;
white-space: nowrap; // Prevent floating inside.
input {
position: absolute;
left: 0; top: 0;
z-index: -1;
width: 1.5em;
height: 1.5em;
opacity: 0;
&:disabled ~ label {
color: $input-disabled-border-color;
cursor: not-allowed;
opacity: .5;
&::before, &::after {
pointer-events: none;
background-color: $input-disabled-bg;
border-color: $input-disabled-border-color;
}
}
}
input:checked:not(:disabled) + label{
&::before {
background-color: $input-focus-color;
}
&::after {
opacity: 1;
}
}
label {
position: relative;
padding: 0 0 0 2em;
margin:0;
line-height: 1.5;
&::before, &::after {
position: absolute;
left: 0; top: 0;
content: '';
display: block;
border: $input-border-width solid $input-border-color;
border-radius: $input-border-radius;
width: 1.5em;
height: 1.5em;
vertical-align: middle;
cursor: pointer;
will-change: opacity, border-color, background, box-shadow;
@include transition($form-check-transition);
}
&::before {
background-color: rgba($input-border-color,.25);
}
&::after {
opacity: 0;
}
}
}
.form-check, .form-radio, .form-switch {
input:focus, input:active {
&:not(:disabled) + label {
&::before {
box-shadow: $input-focus-box-shadow;
border-color: $input-focus-border-color;
}
}
}
}
.form-check {
input:checked:not(:disabled) + label{
&::after{
background-image: escape-svg($form-check-icon-bg) !important;
}
}
label {
&::after {
border:0;
background-color: transparent;
background-repeat: no-repeat;
background-position: center center;
background-size: 75%;
}
}
}
.form-radio {
input:checked:not(:disabled) + label{
&::after{
background-color: $input-bg;
transform: scale(1);
}
}
label {
&::before, &::after {
border-radius: 50%;
}
&::after {
left: .375em; top: .375em;
height: .75em;
width: .75em;
transform: scale(0);
}
}
}
.form-switch {
input {
width: 3em;
&:checked {
& ~ label::after {
left: 1.75em;
}
}
}
label {
padding: 0 0 0 3.5em;
&::before, &::after {
border-radius: 50%;
}
&::before {
height: 1.5em;
width: 3em;
border-radius: .75em;
cursor: default;
}
&::after {
left: .25em; top: .25em;
height: 1em;
width: 1em;
border-radius: .5em;
background-color: $input-bg;
opacity: 1;
}
}
}
// Range
.form-range {
width: 100%;
min-height: $input-height; // Align middle
padding: 0; // Need to reset padding
background-color: transparent;
appearance: none;
--rangeValue: calc(attr(value)*100); // Future?
& ~ output {
position: absolute;
top: -1em;
left: 50%;
display: inline-block;
width: auto; height: 2em;
padding: 0 .75em;
transform: translateX(-50%);
background-color: $form-range-thumb-active-bg;
color: $white;
text-align: center;
line-height: 2;
border-radius: 1em;
opacity: 0;
visibility: hidden;
transition: opacity .15s linear;
}
&:focus {
outline: none;
&::-webkit-slider-thumb { box-shadow: $form-range-thumb-focus-box-shadow; background: $form-range-thumb-active-bg;}
&::-moz-range-thumb { box-shadow: $form-range-thumb-focus-box-shadow; background: $form-range-thumb-active-bg;}
&::-ms-thumb { box-shadow: $form-range-thumb-focus-box-shadow; background: $form-range-thumb-active-bg;}
&::-webkit-slider-runnable-track {
background-image: -webkit-linear-gradient(left, $form-range-track-active-fill-bg calc(var(--rangeValue)*1%), transparent calc(var(--rangeValue)*1%));
}
&::-moz-range-progress { background-color: $form-range-track-active-fill-bg;}
&::-ms-fill-lower { background-color: $form-range-track-active-fill-bg;}
// Output
& ~ output{
opacity: 1;
visibility: visible;
}
}
&:active {
&::-webkit-slider-thumb { background: $form-range-thumb-active-bg; }
&::-moz-range-thumb { background: $form-range-thumb-active-bg; }
&::-ms-thumb { background: $form-range-thumb-active-bg; }
}
&::-moz-focus-outer { border: 0; }
&::-webkit-slider-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
margin-top: ($form-range-track-height - $form-range-thumb-height) / 2; // Webkit specific
background: $form-range-thumb-bg;
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
box-shadow: $form-range-thumb-box-shadow;
@include transition($form-range-thumb-transition);
appearance: none;
}
&::-webkit-slider-runnable-track {
width: $form-range-track-width;
height: $form-range-track-height;
color: transparent; // Why?
cursor: $form-range-track-cursor;
background-image: -webkit-linear-gradient(left, $form-range-track-fill-bg calc(var(--rangeValue)*1%), transparent calc(var(--rangeValue)*1%));
background-color: $form-range-track-bg;
border-color: transparent;
@include border-radius($form-range-track-border-radius);
box-shadow: $form-range-track-box-shadow;
}
&::-moz-range-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
background: $form-range-thumb-bg;
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
box-shadow: $form-range-thumb-box-shadow;
@include transition($form-range-thumb-transition);
appearance: none;
}
&::-moz-range-track {
width: $form-range-track-width;
height: $form-range-track-height;
color: transparent;
cursor: $form-range-track-cursor;
background-color: $form-range-track-bg;
border-color: transparent; // Firefox specific?
@include border-radius($form-range-track-border-radius);
box-shadow: $form-range-track-box-shadow;
}
&::-moz-range-progress {
height: $form-range-track-height;
background-color: $form-range-track-fill-bg;
@include border-radius($form-range-track-border-radius);
}
&::-ms-thumb {
width: $form-range-thumb-width;
height: $form-range-thumb-height;
margin-top: 0; // Edge specific
margin-right: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.
margin-left: $form-range-thumb-focus-box-shadow-width; // Workaround that overflowed box-shadow is hidden.
background: $form-range-thumb-bg;
border: $form-range-thumb-border;
@include border-radius($form-range-thumb-border-radius);
box-shadow: $form-range-thumb-box-shadow;
@include transition($form-range-thumb-transition);
appearance: none;
}
&::-ms-track {
width: $form-range-track-width;
height: $form-range-track-height;
color: transparent;
cursor: $form-range-track-cursor;
background-color: transparent;
border-color: transparent;
border-width: $form-range-thumb-height / 2;
box-shadow: $form-range-track-box-shadow;
}
&::-ms-fill-lower {
background-color: $form-range-track-fill-bg;
@include border-radius($form-range-track-border-radius);
}
&::-ms-fill-upper {
margin-right: 15px; // arbitrary?
background-color: $form-range-track-bg;
@include border-radius($form-range-track-border-radius);
}
&:disabled {
pointer-events: none;
&::-webkit-slider-thumb {
background-color: $form-range-thumb-disabled-bg;
}
&::-moz-range-thumb {
background-color: $form-range-thumb-disabled-bg;
}
&::-ms-thumb {
background-color: $form-range-thumb-disabled-bg;
}
}
}
/// Input group
.input-group {
position: relative;
display: flex;
flex-wrap: wrap; // For form validation feedback
align-items: stretch;
width: 100%;
> .form-control,
> .form-search,
> .form-password,
> .form-select,
> .form-file {
position: relative; // For focus state's z-index
flex: 1 1 auto;
width: 1%;
min-width: 0;
}
// Bring the "active" form control to the top of surrounding elements
> .form-control:focus,
> .form-select:focus,
> .form-search:focus,
> .form-password:focus,
> .form-file .form-file-input:focus ~ .form-file-label {
z-index: 3;
}
// Bring the custom file input above the label
> .form-file {
> .form-file-input:focus {
z-index: 4;
}
&:not(:last-child) > .form-file-label {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
&:not(:first-child) > .form-file-label {
border-bottom-left-radius: 0;
border-top-left-radius: 0;
}
}
.btn {
position: relative;
z-index: 2;
&:focus {
z-index: 3;
}
}
// Border-radius
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
> .form-search input, > .form-password input,
> .dropdown-toggle:nth-last-child(n + 3) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
> :not(:first-child):not(.dropdown-menu) {
margin-left: -$input-border-width;
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
}
// Textual addons
.input-group-text {
display: flex;
align-items: center;
padding: $input-padding-y $input-padding-x;
font-size: $input-font-size; // Match inputs
font-weight: $font-weight-normal;
line-height: $input-line-height;
color: $input-group-addon-color;
text-align: center;
white-space: nowrap;
background-color: $input-group-addon-bg;
border: $input-border-width solid $input-border-color;
@include border-radius($input-border-radius);
}
// Prepend / append input group
.input-group-prepend,
.input-group-append {
display: flex;
.btn {
position: relative;
z-index: 2;
&:focus {
z-index: 3;
}
& + .btn,
& + .input-group-text {
margin-left: -$input-border-width;
}
}
.input-group-text + .input-group-text,
.input-group-text + .btn {
margin-left: -$input-border-width;
}
}
.input-group-prepend { margin-right: -$input-border-width; }
.input-group-append { margin-left: -$input-border-width; }
// Prepend and append rounded corners
.input-group > .input-group-prepend > .form-control,
.input-group > .input-group-prepend > .input-group-text,
.input-group > .input-group-append:not(:last-child) > .btn,
.input-group > .input-group-append:not(:last-child) > .input-group-text,
.input-group > .input-group-append:last-child > .btn:not(:last-child):not(.dropdown-toggle),
.input-group > .input-group-append:last-child > .input-group-text:not(:last-child) {
border-top-right-radius: 0;
border-bottom-right-radius: 0;
}
.input-group > .input-group-append > .btn,
.input-group > .input-group-append > .input-group-text,
.input-group > .input-group-prepend:not(:first-child) > .btn,
.input-group > .input-group-prepend:not(:first-child) > .input-group-text,
.input-group > .input-group-prepend:first-child > .btn:not(:first-child),
.input-group > .input-group-prepend:first-child > .input-group-text:not(:first-child) {
border-top-left-radius: 0;
border-bottom-left-radius: 0;
}
/// Button
.btn {
display: inline-block;
min-width: 1.25rem;
font-size: if($btn-uppercase, 0.85rem, 1rem);
font-weight: 600;
color: $gray-900;
text-align: center;
text-decoration: none;
text-transform: if($btn-uppercase, uppercase, none);
vertical-align: middle;
cursor: $cursor;
background-color: $gray-200;
border: 1px solid transparent;
padding: 0.5em 0.75em;
line-height: 1.35;
border-radius: $border-radius;
transition: $btn-transition;
user-select: none;
&::first-letter {
text-transform: uppercase;
}
&:hover {
text-decoration: none;
color: #fff;
background-color: darken($gray-200, 12%);
}
&.focus, &:focus, &:target {
outline: 0;
text-decoration: none;
box-shadow: 0 0 0 0.25rem rgba($gray-800, 0.1);
}
svg, .icon {
height: 1em;
margin: -.125em 0 0 0;
vertical-align: middle;
}
&.rounded-circle {
padding: .5rem .65rem !important;
}
&.rounded-pill {
padding: .5rem .85rem !important;
}
}
// Button form alignement
button{
&:last-child {
margin-right: 0;
}
&:first-child {
margin-left: 0;
}
}
// Change generic pointer
[type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled), button:not(:disabled) {
cursor: $cursor;
}
// Button theme colors
@each $name, $color in $theme-colors {
.btn-#{$name} {
color: contrast-color($color);
background-color: $color;
border-color: $color;
&:hover {
color: contrast-color($color);
background-color: darken($color, 12%);
border-color: $color;
}
&.focus, &:focus, &:target {
box-shadow: 0 0 0 0.25rem rgba($color, 0.2);
}
&:not(:disabled):not(.disabled).active,
&:not(:disabled):not(.disabled):active,
.show > &.dropdown-toggle {
color: contrast-color($color);
background-color: $color;
border-color: $color;
}
}
}
// Button outline
@each $name, $color in $theme-colors {
.btn-outline-#{$name} {
color: $color;
background-color: transparent;
border-color: $color!important;
&:hover {
color: contrast-color($color);
background-color: $color;
border-color: $color;
}
&.focus, &:focus, &:target {
box-shadow: 0 0 0 0.25rem rgba($color, 0.2);
}
&:not(:disabled):not(.disabled).active,
&:not(:disabled):not(.disabled):active,
.show > &.dropdown-toggle {
color: contrast-color($color);
background-color: darken($color, 12%);
border-color: $color;
}
}
}
/// Cards
.card {
position: relative;
display: flex;
flex-direction: column;
min-width: 0;
word-wrap: break-word;
background-color: $card-bg;
@include dark-scheme() {
background-color: $card-dark-bg;
}
background-clip: border-box;
border: 1px solid rgba(222, 226, 230, 0.5);
border-radius: 0.3rem;
transition: border .15s linear,
box-shadow .15s ease-in-out;
&:hover {
border-color: #dee2e6;
box-shadow: $shadow-elevated;
}
}
.card-img, .card-img-bottom, .card-img-top {
flex-shrink: 0;
width: 100%;
}
.card-img, .card-img-top {
border-top-left-radius: calc(0.3rem - 1px);
border-top-right-radius: calc(0.3rem - 1px);
}
.card-body {
flex: 1 1 auto;
min-height: 1px;
padding: 1.25rem;
}
.card-title {
margin-bottom: .75rem;
}
.card-text:last-child {
margin-bottom: 0;
}
// Card colums
.card-columns .card {
margin-bottom: 1.5rem;
column-break-inside: avoid;
}
@include breakpoint-up("sm") {
.card-columns {
column-count: 2;
column-gap: 1rem;
orphans: 1;
widows: 1;
}
.card-columns .card {
width: 100%;
}
}
@include breakpoint-up("md") {
.card-columns {
column-count: 3;
column-gap: 1.5rem;
orphans: 1;
widows: 1;
}
}
// Cards deck
@include breakpoint-up("sm") {
.card-deck {
display: flex;
flex-flow: row wrap;
margin-right: -1rem;
margin-left: -1rem;
}
}
/// Badge class
.badge {
display: inline-block;
padding: .25em .5em;
font-size: 0.75rem;
font-weight: bold;
line-height: 1;
color: $warning;
text-align: center;
white-space: nowrap;
vertical-align: baseline;
border-radius: $border-radius/2;
@include transition($transition-base);
@at-root a#{&} {
&:focus, &:hover {
text-decoration: none;
}
}
@at-root .btn #{&}{
position: relative;
top: -1px;
}
&:empty {
display: none;
}
}
// Pill
.badge-pill {
padding-right: .75em;
padding-left: .75em;
border-radius: .75em;
}
// Circle
.badge-circle {
letter-spacing: -.05em;
padding: .25em 0;
width: 1.5em;
height: 1.5em;
border-radius: 0.75em;
}
// Colors
@each $color, $value in $theme-colors {
.badge-#{$color} {
color: contrast-color($value);
background-color: $value;
@at-root a#{&} {
&:hover, &:focus{
color: contrast-color($value);
background-color: darken($value, 10%);
}
&:focus,
&.focus {
outline: 0;
box-shadow: 0 0 0 .25em rgba($value, .5);
}
}
}
}
/// Nav
.nav {
width: 100%;
display: flex;
overflow: auto;
ul, ol {
list-style: none;
}
&.nav-horizontal {
li {
display: inline-block;
}
}
}
/// Tabs / Tablist
.tab-list {
position: relative;
padding: 0;
border-bottom: 1px solid $gray-300;
box-shadow: 0 0.25em 0 0.25em rgba($gray-200, 0.3);
white-space: nowrap;
// Make horizontal scrollable but hide scrollbar
overflow-y: hidden;
overflow-x: scroll;
overflow: -moz-scrollbars-none;
-ms-overflow-style: none;
@include dark-scheme() {
border-bottom: 1px solid $gray-700;
box-shadow: 0 0.25em 0 0.25em rgba($gray-800, 0.3);
}
&::-webkit-scrollbar { width: 0 !important; display: none; }
.indicator {
position: absolute;
bottom: 0;
left: 0;
height: 2.5px;
width: 0;
background: $primary;
will-change: left, width;
transition: left .25s ease-out, width .1s linear;
z-index: 1;
overflow: hidden;
text-indent: -9999rem;
}
[role="tab"] {
outline: 0;
font-size: 0.75em;
font-weight: normal;
line-height: 1.5;
letter-spacing: 0.09em;
text-decoration: none;
text-transform: uppercase;
vertical-align: middle;
display: inline-block;
margin: 0;
padding: 1rem;
will-change: background, color;
transition: background-color .3s ease-in-out, color .15s linear;
-webkit-user-drag: none;
&:hover {
background-color: rgba(222, 226, 230, 0.25);
color: $gray-700;
@include dark-scheme() {
color: $gray-400;
}
}
&:focus, &:active {
background-color: rgba(222, 226, 230, 0.75);
}
&.active {
color: $primary;
background-color: rgba(222, 226, 230, 0.15);
pointer-events: none;
cursor: default;
}
}
}
.tab-panels {
width: 100%;
position: relative;
overflow: hidden;
overflow-y: auto;
// Prevent overflow scrolling / touching
overscroll-behavior-x: contain;
-webkit-overflow-scrolling: touch;
&.tab-panels-vertical {
.tab-panels {
float: none;
&.active {
display: block;
}
}
}
.tab-panel {
position: relative;
display: none;
visibility: hidden;
// left: 0; top: 0;
width: 100%;
height: 100%;
// float: left;
outline: none;
will-change: visibility;
&.active { // Don't use &:target (will screw everything!).
display: inline-block;
visibility: visible;
}
&.fade {
opacity: 0;
will-change: opacity;
transition: opacity .15s linear;
&.show {
opacity: 1;
}
&:not(.show) {
opacity: 0;
}
}
&.slide {
// transform: translateX(100%);
will-change: transform;
transition: transform .15s linear;
&.show {
transform: translateX(0%);
}
&.next:not(.show) {
transform: translateX(100%);
}
&.previous:not(.show) {
transform: translateX(-100%);
}
}
}
// script generated indicator
.tab-panel-indicator {
position: fixed;
left: calc(50% - 1.75em);
bottom: 1em;
text-align: center;
a {
display: none;
visibility: hidden;
width: .25em;
height: .25em;
margin-left: .5em;
float: left;
background: currentColor;
border-radius: .125em;
outline: 1px solid rgba(255,255,255, 1);
outline-offset: 0;
will-change: width;
transition: width .5s ease-in-out;
&.active, &.next, &.previous {
display: inline;
visibility: visible;
}
&.active {
width: 1.5em;
}
}
}
}
/// Multistep Tabs / Forms:
.step-list {
width: 100%;
ol, ul {
display: table;
table-layout: fixed;
width: 100%;
padding: 0;
margin: 1em 0;
counter-reset: steps;
li {
position: relative;
display: table-cell;
text-align: center;
vertical-align: middle;
counter-increment: steps;
color: $gray-500;
a {
display: block;
line-height: 1;
text-decoration: none;
font-weight: 200;
padding-top: 2.5em;
pointer-events: none;
will-change: font;
transition: font 0.15s ease-in-out;
&:before, &:after {
display: block;
}
&:before {
position: absolute;
left: calc(50% - 1em); top: 0;
width: 2em;
height: 2em;
overflow: hidden;
border-radius: 50%;
line-height: 2;
color: $white;
background: $gray-500;
content: counter(steps);
z-index: 2;
}
&:after {
content: '';
position: absolute;
width: calc(100% - 2.5em);
height: 0;
border-bottom: 2px dotted currentColor;
right: calc(50% + 1.25em); top: calc(1em - 1px);
z-index: 1;
}
&.active {
font-weight: 500;
color: $link-hover-color;
&:before {
background: $link-hover-color;
}
&:after {
border-bottom-style: solid;
border-color: $link-active-color;
}
}
&.done:not(.active) {
pointer-events: all;
color: $link-active-color;
&:before {
background: $link-active-color;
}
&:after {
border-bottom-style: solid;
}
}
}
&:first-of-type a:after {
content: none;
}
}
.badge {
position: absolute;
outline: 1.5px solid currentColor;
outline-offset: 0;
z-index: 3;
pointer-events: auto;
&.badge-danger {
top: -0.5em;
right: calc(50% - 2em);
}
}
}
}
.steps {
.tab-panel {
&.slide {
transform: translateX(-100%);
&.show ~ .slide {
transform: translateX(100%);
}
}
}
}
/// Drawer
.drawer {
position: absolute;
display: inline-block;
overflow: visible;
will-change: left, width;
transition: .2s;
background-color: $drawer-bg;
@include dark-scheme() {
background-color: $drawer-dark-bg;
}
z-index: $zindex-drawer;
@include breakpoint-down("xs") {
width: 100% !important;
}
&:not(.show) {
display: none;
}
&::before {
content: none;
opacity: 0;
visibility: hidden;
will-change: opacity;
-webkit-transition: opacity .3s linear;
transition: opacity .3s linear;
}
@include breakpoint-down("md") {
&::before {
position: fixed;
content: '';
top: 0;
bottom: 0;
left: 100%;
right: -100%;
display: inline-block;
width: 100%;
opacity: 1;
visibility: visible;
background: $backdrop-bg;
pointer-events: all;
}
}
.close {
position: absolute;
top: 1rem;
right: .5rem;
}
.drawer-header, .drawer-body, .drawer-footer {
padding: 1rem;
}
.drawer-header {
line-height: 2;
}
.drawer-header h4 {
margin: 0;
padding: 0;
}
}
/// Menu bar
.menubar {
display: table;
table-layout: fixed;
margin: 0;
padding: 0;
list-style-type: none;
width: auto;
& ul, & li {
list-style-type: none;
margin: 0;
padding: 0;
}
a {
text-decoration: none;
display: block;
svg, img, .icon {
}
.caret {
float: right;
margin-top: 0.375em;
transform: rotate(-90deg)
}
}
// First level only
& > li {
display: table-cell;
& > ul {
top: 2em;
left: 50%;
transform: translateX(-50%);
}
a {
padding: .25em .5em;
}
}
// All levels
li {
overflow: visible;
position: relative;
&:hover, &:focus, &:focus-within {
& > ul {
display: block;
visibility: visible;
opacity: 1;
}
& > a {
color: $link-hover-color;
}
}
ul {
display: none;
visibility: hidden;
opacity: 0;
ul {
left: calc(100% - 1em);
}
}
}
// Mobile menu view sm down
@include breakpoint-down("sm") {
&.menubar-mobile {
position: absolute;
display: block;
table-layout: none;
z-index: 1000;
ul, li {
display: block;
}
}
}
}
/// Dropdown:
.dropdown {
position: relative;
// z-index: $zindex-dropdown;
&.dropup .caret:empty::before {
top: 0.3em;
transform: rotate(-135deg);
}
.dropdown-menu {
overflow: visible;
}
}
.dropdown-menu {
position: absolute;
top: 0;
left: 0;
display: none;
overflow: visible;
overflow-y: auto;
float: left;
min-width: 10rem;
max-height: 25rem; // 10 menu items
font-size: 1rem;
text-align: left;
list-style: none;
background-color: $dropdown-bg;
@include dark-scheme() {
background-color: $dropdown-dark-bg;
}
background-clip: padding-box;
border: 1px solid rgba($gray-500, 0.1);
border-radius: .25rem;
will-change: top, left, transform;
box-shadow: $shadow-elevated;
z-index: $zindex-dropdown;
&:hover, &:focus-within, & > & {
z-index: $zindex-dropdown + 1; // Bring intended menu forward.
}
&.show {
display: block;
}
[role="menuitem"] {
display: block;
width: 100%;
padding: .75rem 1.5rem;
clear: both;
white-space: nowrap;
text-overflow: ellipsis;
font-weight: normal;
text-align: inherit;
text-decoration: none;
background-color: transparent;
border: 0;
border-radius: 0;
will-change: background, color;
transition: background .15s linear, color .15s linear;
small {
width: 100%;
display: block;
white-space: wrap;
}
&:hover {
text-decoration: none;
background-color: rgba($gray-500, 0.1);
}
&.active, &:focus, &:active {
outline: none;
color: #fff;
text-decoration: none!important;
background-color: $primary;
}
&:first-child:not(:only-child) {
border-top-left-radius: calc(.25rem - 1px);
border-top-right-radius: calc(.25rem - 1px);
}
&:last-child:not(:only-child) {
border-bottom-left-radius: calc(.25rem - 1px);
border-bottom-right-radius: calc(.25rem - 1px);
}
}
// If a list is used to arrange menuitems:
li {
&:first-child > [role="menuitem"] {
border-top-left-radius: calc(.25rem - 1px);
border-top-right-radius: calc(.25rem - 1px);
}
&:last-child > [role="menuitem"] {
border-bottom-left-radius: calc(.25rem - 1px);
border-bottom-right-radius: calc(.25rem - 1px);
}
}
h6, .header {
display: block;
padding: .75rem 1rem;
margin: 0;
font-size: .875rem;
color: $gray-600;
white-space: nowrap;
}
.divider {
height: 0;
margin: .5rem 0;
overflow: hidden;
border-top: 1px solid rgba($gray-500, 0.5);
@include dark-scheme() {
border-color: $gray-800;
}
}
}
/// Modal Dialogs
.modal-open {
overflow: hidden;
}
.modal {
position: fixed;
display: inline-block;
top: 0;
left: 0;
width: 100vw;
height: 100vh;
font-size: 1rem;
background: transparent;
transition: opacity .5s ease;
user-select: none;
opacity: 0;
visibility: hidden;
z-index: $zindex-modal;
&:focus {
outline: 0;
}
&.show {
background: $backdrop-bg;
visibility: visible;
opacity: 1;
& .modal-dialog {
transition-delay: .25s;
opacity: 1;
visibility: visible;
transform: scale(1) translate(-50%, -50%);
}
}
&.modal-static {
cursor: not-allowed;
& .modal-dialog {
perspective: 1000px;
animation: wobble 0.82s cubic-bezier(0.36, 0.07, 0.19, 0.97) both;
transform: scale(1) translate(-50%, -50%);
backface-visibility: hidden;
}
}
}
.modal-dialog {
position: absolute;
left: 50%;
top: 50%;
display: block;
width: 20em;
max-height: 95%;
background-color: $modal-bg;
@include dark-scheme() {
background-color: $modal-dark-bg;
}
border-radius: $border-radius;
box-shadow: $shadow-elevated;
z-index: $zindex-modal + 1;
pointer-events: all;
transform-origin: left top;
transform: scale(0) translate(-50%, -50%);
transition: .15s ease-in;
opacity: 0;
visibility: hidden;
@include breakpoint-down("xs") {
width: calc(100% - 2rem);
}
.modal-content {
position: relative;
display: inline-block;
text-align: center;
height: 100%;
width: 100%;
}
.modal-header, .modal-body, .modal-footer {
position: relative;
padding: $spacer;
}
.modal-header {
line-height: 1.2rem;
h3 {
overflow: hidden;
text-overflow: ellipsis;
white-space: nowrap;
padding: 0;
margin: 0;
&:first-letter {
text-transform: uppercase;
}
}
.close {
position: absolute;
top: .5em;
right: .5em;
}
}
.modal-body {
display: block;
bottom: 0;
max-height: calc(95vh - 6.4rem);
width: 100%;
// word-break: break-all;
overflow: hidden;
overflow-y: auto;
}
.modal-footer {
display: inline-block;
width: 100%;
bottom: 0;
text-align: center;
button{
&:only-child {
float: none;
}
&:nth-child(2) {
float: right;
}
}
}
/// Dialogs: Overwritten js ui-dialogs
&.ui-dialog {
.modal-body {
padding-bottom: 2rem;
& > input {
width: 100%;
margin: 1rem 0 0 0;
font: inherit;
}
& > label {
position: relative;
font: inherit;
}
&:first-letter {
text-transform: uppercase;
}
}
.modal-footer {
padding: 0;
margin: 0;
white-space: nowrap;
button {
position: relative;
margin: 0;
width: 50%;
padding: 1rem .5rem;
white-space: nowrap;
overflow: hidden;
background: transparent;
text-overflow: ellipsis;
font-family: inherit;
font-size: 1rem;
line-height: 1.2;
font-weight: bolder;
color: $primary;
border: 0;
border-top: 1px solid $gray-300;
cursor: pointer;
z-index: 0;
transition: all .15s ease;
@include dark-scheme() {
border-color: $gray-700;
}
&:hover, &:focus {
font-weight: bolder;
background: rgba(127, 127, 127, 0.15);
}
&:focus {
border-top-color: $gray-300;
outline: 0;
box-shadow: none;
z-index: 3;
@include dark-scheme() {
border-color: $gray-700;
}
}
&:active {
background: rgba(127, 127, 127, 0.3);
}
&:first-child {
border-radius: 0 0 0 $border-radius;
font-weight: normal;
}
&:last-child {
border-radius: 0 0 $border-radius 0;
border-left: 1px solid $gray-300;
@include dark-scheme() {
border-color: $gray-700;
}
}
&:only-child {
width: 100%;
font-weight: bolder;
border-left: 0;
border-radius: 0 0 $border-radius $border-radius;
}
&:first-letter {
text-transform: uppercase;
}
}
}
}
}
/// Notifications
.ui-notifications {
position: fixed;
right: 0;
bottom: 0;
width: 100%;
height: auto;
max-width: 25rem;
overflow: visible;
display: inline-block;
padding: 1em;
font-size: 1rem;
background: transparent;
user-select: none;
z-index: $zindex-note;
counter-reset: notifications;
&:focus {
outline: 0;
}
.note {
position: relative;
background-color: $note-bg;
@include dark-scheme() {
background-color: $note-dark-bg;
}
display: block;
overflow: hidden;
width: 100%;
margin: 0 0 1em 0;
padding: 0;
text-align: left;
border-radius: $border-radius;
box-shadow: $shadow;
transform-origin: left center;
transform: scale(0.95) translateX(100%);
opacity: 0;
visibility: hidden;
counter-increment: notifications;
transition: .2s;
&:focus {
outline: none;
}
&:hover .progress i {
animation-play-state: paused;
}
&:last-child, &:only-child {
margin-bottom: 0;
}
&.show {
transform: scale(1) translateX(0%);
opacity: 1;
visibility: visible;
}
// Note styles
&.note-success {
background-color: $success;
color: $white;
figure {
color: currentColor;
}
.progress {
color: lighten($success, 20);
background-color: darken($success, 15);
}
.close {
&:hover, &:focus {
color: $success;
background-color: $white;
}
}
}
&.note-warning {
background: $warning;
color: $white;
figure {
color: currentColor;
}
.progress {
color: lighten($warning, 20);
background: darken($warning, 15);
}
.close {
&:hover, &:focus {
color: $warning;
background-color: $white;
}
}
}
&.note-error {
background: $danger;
color: $white;
figure {
color: currentColor;
}
.progress {
color: lighten($danger, 20);
background: darken($danger, 15);
}
.close {
&:hover, &:focus {
color: $danger;
background-color: $white;
}
}
}
time {
position: absolute;
right: 0;
bottom: 0;
left: 0;
text-align: right;
display: block;
padding: .5rem .75rem;
line-height: 1.5;
font-size: 0.6em;
cursor: default;
}
figure {
position: absolute;
max-width: 6em;
height: 100%;
margin: 0;
padding: 0;
color: $primary;
text-align: right;
overflow: hidden;
z-index: 1;
text-align: center;
img, svg {
position: relative;
}
svg {
fill: currentColor;
width: 60%;
top: 50%;
transform:translateY(-50%);
}
img {
height: 100%;
width: 100%;
object-position: 50% 50%;
object-fit: cover;
}
& + p {
margin-left: 4em;
}
}
p {
display: block;
margin: 0;
padding: 1em 1em 2em 3em;
z-index: 2;
b {
display: block;
&:first-letter {
text-transform: uppercase;
}
}
&:first-letter {
text-transform: uppercase;
}
}
.close {
position: absolute;
top: .25rem;
right: .3rem;
z-index: 3;
font-size: 0.8em;
&:hover, &:focus {
background-color: $primary;
color: $white;
outline: none;
}
}
.progress {
position: absolute;
bottom: 0;
display: block;
left: 0;
width: 100%;
height: 3px;
color: $primary;
background: $gray-200;
z-index: 2;
i {
position: absolute;
left: 0;
display: inline-block;
height: 100%;
width: 0;
background: currentColor;
animation-play-state: play;
animation: progress 15s linear forwards;
}
}
@include breakpoint-up("sm") {
&.note-image {
figure {
max-width: 100%;
position: relative;
height: 10em;
& + p {
margin-left: 0;
}
}
p {
padding: 1em 1em 2em 1em;
}
}
}
}
@include breakpoint-down("sm") {
left: 0;
min-width: 100%;
padding: 0;
&::before {
position: fixed;
content: '';
top: 0;
bottom: 0;
left: 0;
display: inline-block;
width: 100%;
opacity: 0;
visibility: hidden;
background: $backdrop-bg;
pointer-events: none;
will-change: opacity;
transition: opacity .3s linear;
}
&:hover, &.hover {
&::before {
visibility: visible;
opacity: 1;
}
.note {
border-radius: 0;
position: relative;
float: left;
box-shadow: none;
opacity: 0;
transform-origin: top center;
transform: scale(0.95) translateY(-1em);
&:first-child {
opacity: 1;
transform: scale(1) translateY(0);
transition-delay: .1s;
}
&:nth-child(1n+2) {
opacity: 1;
transform: scale(1) translateY(0);
transition-delay: .1s;
}
&:nth-child(1n+3) {
visibility: visible;
transition-delay: .2s;
}
&:last-child {
transition: none;
}
}
}
.note {
position: absolute;
bottom: 0;
display: block;
width: 100%;
margin: 0;
transform-origin: bottom center;
transform: scale(1) translateY(-100%);
&.show {
transform: scale(1) translateY(0%);
}
&:first-child {
transform: scale(1) translateY(0%);
border-radius: 0;
z-index: 3;
}
&:nth-child(1n+2) {
transform: scale(0.95) translateY(-1em);
z-index: 2;
}
&:nth-child(1n+3) {
opacity: 0;
visibility: hidden;
}
}
}
}
/// Tooltip
.ui-tooltip {
position: absolute;
background: $tooltip-bg;
border-radius: 0.25em;
padding: 0.5em 1em;
font-size: 0.8rem;
color: #fff;
overflow: visible;
white-space: nowrap;
font-style: normal;
text-overflow: ellipsis;
opacity: 1;
vertical-align: middle;
pointer-events: none;
visibility: visible;
transform: scale(1);
transform-origin: center bottom;
transition: transform 0.1s linear 0.25s, opacity 0.05s ease-in-out 0.25s;
z-index: $zindex-tooltip;
&:first-letter {
text-transform: uppercase;
}
.indicator {
position: absolute;
display: inline-block;
bottom: -0.5em;
left: calc(50% - 0.5em);
width: 0;
height: 0;
color: rgba(0, 0, 0, 0.7);
border: 0.5em solid transparent;
border-bottom: 0;
border-top: 0.5em solid currentColor;
}
&.bottom .indicator {
top: -0.5em;
bottom: auto;
border: 0.5em solid transparent;
border-top: 0;
border-bottom: 0.5em solid currentColor;
}
&.left .indicator, &.right .indicator {
bottom: auto;
left: auto;
top: calc(50% - 0.5em);
border: 0.5em solid transparent;
}
&.left .indicator {
right: -0.5em;
border-right: 0;
border-left: 0.5em solid currentColor;
}
&.right .indicator {
left: -0.5em;
border-left: 0;
border-right: 0.5em solid currentColor;
}
&[aria-hidden='true'] {
opacity: 0;
visibility: hidden;
transform: scale(0.5);
}
}
/// Toast
#ui-toast {
position: absolute;
left: 50%;
bottom: 3em;
right: auto;
top: auto;
display: inline-block;
overflow: hidden;
width: auto;
max-width: 25rem;
height: 3em;
padding: 0 1.5em;
font-size: .85rem;
line-height: 3;
text-align: center;
white-space: nowrap;
text-overflow: ellipsis;
font-style: normal;
color: #fff;
border-radius: 1.5em;
background-color: $toast-bg;
opacity: 0;
visibility: hidden;
transform: translate(-50%, 300%);
will-change: transform, opacity;
transition: opacity .3s ease-in, transform .5s ease-in-out;
cursor: $cursor;
z-index: $zindex-toast;
@include breakpoint-down("sm") {
font-size: .75rem;
}
&:first-letter {
text-transform: uppercase;
}
&.visible {
opacity: 1;
visibility: visible;
transform: translate(-50%, 0%);
}
&.error, &.success, &.warning {
padding: 0 1.5em 0 3em;
&::before, &::after {
content: '';
display: block;
position: absolute;
left: 1.25em;
top: 1.5em;
width: 1em;
height: .15em;
transform: rotate(-45deg);
background-color: #FFF;
}
&::before {
transform: rotate(45deg);
width: .5em;
}
}
&.error::before {
width: 1em;
}
&.success::before {
left: 1em;
top: 1.65em;
}
&.warning{
&::before {
left: 0.95em;
top: .15em;
width: 0;
height: 0;
transform: none;
background: transparent;
border-radius: .15em;
border: .7em solid transparent;
border-bottom: 1.2em solid $white;
}
&::after {
transform: none;
content: '!';
top: 0;
left: 1.15em;
text-align: center;
font-weight: 700;
background: transparent;
color: rgba($black, 0.7);
}
}
&.closing {
opacity: 0;
transform: translate(-50%, 300%);
}
}
/// Ripple effect
.ripple {
position: relative;
overflow: hidden;
.ink {
display: block;
position: absolute;
pointer-events: none;
border-radius: 50%;
transform: scale(0);
background: $gray-700;
opacity: 1;
&.animating {
width: 1px;
height: 1px;
animation: ripple .5s linear;
z-index: 1;
}
}
}
/// Animations
@keyframes ripple {
100% { opacity: 0; transform: scale(2.5); }
}
@keyframes wobble {
10%, 90% { transform: translate(-51%, -50%); }
20%, 80% { transform: translate(-48%, -50%); }
30%, 50%, 70% { transform: translate(-54%, -50%); }
40%, 60% { transform: translate(-46%, -50%); }
}
@keyframes scale {
from { transform: scale(0) translate(-50%, -50%); }
to { transform: scale(1) translate(-50%, -50%); }
}
@keyframes progress {
from { width: 0%;}
to { width: 100%;}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment