summaryrefslogtreecommitdiff
path: root/design/toolbar.html
blob: 34270f69eb89578da9a7cd1a2791fa50d6f8b37e (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
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>