Repository navigation
Expand file tree
/
Copy pathexample.html
More file actions
175 lines (151 loc) · 7.8 KB
/
Copy pathexample.html
File metadata and controls
175 lines (151 loc) · 7.8 KB
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
<!DOCTYPE html>
<html lang="en-GB">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>Shell example</title>
<!-- The layer order comes before shell.css: a layer ranks by where it is first named, and a reset named after shell would undo Shell's insets. -->
<style>@layer reset, shell, page;</style>
<link rel="stylesheet" href="shell.css">
<script type="importmap">{ "imports": { "shell": "./shell.js" } }</script>
<style>
@layer reset {
* { box-sizing: border-box; margin: 0; padding: 0; }
}
@layer page {
:root { color-scheme: light dark; }
.brand b { letter-spacing: 2px; }
.brand span { margin-left: 10px; color: var(--shell-quiet); }
.body p { margin-block: 1em; max-width: 72ch; }
.body ul { list-style: none; margin-block: 1em; }
.body li button { width: 100%; padding: 4px 0px; text-align: left; border: none; color: var(--shell-quiet); }
.body li button:hover { background: none; color: var(--shell-text); }
.body li button[aria-current] { color: var(--shell-accent); }
.body button { font: inherit; color: inherit; background: none; cursor: pointer; padding: 4px 10px; margin: 0px 6px 6px 0px; border: solid 1px var(--shell-edge); }
.body button:hover { background: var(--shell-hover); }
}
</style>
</head>
<body>
<div id="shell" class="show-menu-main">
<nav id="menu">
<div class="head">
<span class="logo"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M24 4h2v24h-2zm-6 2v20h-4V6h4m0-2h-4a2 2 0 0 0-2 2v20a2 2 0 0 0 2 2h4a2 2 0 0 0 2-2V6a2 2 0 0 0-2-2zM6 4h2v24H6z"/></svg></span>
<span class="brand"><b>SHELL</b><span>0.1.0</span></span>
<span></span>
</div>
<div class="neck"><span></span><span>LAYOUTS</span><span></span></div>
<div class="body"><ul id="layouts"></ul></div>
<div class="foot">
<button class="icon-button" id="scheme" title="Light or dark"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M15 2h2v5h-2zM21.688 8.9l3.506-3.506 1.414 1.414-3.506 3.506zM25 15h5v2h-5zM21.688 23.1l1.414-1.413 3.506 3.506-1.414 1.414zM15 25h2v5h-2zM5.394 25.192 8.9 21.686l1.414 1.414-3.505 3.506zM2 15h5v2H2zM5.395 6.808l1.414-1.414L10.315 8.9 8.9 10.314zM16 12a4 4 0 1 1-4 4 4.005 4.005 0 0 1 4-4m0-2a6 6 0 1 0 6 6 6 6 0 0 0-6-6Z"/></svg></button>
<span id="scheme-name"></span>
<span></span>
</div>
</nav>
<main id="main">
<div class="head">
<button class="icon-button" data-change="toggleMenu" title="Show or hide the menu"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M4 6h24v2H4zm0 18h24v2H4zm0-12h24v2H4zm0 6h24v2H4z"/></svg></button>
<span class="title">Shell example</span>
<button class="icon-button" id="previous" title="Previous layout"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M10 16 20 6l1.4 1.4-8.6 8.6 8.6 8.6L20 26z"/></svg></button>
<button class="icon-button" id="next" title="Next layout"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M22 16 12 26l-1.4-1.4 8.6-8.6-8.6-8.6L12 6z"/></svg></button>
</div>
<div class="neck"><span></span><span id="position"></span><span></span></div>
<div class="body">
<p>Each column has a head, a neck, a body and a foot. Every title and every paragraph sits one base space in from its column's edges. In a head, the icon cells beside the title make that space.</p>
<p>
<button data-change="toggleMenu">toggleMenu</button>
<button data-change="showSide">showSide</button>
<button data-change="hideSide">hideSide</button>
<button data-change="showMore">showMore</button>
<button data-change="hideMore">hideMore</button>
</p>
<p id="layout"></p>
</div>
<div class="foot"><span></span><span>Only a body scrolls</span><span></span></div>
</main>
<aside id="side">
<div class="head">
<span></span>
<span class="title">Side</span>
<button class="icon-button" data-change="hideSide" title="Close side"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M17.414 16 24 9.414 22.586 8 16 14.586 9.414 8 8 9.414 14.586 16 8 22.586 9.414 24 16 17.414 22.586 24 24 22.586 17.414 16z"/></svg></button>
</div>
<div class="neck"><span></span><span>A record opened from main</span><span></span></div>
<div class="body"><p>Side shows next to main. Opening more beside it keeps it open; showing a new side closes more.</p></div>
<div class="foot"><span></span><span>Side foot</span><span></span></div>
</aside>
<aside id="more">
<div class="head">
<span></span>
<span class="title">More</span>
<button class="icon-button" data-change="hideMore" title="Close more"><svg viewBox="0 0 32 32" aria-hidden="true"><path d="M17.414 16 24 9.414 22.586 8 16 14.586 9.414 8 8 9.414 14.586 16 8 22.586 9.414 24 16 17.414 22.586 24 24 22.586 17.414 16z"/></svg></button>
</div>
<div class="neck"><span></span><span>More about the side record</span><span></span></div>
<div class="body"><p>More only shows with side.</p></div>
<div class="foot"><span></span><span>More foot</span><span></span></div>
</aside>
</div>
<script type="module">
import * as shell from "shell"
const LAYOUTS = [ "show-main", "show-menu-main", "show-main-side", "show-menu-main-side", "show-main-side-more", "show-menu-main-side-more" ]
const element = document.getElementById( "shell" )
const list = document.getElementById( "layouts" )
// This page's own wiring: a button names the change it makes in data-change.
for( const button of document.querySelectorAll( "[data-change]" ) ) {
button.addEventListener( "click", () => {
shell[ button.dataset.change ]( element )
showLayout()
} )
}
// The menu lists the six layouts by the columns they show, and the arrows in main's head step through them. A layout is a class on #shell.
for( const layout of LAYOUTS ) {
list.insertAdjacentHTML( "beforeend", `<li><button data-layout="${ layout }" title="${ layout }">${ layout.replace( "show-", "" ).replaceAll( "-", " " ) }</button></li>` )
}
list.addEventListener( "click", event => {
const button = event.target.closest( "[data-layout]" )
if( button ) useLayout( button.dataset.layout )
} )
document.getElementById( "previous" ).addEventListener( "click", () => step( -1 ) )
document.getElementById( "next" ).addEventListener( "click", () => step( 1 ) )
function step( by ) {
const index = LAYOUTS.indexOf( currentLayout() )
useLayout( LAYOUTS[ ( index + by + LAYOUTS.length ) % LAYOUTS.length ] )
}
function useLayout( layout ) {
element.classList.replace( currentLayout(), layout )
showLayout()
}
function currentLayout() {
return LAYOUTS.find( layout => element.classList.contains( layout ) )
}
function showLayout() {
const layout = currentLayout()
document.getElementById( "layout" ).textContent = `#shell has the class ${ layout }.`
document.getElementById( "position" ).textContent = `Layout ${ LAYOUTS.indexOf( layout ) + 1 } of ${ LAYOUTS.length }`
for( const button of list.querySelectorAll( "button" ) ) {
if( button.dataset.layout === layout ) button.setAttribute( "aria-current", "true" )
else button.removeAttribute( "aria-current" )
}
}
// The sun in the menu's foot turns the page from light to dark and back.
const root = document.documentElement
const schemeName = document.getElementById( "scheme-name" )
document.getElementById( "scheme" ).addEventListener( "click", () => {
root.style.colorScheme = isDark() ? "light" : "dark"
showScheme()
} )
function isDark() {
return ( root.style.colorScheme || ( matchMedia( "(prefers-color-scheme: dark)" ).matches ? "dark" : "light" ) ) === "dark"
}
function showScheme() {
schemeName.textContent = isDark() ? "Dark" : "Light"
}
// Enough text for the main body to scroll.
const body = element.querySelector( "#main .body" )
for( let number = 1; number <= 40; number++ ) {
body.insertAdjacentHTML( "beforeend", `<p>Paragraph ${ number }. Scroll this body: the head, neck and foot stay where they are.</p>` )
}
showLayout()
showScheme()
</script>
</body>
</html>