max / makeover-layout
| 1 | // Names this module's prose links to, resolved for rustdoc. |
| 2 | |
| 3 | use crate::; |
| 4 | |
| 5 | /// Which ambient mode a theme is written for. |
| 6 | /// |
| 7 | /// The vocabulary's own spelling of what `makeover` calls a theme's variant, |
| 8 | /// and the duplication is deliberate rather than an oversight. This crate has |
| 9 | /// no dependencies by charter — it emits nothing, reads nothing and resolves |
| 10 | /// nothing — so it cannot take the crate that owns the file format, and a |
| 11 | /// renderer that must group a picker needs the three groups as values. |
| 12 | /// |
| 13 | /// The two are kept in step by the app that converts between them, which is a |
| 14 | /// three-arm `match` at each adopter and the price of the layering. If a fourth |
| 15 | /// mode is ever authored, this enum and `makeover::Variant` move together. |
| 16 | /// |
| 17 | /// Three, not two: one shipped theme is high contrast, and an app matching on |
| 18 | /// light-or-dark alone files it under the wrong one. |
| 19 | |
| 20 | |
| 21 | |
| 22 | /// Written for a light ambient mode. |
| 23 | Light, |
| 24 | /// Written for a dark ambient mode. |
| 25 | Dark, |
| 26 | /// Written to be legible before it is pretty. |
| 27 | HighContrast, |
| 28 | |
| 29 | |
| 30 | |
| 31 | /// The machine spelling, matching the theme file's own `meta.variant`. |
| 32 | /// |
| 33 | /// A data attribute, a stored value, a test assertion. Not a heading: what |
| 34 | /// a group is *called* on screen is [`heading`](Self::heading). |
| 35 | |
| 36 | pub const |
| 37 | match self |
| 38 | Light => "light", |
| 39 | Dark => "dark", |
| 40 | HighContrast => "high-contrast", |
| 41 | |
| 42 | |
| 43 | |
| 44 | /// What the group of themes in this variant is called on screen. |
| 45 | /// |
| 46 | /// Here rather than at each renderer, which is the whole argument for the |
| 47 | /// member existing: three renderers picking their own headings is one |
| 48 | /// picker reading three ways, and the spellings below are the ones |
| 49 | /// goingson's shipped picker used before it was described. |
| 50 | |
| 51 | pub const |
| 52 | match self |
| 53 | Light => "Light", |
| 54 | Dark => "Dark", |
| 55 | HighContrast => "High Contrast", |
| 56 | |
| 57 | |
| 58 | |
| 59 | |
| 60 | |
| 61 | |
| 62 | f.write_str |
| 63 | |
| 64 | |
| 65 | |
| 66 | /// How legible a theme measured, as a picker reports it. |
| 67 | /// |
| 68 | /// A measurement carried into the description, which is unusual here and is the |
| 69 | /// one case that earns it: the number comes off the theme's resolved colours, |
| 70 | /// so the layer that loaded the theme is the only party that has it, and an app |
| 71 | /// re-deriving it would be parsing every theme file a second time to learn what |
| 72 | /// was already known. What a renderer does with it is a badge beside the name. |
| 73 | /// |
| 74 | /// Ordered worst-first, matching `makeover::ContrastTier`, so the two sort the |
| 75 | /// same way and an adopter's `match` cannot invert an ordering by accident. |
| 76 | |
| 77 | |
| 78 | |
| 79 | /// Muted text below the 3:1 floor for large text and UI parts. |
| 80 | Low, |
| 81 | /// Muted text clears 3:1 but not the 4.5:1 bar for normal text. |
| 82 | Standard, |
| 83 | /// Muted text meets WCAG AA on every panel ground. |
| 84 | High, |
| 85 | |
| 86 | |
| 87 | |
| 88 | /// The machine spelling, for a data attribute or a test. |
| 89 | |
| 90 | pub const |
| 91 | match self |
| 92 | Low => "low", |
| 93 | Standard => "standard", |
| 94 | High => "high", |
| 95 | |
| 96 | |
| 97 | |
| 98 | /// The short mark shown beside a theme's name. |
| 99 | /// |
| 100 | /// One spelling for the tree, for [`ThemeVariant::heading`]'s reason. These |
| 101 | /// are the marks audiofiles shipped before its picker was described, which |
| 102 | /// is the only implementation that ever drew them. |
| 103 | /// |
| 104 | /// [`Standard`](Self::Standard) is not the absence of a mark: a reader |
| 105 | /// scanning a column of badges learns more from three marks than from two |
| 106 | /// and a gap, and "OK" is the honest reading of a theme that clears the UI |
| 107 | /// floor and misses the text one. |
| 108 | |
| 109 | pub const |
| 110 | match self |
| 111 | Low => "low", |
| 112 | Standard => "OK", |
| 113 | High => "AA", |
| 114 | |
| 115 | |
| 116 | |
| 117 | |
| 118 | |
| 119 | |
| 120 | f.write_str |
| 121 | |
| 122 | |
| 123 | |
| 124 | /// One theme, as a picker offers it. |
| 125 | /// |
| 126 | /// Four facts where a [`Choice`] has two, and the two extra ones are why this |
| 127 | /// is its own type rather than options with the variant folded into the label. |
| 128 | /// Both are facts the theme layer resolved and neither survives being written |
| 129 | /// into a string: a group is structure and a badge is a second column. |
| 130 | /// |
| 131 | /// # No `unavailable` |
| 132 | /// |
| 133 | /// [`Choice::unavailable`]'s counterpart is absent for its own sibling's |
| 134 | /// reason. A theme that is installed can be picked, and a theme that is not |
| 135 | /// installed is not in the list. There is no third state for a reason to |
| 136 | /// explain. |
| 137 | /// |
| 138 | /// `#[non_exhaustive]` from birth, so a new member costs no call site. |
| 139 | |
| 140 | |
| 141 | |
| 142 | /// What is submitted, and what the app stores. |
| 143 | pub id: &'a str, |
| 144 | /// What is read. |
| 145 | pub name: &'a str, |
| 146 | /// Which group it belongs to. |
| 147 | pub variant: ThemeVariant, |
| 148 | /// How legible its muted text measured. |
| 149 | pub contrast: Contrast, |
| 150 | |
| 151 | |
| 152 | |
| 153 | /// A theme, with everything a picker needs to place and mark it. |
| 154 | /// |
| 155 | /// Every fact is an argument and none is a builder, which is the opposite |
| 156 | /// of [`Choice`]'s arrangement and is deliberate: a theme missing its |
| 157 | /// variant has no group to sit in and a theme missing its tier has no badge |
| 158 | /// to draw, so both are the control rather than embellishments on it. The |
| 159 | /// same reasoning [`Field::range`] applies to its bounds. |
| 160 | |
| 161 | pub const |
| 162 | id: &'a str, |
| 163 | name: &'a str, |
| 164 | variant: ThemeVariant, |
| 165 | contrast: Contrast, |
| 166 | |
| 167 | Self |
| 168 | id, |
| 169 | name, |
| 170 | variant, |
| 171 | contrast, |
| 172 | |
| 173 | |
| 174 | |
| 175 |