@gemboss/website-ui 0.2.0 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +47 -22
- package/CHANGELOG.md +32 -0
- package/README.md +16 -8
- package/bin/lib/check.mjs +76 -7
- package/bin/lib/contrast.mjs +67 -0
- package/css/components.css +8 -6
- package/css/header.css +37 -5
- package/css/prose.css +3 -2
- package/css/tokens.css +19 -0
- package/demo/brand-profiles.html +199 -0
- package/docs/components.md +26 -11
- package/docs/markup-contract.md +16 -5
- package/docs/philosophy.md +14 -9
- package/docs/theming.md +85 -29
- package/js/website.js +1 -1
- package/package.json +1 -1
- package/skill/SKILL.md +3 -1
- package/system.json +31 -7
- package/templates/header.html +3 -1
- package/templates/page.html +2 -0
- package/website.css +68 -14
- package/website.min.css +1 -1
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
<!doctype html>
|
|
2
|
+
<!-- Kit demo: one brand that chose all three profiles (docs/theming.md). The profiles are two attributes on <html> and
|
|
3
|
+
one class on the header; the only CSS of the brand is the accent family below. Sample text, not a brand's copy. -->
|
|
4
|
+
<html lang="en" data-gw-action="accent" data-gw-radius="soft">
|
|
5
|
+
<head>
|
|
6
|
+
<meta charset="utf-8">
|
|
7
|
+
<meta name="viewport" content="width=device-width, initial-scale=1">
|
|
8
|
+
<title>GemPages-style example · website UI kit</title>
|
|
9
|
+
<meta name="description" content="A kit demo with all three brand profiles on: the accent action, soft corners and the floating header, with a GemPages-style blue.">
|
|
10
|
+
<script>try{var t=localStorage.getItem('gw-theme');if(t==='light'||t==='dark')document.documentElement.setAttribute('data-theme',t)}catch(e){}</script>
|
|
11
|
+
<link rel="preconnect" href="https://fonts.googleapis.com">
|
|
12
|
+
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
|
|
13
|
+
<link rel="stylesheet" href="https://fonts.googleapis.com/css2?family=Inter:wght@400;500;600;650;700&display=swap">
|
|
14
|
+
<link rel="stylesheet" href="../website.css">
|
|
15
|
+
<style>
|
|
16
|
+
/* The brand's whole CSS: the accent family, light and dark, in one :root block (docs/theming.md).
|
|
17
|
+
Light: #3c67ff fills the primary button, white words on it are 4.58:1 (6.36:1 on the hover #2f52d6).
|
|
18
|
+
#2f52d6 as accent-strong is an EXAMPLE, not confirmed by the GemPages team: accent text needs it, because
|
|
19
|
+
#3c67ff is 4.13:1 on --gw-bg-soft; #2f52d6 is 6.36:1 on white, 5.73:1 on --gw-bg-soft, 5.54:1 on its tint.
|
|
20
|
+
Dark and night bands: #7c9bff is 7.37:1 on the dark page, and #0d0d12 words on it are 7.37:1. */
|
|
21
|
+
:root {
|
|
22
|
+
--gw-accent-light: #3c67ff;
|
|
23
|
+
--gw-accent-strong-light: #2f52d6;
|
|
24
|
+
--gw-accent-soft-light: #eaefff;
|
|
25
|
+
--gw-on-accent-light: #ffffff;
|
|
26
|
+
--gw-accent-dark: #7c9bff;
|
|
27
|
+
--gw-accent-strong-dark: #a9beff;
|
|
28
|
+
--gw-accent-soft-dark: #16213d;
|
|
29
|
+
--gw-on-accent-dark: #0d0d12;
|
|
30
|
+
}
|
|
31
|
+
</style>
|
|
32
|
+
</head>
|
|
33
|
+
<body class="gw-page">
|
|
34
|
+
<a class="gw-skip" href="#main">Skip to content</a>
|
|
35
|
+
|
|
36
|
+
<div class="gw-announce" role="region" aria-label="Announcement">Kit demo: a GemPages-style brand with all three profiles on. Sample text, not a brand's page. <a href="index.html">Back to the full demo</a></div>
|
|
37
|
+
<header class="gw-header gw-header--float" data-gw-header>
|
|
38
|
+
<div class="gw-wrap gw-header__bar">
|
|
39
|
+
<a class="gw-brand" href="brand-profiles.html"><svg class="gw-brand__mark" viewBox="0 0 26 26" aria-hidden="true"><rect width="26" height="26" rx="7" style="fill:var(--gw-accent)"/><path d="M8 9h10M8 13h10M8 17h6" fill="none" stroke="#ffffff" stroke-width="2" stroke-linecap="round"/></svg><span class="gw-brand__name">Example brand</span></a>
|
|
40
|
+
<nav class="gw-nav" aria-label="Main">
|
|
41
|
+
<ul class="gw-nav__list">
|
|
42
|
+
<li class="gw-nav__item">
|
|
43
|
+
<button class="gw-nav__trigger" type="button" aria-expanded="false" aria-controls="gw-mega-kit" data-gw-mega="gw-mega-kit">The kit</button>
|
|
44
|
+
<div class="gw-mega" id="gw-mega-kit" hidden>
|
|
45
|
+
<div class="gw-wrap gw-mega__grid">
|
|
46
|
+
<div class="gw-mega__col">
|
|
47
|
+
<p class="gw-mega__heading">See it</p>
|
|
48
|
+
<a class="gw-mega__link" href="index.html#components-h"><span class="gw-mega__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="4" width="7" height="7" rx="1.5"/><rect x="13" y="4" width="7" height="7" rx="1.5"/><rect x="4" y="13" width="7" height="7" rx="1.5"/><rect x="13" y="13" width="7" height="7" rx="1.5"/></svg></span><span><b>Components</b><i>Buttons, chips, cards, tables</i></span></a>
|
|
49
|
+
<a class="gw-mega__link" href="index.html#features-h"><span class="gw-mega__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><rect x="4" y="3" width="16" height="18" rx="2"/><path d="M8 8h8M8 12h8M8 16h5"/></svg></span><span><b>Sections</b><i>Hero, features, pricing, FAQ</i></span></a>
|
|
50
|
+
</div>
|
|
51
|
+
<div class="gw-mega__col">
|
|
52
|
+
<p class="gw-mega__heading">Brands</p>
|
|
53
|
+
<a class="gw-mega__link" href="theme-example.html"><span class="gw-mega__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><circle cx="12" cy="12" r="8"/><path d="M12 4a8 8 0 0 1 0 16z"/></svg></span><span><b>Accent only</b><i>A brand that changed one colour</i></span></a>
|
|
54
|
+
<a class="gw-mega__link" href="#profiles"><span class="gw-mega__icon" aria-hidden="true"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.7" stroke-linecap="round" stroke-linejoin="round"><path d="M4 7h10M18 7h2M4 17h2M10 17h10"/><circle cx="16" cy="7" r="2"/><circle cx="8" cy="17" r="2"/></svg></span><span><b>All three profiles</b><i>This page</i></span></a>
|
|
55
|
+
</div>
|
|
56
|
+
<a class="gw-mega__feature" href="#profiles"><b>Three named choices</b><i>Action colour, corners and header. Chosen once per site.</i><span class="gw-link gw-link--arrow">See the profiles</span></a>
|
|
57
|
+
</div>
|
|
58
|
+
</div>
|
|
59
|
+
</li>
|
|
60
|
+
<li class="gw-nav__item"><a class="gw-nav__link" href="index.html">Default demo</a></li>
|
|
61
|
+
<li class="gw-nav__item"><a class="gw-nav__link" href="theme-example.html">Accent only</a></li>
|
|
62
|
+
</ul>
|
|
63
|
+
</nav>
|
|
64
|
+
<div class="gw-header__actions">
|
|
65
|
+
<button class="gw-theme-toggle" type="button" data-gw-theme-toggle aria-label="Switch to dark theme"><svg viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" aria-hidden="true"><circle cx="12" cy="12" r="8"/><path d="M12 4a8 8 0 0 1 0 16z" fill="currentColor"/></svg></button>
|
|
66
|
+
<a class="gw-btn gw-btn--secondary gw-btn--sm" href="index.html">Default demo</a>
|
|
67
|
+
<a class="gw-btn gw-btn--sm" href="#profiles">See the profiles</a>
|
|
68
|
+
<button class="gw-menu-toggle" type="button" aria-expanded="false" aria-controls="gw-mobile-menu" data-gw-menu-toggle aria-label="Open menu"><svg class="gw-menu-toggle__open" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M4 7h16M4 12h16M4 17h16"/></svg><svg class="gw-menu-toggle__close" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="1.8" stroke-linecap="round" aria-hidden="true"><path d="M6 6l12 12M18 6 6 18"/></svg></button>
|
|
69
|
+
</div>
|
|
70
|
+
</div>
|
|
71
|
+
<div class="gw-mobile-menu" id="gw-mobile-menu" hidden>
|
|
72
|
+
<nav class="gw-wrap" aria-label="Main, mobile">
|
|
73
|
+
<details class="gw-mobile-menu__group">
|
|
74
|
+
<summary>The kit</summary>
|
|
75
|
+
<ul class="gw-mobile-menu__list">
|
|
76
|
+
<li><a class="gw-mobile-menu__link" href="index.html#components-h">Components</a></li>
|
|
77
|
+
<li><a class="gw-mobile-menu__link" href="index.html#features-h">Sections</a></li>
|
|
78
|
+
<li><a class="gw-mobile-menu__link" href="#profiles">All three profiles</a></li>
|
|
79
|
+
</ul>
|
|
80
|
+
</details>
|
|
81
|
+
<a class="gw-mobile-menu__top" href="index.html">Default demo</a>
|
|
82
|
+
<a class="gw-mobile-menu__top" href="theme-example.html">Accent only</a>
|
|
83
|
+
<div class="gw-mobile-menu__actions">
|
|
84
|
+
<a class="gw-btn gw-btn--block" href="#profiles">See the profiles</a>
|
|
85
|
+
<a class="gw-btn gw-btn--secondary gw-btn--block" href="index.html">Default demo</a>
|
|
86
|
+
</div>
|
|
87
|
+
</nav>
|
|
88
|
+
</div>
|
|
89
|
+
</header>
|
|
90
|
+
|
|
91
|
+
<main id="main">
|
|
92
|
+
<section class="gw-hero" aria-labelledby="hero-h">
|
|
93
|
+
<div class="gw-hero__wash" aria-hidden="true"></div>
|
|
94
|
+
<div class="gw-wrap">
|
|
95
|
+
<p class="gw-label">Brand profiles</p>
|
|
96
|
+
<h1 id="hero-h"><span class="gw-dim">The same kit, three named choices.</span> Still one family.</h1>
|
|
97
|
+
<p class="gw-lead">This brand fills its primary button with its accent, rounds its corners one step and floats its header as a card. Everything else is the kit as it ships.</p>
|
|
98
|
+
<div class="gw-actions">
|
|
99
|
+
<a class="gw-btn" href="#profiles">See the three profiles</a>
|
|
100
|
+
<a class="gw-btn gw-btn--secondary" href="index.html">Open the default demo</a>
|
|
101
|
+
</div>
|
|
102
|
+
</div>
|
|
103
|
+
</section>
|
|
104
|
+
|
|
105
|
+
<section class="gw-section gw-section--soft" id="profiles" aria-labelledby="profiles-h">
|
|
106
|
+
<div class="gw-wrap">
|
|
107
|
+
<div class="gw-section__head">
|
|
108
|
+
<p class="gw-label">Three knobs</p>
|
|
109
|
+
<h2 id="profiles-h"><span class="gw-dim">Set once for the site.</span> Every component follows.</h2>
|
|
110
|
+
<p class="gw-lead">Each knob is a named profile, not a free value. A brand picks one of each, and the kit does the rest.</p>
|
|
111
|
+
</div>
|
|
112
|
+
<div class="gw-grid--3">
|
|
113
|
+
<div class="gw-card">
|
|
114
|
+
<h3>Action colour</h3>
|
|
115
|
+
<p>The primary button takes the accent. Its label must reach 4.5:1 on the fill in light and dark, or the check fails.</p>
|
|
116
|
+
</div>
|
|
117
|
+
<div class="gw-card">
|
|
118
|
+
<h3>Soft corners</h3>
|
|
119
|
+
<p>Actions 12px, cards 20px, panels 24px. Chips stay pills, and nothing else is allowed in between.</p>
|
|
120
|
+
</div>
|
|
121
|
+
<div class="gw-card">
|
|
122
|
+
<h3>Floating header</h3>
|
|
123
|
+
<p>An inset card over a light blur, from 1080px. The same bar and mega menu; phones keep the flat bar.</p>
|
|
124
|
+
</div>
|
|
125
|
+
</div>
|
|
126
|
+
</div>
|
|
127
|
+
</section>
|
|
128
|
+
|
|
129
|
+
<section class="gw-section" aria-labelledby="shapes-h">
|
|
130
|
+
<div class="gw-wrap gw-split">
|
|
131
|
+
<div>
|
|
132
|
+
<p class="gw-label">Radius profiles</p>
|
|
133
|
+
<h2 id="shapes-h">Two sets of corners, nothing in between.</h2>
|
|
134
|
+
<p class="gw-lead">Tight is the default. Soft rounds every action, card and panel by one step.</p>
|
|
135
|
+
<div class="gw-actions">
|
|
136
|
+
<button class="gw-chip" type="button" aria-pressed="false">Tight</button>
|
|
137
|
+
<button class="gw-chip" type="button" aria-pressed="true">Soft</button>
|
|
138
|
+
<span class="gw-badge gw-badge--accent">Chosen on the page</span>
|
|
139
|
+
</div>
|
|
140
|
+
<div class="gw-actions">
|
|
141
|
+
<a class="gw-btn" href="#rules-h">See what stays fixed</a>
|
|
142
|
+
<a class="gw-btn gw-btn--ghost" href="theme-example.html">Accent only</a>
|
|
143
|
+
</div>
|
|
144
|
+
</div>
|
|
145
|
+
<div class="gw-table" role="region" aria-labelledby="shapes-h" tabindex="0">
|
|
146
|
+
<table>
|
|
147
|
+
<thead><tr><th scope="col">Profile</th><th scope="col">Action</th><th scope="col">Card</th><th scope="col">Panel</th></tr></thead>
|
|
148
|
+
<tbody>
|
|
149
|
+
<tr><th scope="row">Tight, the default</th><td>8px</td><td>12px</td><td>16px</td></tr>
|
|
150
|
+
<tr><th scope="row">Soft</th><td>12px</td><td>20px</td><td>24px</td></tr>
|
|
151
|
+
</tbody>
|
|
152
|
+
</table>
|
|
153
|
+
</div>
|
|
154
|
+
</div>
|
|
155
|
+
</section>
|
|
156
|
+
|
|
157
|
+
<section class="gw-section gw-section--soft" aria-labelledby="rules-h">
|
|
158
|
+
<div class="gw-wrap gw-wrap--narrow">
|
|
159
|
+
<div class="gw-section__head">
|
|
160
|
+
<p class="gw-label">Still fixed</p>
|
|
161
|
+
<h2 id="rules-h"><span class="gw-dim">Three knobs, no more.</span> The rest is the kit's.</h2>
|
|
162
|
+
</div>
|
|
163
|
+
<div class="gw-faq">
|
|
164
|
+
<details class="gw-faq__item"><summary>Can a brand choose its own radius?</summary><p>No. It picks tight or soft. A radius of its own, or a token it redefines, is reported by the check.</p></details>
|
|
165
|
+
<details class="gw-faq__item"><summary>Can a heading use the accent?</summary><p>No. Words in a heading stay ink or muted, never the accent or a gradient. Bands are white, soft grey or night, never the accent. Labels stay in sentence case.</p></details>
|
|
166
|
+
<details class="gw-faq__item"><summary>What changes on a phone?</summary><p>Nothing. Below 1080px the floating header is the flat bar, and the menu opens the same way.</p></details>
|
|
167
|
+
<details class="gw-faq__item"><summary>What if a visitor turns transparency off?</summary><p>The header becomes a solid card. A browser that cannot blur gets the same solid card.</p></details>
|
|
168
|
+
</div>
|
|
169
|
+
</div>
|
|
170
|
+
</section>
|
|
171
|
+
|
|
172
|
+
<section class="gw-section gw-band--night" aria-labelledby="cta-h">
|
|
173
|
+
<div class="gw-wrap gw-cta">
|
|
174
|
+
<p class="gw-label">Night band</p>
|
|
175
|
+
<h2 id="cta-h">The accent button keeps its contrast at night.</h2>
|
|
176
|
+
<p class="gw-lead">In a night band and in dark mode it takes the dark accent with dark words, also checked at 4.5:1.</p>
|
|
177
|
+
<div class="gw-actions">
|
|
178
|
+
<a class="gw-btn" href="theme-example.html">Open the accent example</a>
|
|
179
|
+
<a class="gw-btn gw-btn--secondary" href="index.html">Open the default demo</a>
|
|
180
|
+
</div>
|
|
181
|
+
</div>
|
|
182
|
+
</section>
|
|
183
|
+
</main>
|
|
184
|
+
|
|
185
|
+
<footer class="gw-footer">
|
|
186
|
+
<div class="gw-wrap">
|
|
187
|
+
<div class="gw-footer__bottom">
|
|
188
|
+
<span>Website UI kit demo. Sample text.</span>
|
|
189
|
+
<ul aria-label="Demo pages">
|
|
190
|
+
<li><a href="index.html">Default demo</a></li>
|
|
191
|
+
<li><a href="theme-example.html">Accent only</a></li>
|
|
192
|
+
</ul>
|
|
193
|
+
</div>
|
|
194
|
+
</div>
|
|
195
|
+
</footer>
|
|
196
|
+
|
|
197
|
+
<script src="../js/website.js" defer></script>
|
|
198
|
+
</body>
|
|
199
|
+
</html>
|
package/docs/components.md
CHANGED
|
@@ -8,6 +8,10 @@ Conventions: kit classes start with `gw-`, variants are `--name`, parts are `__n
|
|
|
8
8
|
`is-*`. Never style a `.gw-*` class in your site's CSS: if the kit's version is wrong for you, that is a gap
|
|
9
9
|
(`AGENTS.md` section 9).
|
|
10
10
|
|
|
11
|
+
Radii and the button fill follow the site's brand profiles (`docs/theming.md`): below, "radius 8 / 12 / 16" is the
|
|
12
|
+
default `tight` profile, and `soft` makes them 12 / 20 / 24; "ink fill" is the default `ink` action profile, and
|
|
13
|
+
`data-gw-action="accent"` makes it the accent.
|
|
14
|
+
|
|
11
15
|
Spacing between the children of text blocks is automatic: inside `.gw-section__head`, the hero, a split column,
|
|
12
16
|
`.gw-cta`, `.gw-card`, `.gw-feature` and `.gw-plan`, each child is 16px below the previous one, a `.gw-actions` row
|
|
13
17
|
32px, a `.gw-list--check` 24px. Do not add margins to fix rhythm; reorder or remove content instead.
|
|
@@ -86,7 +90,8 @@ Don't: more than three night bands on a page (the closing CTA does not count), o
|
|
|
86
90
|
|
|
87
91
|
### Buttons `.gw-btn`
|
|
88
92
|
|
|
89
|
-
40px tall, radius 8, 14px/600, sentence case,
|
|
93
|
+
40px tall, the action radius (8, 12 in `soft`), 14px/600, sentence case, the action colour as fill: ink, or the
|
|
94
|
+
brand's accent with `--gw-on-accent` words under `data-gw-action="accent"` (one colour on the whole site). Variants: `--secondary` (hairline, transparent), `--ghost`
|
|
90
95
|
(no frame), `--on-night` (light fill for a dark surface that is not a `.gw-band--night`), `--sm` (36px, with a 44px
|
|
91
96
|
hit area), `--lg` (48px, 16px type), `--block` (full width). On touch screens every button is at least 44px tall and
|
|
92
97
|
its label may wrap. Inside a night band the default button turns light by itself.
|
|
@@ -98,7 +103,8 @@ its label may wrap. Inside a night band the default button turns light by itself
|
|
|
98
103
|
</div>
|
|
99
104
|
```
|
|
100
105
|
|
|
101
|
-
Pressed (`:active`): the
|
|
106
|
+
Pressed (`:active`): the fill one step stronger (the hover fill: the darker ink, or `--gw-accent-strong`), and
|
|
107
|
+
nothing moves; `--secondary` takes the soft tint and
|
|
102
108
|
`--ghost` the hairline tint.
|
|
103
109
|
|
|
104
110
|
**Loading.** While a `<button>` waits on the network (a form sent, an audit started), set `aria-busy="true"` on it and
|
|
@@ -116,7 +122,8 @@ button.setAttribute('aria-busy', 'true'); // the request leaves
|
|
|
116
122
|
button.removeAttribute('aria-busy'); // the answer came
|
|
117
123
|
```
|
|
118
124
|
|
|
119
|
-
Don't:
|
|
125
|
+
Don't: a fill of your own (the accent comes only from the action profile, set on `<html>`), a gradient or a wash; a
|
|
126
|
+
raised or inset shadow; pill-shaped buttons; uppercase; two filled buttons side by side (one
|
|
120
127
|
`.gw-btn` per view, the second is `--secondary` or a link); a `<div>` with a click handler instead of `<a>`/`<button>`;
|
|
121
128
|
a loading class, your own spinner or `disabled` on a waiting button (`check` reports `busy-button`: `disabled` throws
|
|
122
129
|
the keyboard focus to the top of the page); a "Loading…" label in place of the real one.
|
|
@@ -136,7 +143,7 @@ Don't: use a chip as the page's action; square it; more than about six in a row.
|
|
|
136
143
|
|
|
137
144
|
One choice out of two to four, shown as one group: Monthly / Yearly on a pricing page, Run it yourself / We run it for
|
|
138
145
|
you. It is a radio group: one Tab stop, the arrow keys (and Home, End) move and choose, a click or Space chooses. The
|
|
139
|
-
look is the dashboard's (`@gemboss/ui` `.ui-seg`): one hairline group, radius
|
|
146
|
+
look is the dashboard's (`@gemboss/ui` `.ui-seg`): one hairline group, the action radius, a hairline between options, the chosen
|
|
140
147
|
option on the accent tint, so it follows a brand's accent. 40px tall; on touch screens every option is at least 44px
|
|
141
148
|
and its label may wrap. `--block` stretches it to the row and shares the width equally.
|
|
142
149
|
|
|
@@ -176,7 +183,7 @@ Don't: make a badge clickable; write a sentence in it; use success or warning fo
|
|
|
176
183
|
|
|
177
184
|
### Cards `.gw-card`
|
|
178
185
|
|
|
179
|
-
A white box with a 1px hairline, radius 12, the resting shadow `--gw-shadow` (as the dashboard's cards), 24px padding
|
|
186
|
+
A white box with a 1px hairline, the card radius (12, 20 in `soft`), the resting shadow `--gw-shadow` (as the dashboard's cards), 24px padding
|
|
180
187
|
(32px from 768px). It sits: no hover lift. `--soft` is a tint and has no shadow.
|
|
181
188
|
Variants: `--soft` (on `--gw-bg-soft`), `--link` (the whole card is one `<a>`; the border darkens on hover).
|
|
182
189
|
|
|
@@ -188,8 +195,8 @@ Variants: `--soft` (on `--gw-bg-soft`), `--link` (the whole card is one `<a>`; t
|
|
|
188
195
|
</a>
|
|
189
196
|
```
|
|
190
197
|
|
|
191
|
-
Don't: put links or buttons inside a `--link` card (one card, one destination); a bigger shadow or a hover lift;
|
|
192
|
-
|
|
198
|
+
Don't: put links or buttons inside a `--link` card (one card, one destination); a bigger shadow or a hover lift; a
|
|
199
|
+
radius of your own (cards take the card radius, plans and the quote the panel radius, both from the profile).
|
|
193
200
|
|
|
194
201
|
### Window `.gw-window`
|
|
195
202
|
|
|
@@ -238,7 +245,7 @@ Don't: more than five or six items; full paragraphs as items.
|
|
|
238
245
|
|
|
239
246
|
### Table `.gw-table`
|
|
240
247
|
|
|
241
|
-
A wrapper around a plain `<table>`: hairline, radius
|
|
248
|
+
A wrapper around a plain `<table>`: hairline, the card radius, and it scrolls inside its own box when the table is wider
|
|
242
249
|
than the screen. `--compare`: centred values, a 640px minimum width and a sticky first column, for plan comparisons.
|
|
243
250
|
Give the wrapper `role="region"`, an accessible name and `tabindex="0"` so keyboard users can scroll it.
|
|
244
251
|
|
|
@@ -275,10 +282,11 @@ Don't: hide content a reader needs to decide (prices, terms) only inside a close
|
|
|
275
282
|
|---|---|
|
|
276
283
|
| `.gw-announce` | optional one-sentence bar above the header, with one link |
|
|
277
284
|
| `.gw-header` (`data-gw-header`) | the sticky, flat 64px bar with one hairline; `.is-scrolled` darkens the hairline |
|
|
285
|
+
| `.gw-header--float` | with `.gw-header`, a brand's header profile: from 1080px the same bar as an inset card (panel radius, the surface at 85% over a blur, one hairline, the raised shadow, 16px from the top); the flat bar below 1080px; solid under `prefers-reduced-transparency` |
|
|
278
286
|
| `.gw-header__bar` | the row inside (`.gw-wrap gw-header__bar`) |
|
|
279
287
|
| `.gw-brand`, `__mark`, `__name` | logo (26px) and name, linking home |
|
|
280
288
|
| `.gw-nav`, `__list`, `__item`, `__trigger`, `__link` | the desktop nav (from 1080px); `__trigger` opens a mega panel, `__link` is a plain link; `aria-current="page"` underlines it in the accent |
|
|
281
|
-
| `.gw-mega`, `__grid`, `__col`, `__heading`, `__link`, `__icon`, `__feature` | a floating card centred under the bar (radius 20, raised shadow, as on gemboss.ai): columns of links with an icon and one line each, and at most one feature card |
|
|
289
|
+
| `.gw-mega`, `__grid`, `__col`, `__heading`, `__link`, `__icon`, `__feature` | a floating card centred under the bar (the popover radius: 20, 24 in `soft`; raised shadow, as on gemboss.ai): columns of links with an icon and one line each, and at most one feature card |
|
|
282
290
|
| `.gw-header__actions` | theme toggle, Sign in, Book a demo, Start free, menu button |
|
|
283
291
|
| `.gw-header__signin` | with `.gw-nav__link`: hidden below 1080px (it moves into the mobile menu) |
|
|
284
292
|
| `.gw-theme-toggle` | icon button (`data-gw-theme-toggle`), 40px, 44px on touch |
|
|
@@ -292,7 +300,8 @@ Don't: hide content a reader needs to decide (prices, terms) only inside a close
|
|
|
292
300
|
Header buttons: the secondary one shows from 768px, the primary one from 480px; below that they live in the mobile
|
|
293
301
|
menu. Full markup: `templates/header.html`.
|
|
294
302
|
|
|
295
|
-
Don't: a floating, rounded or blurred header
|
|
303
|
+
Don't: a floating, rounded or blurred header of your own (the one floating header is `.gw-header--float`, chosen
|
|
304
|
+
for the whole site); more than five top-level items; a second filled button in the bar; a
|
|
296
305
|
hero pulled up under the header.
|
|
297
306
|
|
|
298
307
|
## Footer
|
|
@@ -361,7 +370,7 @@ The HTML a CMS or a markdown renderer writes needs no classes. Inside `.gw-prose
|
|
|
361
370
|
| `code` | a tint chip in `--gw-font-mono` (16px, 14px in `--sm`) that wraps on a phone; in a table it stays whole |
|
|
362
371
|
| `pre` | a soft box, 14px mono, that scrolls sideways inside itself |
|
|
363
372
|
| `table` | as a direct child: the `.gw-table` look, and it scrolls inside its own box when it is wider than the column |
|
|
364
|
-
| `img`, `figure`, `figcaption` | images radius
|
|
373
|
+
| `img`, `figure`, `figcaption` | images take the card radius; a caption 14px muted, 12px under its figure |
|
|
365
374
|
| `hr`, `a` | a hairline with 32px of air; links in the accent, underlined |
|
|
366
375
|
|
|
367
376
|
Kit components inside the prose keep their own look (`.gw-table`, `.gw-window`, `.gw-list--check`, `.gw-quote`,
|
|
@@ -394,6 +403,12 @@ them in order); a page without `.gw-prose` that styles its articles in site CSS
|
|
|
394
403
|
Put it on a block (a grid, a list, a window), not on each card in a grid. Don't use it on the hero or anything in
|
|
395
404
|
the first screen, and don't animate anything but `transform` and `opacity`.
|
|
396
405
|
|
|
406
|
+
## Additions to the markup contract in 0.3.0
|
|
407
|
+
|
|
408
|
+
The brand profiles: `data-gw-action="ink|accent"` and `data-gw-radius="tight|soft"` on `<html>`, and
|
|
409
|
+
`.gw-header--float` on the header (`docs/theming.md`). Tokens: `--gw-radius-popover` (the mega menu), `--gw-radius-24`,
|
|
410
|
+
`--gw-header-gap`, `--gw-header-surface`, `--gw-header-blur`. No markup of 0.2.0 changes.
|
|
411
|
+
|
|
397
412
|
## Additions to the markup contract in 0.2.0
|
|
398
413
|
|
|
399
414
|
The button states (`:active`, `[aria-busy="true"]`), `.gw-segmented` (+ `--block`) with its `data-gw-segmented` /
|
package/docs/markup-contract.md
CHANGED
|
@@ -12,7 +12,9 @@ BEM-ish: `.gw-block`, `.gw-block__part`, `.gw-block--variant`.
|
|
|
12
12
|
## Page
|
|
13
13
|
|
|
14
14
|
```html
|
|
15
|
-
<html lang="en" data-theme?="light|dark"
|
|
15
|
+
<html lang="en" data-theme?="light|dark" data-gw-action?="accent" data-gw-radius?="soft">
|
|
16
|
+
<!-- data-theme absent = follow the system; the toggle sets it. data-gw-action, data-gw-radius: brand profiles (0.3.0),
|
|
17
|
+
absent = ink, tight -->
|
|
16
18
|
<body class="gw-page">
|
|
17
19
|
<a class="gw-skip" href="#main">Skip to content</a>
|
|
18
20
|
<div class="gw-announce" role="region" aria-label="Announcement">…<a href="…">…</a></div> <!-- optional -->
|
|
@@ -25,7 +27,7 @@ BEM-ish: `.gw-block`, `.gw-block__part`, `.gw-block--variant`.
|
|
|
25
27
|
## Header
|
|
26
28
|
|
|
27
29
|
```html
|
|
28
|
-
<header class="gw-header" data-gw-header>
|
|
30
|
+
<header class="gw-header gw-header--float?" data-gw-header> <!-- --float: a brand's header profile (0.3.0) -->
|
|
29
31
|
<div class="gw-wrap gw-header__bar">
|
|
30
32
|
<a class="gw-brand" href="/"><img class="gw-brand__mark" src="…" alt="" width="26" height="26"><span class="gw-brand__name">GemBoss</span></a>
|
|
31
33
|
<nav class="gw-nav" aria-label="Main">
|
|
@@ -73,10 +75,19 @@ Script behaviour:
|
|
|
73
75
|
2.5s, or if IntersectionObserver is missing, all get `.is-in`. Under `prefers-reduced-motion` the CSS shows them
|
|
74
76
|
without motion.
|
|
75
77
|
- **Header**: `.is-scrolled` on `[data-gw-header]` once the page scrolled more than 8px (the CSS may use it for the
|
|
76
|
-
hairline only; the bar does not change height or colour).
|
|
78
|
+
hairline only; the bar does not change height or colour). The floating header needs nothing more from the script:
|
|
79
|
+
it is the same element with one more class.
|
|
77
80
|
- **Current page**: the script marks `aria-current="page"` on `.gw-nav__link` / `.gw-mega__link` whose `href`
|
|
78
81
|
pathname equals `location.pathname` (when the markup did not already).
|
|
79
82
|
|
|
83
|
+
## Brand profiles (0.3.0)
|
|
84
|
+
|
|
85
|
+
- `data-gw-action` and `data-gw-radius` sit on `<html>` only, with a name from `system.json` `profiles` (`ink` or
|
|
86
|
+
`accent`, `tight` or `soft`); absent means the first. The CSS reads them (`css/tokens.css`), the script does not.
|
|
87
|
+
- `.gw-header--float` sits on the `<header class="gw-header">` itself, next to `gw-header`.
|
|
88
|
+
- `check` reports any other name or place (`profile-unknown`, `header-float-markup`) and, with `accent`, words on the
|
|
89
|
+
button below 4.5:1 (`action-contrast`).
|
|
90
|
+
|
|
80
91
|
## Segmented control (0.2.0)
|
|
81
92
|
|
|
82
93
|
```html
|
|
@@ -112,14 +123,14 @@ Script behaviour:
|
|
|
112
123
|
|
|
113
124
|
| class | what |
|
|
114
125
|
|---|---|
|
|
115
|
-
| `.gw-btn` (+ `--secondary`, `--ghost`, `--on-night`, `--sm`, `--lg`, `--block`) | actions; rectangle
|
|
126
|
+
| `.gw-btn` (+ `--secondary`, `--ghost`, `--on-night`, `--sm`, `--lg`, `--block`) | actions; a rectangle with the action radius, the action colour as fill (ink, or the accent under `data-gw-action="accent"`); `:active` pressed, `[aria-busy="true"]` loading (script above) |
|
|
116
127
|
| `.gw-link` (+ `--arrow`) | inline text link in the accent; `--arrow` adds → that moves 2px on hover |
|
|
117
128
|
| `.gw-label` | the label above a heading: 13px muted, 8px accent square before it |
|
|
118
129
|
| `.gw-dim` | the muted first sentence inside a headline |
|
|
119
130
|
| `.gw-chip` (+ `.is-active`) | selectable token, pill |
|
|
120
131
|
| `.gw-segmented` (+ `--block`) | one choice out of two to four (script above) |
|
|
121
132
|
| `.gw-badge` (+ `--accent`, `--success`, `--warning`) | small status, pill |
|
|
122
|
-
| `.gw-card` (+ `--soft`, `--link`) | white box, 1px hairline, radius
|
|
133
|
+
| `.gw-card` (+ `--soft`, `--link`) | white box, 1px hairline, the card radius; `--link` makes the whole card an `<a>` |
|
|
123
134
|
| `.gw-window` (+ `__bar`, `__body`, `__caption`) | a framed screenshot/mock-up, like a browser or app window; `__caption` (last child) says what its numbers are: "Illustrative data." or their source |
|
|
124
135
|
| `.gw-icon` | 20px inline stroke SVG wrapper |
|
|
125
136
|
| `.gw-list--check` | list with check marks |
|
package/docs/philosophy.md
CHANGED
|
@@ -7,26 +7,31 @@ spirit. Each rule came from measuring real pages, not from taste alone.
|
|
|
7
7
|
|
|
8
8
|
A visitor crosses from the website into the product in one click. If the two disagree (a cream site and a white app,
|
|
9
9
|
a purple button outside and a black one inside), the seam is exactly where trust is decided. So the website uses the
|
|
10
|
-
product's language: white canvas,
|
|
10
|
+
product's language: white canvas, the product's action colour, one accent, hairlines, almost no shadow.
|
|
11
11
|
|
|
12
|
-
## The thing you click is
|
|
12
|
+
## The thing you click is one colour: the product's
|
|
13
13
|
|
|
14
|
-
A page has one thing it wants you to do
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
14
|
+
A page has one thing it wants you to do, and the button that does it looks the same on every page. For GemBoss that
|
|
15
|
+
is near-black ink, as in its dashboard: the strongest mark on white, readable in every light. Since 0.3.0 a brand
|
|
16
|
+
whose product clicks in its accent (GemPages' product uses blue primary buttons) may do the same on its site, with
|
|
17
|
+
the `accent` action profile: the site and the product still speak one language. It is a mode, not a colour picked
|
|
18
|
+
per button; its words must reach 4.5:1 on it, and it never gains a shadow or a gradient. Everywhere else the accent
|
|
19
|
+
marks where you are and what is interactive in text: links, focus, the active item, the small square before a
|
|
20
|
+
label. It never colours the words of a heading or a whole section band: that makes a page louder, not clearer.
|
|
18
21
|
|
|
19
22
|
## Shapes carry meaning
|
|
20
23
|
|
|
21
24
|
Rectangles act, pills choose. When every button is a rectangle and every chip is a pill, people stop reading the
|
|
22
|
-
shape and read the words. A
|
|
23
|
-
the kind of drift that makes a page feel
|
|
25
|
+
shape and read the words. A site has one set of corners, a named profile (`tight` for GemBoss, `soft` for GemPages,
|
|
26
|
+
as in each product), so two cards side by side never differ by 2px, which is the kind of drift that makes a page feel
|
|
27
|
+
assembled rather than designed. Profiles, not free values: a brand can look like itself without inventing a radius.
|
|
24
28
|
|
|
25
29
|
## Separation by line and space, light only at rest
|
|
26
30
|
|
|
27
31
|
A shadow says "this floats above". Cards on a page do not float; they sit on it. A 1px hairline and the dashboard's
|
|
28
32
|
resting shadow (two faint pixels) separate a card and keep the page calm; nothing lifts on hover. Larger light is
|
|
29
|
-
spent where it means something: a popover such as the mega menu,
|
|
33
|
+
spent where it means something: a popover such as the mega menu, the floating header a brand may choose (it does
|
|
34
|
+
float), an illustration that lights itself.
|
|
30
35
|
|
|
31
36
|
## Scales instead of eyeballing
|
|
32
37
|
|
package/docs/theming.md
CHANGED
|
@@ -1,27 +1,37 @@
|
|
|
1
1
|
# Theming for a brand other than GemBoss
|
|
2
2
|
|
|
3
|
-
A GemCommerce brand (GemPages, Gemians…) uses the kit as it is and
|
|
4
|
-
wash hues**, **its logo** and **its favicon**. Everything else stays the kit's: the shapes, the scales, the ink
|
|
5
|
-
buttons, the white canvas, the type. That is what makes the sites look like one family, and it is why a site built
|
|
6
|
-
by someone with no design training still looks careful.
|
|
3
|
+
A GemCommerce brand (GemPages, Gemians…) uses the kit as it is and chooses six things, **and nothing else**:
|
|
7
4
|
|
|
8
|
-
|
|
5
|
+
1. **the accent variables** (eight, light and dark),
|
|
6
|
+
2. **the wash hues** (only if the brand has its own),
|
|
7
|
+
3. **the logo** (and the favicon),
|
|
8
|
+
4. **the action colour mode**: `data-gw-action="ink|accent"` on `<html>`,
|
|
9
|
+
5. **the radius profile**: `data-gw-radius="tight|soft"` on `<html>`,
|
|
10
|
+
6. **the header style**: the flat bar, or `.gw-header--float`.
|
|
9
11
|
|
|
10
|
-
|
|
12
|
+
The last three are **named profiles**, not values: a brand picks one of a short list, once for the whole site, and
|
|
13
|
+
every component follows. Everything else stays the kit's: the neutrals, the type, the spacing, the shadows, the
|
|
14
|
+
widths. That is what makes the sites look like one family, and why a site built by someone with no design training
|
|
15
|
+
still looks careful. `npx gemboss-website check` reports anything outside this set.
|
|
16
|
+
|
|
17
|
+
Working examples: `demo/theme-example.html` (the accent only) and `demo/brand-profiles.html` (a GemPages-style brand:
|
|
18
|
+
the accent, all three profiles and the floating header).
|
|
19
|
+
|
|
20
|
+
## 1 to 3. Accent, wash, logo
|
|
11
21
|
|
|
12
22
|
Put these in the site's own CSS (`site.css`, linked **after** `website.css`), in **one `:root {}` block**, and nowhere
|
|
13
23
|
else.
|
|
14
24
|
|
|
15
25
|
| variable | what it is | GemBoss value |
|
|
16
26
|
|---|---|---|
|
|
17
|
-
| `--gw-accent-light` | the accent on light pages: links, focus ring, active item, label square, chart line | `#5661f5` |
|
|
18
|
-
| `--gw-accent-strong-light` | the accent
|
|
27
|
+
| `--gw-accent-light` | the accent on light pages: links, focus ring, active item, label square, chart line; the primary button's fill under `data-gw-action="accent"` | `#5661f5` |
|
|
28
|
+
| `--gw-accent-strong-light` | accent text (links, the active item), and the accent button's hover and pressed fill | `#3a44de` |
|
|
19
29
|
| `--gw-accent-soft-light` | the accent's tint: active chip, chosen segmented option, accent badge, icon hover | `#eef0fe` |
|
|
20
|
-
| `--gw-on-accent-light` |
|
|
30
|
+
| `--gw-on-accent-light` | words on a solid accent: the accent button's label | `#ffffff` |
|
|
21
31
|
| `--gw-accent-dark` | the accent in dark mode **and inside night bands** | `#7c84ff` |
|
|
22
|
-
| `--gw-accent-strong-dark` | its
|
|
32
|
+
| `--gw-accent-strong-dark` | its text and hover form | `#a3a9ff` |
|
|
23
33
|
| `--gw-accent-soft-dark` | its tint | `#1f2140` |
|
|
24
|
-
| `--gw-on-accent-dark` |
|
|
34
|
+
| `--gw-on-accent-dark` | words on it | `#0d0d12` |
|
|
25
35
|
| `--gw-wash-pink`, `--gw-wash-violet`, `--gw-wash-sky`, `--gw-wash-mint` | the secondary hues of the hero wash and illustrations | `#ff6f5e`, `#7c8af7`, `#43b0ff`, `#1fcf9f` |
|
|
26
36
|
|
|
27
37
|
Why the `-light` / `-dark` names and not `--gw-accent` itself: the kit sets `--gw-accent` from these in four places
|
|
@@ -33,45 +43,86 @@ The logo and the favicon are files, not variables: the `<img class="gw-brand__ma
|
|
|
33
43
|
`alt=""` because the name is written next to it) and the `<span class="gw-brand__name">` in the header and footer
|
|
34
44
|
partials, and `<link rel="icon">` in the page head.
|
|
35
45
|
|
|
46
|
+
## 4 to 6. The three profiles
|
|
47
|
+
|
|
48
|
+
Chosen once, in the page skeleton (the layout or partial every page shares). The first of each is the default and
|
|
49
|
+
needs no markup, so a GemBoss page, and every page written for 0.2.0, stays exactly as it was.
|
|
50
|
+
|
|
51
|
+
```html
|
|
52
|
+
<html lang="en" data-gw-action="accent" data-gw-radius="soft">
|
|
53
|
+
…
|
|
54
|
+
<header class="gw-header gw-header--float" data-gw-header> …the same header markup… </header>
|
|
55
|
+
```
|
|
56
|
+
|
|
57
|
+
| knob | profiles | what changes |
|
|
58
|
+
|---|---|---|
|
|
59
|
+
| action colour, `data-gw-action` on `<html>` | `ink` (GemBoss, default), `accent` | `accent`: the primary `.gw-btn` is filled with `--gw-accent`, its words are `--gw-on-accent`, hover and pressed are `--gw-accent-strong`. In dark mode and night bands it takes the `-dark` family. Secondary, ghost and on-night buttons do not change. |
|
|
60
|
+
| radius, `data-gw-radius` on `<html>` | `tight` (GemBoss, default): 8 action, 12 card, 16 panel, 20 mega menu; `soft` (GemPages): 12, 20, 24, 24 | every button, control, card, window, table, FAQ, plan, quote and the mega menu. Chips and badges stay pills. |
|
|
61
|
+
| header, a class on the `<header>` | flat (default), `.gw-header--float` | from 1080px the bar becomes an inset card: the panel radius of the profile (16 tight, 24 soft), the surface at 85% over a 10px blur, one hairline, the raised shadow, 16px from the top. Same bar, same mega menu, same script; below 1080px it is the flat bar, so the phone menu is unchanged. Solid for a visitor who asks for less transparency, and in a browser that cannot blur. |
|
|
62
|
+
|
|
63
|
+
Why the action colour is a mode and not a colour of its own: the button stays one colour on the whole site, and that
|
|
64
|
+
colour is a family the brand already checked for contrast. "Site and product speak one language": GemBoss's dashboard
|
|
65
|
+
clicks in ink, so gemboss.ai does; GemPages' product uses blue primary buttons, so a GemPages site may too. Still no
|
|
66
|
+
raised or inset shadow on a button, no gradient, no wash.
|
|
67
|
+
|
|
68
|
+
Why the header uses the panel radius: it is the largest piece of chrome on the page, so it follows the profile with
|
|
69
|
+
the panels; in `tight` that is the 16px the header was designed with.
|
|
70
|
+
|
|
36
71
|
## What you may not change
|
|
37
72
|
|
|
38
73
|
- **Neutrals**: `--gw-bg`, `--gw-bg-soft`, `--gw-surface`, `--gw-ink`, `--gw-ink-2`, `--gw-muted`, `--gw-line`,
|
|
39
74
|
`--gw-line-strong`, and the night colours. No cream or grey page, no brand-coloured ink.
|
|
40
|
-
- **The action**: `--gw-action`, `--gw-action-hover`, `--gw-on-action`.
|
|
41
|
-
|
|
75
|
+
- **The action tokens**: `--gw-action`, `--gw-action-hover`, `--gw-on-action`. Choose the `accent` profile instead;
|
|
76
|
+
a colour set here is not checked and does not follow dark mode or night bands.
|
|
42
77
|
- **State**: `--gw-success`, `--gw-warning` and their tints. Green and amber mean state on every GemCommerce site.
|
|
43
|
-
- **Scales and shapes**: type sizes and weights, spacing,
|
|
44
|
-
font family. No
|
|
78
|
+
- **Scales and shapes**: type sizes and weights, spacing, the radius tokens (`--gw-radius-*`: choose a profile), shadows,
|
|
79
|
+
widths, the header height, the font family. No pill buttons, no bigger shadows, no other font.
|
|
45
80
|
- **Kit classes**: never restyle a `.gw-*` class. If the kit cannot do what your brand needs, that is a gap
|
|
46
81
|
(`AGENTS.md` section 9), not a theme.
|
|
47
82
|
|
|
48
|
-
|
|
49
|
-
|
|
83
|
+
### Still forbidden with every profile
|
|
84
|
+
|
|
85
|
+
- **Gradient or accent-coloured words in a heading.** A heading is ink, with a muted first sentence (`.gw-dim`).
|
|
86
|
+
- **Accent-coloured section bands.** A section is white, `--gw-bg-soft` or a night band; the accent only lights a
|
|
87
|
+
night band's top edge.
|
|
88
|
+
- **All-caps labels.** Labels are sentence case, muted, led by the 8px accent square.
|
|
89
|
+
|
|
90
|
+
These make a page louder without making it clearer, and `check` reports the last one (`uppercase-label`) and any
|
|
91
|
+
button filled from site CSS (`accent-button`).
|
|
92
|
+
|
|
93
|
+
`check` also reports: colours outside the tokens, a redefined kit token (`token-redefined`, including the radius and
|
|
94
|
+
action tokens), overrides of `.gw-*` classes, an unknown profile or one set on another element than `<html>`
|
|
95
|
+
(`profile-unknown`), `.gw-header--float` anywhere but the header itself (`header-float-markup`), and, on a page with
|
|
96
|
+
`data-gw-action="accent"`, accent button words below 4.5:1 (`action-contrast`).
|
|
50
97
|
|
|
51
98
|
## A full example
|
|
52
99
|
|
|
53
100
|
```css
|
|
54
|
-
/* site.css, linked after website.css. The whole
|
|
101
|
+
/* site.css, linked after website.css. The whole CSS of a GemPages-style brand. */
|
|
55
102
|
:root {
|
|
56
|
-
/*
|
|
57
|
-
--gw-accent-light: #
|
|
58
|
-
|
|
59
|
-
|
|
103
|
+
/* light pages. #3c67ff fills the accent button: white words on it are 4.58:1 */
|
|
104
|
+
--gw-accent-light: #3c67ff;
|
|
105
|
+
/* EXAMPLE, not confirmed by the GemPages team: accent text needs a darker step, because #3c67ff is 4.13:1 on
|
|
106
|
+
--gw-bg-soft. #2f52d6 is 6.36:1 on white and 5.73:1 on --gw-bg-soft, and the button's hover. */
|
|
107
|
+
--gw-accent-strong-light: #2f52d6;
|
|
108
|
+
--gw-accent-soft-light: #eaefff;
|
|
60
109
|
--gw-on-accent-light: #ffffff;
|
|
61
|
-
/*
|
|
62
|
-
--gw-accent-dark: #
|
|
63
|
-
--gw-accent-strong-dark: #
|
|
110
|
+
/* dark mode and night bands: #7c9bff is 7.37:1 on #0d0d12, and #0d0d12 words on it are 7.37:1 */
|
|
111
|
+
--gw-accent-dark: #7c9bff;
|
|
112
|
+
--gw-accent-strong-dark: #a9beff;
|
|
64
113
|
--gw-accent-soft-dark: #16213d;
|
|
65
114
|
--gw-on-accent-dark: #0d0d12;
|
|
66
115
|
/* wash: only if the brand has its own secondary hues; otherwise leave the kit's */
|
|
67
|
-
--gw-wash-violet: #7b9cff;
|
|
68
116
|
}
|
|
69
117
|
```
|
|
70
118
|
|
|
71
119
|
```html
|
|
120
|
+
<html lang="en" data-gw-action="accent" data-gw-radius="soft">
|
|
72
121
|
<link rel="icon" href="/favicon.svg" type="image/svg+xml">
|
|
73
122
|
…
|
|
74
|
-
<
|
|
123
|
+
<header class="gw-header gw-header--float" data-gw-header>
|
|
124
|
+
<div class="gw-wrap gw-header__bar">
|
|
125
|
+
<a class="gw-brand" href="/"><img class="gw-brand__mark" src="/logo-mark.svg" alt="" width="26" height="26"><span class="gw-brand__name">GemPages</span></a>
|
|
75
126
|
```
|
|
76
127
|
|
|
77
128
|
## Check the contrast before you ship
|
|
@@ -87,10 +138,15 @@ So:
|
|
|
87
138
|
3. `--gw-accent-dark` and `--gw-accent-strong-dark` on `#0d0d12` (dark page) and on `#0c0e14` (night band): at
|
|
88
139
|
least 4.5:1.
|
|
89
140
|
4. `--gw-accent-strong-dark` on `--gw-accent-soft-dark`: at least 4.5:1.
|
|
141
|
+
5. **With `data-gw-action="accent"`**: `--gw-on-accent-light` on `--gw-accent-light` and on
|
|
142
|
+
`--gw-accent-strong-light`, and `--gw-on-accent-dark` on `--gw-accent-dark` and on `--gw-accent-strong-dark`: at
|
|
143
|
+
least 4.5:1. `check` computes these four and fails the site below it (write the colours as `#rrggbb`); the kit's
|
|
144
|
+
build does the same for its own colours.
|
|
90
145
|
|
|
91
146
|
Any WCAG contrast checker works (paste the two hex values). A bright brand colour (yellow, light green, cyan) almost
|
|
92
147
|
never passes on white: darken it for `-light` and keep the bright one for `-dark`. If you cannot get 4.5:1 without
|
|
93
148
|
changing the brand colour beyond recognition, keep the kit's accent and use the brand colour only in the logo and
|
|
94
|
-
illustrations.
|
|
149
|
+
illustrations, and keep the ink button.
|
|
95
150
|
|
|
96
|
-
Then open the site in light and dark (the toggle in the header), at 320px and at 1366px, and look at a night band
|
|
151
|
+
Then open the site in light and dark (the toggle in the header), at 320px and at 1366px, and look at a night band and
|
|
152
|
+
at the header while the page scrolls under it.
|
package/js/website.js
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
(function () {
|
|
3
3
|
'use strict';
|
|
4
4
|
if (window.gwWebsite) return;
|
|
5
|
-
window.gwWebsite = { version: '0.
|
|
5
|
+
window.gwWebsite = { version: '0.3.0' };
|
|
6
6
|
var doc = document, root = doc.documentElement;
|
|
7
7
|
function mq(q) { return window.matchMedia ? matchMedia(q) : { matches: false }; }
|
|
8
8
|
function watch(m, fn) { if (m.addEventListener) m.addEventListener('change', fn); }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@gemboss/website-ui",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "The GemBoss website kit: tokens, header, footer, sections and the rules (AGENTS.md) that GemCommerce public websites share, plus a CLI that checks a site, reports kit gaps and upgrades.",
|
|
5
5
|
"license": "UNLICENSED",
|
|
6
6
|
"type": "module",
|