Skip to content

Instantly share code, notes, and snippets.

@toomanyredirects
Created May 15, 2020 15:50
Show Gist options
  • Save toomanyredirects/91f27f28603a4b64ec685881e0385c0c to your computer and use it in GitHub Desktop.
Save toomanyredirects/91f27f28603a4b64ec685881e0385c0c to your computer and use it in GitHub Desktop.
Replace Native UI Alert, Prompt & Confirm Dialogs
<body id="app" role="application" data-scheme="auto">
<!-- 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="#!" class="float-left">
<figure id="logo">
<svg viewBox="0 0 9 9" role="presentation">
<use xlink:href="#ui-icon"/>
</svg>
<figcaption>UX</figcaption>
</figure>
</a>
<!-- Navigation trigger-->
<a href="#navigation" class="float-left d-none hamburger" data-toggle="collapse" aria-expanded="false" data-expanded="Close navigation">Open navigation</a>
<!-- Navigation -->
<nav id="navigation" class="d-none d-m-block" aria-labelledby="titleNavigation">
<h4 id="titleNavigation">Navigation</h4>
<ul class="nav">
<li>
<a href="#!">Home <span class="sr-only">(current)</span></a>
</li>
<li>
<a href="#!">Something</a>
</li>
<li>
<a href="#!">Somthing else</a>
</li>
</ul>
</nav>
<div class="dropdown float-right">
<a href="#menu" class="ripple" type="button" id="dots" data-toggle="dropdown" data-offset="-35" data-align="right" aria-haspopup="true" aria-expanded="false" title="more..." data-tooltip="left">
<svg viewBox="0 0 9 9" role="img">
<use xlink:href="#dots-icon"/>
</svg>
</a>
<div class="dropdown-menu" id="menu" aria-labelledby="dots">
<h6>Settings</h6>
<a role="menuitem" href="#sidebar" data-toggle="collapse" aria-controls="sidebar" aria-expanded="false" data-expanded="Close profile">Open profile</a>
<a role="menuitem" href="#!">Something else here</a>
</div>
</div>
</div>
</header>
<!--Tab List / Navigation -->
<nav id="nav" class="nav tab-list" role="tablist" aria-label="Tab Navigation">
<a href="#grid-tab" id="grid" role="tab" data-toggle="tab" aria-selected="false" aria-controls="grid-tab" tabindex="-1">Grid</a>
<a href="#cards-tab" id="cards" role="tab" data-toggle="tab" aria-selected="false" aria-controls="cards-tab" tabindex="-1">Cards</a>
<a href="#forms-tab" id="forms" role="tab" data-toggle="tab" aria-selected="false" aria-controls="forms-tab" tabindex="-1">Forms</a>
<a href="#buttons-tab" id="forms" role="tab" data-toggle="tab" aria-selected="false" aria-controls="buttons-tab" tabindex="-1">Buttons</a>
<a href="#icons-tab" id="icons" role="tab" data-toggle="tab" aria-selected="false" aria-controls="icons-tab" tabindex="-1">Icons</a>
<a href="#nativeui-tab" id="nativeui" role="tab" data-toggle="tab" aria-selected="false" aria-controls="nativeui-tab" tabindex="-1">Native UI</a>
<a href="#dropdowns-tab" id="dropdowns" role="tab" data-toggle="tab" aria-selected="false" aria-controls="dropdowns-tab" tabindex="-1">Dropdowns</a>
<a href="#tooltips-tab" class="active" id="tooltips" role="tab" data-toggle="tab" aria-selected="true" aria-controls="tooltips-tab">Tooltips</a>
<a href="#notifications-tab" id="notifications" role="tab" data-toggle="tab" aria-selected="false" aria-controls="notifications-tab" tabindex="-1">Notifications</a>
<a href="#toasts-tab" id="toasts" role="tab" data-toggle="tab" aria-selected="false" aria-controls="toasts-tab" tabindex="-1">Toasts</a>
<i class="indicator">current item</i>
</nav>
<!-- Tabs -->
<main id="main" class="tabs">
<!--Tab Grid -->
<section class="tab-panel slide" tabindex="0" role="tabpanel" id="grid-tab" aria-labelledby="grid">
<div class="container-fluid container-sm">
<legend>Grid</legend>
<p>A responsive grid system based on bootstrap logic.</p>
<style>
#grid-tab .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 Cards -->
<section class="tab-panel slide" tabindex="0" role="tabpanel" id="cards-tab" aria-labelledby="cards">
<div class="container-fluid container-sm">
<h2>Cards</h2>
<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 class="tab-panel slide" tabindex="0" role="tabpanel" id="forms-tab" aria-labelledby="forms">
<div class="container-fluid container-sm">
<h2>Forms</h2>
<p>Native UI &amp; Form Submission</p>
<form lang="en" data-validate="true" id="form">
<legend>Example</legend>
<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" 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="input-number" class="form-label">No.</label>
<input class="form-control" id="input-number" type="number" min="1" max="99" step="1" value="" inputmode="numeric" 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" 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="tel" 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>
<optgroup label="Group">
<option>Please select</option>
<option value="option1">Option 1</option>
<option value="option2">Option 2</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="%" 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" required></textarea>
</fieldset>
<fieldset class="form-group">
<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>
<button type="reset" class="btn float-left">Reset</button>
<button type="submit" class="btn btn-primary float-right">Submit</button>
</fieldset>
</form>
</div>
</section>
<!--Tab buttons -->
<section class="tab-panel slide" tabindex="0" role="tabpanel" id="buttons-tab" aria-labelledby="forms">
<div class="container-fluid container-sm">
<h2>Buttons</h2>
<p>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>
<p>With SVG icons:</p>
<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>
<p>Outlined:</p>
<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>
<p>Variations:</p>
<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 class="tab-panel slide" tabindex="0" role="tabpanel" id="icons-tab" aria-labelledby="icons">
<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">
<div class="input-group-prepend">
<label for="search-icons" class="input-group-text">Search</label>
</div>
<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 class="tab-panel slide" tabindex="0" role="tabpanel" id="nativeui-tab" aria-labelledby="nativeui">
<div class="container-fluid container-sm">
<form onsubmit="alert('submitted form!')" id="native-ui" class="clearfix">
<legend>Native UI &amp; Form Submission</legend>
<p>Native UI &amp; Form Submission</p>
<fieldset>
<input class="form-control" type="text" placeholder="Change input here" inputmode="tel"/>
<input class="form-control" type="text" placeholder="Disabled input" disabled/>
<select class="form-control form-select" type="text" placeholder="Disabled input">
<optgroup label="Group">
<option>Option 1</option>
<option>Option 2</option>
</optgroup>
</select>
</fieldset>
<button type="button" onclick="alert('Something just happened!')" title="alert('text' [ , options, callback ]);" class="btn">Alert</button>
<button type="submit" onclick="confirm('Do you really want to do this?')" title="confirm('text' [ , options, callback ]);" class="btn">Confirm</button>
<button type="button" onclick="prompt('Type something. Just do it.', 'something')" title="prompt('text', value [ , options, callback ]);" class="btn">Prompt</button>
<button type="button" onclick="prompt('Type something. Just do it.', 'something')" title="dialog('text', value [ , options, callback ]);" class="btn">Dialog</button>
<button type="submit" data-tooltip="bottom" onclick="confirm('Would you like to submit the form?')" title="Confirm form submission" class="btn">Submit</button>
</form>
<form id="dialog">
<h2>Dialog</h2>
<p>Open a <a href="#customModal" data-toggle="modal" data-target="customModal" title="Custom modal dialog">Custom modal dialog</a> for testing purpose.</p>
</form>
</div>
</section>
<!--Tab Dropdowns -->
<section class="tab-panel slide" role="tabpanel" id="dropdowns-tab" aria-labelledby="dropdowns">
<div class="container-fluid container-sm">
<form id="dropdowns">
<legend>Dropdowns</legend>
<p>Dropdowns are absolute positioned to their parent element.</p>
<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 class="tab-panel slide show active" tabindex="0" role="tabpanel" id="tooltips-tab" aria-labelledby="tooltips">
<form id="tooltips" class="container-fluid container-sm">
<legend>Tooltips</legend>
<p>Tooltips for the HTML title property are single elements for descriptive user interface feedbacks or descriptions.</p>
<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>
</section>
<!--Tab Notifications -->
<section class="tab-panel slide" tabindex="0" role="tabpanel" id="notifications-tab" aria-labelledby="notifications">
<form id="notifications" class="container-fluid container-sm">
<legend>Notifications</legend>
<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>
<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')" 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>
</section>
<!--Tab Toasts -->
<section class="tab-panel slide" tabindex="0" role="tabpanel" id="toasts-tab" ria-labelledby="toasts">
<form id="Toaster" class="container-fluid container-sm">
<legend>Toaster</legend>
<p>Toast messages are single elements for user interface feedbacks for the user and can not be stacked.</p>
<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>
</section>
</main>
<footer>
<div class="container-fluid container-md"></div>
</footer>
<!-- Inline Modals -->
<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="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-icon" viewBox="0 0 9 9" fill="currentColor">
<path d="M4.5 4.1c-.7 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4 1.4-.6 1.4-1.4-.7-1.4-1.4-1.4zm0-2.2C2 1.9 0 3.5 0 5.5h1C1 4 2.5 2.9 4.5 2.9 6.4 2.9 8 4 8 5.5h1c0-2-2-3.6-4.5-3.6z"/>
</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="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>
</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: 15rem; }
#header, #nav { position: absolute; display: inline-block;}
#nav { width: 100%; top: 4rem;}
#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); }
#header { padding: 1rem 0.5rem 0.5rem 0.5rem; top:0;}
#header .dropdown { float:right; vertical-align: middle; top: 0.3rem; font-size: 1em; }
#logo svg { width: 2rem;}
#logo {width: auto; text-align: left; margin:0; padding:0; display: inline-block; }
#logo figcaption {position: absolute; margin-left: 0.5rem; font-size: 1.75em; font-weight: bold; display: inline-block; line-height: 1.1;}
#icons-wrapper .icons { text-align: center;}
#icons-wrapper .icons figure { display: inline-block; margin:0;}
#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; }
#icons-wrapper .icon:hover { 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; }
#dots {border:0; background:none; outline:0; display:block; width: 1em; font-size: 1.5em;}
#tooltips-tab fieldset { text-align: center; }
#tooltips-tab button { display: inline; min-width: 6em; margin: 0.5rem 0;}
#tooltips-tab button:first-of-type, #tooltips-tab button:last-of-type { float: none; clear: right; }
#tooltips-tab button:nth-of-type(2), #tooltips-tab button:nth-of-type(4) {float: none; max-width: 47.5%; margin-right:6em; margin-left: 0;}
#tooltips-tab button:nth-of-type(3), #tooltips-tab button:nth-of-type(5) {float: none; max-width: 47.5%; margin-left: 0; margin-right: 0; }
@media (max-width: 567.98px) { #tooltips-tab button:nth-of-type(2), #tooltips-tab button:nth-of-type(4) {float: left;} #tooltips-tab button:nth-of-type(3), #tooltips-tab button:nth-of-type(5) {float: right;} }
#dropdowns-tab form { clear: both; display: inline-block; width: 100%;}
#dropdowns-tab fieldset { width: 45%; display:block; float: left; }
#dropdowns-tab fieldset:last-child { float: right;}
#dropdowns-tab fieldset:last-child button { float: right;}
</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',
success: 'Alles klar'
}
// Class initialization
new UI(lang);
// Trigger delayed notification
// setTimeout(function (){ notify('Do you really want to do this?', 'alert'); }, 5000)
// Icon display
Icons('#ui-icons', '#icons-wrapper');
}, false);
// Functions
// 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('input[type=search]');
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('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);
container.appendChild(figure);
});
// 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);
match ? fig.removeAttribute('hidden') : fig.setAttribute('hidden', '');
});
});
search.focus();
}
}
</script>
</body>
// Replace Native UI Alert, Prompt & Confirm Dialogs
// -------------------------------------------------
// 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.
// Language: Internationalisation (i18n) with language object
// 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 Element prototypes
var d = document, w = window, 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) {}
// Register changes in document inputs
var hasChanged = changed(d, 'hasChanged');
// 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',
success: 'success',
permisssion: 'permmission',
unload: 'Leave this page?',
onunload: 'Changes will not be saved.'
};
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.1c-.7 0-1.4.6-1.4 1.4s.6 1.4 1.4 1.4 1.4-.6 1.4-1.4-.7-1.4-1.4-1.4zm0-2.2C2 1.9 0 3.5 0 5.5h1C1 4 2.5 2.9 4.5 2.9 6.4 2.9 8 4 8 5.5h1c0-2-2-3.6-4.5-3.6z"/>',
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"/>'
};
// 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); };
w.onbeforeunload = function(m, o, c) { new BeforeUnload(m, o, c); };
// 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
Viewport(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);
});
// Tab togglers
[].slice.call(d.querySelectorAll('[data-toggle="tab"]')).forEach(function(tb){
tb.addEventListener('click', function(e){ new Tab(e); }, false);
// if(tbs.className.match(/\bactive\b/gi)) tbs.click(); activate tab / swiping
});
// 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(rg){
new Range(rg);
});
// 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);
}
// Before unload modal dialog
function BeforeUnload(e, options, callback ) {
if (hasChanged) new Modal('confirm unload', options, null, callback);
}
// Notifications
function Notify(message, type, options, callback) {
new Notifications(type, message, options, callback);
}
// Private methods
// Global viewport height CSS var
function Viewport (){
w.addEventListener('resize', set, false);
w.addEventListener('orientationchange', set, false);
set();
function set(){
d.documentElement.style.setProperty('--vh', (w.innerHeight * 0.01) +'px');
}
}
// Modal dialogs
function Modal (type, options, message, value, callback){
// Constructor
var origEvent = w.event || d.event;
if (origEvent) prevent(origEvent);
var modal = typeof type === 'string' ? create(type, options, message, value, callback) : type;
if(typeof type !== 'string') type = 'custom';
open(modal, type, origEvent, callback);
// Private methods:
// Create ui modal dialog
function create(type, options, message, value, callback) {
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;
message = message ? i18n.onunload : null;
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" 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.setAttribute('tabindex', '-1');
modal.setAttribute('aria-hidden', true);
modal.setAttribute('aria-labelledby', type +'Title');
modal.addEventListener('click', function(e){
modal.className += ' modal-static';
vibration([500]);
setTimeout(function(){
modal.className = modal.className.replace(/\b(modal-static)\b/g, '').trim();
modal.querySelector('button:first-of-type').focus();
}, 500);
}, false);
modal.innerHTML = tpl;
d.body.appendChild(modal);
return modal;
}
// Open modal
function open(modal, type, origEvent, callback) {
scrollbar();
modal.removeAttribute('aria-hidden');
modal.setAttribute('aria-modal', true);
modal.setAttribute('open', '');
// Event listeners
modal.addEventListener('blur', focustrap, true);
var cls = modal.querySelectorAll('[data-dismiss="modal"], .modal-footer button, [type="submit"]');
for(var i = 0; i < cls.length; i++) {
cls[i].addEventListener('click', function(e){ close(modal, origEvent, callback); }, false);
}
modal.firstChild.addEventListener('click', nopropagate, false);
// if(type.match(/(confirm|prompt)/gi))
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);
}
// Remove 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();
}
}
// Focus trap
function focustrap (e) {
if (!e.relatedTarget || !modal.contains(e.relatedTarget)) {
setTimeout(function() {
var f = modal.querySelectorAll('button, [href], input, select, textarea, [tabindex]:not([tabindex="-1"])');
f[0].focus();
}, 1);
}
}
// Close / hide modal dialog
function close (el, event, callback){
var target = (event || w.event).target, // event.originalTarget ||;
action = typeof callback === 'function' ? callback : null;
el = typeof el ==='string' ? d.getElementById('custom'+ el) : el;
el.removeAttribute('aria-modal');
el.removeAttribute('open');
el.setAttribute('aria-hidden', true);
el.className = el.className.replace(/\bshow\b/g, '').trim();
// if(el.id.match(/(confirm|prompt)/gi))
w.removeEventListener('keydown', keylistener, false);
scrollbar();
if (action) return action.call();
if (el.id.match(/confirm/gi)) {
action = target.getAttribute('onclick') || target.onclick;
if (typeof action === 'function') target.onclick = false;
else target.removeAttribute('onclick');
if('focus' in target) target.focus();
target.click();
if (typeof action === 'function') target.onclick = action;
else target.setAttribute('onclick', action);
}
else if ('focus' in target) target.focus();
}
dispatchEvent('ui.modal.close', modal);
setTimeout(function(){}, 0)
}
// Notifications:
function Notifications (type, message, options, callback) {
var wrap = d.getElementById('ui-notifications');
if(!wrap){
wrap = d.createElement('div');
wrap.id = 'ui-notifications';
wrap.className = 'ui-notifications';
wrap.setAttribute('tabindex', '-1');
wrap.setAttribute('aria-live', 'polite');
wrap.setAttribute('aria-relevant', 'additions removals');
wrap.innerHTML = '<a href="#!" class="counter" role="region" aria-live="polite"></a>'
d.body.appendChild(wrap);
}
create(wrap);
// Private methods
// Create notification
function create (wrap) {
type = type ? type : '';
i18n.title = type.match(/(error)/gi) ? 'error' : type.match(/(warn)/gi) ? 'warning' : type.match(/(ok)/gi) ? 'success' : 'notification';
var timed = type.match(/(timed)/gi);
var img = options ? (options.image ? options.image : null) : null,
tpl = [
'<figure aria-label="icon '+ type +'">',
'<svg viewbox="0 0 9 9">'+ icons.note +'</svg>',
'</figure>',
'<p><b>'+ i18n.title +'</b> '+ message +'</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';
note.className += timed ? ' timed' : '';
note.className += timed ? ' timed' : '';
note.setAttribute('role','alert');
note.setAttribute('aria-live','assertive');
note.setAttribute('aria-atomic', true);
note.setAttribute('tabindex', 0);
note.setAttribute('draggable','');
note.innerHTML = tpl;
var close = note.querySelector('.close'),
time = note.querySelector('time'),
img = note.querySelector('figure svg, figure img'),
progress = note.querySelector('.progress i');
ago(time);
close.addEventListener('click', function(e) { remove(note, wrap); }, false);
wrap.insertAdjacentElement('afterbegin', note);
if(timed) addPrefixedListener(progress, 'AnimationEnd', function() { remove(note, wrap); });
// 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(note, wrap);
if(gesture === 'right') hide(note, wrap);
}, true);
// vibration([400]);
if (!d.hasFocus()) notification(type, message, img ? (img.src ? img.src : png64(img)) : null, null, audiopool.pop );
dispatchEvent('ui.notification.show', note);
}, 1);
}
// Delete notification
function remove (note, wrap) {
note.className = note.className.replace(/\bshow\b/g, '').trim();
setTimeout(function() {
wrap.removeChild(note);
dispatchEvent('ui.notification.destroy', note);
}, 500);
}
// Hide notification after timeout
function hide (note, wrap) {
note.className = note.className.replace(/\bshow\b/g, '').trim();
dispatchEvent('ui.notification.hide', note);
}
}
// Dropdown
function Dropdown(e) {
var trigger = e.target || w.event.target,
parent = trigger.parentNode,
menu = d.querySelector('[aria-labelledby="'+ trigger.id +'"]'),
persist = trigger.getAttribute('data-persist') === 'true',
isShown = 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(!persist) d.addEventListener('click', hide, true);
if(!persist) menu.addEventListener('click', hide, false);
toggle(e);
}
// Private methods
function toggle (e) {
isShown ? 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(!persist) 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)
};
var vh = d.documentElement.clientHeight, vw = d.body.clientWidth;
var tH = trigger.offsetHeight, tT = trigger.offsetTop, tL = trigger.offsetLeft;
var mH = menu.offsetHeight, mW = menu.offsetWidth;
var 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]);
}
// Private methods
function show (target){
var dismiss = target.querySelectorAll('[data-dismiss="drawer"]');
trigger.setAttribute('aria-expanded', true);
target.className += target.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', target);
}
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 Tab(e) {
var tab = e.target || w.event.target,
panel = tab.hash ? d.getElementById(tab.hash.substr(1)) : d.querySelector('[aria-labelledby="'+ tab.id +'"]'),
isSelected = tab.getAttribute('aria-selected') === 'true' || panel.className.match(/\bshow\b/gi),
isBefore = panel.nextElementSibling ? panel.nextElementSibling.className.match(/active/) : false,
indicator = tab.parentNode.querySelector('.indicator'),
tabs = tab.parentNode.querySelectorAll('[data-toggle="tab"]'),
panels = panel.parentNode.querySelectorAll('.tab-panel');
prevent(e);
new Swipe(panel, 'x', panel, function(swipe) {
var prev = tab.previousElementSibling !== null ? tab.previousElementSibling : tabs[tabs.length - 1];
var next = tab.nextElementSibling.getAttribute('data-toggle') !== null ? tab.nextElementSibling : tabs[0];
if(swipe.direction === 'right') { prev.click(); prev.focus(); return; }
else if(swipe.direction === 'left') { next.click(); next.focus(); return;}
new Toast(swipe.direction);
}, true);
position(e);
if(isBefore) panel.className += ' slide-before';
if(indicator) indicate(e);
if(!isSelected) show(e);
// Private methods
function show (e) {
hide(e);
tab.removeAttribute('tabindex');
tab.setAttribute('aria-selected', true);
tab.className += ' active';
panel.setAttribute('tabindex', '0');
panel.className += ' active';
setTimeout(function(){
panel.className += ' show';
panel.className = panel.className.replace(/(slide-before)/gi,'').trim();
}, 0);
position(e);
if(indicator) indicate(e);
dispatchEvent('ui.tab.show', panel);
}
function hide (e) {
for(var i = 0; i < panels.length; i++){
panels[i].setAttribute('tabindex', '0');
panels[i].className = panels[i].className.replace(/(active|show)/gi,'').trim();
dispatchEvent('ui.tab.hide', panels[i]);
}
for(var i = 0; i < tabs.length; i++){
tabs[i].setAttribute('aria-selected', false);
tabs[i].setAttribute('tabindex', '-1');
tabs[i].className = tabs[i].className.replace(/(active)/gi,'').trim();
}
}
function position (e) {
// var vw = tab.parentNode.clientWidth,
// hidden = (tab.clientWidth + parseInt(tab.getBoundingClientRect().left, 10)) >= vw;
tab.parentNode.setAttribute('scrolling','');
tab.parentNode.scrollLeft = tab.offsetLeft;
// tab.scrollIntoView({false, 'smooth'});
tab.focus();
tab.parentNode.removeAttribute('scrolling');
}
function indicate (e) {
var active = tab.parentNode.querySelector('.active');
indicator.style.width = active.offsetWidth +'px';
indicator.style.left = active.offsetLeft +'px';
d.addEventListener('scroll', indicate, hasPassive);
w.addEventListener('resize', indicate, false);
w.addEventListener('orientationchange', indicate, false);
}
}
// Tooltips
function Tooltips (options) {
var TIPS = d.querySelectorAll('[title]');
var 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);
}
});
// Private 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'),
vh = d.documentElement.clientHeight, vw = d.body.clientWidth;
var sY = w.scrollY || w.pageYOffset;
var sX = w.scrollX || w.pageXOffset;
var rect = trigger.getBoundingClientRect();
var tW = rect.width;
var tH = rect.height;
var tL = rect.left + sX;
var tT = rect.top + sY;
var X = tL + tW/2;
var Y = tT + tH/2;
var W = tip.offsetWidth;
var H = tip.offsetHeight;
var hT, hB, hR, hL;
var css = tip.style;
var icss = tip.querySelector('.indicator').style;
var offset = trigger.hasAttribute('data-offset') ? trigger.getAttribute('data-offset') : OFFSET;
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) {
type = type ? type : '';
message = message ? message.message || message.toString() : i18n.unknown;
var toast = d.getElementById('ui-toast'),
time = ms ? parseInt(ms, 10) : 10000;
if(!toast) {
toast = d.createElement('div');
toast.id = 'ui-toast';
}
clearTimeout(w.toastTimeout);
toast.className = type;
toast.innerHTML = message;
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, time);
// Close Toast
function close (e){
toast.className += ' closing';
dispatchEvent('ui.toast.hide', toast);
setTimeout(function() { toast.removeAttribute('class'); }, 500);
clearTimeout(w.toastTimeout);
}
}
// Range
function Range(el) {
var ini = el.defaultValue || el.value || 0,
output = el.parentNode.querySelector('output'),
unit = el.getAttribute('data-unit');
if(!output) {
output = d.createElement('output');
el.parentNode.appendChild(output);
};
set(el, el.value, output);
el.addEventListener('input', function(e) { set(el, el.value, output); }, false);
el.form.addEventListener('reset', function(e) { set(el, ini, output); }, false);
// Private method
function set(range, value, output){
if(range === null || value === null) return;
var min = parseFloat(range.min) || 0,
max = parseFloat(range.max) || 1,
r = 100/(max-min);
range.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) {
var self = this, root = d.documentElement;
if(!target) return alert('No swipe target defined. Aborting...');
remove = remove ? remove : false; // Remove initial listener from target?
axis = axis ? axis : 'y'; // y default, allowed 'x, h, horizontal, horiz'
zone = zone ? zone : target;
var x, y, sX = 0, sY = 0, eX = 0, eY = 0,
minDeg = Math.tan(45*1.5/180 * Math.PI),
minPx = minPx ? minPx : 35, minMs = 200, sT = null, eT = null,
distance, direction, duration, dragging = false;
target.style = '';
// Event mouse listeners
zone.addEventListener('mousedown', start, false);
// Event touch listeners
zone.addEventListener('touchstart', start, hasPassive);
// Private methods
function start(e) {
if(dragging) end(e);
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('dragging', '');
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;
raf(transform);
}
function end(e) {
dragging = false;
eT = e.timeStamp;
dispatch(e);
target.style = '';
zone.removeAttribute('dragging');
root.removeAttribute('manipulating');
// target.removeAttribute('noanimate');
sT = null; eT = 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.match(/(x|h|horiz|horizontal)/gi)) {
if (eX <= sX) { distance = sX - eX; direction = 'left'; }
if (eX >= sX) { distance = eX - sX; direction = 'right'; }
} else {
if (eY <= sY) { distance = sY - eY; direction = 'up'; }
if (eY >= sY) { 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() {
if(axis.match(/(x|h|horiz|horizontal)/gi)) y = 0;
else 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: '\b[\w\.-]+@[\w\.-]+\.\w{2,4}\b',
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}( \d{1,2}[:-]\d{2}([:-]\d{2,3})*)?',
number: '(^\d{1,10}$)',
tel: '(\+?( |-|\.)?\d{1,2}( |-|\.)?)?(\(?\d{3}\)?|\d{3})( |-|\.)?(\d{3}( |-|\.)?\d{4})',
color: '^((rgb|hsl)(a?)\(([\d\.\-\s,]{5,})\)$)|^((#)(([0-9A-F]{3})$|([0-9A-F]{6})$))'
},
sets = el.tagName.match(/form/gi) ? [el] : el.querySelectorAll('form'),
isTabbed = el.closest('.tabs').contains(el),
hasAlert = false;
[].slice.call(sets).forEach(function(set) {
set.setAttribute('novalidate', true);
// Check error handler on form submit / reset
set.addEventListener('submit', function(e) {
prevent(e);
errors = []; // reset errors
validate(sets);
if (errors) { prevent(e); }
return false;
}, false);
});
// Private methods
// Validate forms / sets form parts
function validate (sets) {
[].slice.call(sets).forEach(function(set) {
var inputs = set.querySelectorAll('[required]:not([disabled]), [pattern]:not([disabled])');
[].slice.call(inputs).forEach(function(input) { checkInput(input, set); });
displayErrors(set);
});
}
// 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,
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 && !/pattern/.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(/has-error/gi);
if (!hasError) {
group.className += ' has-error';
group.setAttribute('title', error);
}
errors.push({
'set': '#'+ set.id,
'input': '#'+ input.id,
'message': error
});
input.addEventListener('change', function(){checkInput(input, set); }, hasPassive);
group.form.addEventListener('reset', function(e) {removeError(input, group, set); }, false);
}
// Remove error
function removeError(input, group, set) {
errors.splice(errors.indexOf('#'+ input.id), 1);
group.className = group.className.replace(/has-error/gi,'').trim();
input.className = input.className.replace(/is-error/gi,'').trim();
input.removeEventListener('change', function(){checkInput(input, set); }, hasPassive);
group.form.removeEventListener('reset', function(e) {removeError(input, group, set); }, false);
}
// Display error count or error list in set
function displayErrors(set){
var count = 1;
[].slice.call(errors).forEach(function(error){ if(error.set === '#'+set.id) count++; });
// Display tab badge
if (isTabbed) {
var panel = set.closest('.tab-panel'),
tab = d.querySelector('a[href="#'+ panel.id +'"]'),
badge = tab.querySelector('.badge');
if(!badge) badge = d.createElement('b');
if(tab) {
badge.setAttributes({
'class': 'badge badge-circle badge-danger scale',
'aria-live': 'assertive',
'title': count +' '+ i18n.error,
'data-tooltip': 'right'
});
tab.appendChild(badge);
badge.innerText = count;
}
}
// Scroll to first error in set
var first = set.querySelector('.has-error'),
scroll = scrollParent(first);
if(scroll) scroll.setAttribute('scrolling','');
first.scrollIntoView();
if(scroll) scroll.removeAttribute('scrolling');
first.querySelector('input, select, textarea').focus();
}
}
// Backdrop
function Backdrop (color) {
var drop = d.getElementById('backdrop');
if(!drop) { drop = d.createElement('div'); drop.id = 'backdrop'; }
drop.className = 'visible';
theme(w.getComputedStyle(drop).backgroundColor);
// Head methods
function theme(color){
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]'),
oColor = head.querySelector('meta["'+ metas[0] +'"]').getAttribute('content'),
oStyle = head.querySelector('meta["'+ metas[2] +'"]').getAttribute('content'),
isBlack = oColor.replace(' ','').match(/(#000|#000000|0,0,0)/gi) || oStyle.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' + isBlack ? '-black' : '');
else entry.setAttribute('content', color);
});
}
function reset(e){
metas.forEach(function(meta){
var entry = head.querySelector('meta["'+meta+'"]');
if(meta.match(/(status-bar)/gi)) entry.setAttribute('content', oStyle);
else entry.setAttribute('content', oColor);
});
}
}
}
// 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);
}
// Helpers:
// Get closes scrollable parent
function scrollParent(node) {
if (!node) 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, key, value) { vars[key] = value; }
);
return vars;
}
// Get value of css var
function getRootVar(name){
var root = d.querySelector(':root');
return w.getComputedStyle(root).getPropertyValue(name);
}
// Color conversion
function rgb2hex(string) {
var parts = (string || '').match(/\d+/g);
return "#" + (16777216 | b | (g << 8) | (r << 16)).toString(16).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';
}
// Remove listenner from element by type
function removeListeners(el, event){
var ls = getEventListeners(el)[event];
for(var i = 0; i < ls.length; i++){
removeEventListener(event, ls[i].listener);
}
}
// Replace / refresh / update listenner
function replaceListener (event, action, passive, el) {
el.removeEventListener(event, action, passive);
el.addEventListener(event, action, passive);
}
// Add event observe
function dispatchEvent(name, el) {
var e = d.createEvent('Event');
e.initEvent(name, true, true);
if(el) el.dispatchEvent(e);
}
// 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 objects
function merge(obj1, obj2) {
for (var key in obj2) obj1[key] = obj2[key];
return obj1;
}
// Listen to changes in element / document
function changed(el, value){
var inputs = el.querySelectorAll('input, select, [contenteditable], textarea');
value = [value] ? [value] : false;
for(var i = 0; i < inputs;i++){
inputs[i].addEventListener('change', function(e){ [value] = true; }, false);
};
return value;
}
// 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);
}
}
// Send notification via Notifications API (IE 11 and lower isn't supported.)
function notification (title, body, icon, img, sound) {
if (!('Notification' in w)) return false;
var title = title || 'Undefined title';
var options = {
body: body || 'Undefined content',
icon: (icon) ? 'notification/'+ icon : 'https://s3-us-west-2.amazonaws.com/s.cdpn.io/515428/skype_icon.png',
badge: 'notification/badge.png',
image: (img) ? img : '',
vibrate: [400],
sound: audiopool.pop
};
var ask = Notification.requestPermission();
ask.then( function(permission) {
if (permission === 'granted') {
var n = new Notification(title, options);
n.addEventListener('click', function(e) {
alert('Click from notification.', {title: 'Notification API'});
});
} else if (permission !== 'denied') {
Notification.requestPermission().then(function (permission) {
if (permission === 'granted') var n = new Notification(title, options);
else return alert('Permission '+ permission +'.', {title: 'Notification API'});
});
} else {
return alert('Permission '+ permission +'.', {title: 'Notification API'});
}
});
}
// IE 9 SVG 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);
}
});
});
// 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() {
ctx.drawImage(img, 0, 0);
alert(canvas.toDataURL('image/png'));
};
return canvas.toDataURL('image/png');
}
// 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)
}
}
// Display human readable n time ago
function ago(el, int) {
var instance, interval = int ? int : 10000,
timestamp = parseInt(el.getAttribute('timestamp'), 10),
units = i18n.units ? i18n.units : [
{text: 'just now', sec: 0},
{text: '%n second%s ago', sec: 1},
{text: '%n minute%s ago', sec: 60},
{text: '%n hour%s ago', sec: 3600},
{text: '%n day%s ago', sec: 86400},
{text: '%n week%s ago', sec: 604800},
{text: '%n month%s ago', sec: 2592000},
{text: '%n year%s ago', sec: 31536000},
{text: '%n decade%s ago', sec: 315360000}
];
// 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;
}
}
}
}
// Vibrate
function vibration (pattern) {
pattern = pattern ? pattern : [300, 100, 300];
w.navigator.vibrate(pattern);
}
// Play sound via HTML element (IE9 support)
function sound(url){
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='};
}
@charset "UTF-8";
/*! UI v0.1 - SCSS (https://host-one.ch/) */
/// 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: .875em !default;
$font-size-lg: 1.125em !default;
$font-size-sub-sup: .75em !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: (
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;
// 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-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-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 !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;
// 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-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;
// 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: null !default;
$form-label-margin-bottom:.75rem !default;
$form-label-font-size: null !default;
$form-label-font-style: null !default;
$form-label-font-weight:null !default;
$form-label-color: null !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 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};
}
.g#{$infix}-#{$key},
.gy#{$infix}-#{$key} {
--ui-gutter-y: #{$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;
-ms-text-size-adjust: 100%;
-webkit-text-size-adjust: 100%;
-webkit-tap-highlight-color: transparent;
}
@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.25rem; } }
// 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;
@include dark-scheme (true){
background-color: $body-dark-bg;
color: $body-dark-color;
}
-webkit-font-smoothing: antialiased;
}
// Viewport mobile hack
.vh {
height: 100vh;
height: calc(var(--vh, 1vh) * 100);
}
// Outline normalization
* {
outline-color: $primary;
}
// 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;
}
}
// 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;
}
/// Text classes
.text-hide {
font: 0/0 a;
color: transparent;
text-shadow: none;
background-color: transparent;
border: 0;
}
.text-mute {
}
/// Screenreaders
.sr-only,
.sr-only-focusable:not(:focus) {
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;
}
// 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;
}
}
}
/// Alert mixin
@mixin alert-variant($background, $border, $color) {
color: $color;
background-color: $background;
border-color: $border;
.alert-link {
color: darken($color, 10%);
}
}
/// 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();
}
}
}
// 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 X
.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
.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
.hamburger {
position: relative;
display: inline-block;
width: 2em;
height: 2em;
line-height: 1;
text-indent: -9999rem;
border-radius: 50%;
&:focus {
background-color: $primary;
color: contrast-color($primary);
}
&::before, &::after {
content: '';
position: absolute;
top: 25%;
left: 25%;
width: 50%;
height: 10%;
background-color: currentColor;
}
&::before {
box-shadow: 0 50% 0 0 currentColor,
}
&::after {
top:65%;
}
}
// Disabled property / pseudo / class
[disabled], :disabled, .disabled {
cursor: not-allowed;
opacity: 0.5;
}
// Hidden property / pseudo / class
[hidden], :hidden, .hidden {
display: none!important;
}
// UI interaction / manipulation properties
[scrolling] {
scroll-behavior: smooth;
}
[swiping], [dragging], [paning] {
-webkit-overflow-scrolling: none;
overscroll-behavior: none;
-ms-scroll-chaining: none;
/* autoprefixer: off */
-ms-touch-action: none;
touch-action: none;
}
[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);
}
// Form normalization
form, fieldset {
padding: 0;
margin: 0;
border: 0;
}
form {
width: 100%;
}
// 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;}
button{
&:last-child {
margin-right: 0;
}
&:first-child {
margin-left: 0;
}
}
[type=button]:not(:disabled), [type=reset]:not(:disabled), [type=submit]:not(:disabled), button:not(:disabled) {
cursor: $cursor;
}
/// 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;
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;
@include transition($input-transition);
@include dark-scheme (){
background-color: $input-dark-bg;
color: $input-dark-color;
}
&:focus {
color: $input-focus-color;
background-color: $input-focus-bg;
border-color: $input-focus-border-color;
outline: 0;
box-shadow: $input-focus-box-shadow;
@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;
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;
}
// Password
&[type*="password"]{
font-family: 'Dots', $input-font-family;
&::-ms-reveal {
display:none;
}
}
// Color input
&[type*="color"] {
max-width: 3rem;
padding: $input-padding-y;
&: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%;
}
// 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 {
background-image: escape-svg($input-select-icon-bg-focus);
&::-ms-value {
color: $input-color;
background-color: $input-bg;
}
}
optgroup {
font-style: normal;
}
option {
font-style: normal;
}
// W3C recos, Firefox label display
optgroup[label], option[label]{
content: attr(label);
}
option[selected]::before{
display: inline;
content: check;
}
}
// 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="month"] {
appearance: listbox;
background-repeat: no-repeat;
background-size: 1em 1em;
background-position: substract(100%, $input-padding-x, true) center;
&::-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="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"]::-webkit-search-cancel-button {
display: none;
}
// Prepended labels
& ~ .form-label, & ~ label {
position: relative;
top: 0;
}
// Autofill
&:-webkit-autofill {
color: $input-color !important;
-webkit-text-fill-color: $input-color !important;
background-color: $input-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 transition($input-transition, background-image .15s linear, background-color 99999s linear 99999s);
@include dark-scheme (){
background-color: $input-dark-bg;
}
&:hover, &:focus, &:active {
color: $primary !important;
-webkit-text-fill-color: $primary !important;
background-image: escape-svg($input-autofill-active-icon-bg) !important;
}
}
&:-internal-autofill-selected,
&:-internal-autofill-previewed,
&:-internal-input-suggested {
font: inherit !important;
color: $input-color !important;
-webkit-text-fill-color: $input-color !important;
background-color: $input-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 transition($input-transition, background-image .15s linear, background-color 99999s linear 99999s);
@include dark-scheme (){
background-color: $input-dark-bg;
}
}
// 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;
&: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);
}
}
}
@at-root .is-valid #{&} {
}
}
// 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-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-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-right-radius: 0;
border-bottom-radius: 0;
}
&:not(:first-child) > .form-file-label {
border-left-radius: 0;
border-top-radius: 0;
}
}
.btn {
position: relative;
z-index: 2;
&:focus {
z-index: 3;
}
}
// Border-radius
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
> .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 > .btn,
.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;
}
// Form
.form-inline {
display: flex;
flex-flow: row wrap;
align-items: center;
.form-check {
width: 100%;
}
}
// Form group
.form-group, fieldset {
position: relative;
margin-bottom: $form-group-margin-bottom;
}
// 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;
}
}
/// Labels
.form-label {
margin-bottom: $form-label-margin-bottom;
font-size: inherit;
font-style: $form-label-font-style;
font-weight: $form-label-font-weight;
color: $form-label-color;
// Validation states
@at-root .has-error #{&} {
color: $danger;
font-weight: $font-weight-bold;
}
}
/// 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;
user-select: none;
background-color: $gray-200;
border: 1px solid transparent;
padding: 0.5em 0.75em;
line-height: 1.35;
border-radius: $border-radius;
transition: $btn-transition;
&::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 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;
}
}
}
/// Input group
.input-group {
position: relative;
display: flex;
flex-wrap: wrap; // For form validation feedback
align-items: stretch;
width: 100%;
> .form-control,
> .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-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-right-radius: 0;
border-bottom-radius: 0;
}
&:not(:first-child) > .form-file-label {
border-left-radius: 0;
border-top-radius: 0;
}
}
// Ensure buttons are always above inputs for more visually pleasing borders.
.btn {
position: relative;
z-index: 2;
&:focus {
z-index: 3;
}
}
// Rounded corners
> :not(:last-child):not(.dropdown-toggle):not(.dropdown-menu),
> .dropdown-toggle:nth-last-child(n + 3) {
border-right-radius: 0;
border-bottom-radius: 0;
}
> :not(:first-child):not(.dropdown-menu) {
margin-left: -$input-border-width;
border-left-radius: 0;
border-top-radius: 0;
}
}
/// Card
.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;
list-style: none;
}
// Tab / tablist
.tab-list {
position: relative;
overflow: auto;
overflow-y: hidden;
overflow-x: hidden;
white-space: nowrap;
border-bottom: 1px solid #dee2e6;
box-shadow: 0 0.25em 0 0.25em rgba(222, 226, 230, 0.25);
padding: 0;
.indicator {
position: absolute;
bottom: 0;
left: 0;
height: 2.5px;
width: 0;
background: #007bff;
will-change: left, width;
transition: left .25s ease-out, width .1s linear;
z-index: 1;
}
[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;
transition: background-color .3s ease;
&:hover {
background-color: rgba(222, 226, 230, 0.25);
color: #212529;
}
&:focus, &:active {
background-color: rgba(222, 226, 230, 0.75);
}
&.active {
color: $primary;
background-color: rgba(222, 226, 230, 0.15);
}
}
}
.tabs {
width: 100%;
position: relative;
overflow: hidden;
.tab-panel {
width: 100%;
outline: none;
display: none;
opacity: 1;
will-change: translate;
transform: translateX(-100%);
&.active, &:target {
display: inline-block;
transform: translateX(0%);
}
&.fade {
transition: opacity .15s linear;
}
&.fade:not(.show) {
opacity: 0;
}
&.slide {
transition: transform .15s linear, opacity .1s linear;
&:not(.show) {
transform: translateX(100%);
}
&.slide-before:not(.show) {
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;
}
}
// Dropdown
.dropdown {
position: relative;
z-index: $zindex-dropdown;
&.dropup .caret:empty::before {
top: 0.3em;
transform: rotate(-135deg);
}
}
.dropdown-menu {
position: absolute;
top: 0;
left: 0;
display: none;
overflow: hidden;
float: left;
min-width: 10rem;
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;
box-shadow: $shadow-elevated;
z-index: $zindex-dropdown + 1;
&.show {
display: block;
}
[role="menuitem"] {
display: block;
width: 100%;
padding: .75rem 1.5rem;
clear: both;
font-weight: normal;
text-align: inherit;
text-decoration: none;
white-space: nowrap;
text-overflow: ellipsis;
background-color: transparent;
border: 0;
will-change: background;
transition: background .15s linear;
&: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;
}
}
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);
}
}
// Modal
.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;
}
}
}
// Overwritten js ui-dialogs
&.ui-dialog {
.modal-body {
padding-bottom: 2rem;
& > input {
width: 100%;
margin: 1rem 0 0 0;
font: inherit;
padding: .5em .75em;
border-radius: 0.15rem;
border: 1px solid #dee2e6;
transition: .2s;
cursor: default;
&:focus {
outline: none;
box-shadow: 0 0 0 0.25em rgba(222, 226, 230, 0.75);
}
&::placeholder {
opacity: 0.5;
}
}
& > 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;
&: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;
}
&: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;
}
&: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;
}
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: 4em;
height: 100%;
margin: 0;
padding: 0;
color: #007bff;
text-align: right;
z-index: 1;
svg {
top: 25%;
position: relative;
width: 70%;
fill: currentColor;
}
img {
position: relative;
width: 100%;
}
& + p {
margin-left: 4em;
}
}
p {
display: block;
margin: 0;
padding: 1em 1em 2em 1em;
z-index: 2;
b {
display: block;
&:first-letter {
text-transform: uppercase;
}
}
&:first-letter {
text-transform: uppercase;
}
}
.close {
position: absolute;
top: .25rem;
right: .25rem;
z-index: 3;
font-size: 0.8em;
&:hover, &:focus {
background: #007bff;
color: #FFF;
outline: none;
}
}
.progress {
position: absolute;
bottom: 0;
display: block;
left: 0;
width: 100%;
height: 3px;
color: #007bff;
background: rgba(127, 127, 127, 0.1);
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-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;
&: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