summaryrefslogtreecommitdiff
path: root/design/toolbar.html
diff options
context:
space:
mode:
Diffstat (limited to 'design/toolbar.html')
-rw-r--r--design/toolbar.html201
1 files changed, 201 insertions, 0 deletions
diff --git a/design/toolbar.html b/design/toolbar.html
new file mode 100644
index 0000000..34270f6
--- /dev/null
+++ b/design/toolbar.html
@@ -0,0 +1,201 @@
+<!DOCTYPE html>
+<html lang="en">
+ <head>
+ <title>Toolbar</title>
+ <meta charset="UTF-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0">
+ <meta name="apple-mobile-web-app-capable" content="yes">
+ <meta name="mobile-web-app-capable" content="yes">
+ <meta name="theme-color" content="#FFFFFF">
+ <link rel="manifest" href="manifest.json">
+
+ <link rel="preconnect" href="https://fonts.gstatic.com">
+ <link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Roboto+Mono:ital,wght@0,400;0,700;1,400;1,700&family=Roboto:ital,wght@0,400;0,500;0,700;1,400;1,700&display=swap">
+ <style>
+ :root {
+ --bg-color: #FFF;
+ --page-bg-color: #EEE;
+ --text-color: rgba(0,0,0,.87);
+ --error-triple: 176, 0, 32;
+ --error-color: rgb(var(--error-triple));
+ --icon-opacity-active: .87;
+ --icon-opacity-inactive: .6;
+ --icon-opacity-disabled: .38;
+ --icon-inactive-filter: brightness(0);
+ --icon-add-hover-filter: brightness(1);
+ --icon-menu-hover-filter: brightness(1);
+ --icon-search-hover-filter: brightness(1);
+ --icon-window-hover-filter: brightness(1);
+ --menu-button-hover-bg-color: #FBBC04;
+ --button-hover-bg-color: #FFF;
+ --button-hover-shadow: 0 2px 16px rgba(0,0,0,.1), 0 2px 4px rgba(0,0,0,.2);
+ --fab-bg: #FFF;
+ --fab-shadow: 0 2px 12px rgba(0,0,0,.15), 0 2px 6px rgba(0,0,0,.2);
+ --fab-shadow-hover: 0 4px 16px rgba(0,0,0,.2), 0 3px 6px rgba(0,0,0,.3);
+ --toolbar-shadow-mobile: 0 8px 8px 8px rgba(0,0,0,.2);
+ --toolbar-hide-distance-mobile: calc(-56px - 8px);
+ --toolbar-button-hover-bg-mobile: rgba(0,0,0,.1);
+ }
+
+ @media (prefers-color-scheme: dark) { :root {
+ --bg-color: #000;
+ --page-bg-color: #000;
+ --text-color: rgba(255,255,255,.87);
+ --error-triple: 245, 0, 45;
+ --error-color: rgb(var(--error-triple));
+ --icon-opacity-active: .87;
+ --icon-opacity-inactive: .6;
+ --icon-opacity-disabled: .38;
+ --icon-inactive-filter: brightness(0) invert(1) hue-rotate(180deg);
+ --icon-add-hover-filter: brightness(1.4) invert(.1) hue-rotate(0);
+ --icon-menu-hover-filter: brightness(1) invert(1) hue-rotate(180deg);
+ --icon-search-hover-filter: brightness(1) invert(1) hue-rotate(180deg);
+ --icon-window-hover-filter: brightness(.75) invert(1) hue-rotate(180deg);
+ --menu-button-hover-bg-color: #FBBC04;
+ --button-hover-bg-color: #181818;
+ --button-hover-shadow: 0 0 0 transparent;
+ --fab-bg: #333;
+ --fab-shadow: 0 2px 12px rgba(0,0,0,.2), 0 2px 6px rgba(0,0,0,.24);
+ --fab-shadow-hover: 0 2px 12px rgba(0,0,0,.2), 0 2px 6px rgba(0,0,0,.24);
+ --toolbar-shadow-mobile: 0 8px 8px 8px #000, 0 56px 56px -56px rgba(255,255,255,.25) inset;
+ --toolbar-hide-distance-mobile: calc(-56px - 8px);
+ --toolbar-button-hover-bg-mobile: rgba(255,255,255,.1);
+ }}
+
+ * { box-sizing: border-box; margin: 0; padding: 0; font-family: "Roboto", sans-serif; transition-timing-function: cubic-bezier(.4,0,.2,1); }
+ html { background: var(--page-bg-color); color: var(--text-color); }
+
+ #toolbar { position: fixed; font-size: 0; }
+ #toolbar > * { font-size: 16px; text-align: center; }
+ .toolbar-btn, .toolbar-fab { position: relative; border-radius: 100%; }
+ .toolbar-btn { height: 48px; width: 48px; }
+
+ .toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { content: ""; display: block; height: 24px; width: 24px; background-image: url("icons.svg"); filter: var(--icon-inactive-filter); opacity: var(--icon-opacity-active); position: absolute; top: 50%; left: 50%; transform: translate(-50%,-50%); }
+ #menu-btn::after { background-position: 0 0; }
+ #window-btn::after { background-position: -24px 0; }
+ #search-btn::after { background-position: -48px 0; }
+ #add-btn::after { background-position: -72px 0; }
+
+ #conflict-btn { display: none; vertical-align: bottom; }
+ #conflict-btn::after { content: ""; position: absolute; top: 50%; left: 50%; display: block; height: 8px; width: 8px; border-radius: 4px; background: rgba(var(--error-triple), .8); transform: translate(-50%,-50%); }
+
+ @media (hover:hover) {
+ .toolbar-btn, .toolbar-fab { cursor: pointer; transition: background-color .2s, box-shadow .2s; }
+ .toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { transition: opacity .1s, filter .1s; filter: var(--icon-inactive-filter); }
+ .toolbar-btn:not(#conflict-btn):hover::after, .toolbar-fab:hover::after { opacity: 1; }
+
+ #menu-btn:hover::after { filter: var(--icon-menu-hover-filter); }
+ #window-btn:hover::after { filter: var(--icon-window-hover-filter); }
+ #search-btn:hover::after { filter: var(--icon-search-hover-filter); }
+ #add-btn:hover::after { filter: var(--icon-add-hover-filter); }
+
+ #conflict-btn::after { transition: box-shadow .1s; }
+ #conflict-btn:hover::after { box-shadow: 0 0 0 4px rgba(var(--error-triple),.25); }
+ }
+
+ @media (hover:hover) and (min-width:481px) {
+ body { padding: 0 80px 16px; }
+ #toolbar { top: 16px; left: 50%; transform: translate(-50%,0); width: 100%; max-width: calc(7in + 16px); pointer-events: none; }
+ #toolbar > * { pointer-events: auto; }
+ .toolbar-fab { height: 48px; width: 48px; }
+ .toolbar-btn, .toolbar-fab { display: block; margin: 0 16px; }
+ .toolbar-btn:not(#conflict-btn):hover, .toolbar-fab:hover { background-color: var(--button-hover-bg-color); box-shadow: var(--button-hover-shadow); }
+ .toolbar-btn:not(#conflict-btn)::after, .toolbar-fab::after { opacity: var(--icon-opacity-inactive) }
+ .toolbar-btn:not(#conflict-btn):hover::after, .toolbar-fab:hover::after { opacity: var(--icon-opacity-active) }
+
+ #menu-btn:hover { background-color: var(--menu-button-hover-bg-color) !important; }
+ #search-btn { position: absolute; top: 0; right: 0; }
+ #add-btn { position: absolute; top: 48px; right: 0; }
+ #conflict-btn { height: 42px; }
+ #conflict-btn.show { display: block; }
+ }
+
+ @media (hover:none), (max-width:480px) {
+ body { padding: 0 16px 16px; }
+ #toolbar { bottom: 0; left: 0; right: 0; width: 100%; box-shadow: var(--toolbar-shadow-mobile); padding: 0 4px; background: var(--bg-color); transition: bottom .25s; /* reentrance speed */ }
+ .toolbar-btn { display: inline-block; }
+ .toolbar-fab { position: absolute; display: block; right: 16px; top: -28px; width: 56px; height: 56px; box-shadow: var(--fab-shadow); background: var(--fab-bg); transition: top .25s; }
+ #conflict-btn { width: 36px; }
+ #conflict-btn.show { display: inline-block; }
+
+ #toolbar.hide { bottom: var(--toolbar-hide-distance-mobile); transition: bottom .2s; /* exit speed */ }
+ #toolbar.hide .toolbar-fab { top: calc(var(--toolbar-hide-distance-mobile) - 16px); transition: top .2s; }
+
+ @media (orientation:portrait) {
+ .toolbar-btn { margin: 4px 0; }
+ }
+
+ @media (orientation:landscape) {
+ .toolbar-btn { margin: 0; }
+ }
+ }
+
+ @media (hover:hover) and (max-width:480px) {
+ .toolbar-btn:not(#conflict-btn)::before { content: ""; display: block; position: absolute; top: 50%; left: 50%; height: 40px; width: 40px; border-radius: 20px; transform: translate(-50%,-50%); transition: background-color .2s; }
+ .toolbar-btn:not(#conflict-btn):hover::before { background-color: var(--toolbar-button-hover-bg-mobile); }
+ #menu-btn:hover::before { background-color: var(--menu-button-hover-bg-color) !important; }
+ .toolbar-fab { transition: top .25s, box-shadow .2s; }
+ #toolbar.hide .toolbar-fab { transition: top .2s, box-shadow .2s; }
+ .toolbar-fab:hover { box-shadow: var(--fab-shadow-hover); }
+ #add-btn::after { transition: opacity .15s, filter .15s, transform .2s; }
+ #add-btn:hover::after { filter: var(--icon-add-hover-filter); transform: translate(-50%,-50%) scale(1.25); }
+ }
+
+ a { display: block; margin: 16px auto; padding: 24px; max-width: 5.5in; background-color: var(--bg-color); border-radius: 16px; box-shadow: 0 2px 16px rgba(0,0,0,.05), 0 2px 4px rgba(0,0,0,.1), 0 0 0 1px rgba(255,255,255,.2) inset; transition: box-shadow .2s; }
+ a:hover { box-shadow: 0 2px 16px rgba(0,0,0,.15), 0 2px 4px rgba(0,0,0,.15), 0 0 0 2px rgba(255,255,255,.25) inset; }
+ </style>
+ </head>
+ <body>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <a href="#">Hello!</a>
+ <div id="toolbar">
+ <div class="toolbar-btn" id="menu-btn"></div>
+ <div class="toolbar-btn" id="window-btn"></div>
+ <div class="toolbar-btn" id="search-btn"></div>
+ <div class="toolbar-btn" id="conflict-btn"></div>
+ <div class="toolbar-fab" id="add-btn"></div>
+ </div>
+ <script>
+ function changeThemeColor(color) {
+ document.querySelector("meta[name=theme-color]")
+ .setAttribute("content", color);
+ }
+
+ //changeThemeColor("#eee");
+
+ function debounce(func, wait, immediate) {
+ var timeout;
+ return function() {
+ var context = this, args = arguments;
+ var later = function() {
+ timeout = null;
+ if (!immediate) func.apply(context, args);
+ };
+ var callNow = immediate && !timeout;
+ clearTimeout(timeout);
+ timeout = setTimeout(later, wait);
+ if (callNow) func.apply(context, args);
+ };
+ };
+
+ document.addEventListener("DOMContentLoaded", debounce(() => {
+ let prevScroll = 0;
+ window.addEventListener("scroll", function() {
+ if (this.scrollY && this.scrollY > prevScroll) {
+ document.querySelector("#toolbar").classList.add("hide");
+ } else {
+ document.querySelector("#toolbar").classList.remove("hide");
+ }
+ prevScroll = this.scrollY;
+ });
+ }, 250, true));
+ </script>
+ </body>
+</html>