Skip to main content

euv_ui/style/css/
const.rs

1/// Raw stylesheet for rendered markdown bodies ([`crate::euv_markdown`]).
2///
3/// `class!` cannot express descendant selectors, so markdown typography is
4/// injected once at startup through `Css::inject_css`. All colors reference
5/// the theme CSS variables, so light/dark switching works unchanged.
6pub const EUV_MD_CSS: &str = r#"
7.md-body {
8    line-height: 1.7;
9    font-size: var(--font-base);
10    word-wrap: break-word;
11}
12.md-body h1, .md-body h2, .md-body h3, .md-body h4, .md-body h5, .md-body h6 {
13    position: relative;
14    font-weight: 700;
15    letter-spacing: -0.01em;
16    margin-top: 1.8em;
17    margin-bottom: 0.6em;
18    scroll-margin-top: 72px;
19    line-height: 1.3;
20}
21.md-body h1 {
22    font-size: var(--font-3xl);
23    margin-top: 0;
24    padding-bottom: 0.4em;
25    border-bottom: 1px solid var(--border);
26}
27.md-body h2 {
28    font-size: var(--font-2xl);
29    padding-bottom: 0.3em;
30    border-bottom: 1px dashed var(--border);
31}
32.md-body h3 { font-size: var(--font-xl); }
33.md-body h4 { font-size: var(--font-lg); }
34.md-body h5, .md-body h6 { font-size: var(--font-base); }
35.md-body .header-anchor {
36    float: left;
37    margin-left: -0.9em;
38    padding-right: 0.2em;
39    opacity: 0;
40    color: var(--muted-foreground);
41    font-weight: 400;
42    transition: opacity 0.15s ease-out;
43    user-select: none;
44    /* The `.md-body a` rule below applies `text-decoration: underline
45       dashed` to every anchor. The header-anchor is a typographic
46       icon, not a navigable link in the visual sense, so drop the
47       underline. */
48    text-decoration: none;
49}
50.md-body h1:hover .header-anchor,
51.md-body h2:hover .header-anchor,
52.md-body h3:hover .header-anchor,
53.md-body h4:hover .header-anchor,
54.md-body h5:hover .header-anchor,
55.md-body h6:hover .header-anchor {
56    opacity: 1;
57}
58/* On narrow viewports the negative `margin-left: -0.9em` pushes the `#`
59   sign past the left edge of the viewport (anchor x ≈ -11px on a 380px
60   viewport), so hover-revealed anchors get clipped. On mobile we drop
61   the float + negative margin and absolutely position the anchor at
62   the heading's left edge instead, with the heading content shifted
63   right via `padding-left`. This way:
64
65   * The `#` stays inside the viewport at all times.
66   * The `#` is vertically centered against the first line of the
67     heading (`align-items: center`), so the two sit on the same
68     optical line instead of the `#` floating above the heading text.
69   * The heading text gets the full content width (minus the small
70     reserved gutter), so a long heading like "Markdown Features" no
71     longer wraps with one orphan word on its own line leaving a big
72     empty space at the end of the first line. */
73@media (max-width: 767px) {
74    .md-body h1,
75    .md-body h2,
76    .md-body h3,
77    .md-body h4,
78    .md-body h5,
79    .md-body h6 {
80        position: relative;
81        padding-left: 1.6em;
82    }
83    .md-body .header-anchor {
84        position: absolute;
85        left: 0;
86        top: 0;
87        height: 100%;
88        width: 1em;
89        margin: 0;
90        padding: 0;
91        float: none;
92        display: inline-flex;
93        align-items: center;
94        justify-content: center;
95        font-size: 0.85em;
96        line-height: 1;
97    }
98}
99.md-body p, .md-body ul, .md-body ol, .md-body blockquote, .md-body pre, .md-body table {
100    margin: 1em 0;
101}
102.md-body ul, .md-body ol {
103    padding-left: 1.4em;
104}
105.md-body ul { list-style: disc; }
106.md-body ol { list-style: decimal; }
107.md-body ul ul, .md-body ul ol, .md-body ol ul, .md-body ol ol {
108    margin: 0.25em 0;
109}
110.md-body li { margin: 0.25em 0; }
111.md-body li input[type="checkbox"] {
112    margin-right: 0.4em;
113    accent-color: var(--accent);
114}
115.md-body a {
116    color: var(--accent);
117    font-weight: 500;
118    text-decoration: underline;
119    text-underline-offset: 3px;
120    text-decoration-style: dashed;
121    text-decoration-color: var(--border);
122}
123.md-body a:hover {
124    text-decoration-style: solid;
125    text-decoration-color: var(--accent);
126}
127.md-body strong { font-weight: 700; }
128.md-body em { font-style: italic; }
129.md-body del { opacity: 0.6; }
130.md-body hr {
131    border: none;
132    border-top: 1px dashed var(--border);
133    margin: 2em 0;
134}
135.md-body blockquote {
136    margin: 1em 0;
137    padding: 0.4em 1em;
138    border-left: 4px solid var(--border);
139    color: var(--muted-foreground);
140}
141.md-body blockquote p { margin: 0.4em 0; }
142.md-body code {
143    font-family: ui-monospace, monospace;
144    font-size: 0.875em;
145    padding: 0.15em 0.4em;
146    background: var(--accent-muted);
147    border: 1px solid var(--border);
148    /* Inline <code> that wraps to multiple lines must keep its border
149       on every fragment, otherwise the first line loses its right border
150       and subsequent lines lose their left border.
151
152       box-decoration-break: clone alone is not enough in practice: the
153       per-fragment borders stack against the next fragment's background
154       and the visual gap between fragments collapses, making the right
155       border of one line look like the left border of the next (and
156       neither looks fully closed). Making the element inline-block
157       guarantees each fragment draws its own box with its own four
158       borders, exactly the same trick used by euv_tag. */
159    -webkit-box-decoration-break: clone;
160    box-decoration-break: clone;
161    display: inline-block;
162    /* `vertical-align: baseline` plus `line-height: 1` keeps the
163       <code> box visually on the same baseline as the surrounding
164       text. Earlier revisions used `vertical-align: text-top` with
165       `line-height: 1.4`, which pushed the box downward and made the
166       framed text look like it was sitting on a lower line than the
167       surrounding body text — a small offset, but very noticeable in
168       tight running prose like list items and paragraphs. With
169       `line-height: 1` the inline-block has no extra leading so its
170       baseline aligns with the baseline of the parent line. */
171    vertical-align: baseline;
172    line-height: 1;
173}
174.md-body pre {
175    padding: 1em 1.2em;
176    overflow-x: auto;
177    border: 1px solid var(--border);
178    background: var(--accent-muted);
179}
180.md-body pre code {
181    padding: 0;
182    border: none;
183    background: transparent;
184    font-size: 0.875rem;
185    line-height: 1.6;
186}
187.md-body table {
188    width: 100%;
189    border-collapse: collapse;
190    font-size: var(--font-sm);
191    display: block;
192    overflow-x: auto;
193}
194.md-body table thead { border-bottom: 2px solid var(--border); }
195.md-body table th, .md-body table td {
196    padding: 0.5em 0.9em;
197    border: 1px solid var(--border);
198    text-align: left;
199}
200.md-body table th { font-weight: 700; }
201.md-body table tbody tr:nth-child(2n) { background: var(--accent-muted); }
202.md-body img { max-width: 100%; }
203.md-body .docs-container {
204    margin: 1.2em 0;
205    padding: 0.1em 1.2em;
206    border-left: 4px solid var(--foreground);
207    background: var(--accent-muted);
208}
209.md-body .docs-container .docs-container-title {
210    font-weight: 700;
211    font-size: var(--font-sm);
212    letter-spacing: 0.04em;
213    text-transform: uppercase;
214    margin: 0.8em 0 0.4em;
215}
216.md-body .docs-container.tip { border-left-style: solid; }
217.md-body .docs-container.warning { border-left-style: dashed; }
218.md-body .docs-container.danger {
219    border-left: 4px double var(--foreground);
220}
221.md-body .docs-container.details {
222    border-left: 1px solid var(--border);
223    background: transparent;
224}
225.md-body .footnote-definition { font-size: var(--font-sm); color: var(--muted-foreground); }
226"#;