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
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
//! Token-derived chrome geometry for Snora Design (RFC-040).
//!
//! RFC-038 made chrome *colours* follow the emitted theme, because the
//! prefab widgets already read `theme.extended_palette()`. Geometry does
//! not follow, and cannot — an `iced::Theme` carries no spacing or
//! radius. This module adds a styled variant of each chrome widget that
//! takes `&Tokens` and maps its numeric literals (padding, inter-element
//! gaps, corner radii) to the [`Spacing`]/[`Radius`] scales, leaving the
//! unstyled `snora::widget::*` set exactly as it renders today.
//!
//! # One implementation, two geometry sources
//!
//! Every widget's body is written exactly once — in its home module
//! (`crate::header`, `crate::footer`, `crate::sidebar`, `crate::tab`,
//! `crate::crumb`), as a `pub(crate) fn build_*` taking a small geometry
//! struct. The unstyled `snora::widget::*` function passes that struct's
//! `::unstyled()` constructor (today's literals, unchanged); the styled
//! functions here pass a token-derived one instead. Drift between the two
//! is structurally impossible, not merely discouraged: there is nowhere
//! for a second copy of a widget body to live.
//!
//! # The mapping (Step 3 — deliberate, not reverse-engineered)
//!
//! `Spacing::comfortable()` is `{xs: 4, sm: 8, md: 12, lg: 16, xl: 24,
//! xxl: 32}`; `Radius::default_roles()` is `{sm: 4, md: 6, lg: 10, pill:
//! 999}`. Each geometry value below is mapped to the token whose own
//! documented semantic fits it, not to whichever token happens to equal
//! today's number — several *do* land on today's exact literal, because
//! the original hardcoded numbers already followed something close to
//! this scale; that is stated per-value below, not hidden.
//!
//! | Widget | Value | Today | Token | Exact? | Why |
//! |---|---|---|---|---|---|
//! | header | `pad_y` | 8 | `Spacing::sm` | yes | "compact internal gap" fits a shallow bar inset |
//! | header | `pad_x` | 16 | `Spacing::lg` | yes | "section spacing" fits outer chrome padding |
//! | header | `gap` | 12 | `Spacing::md` | yes | "ordinary component gap" between sibling controls |
//! | header | `radius` | 0 | `Radius::sm` | **no** | RFC-040's stated target — see "Chrome radius" below |
//! | footer | `pad_x` | 16 | `Spacing::lg` | yes | same role as header's `pad_x` |
//! | footer | `pad_y` | 6 | `Spacing::sm` | **no** | 6 has no clean token; `sm` chosen for cross-bar rhythm with header |
//! | footer | `radius` | 0 | `Radius::sm` | **no** | same as header |
//! | sidebar | `gap` | 16 | `Spacing::md` | **no** | reclassified: sibling icon buttons in one list read as "ordinary component gap", not "section spacing" — deliberately not reproducing 16 |
//! | sidebar | `padding` | 16 | `Spacing::lg` | yes | rail's outer edge padding, same role as header/footer `pad_x` |
//! | sidebar | `button_radius` | 6 | `Radius::md` | yes | `Radius::md` is documented "buttons, chips, notices" |
//! | tab | `bar_gap` | 2 | `Spacing::xs` | **no** | no clean equivalent; `xs` is the smallest available |
//! | tab | `bar_pad_x` | 12 | `Spacing::md` | yes | ordinary component padding |
//! | tab | `content_gap` | 6 | `Spacing::sm` | **no** | shared "icon-label inline gap" rhythm with menu/crumb, below |
//! | tab | `tab_pad_x` | 12 | `Spacing::md` | yes | button horizontal padding |
//! | tab | `tab_pad_y` | 8 | `Spacing::sm` | yes | button vertical padding, smaller than horizontal |
//! | tab | `bar_border_radius` | 0 | `Radius::sm` | **no** | RFC-040's stated target |
//! | crumb | `gap` | 6 | `Spacing::sm` | **no** | shared inline-gap rhythm (see below) |
//! | crumb | `row_pad_x` | 12 | `Spacing::md` | yes | trail's horizontal padding |
//! | crumb | `row_pad_y` | 4 | `Spacing::xs` | yes | trail's shallow vertical padding |
//! | crumb | `btn_pad_x` | 4 | `Spacing::xs` | yes | per-crumb button horizontal padding |
//! | crumb | `btn_pad_y` | 2 | `Spacing::xs` | **no** | no token smaller than `xs`; used as the floor |
//! | crumb | `btn_radius` | 3 | `Radius::sm` | **no** | `sm` is the smallest radius available |
//! | menu | `gap` | 6 | `Spacing::sm` | **no** | shared inline-gap rhythm (see below) |
//!
//! **Shared inline-gap rhythm.** Tab's icon-to-label gap, crumb's
//! item-to-separator gap, and menu's icon-to-label gap were all
//! independently hardcoded at `6` — the same value, for the same kind of
//! thing (a compact gap between two adjacent inline elements), in three
//! unrelated files. All three map to `Spacing::sm` (8): `sm` is
//! literally documented as "compact internal gap", the closest semantic
//! fit, and using it uniformly gives these three sites one shared rhythm
//! instead of an accidentally-identical-but-unrelated `6` — which is the
//! whole point of a token scale, per RFC-040's own framing.
//!
//! **Chrome radius.** `header`, `footer`, and the tab bar's own border
//! all hardcode `radius: 0.0` — square corners — which RFC-040 names
//! directly as "a large part of why stock snora chrome reads as flat and
//! dated". All three map to `Radius::sm` (4): the smallest available
//! radius, a modest rounding appropriate for a full-width chrome strip
//! rather than the more pronounced rounding `Radius::lg` (cards) or
//! `Radius::md` (buttons) would give.
//!
//! **Unmapped literals** (no `Spacing`/`Radius` equivalent, left as
//! literal constants, identical in both the unstyled and styled paths):
//! sidebar's and crumb's button border *widths* (`0.0` — "no border" is
//! not expressible on either scale); the tab bar container's border
//! *width* (`1.0` — border widths aren't part of either scale, same as
//! `style.rs`'s own `chrome_container_style` border width); the tab
//! bar's vertical padding (`0.0` — structural: tabs supply their own
//! vertical padding, this is an absence of a value, not a design
//! literal).
//!
//! # Density (RFC-040 Q-1)
//!
//! Every function below reads geometry from `tokens.spacing`/
//! `tokens.radius` directly — **not** by branching on `tokens.density`.
//! This is deliberate, not an oversight: `snora_design::Density::Compact`
//! is documented as "reserved; not resolved" — `Spacing` has only a
//! `comfortable()` constructor, no compact scale exists to select. Adding
//! one would be inventing token values RFC-040 does not authorize (its
//! own scope: no new token roles or scales). Reading `tokens.spacing`/
//! `tokens.radius` directly means this module is already
//! density-*correct* in the sense the owner asked for: whatever a future
//! compact scale resolves to (or a hand-mutated custom `Tokens` supplies
//! today) flows through unchanged, with no widget-level branch to keep in
//! sync. `widget/tests.rs` verifies this plumbing with a hand-mutated
//! `Tokens` pair, since no built-in preset currently offers two distinct
//! `Spacing` values to compare.
//!
//! [`Spacing`]: snora_design::Spacing
//! [`Radius`]: snora_design::Radius
use Element;
use ;
use Tokens;
use Debug;
use crate;
use crate;
use crate;
use crate;
use crate;
/// Token-derived styled variant of [`crate::app_header`] (RFC-040).
/// Colors already follow the theme (RFC-038); this maps geometry —
/// padding, gap, and corner radius — to `tokens.spacing`/`tokens.radius`.
/// See the module documentation for the full mapping table.
/// Token-derived styled variant of [`crate::app_footer`] (RFC-040).
/// Token-derived styled variant of [`crate::app_side_bar`] (RFC-040).
/// Token-derived styled variant of [`crate::app_tab_bar`] (RFC-040).
/// Token-derived styled variant of [`crate::app_breadcrumb`] (RFC-040).