| 77 |
77 |
|
std::fs::write(path, makeover_webview::stylesheet(opts)).expect("write layout css");
|
| 78 |
78 |
|
}
|
| 79 |
79 |
|
|
| 80 |
|
- |
/// Write `makeover-geometry`'s spacing layer to `path`, with the canonical
|
| 81 |
|
- |
/// density selection.
|
|
80 |
+ |
/// Write `makeover-geometry`'s spacing layer, with its canonical density
|
|
81 |
+ |
/// selection, to `path`.
|
| 82 |
82 |
|
///
|
| 83 |
|
- |
/// **Density is a capability, not a device and not a width.** A narrow window
|
| 84 |
|
- |
/// on a desktop still has a pointer in it and a tablet at full width still has
|
| 85 |
|
- |
/// a finger, so the touch preset hangs off `(hover: none), (pointer: coarse)`
|
| 86 |
|
- |
/// rather than off a breakpoint or a user-agent string. That is the question
|
| 87 |
|
- |
/// the platform actually answers.
|
| 88 |
|
- |
///
|
| 89 |
|
- |
/// `explicit_touch` names a selector an app sets when the *user* has chosen,
|
| 90 |
|
- |
/// which is emitted last and therefore wins at equal specificity. Detection is
|
| 91 |
|
- |
/// a default, not a verdict: a touchscreen laptop and someone who simply wants
|
| 92 |
|
- |
/// roomier targets are both real and neither is visible to a media query.
|
| 93 |
|
- |
///
|
| 94 |
|
- |
/// This settles a policy the three consumers previously answered three ways:
|
| 95 |
|
- |
/// GoingsOn sniffed the user agent behind a class, Balanced Breakfast used
|
| 96 |
|
- |
/// `(hover: none)` alone, and audiofiles had no switch at all. It lives here
|
| 97 |
|
- |
/// rather than in `makeover-geometry` only because that crate is published at
|
| 98 |
|
- |
/// 0.1.0 and five consumers take it from the registry; it belongs there at its
|
| 99 |
|
- |
/// next release.
|
|
83 |
+ |
/// The policy is the crate's, not this one's: touch hangs off
|
|
84 |
+ |
/// `(hover: none), (pointer: coarse)` because density is a capability rather
|
|
85 |
+ |
/// than a device or a width, and `explicit_touch` names a selector an app sets
|
|
86 |
+ |
/// when the user has chosen. See [`makeover_geometry::density_css`]. All this
|
|
87 |
+ |
/// adds is the generated-file banner and the write.
|
| 100 |
88 |
|
///
|
| 101 |
89 |
|
/// # Panics
|
| 102 |
90 |
|
///
|
| 103 |
91 |
|
/// If the file cannot be written.
|
| 104 |
92 |
|
pub fn geometry_css(path: impl AsRef<Path>, explicit_touch: Option<&str>) {
|
| 105 |
|
- |
use makeover_geometry::{Density, gap_css_overrides, geometry_css_vars};
|
| 106 |
|
- |
|
| 107 |
93 |
|
let mut css = String::from(
|
| 108 |
94 |
|
"/* Generated by makeover-build from makeover-geometry. Do not edit.\n \
|
| 109 |
95 |
|
Spacing is named by relationship, not by size. Touch density is a\n \
|
| 110 |
96 |
|
capability question: a narrow desktop window still has a pointer, a\n \
|
| 111 |
97 |
|
full-width tablet still has a finger. */\n",
|
| 112 |
98 |
|
);
|
| 113 |
|
- |
css.push_str(&geometry_css_vars(Density::Pointer));
|
| 114 |
|
- |
css.push_str("\n@media (hover: none), (pointer: coarse) {\n");
|
| 115 |
|
- |
for line in gap_css_overrides(":root", Density::Touch).lines() {
|
| 116 |
|
- |
css.push_str(" ");
|
| 117 |
|
- |
css.push_str(line);
|
| 118 |
|
- |
css.push('\n');
|
| 119 |
|
- |
}
|
| 120 |
|
- |
css.push_str("}\n");
|
| 121 |
|
- |
if let Some(selector) = explicit_touch {
|
| 122 |
|
- |
css.push_str("\n/* An explicit user choice, last so it wins over detection. */\n");
|
| 123 |
|
- |
css.push_str(&gap_css_overrides(selector, Density::Touch));
|
| 124 |
|
- |
}
|
| 125 |
|
- |
|
|
99 |
+ |
css.push_str(&makeover_geometry::density_css(explicit_touch));
|
| 126 |
100 |
|
std::fs::write(path, css).expect("write geometry css");
|
| 127 |
101 |
|
}
|
| 128 |
102 |
|
|
| 205 |
179 |
|
}
|
| 206 |
180 |
|
|
| 207 |
181 |
|
#[test]
|
| 208 |
|
- |
fn density_is_selected_by_capability_not_by_width_or_agent() {
|
| 209 |
|
- |
let dir = scratch("density");
|
| 210 |
|
- |
let path = dir.join("geometry.css");
|
| 211 |
|
- |
geometry_css(&path, None);
|
| 212 |
|
- |
let css = std::fs::read_to_string(&path).unwrap();
|
| 213 |
|
- |
assert!(css.contains("@media (hover: none), (pointer: coarse)"));
|
| 214 |
|
- |
// The three things density must never be selected by.
|
| 215 |
|
- |
assert!(!css.contains("max-width"), "a breakpoint crept in");
|
| 216 |
|
- |
assert!(!css.contains("min-width"), "a breakpoint crept in");
|
| 217 |
|
- |
assert!(!css.contains("ui-mode"), "a device mode crept in");
|
| 218 |
|
- |
}
|
| 219 |
|
- |
|
| 220 |
|
- |
#[test]
|
| 221 |
|
- |
fn an_explicit_choice_is_emitted_after_the_detection() {
|
| 222 |
|
- |
let dir = scratch("explicit");
|
|
182 |
+ |
fn the_geometry_file_carries_the_crates_policy_and_a_banner() {
|
|
183 |
+ |
// The policy itself is tested in makeover-geometry. What is this
|
|
184 |
+ |
// crate's job is that the banner is there and the policy reached the
|
|
185 |
+ |
// file at all.
|
|
186 |
+ |
let dir = scratch("geometry");
|
| 223 |
187 |
|
let path = dir.join("geometry.css");
|
| 224 |
188 |
|
geometry_css(&path, Some(".ui-mode-mobile"));
|
| 225 |
189 |
|
let css = std::fs::read_to_string(&path).unwrap();
|
| 226 |
|
- |
let media = css.find("@media").expect("media query");
|
| 227 |
|
- |
let explicit = css.find(".ui-mode-mobile").expect("explicit selector");
|
| 228 |
|
- |
// Equal specificity, so order is the whole mechanism: the user's
|
| 229 |
|
- |
// choice has to come last or detection quietly overrides it.
|
| 230 |
|
- |
assert!(explicit > media, "the explicit selector must come last");
|
| 231 |
|
- |
}
|
| 232 |
|
- |
|
| 233 |
|
- |
#[test]
|
| 234 |
|
- |
fn no_explicit_selector_means_no_extra_rule() {
|
| 235 |
|
- |
let dir = scratch("noexplicit");
|
| 236 |
|
- |
let path = dir.join("geometry.css");
|
| 237 |
|
- |
geometry_css(&path, None);
|
| 238 |
|
- |
let css = std::fs::read_to_string(&path).unwrap();
|
| 239 |
|
- |
assert_eq!(
|
| 240 |
|
- |
css.matches("--gap-peer").count(),
|
| 241 |
|
- |
2,
|
| 242 |
|
- |
"pointer and touch, no more"
|
| 243 |
|
- |
);
|
|
190 |
+ |
assert!(css.starts_with("/* Generated by makeover-build"));
|
|
191 |
+ |
assert!(css.contains("@media (hover: none), (pointer: coarse)"));
|
|
192 |
+ |
assert!(css.contains(".ui-mode-mobile"));
|
| 244 |
193 |
|
}
|
| 245 |
194 |
|
|
| 246 |
195 |
|
#[test]
|