| 144 |
144 |
|
std::fs::write(path, css).expect("write geometry css");
|
| 145 |
145 |
|
}
|
| 146 |
146 |
|
|
|
147 |
+ |
/// Write `makeover-timing`'s time axis, and the motion-off block that rides
|
|
148 |
+ |
/// with it, to `path`.
|
|
149 |
+ |
///
|
|
150 |
+ |
/// The third generated axis, and it arrives the same way the spacing one does:
|
|
151 |
+ |
/// a consumer that calls this gets `--timing-*`, `--motion-fade` and
|
|
152 |
+ |
/// `--cadence-activity` without stating a number anywhere. All this adds is the
|
|
153 |
+ |
/// banner and the write; `makeover_timing::timing_css` is the whole file and
|
|
154 |
+ |
/// already wraps itself in [`makeover_geometry::CSS_LAYER`].
|
|
155 |
+ |
///
|
|
156 |
+ |
/// # Its own file, for the reason geometry has its own file
|
|
157 |
+ |
///
|
|
158 |
+ |
/// One generated file per crate, named for the axis it carries. Time is not a
|
|
159 |
+ |
/// narrower claim about space the way size class is about density, so folding
|
|
160 |
+ |
/// it into `geometry.css` would leave a file whose banner names one crate and
|
|
161 |
+ |
/// whose contents come from two. The cost is a fourth `<link>` in the consumer,
|
|
162 |
+ |
/// which is the cost the family already pays three times.
|
|
163 |
+ |
///
|
|
164 |
+ |
/// # The `prefers-reduced-motion` block is not optional
|
|
165 |
+ |
///
|
|
166 |
+ |
/// `makeover_timing::timing_css` emits the `:root` values and then a media
|
|
167 |
+ |
/// block overriding two of them. Both land here, in that order, because they
|
|
168 |
+ |
/// are one statement: a sheet carrying only the values animates at every rung
|
|
169 |
+ |
/// for a reader who asked it not to, and does it silently.
|
|
170 |
+ |
///
|
|
171 |
+ |
/// # Panics
|
|
172 |
+ |
///
|
|
173 |
+ |
/// If the file cannot be written.
|
|
174 |
+ |
pub fn timing_css(path: impl AsRef<Path>) {
|
|
175 |
+ |
let mut css = String::from(
|
|
176 |
+ |
"/* Generated by makeover-build from makeover-timing. Do not edit.\n \
|
|
177 |
+ |
A duration is named by what it is waiting for; the number follows.\n \
|
|
178 |
+ |
Three axes: how long a state lasts, how long a change takes, and how\n \
|
|
179 |
+ |
often a repeating mark repeats. The reduced-motion block below zeroes\n \
|
|
180 |
+ |
the last two and leaves the waits alone. A reader asking for less\n \
|
|
181 |
+ |
motion has not asked for a notice to leave early. */\n",
|
|
182 |
+ |
);
|
|
183 |
+ |
css.push_str(&makeover_timing::timing_css());
|
|
184 |
+ |
std::fs::write(path, css).expect("write timing css");
|
|
185 |
+ |
}
|
|
186 |
+ |
|
| 147 |
187 |
|
/// Write the house typography layer to `path`: the two `@font-face` rules and
|
| 148 |
188 |
|
/// the two tokens they back.
|
| 149 |
189 |
|
///
|
| 215 |
255 |
|
|
| 216 |
256 |
|
/// All the generated files at the layout every Tauri consumer already uses:
|
| 217 |
257 |
|
/// `themes/` beside the manifest, and
|
| 218 |
|
- |
/// `frontend/css/{geometry,layout,typography}.css` under it.
|
|
258 |
+ |
/// `frontend/css/{geometry,timing,layout,typography}.css` under it.
|
| 219 |
259 |
|
///
|
| 220 |
260 |
|
/// Pass `env!("CARGO_MANIFEST_DIR")`. Consumers that want different paths call
|
| 221 |
261 |
|
/// [`themes`], [`layout_css`] and [`typography_css`] directly.
|
| 264 |
304 |
|
let css = root.join("frontend").join("css");
|
| 265 |
305 |
|
themes(root.join("themes"));
|
| 266 |
306 |
|
geometry_css(css.join("geometry.css"), explicit_touch);
|
|
307 |
+ |
// Beside geometry rather than after layout: both are value files the
|
|
308 |
+ |
// component sheet reads, and a consumer's `<link>` order follows this one.
|
|
309 |
+ |
timing_css(css.join("timing.css"));
|
| 267 |
310 |
|
layout_css(css.join("layout.css"), opts);
|
| 268 |
311 |
|
typography_css_from(css.join("typography.css"), typography);
|
| 269 |
312 |
|
}
|
| 417 |
460 |
|
}
|
| 418 |
461 |
|
|
| 419 |
462 |
|
#[test]
|
| 420 |
|
- |
fn the_tauri_layout_puts_all_three_where_the_apps_look() {
|
|
463 |
+ |
fn the_timing_file_carries_the_values_and_the_block_that_overrides_them() {
|
|
464 |
+ |
// The rungs themselves are tested in makeover-timing. What is this
|
|
465 |
+ |
// crate's to get wrong is dropping half the file: the values are
|
|
466 |
+ |
// useless noise without the media block, and the media block on its
|
|
467 |
+ |
// own overrides nothing.
|
|
468 |
+ |
let dir = scratch("timing");
|
|
469 |
+ |
let path = dir.join("timing.css");
|
|
470 |
+ |
timing_css(&path);
|
|
471 |
+ |
let css = std::fs::read_to_string(&path).unwrap();
|
|
472 |
+ |
assert!(css.starts_with("/* Generated by makeover-build"));
|
|
473 |
+ |
// One token per axis, so a crate that grows a fourth axis and is not
|
|
474 |
+ |
// emitted here fails somewhere other than on screen.
|
|
475 |
+ |
assert!(css.contains("--timing-dismiss"), "no intent tokens");
|
|
476 |
+ |
assert!(css.contains("--motion-fade"), "no motion token");
|
|
477 |
+ |
assert!(css.contains("--cadence-activity"), "no cadence token");
|
|
478 |
+ |
assert!(
|
|
479 |
+ |
css.contains("@media (prefers-reduced-motion: reduce)"),
|
|
480 |
+ |
"the values shipped without the block that turns them off"
|
|
481 |
+ |
);
|
|
482 |
+ |
// The block comes after the values it overrides. Same specificity,
|
|
483 |
+ |
// so the order is the whole of the win.
|
|
484 |
+ |
assert!(
|
|
485 |
+ |
css.find(":root").unwrap() < css.find("prefers-reduced-motion").unwrap(),
|
|
486 |
+ |
"the motion-off block cannot override values declared after it"
|
|
487 |
+ |
);
|
|
488 |
+ |
// Inside the family's layer, like every other generated sheet:
|
|
489 |
+ |
// unlayered declarations outrank every named layer, so a generated
|
|
490 |
+ |
// file outside it beats the app's own overrides.
|
|
491 |
+ |
assert!(css.contains(makeover_geometry::CSS_LAYER));
|
|
492 |
+ |
}
|
|
493 |
+ |
|
|
494 |
+ |
#[test]
|
|
495 |
+ |
fn the_tauri_layout_puts_all_four_where_the_apps_look() {
|
| 421 |
496 |
|
let root = scratch("tauri");
|
| 422 |
497 |
|
std::fs::create_dir_all(root.join("frontend").join("css")).unwrap();
|
| 423 |
498 |
|
tauri_frontend(&root, &makeover_webview::Emit::default(), None);
|
| 424 |
|
- |
assert!(
|
| 425 |
|
- |
root.join("frontend")
|
| 426 |
|
- |
.join("css")
|
| 427 |
|
- |
.join("geometry.css")
|
| 428 |
|
- |
.exists()
|
| 429 |
|
- |
);
|
| 430 |
|
- |
assert!(
|
| 431 |
|
- |
root.join("frontend")
|
| 432 |
|
- |
.join("css")
|
| 433 |
|
- |
.join("layout.css")
|
| 434 |
|
- |
.exists()
|
| 435 |
|
- |
);
|
|
499 |
+ |
let css = root.join("frontend").join("css");
|
|
500 |
+ |
for file in ["geometry.css", "timing.css", "layout.css", "typography.css"] {
|
|
501 |
+ |
assert!(css.join(file).exists(), "{file} was not written");
|
|
502 |
+ |
}
|
| 436 |
503 |
|
assert!(root.join("themes").is_dir());
|
| 437 |
504 |
|
}
|
| 438 |
505 |
|
}
|