-
Notifications
You must be signed in to change notification settings - Fork 14
Expand file tree
/
Copy pathCodeChatEditor.css
More file actions
177 lines (156 loc) · 8.4 KB
/
Copy pathCodeChatEditor.css
File metadata and controls
177 lines (156 loc) · 8.4 KB
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
/* Copyright (C) 2026 Bryan A. Jones.
This file is part of the CodeChat Editor.
The CodeChat Editor is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by the Free
Software Foundation, either version 3 of the License, or (at your option) any
later version.
The CodeChat Editor is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
details.
You should have received a copy of the GNU General Public License along with
the CodeChat Editor. If not, see
[http://www.gnu.org/licenses/](http://www.gnu.org/licenses/).
`CodeChatEditor.css` -- Styles for the CodeChat Editor
======================================================
This style sheet is used by the HTML generated by
[CodeChatEditor.mts](../CodeChatEditor.mts). It is the entry point the
bundler builds; the two imports below pull in everything else.
The cascade
-----------
Both imports go into the same
[cascade layer](https://developer.mozilla.org/en-US/docs/Web/CSS/@layer).
Within a layer the ordinary cascade applies, so putting the theme and the
base styles in one layer leaves their relationship exactly as it was before
this file declared any layer at all: the theme is imported first, so a base
rule of equal specificity wins by source order, and a more specific theme
rule wins over a less specific base rule.
What the layer buys is everything *outside* it. A declaration which belongs
to no layer beats every layered declaration regardless of specificity, so the
rules at the end of this file -- and only those -- are out of reach of both
the base styles and any theme. That is a property of the cascade rather than
of the selectors involved, which is what the
[gathered fragment styling](gathered-fragments) needs: it aligns generated
content against the source it came from, and a theme which happened to style
the elements it uses would break that alignment rather than restyle it.
Nothing but that section belongs out here; anything a theme should be free to
restyle goes in
[CodeChatEditorBase.css](CodeChatEditorBase.css) instead.
Eventually, the theme will be a user-configurable setting. */
@import url("themes/light.css") layer(app);
@import url("CodeChatEditorBase.css") layer(app);
/* <span id="gathered-fragments">Gathered fragment styling</span>
---------------------------------------------------------
These rules are deliberately outside the layer the imports above go into; see
[The cascade](cascade).
A gather element is followed by `<div class="cc-gather-items">`, which holds
the rendered content of each fragment the element lists; the Server produces
this markup in `render_fragment_content` (see
[processing.rs](../../../server/src/processing.rs)). That rendering
reproduces the layout of the source the fragment came from: each doc block
carries the indent it had there, each line of a code block and the first line
of each doc block are preceded by that line's number, and equal indents in the
source line up:
```
\<gutter> \<doc block indent> \<doc block contents>
\<gutter> \<code>
```
where the \<gutter> holds a line number and is the same width in both.
Achieving that alignment is what the rules below are for; two constraints
follow from it, and anything added here must respect them.
* <span id="cc-fragment-font">The indent and the code must render in the same
font at the same size</span>, since the indent's job is to occupy exactly
as many character widths as the equivalent indent in the code. Both are
therefore styled here, together, and both begin by discarding every author
declaration which reached them (`all: revert`). Both are `<pre>` elements:
that is what keeps their whitespace -- which is the layout -- from being
collapsed on its way to the screen (see `render_fragment_content` in
[processing.rs](../../../server/src/processing.rs)), but it also puts them
in reach of the `pre` styling nearly every theme has. Being outside the
layer wins the properties declared below; the `all: revert` is what
disposes of the rest, such as the background and padding a theme gives code
blocks it means to set apart.
* The gutter is a `.cc-line-number` on both sides -- the first child of
`.cc-fragment-indent` on the doc side, and the start of each line on the
code side -- so a single rule gives the two the same width. That width comes
from `--cc-gutter-width`, measured in `ch`: a custom property is substituted
before it's computed, so that width is a character width of the font of
whichever element uses it -- the same font in both, per the constraint
above (a `.cc-line-number` inherits the font of the `.cc-fragment-indent` or
`.cc-fragment-code` containing it). */
:root {
/* The width of the line number gutter: room for a three-digit line number
plus the space separating it from what follows. */
--cc-gutter-width: 4ch;
/* The font shared by a rendered fragment's indents and code. Declaring it
once, and applying it with the `font` shorthand (which resets the font
properties it omits), is what guarantees the two are measured in the same
character width. The size is absolute, both so that the two can't diverge
through what they inherit and because a generic monospace family with no
size of its own renders smaller than the surrounding text in most
browsers. */
--cc-fragment-font: 0.9rem monospace;
}
/* One doc block of a rendered fragment. This is the layout `.CodeChat-doc` uses
for the doc blocks the editor itself displays. */
.cc-fragment-doc {
display: flex;
}
/* The whitespace which indents this doc block in its source file, preceded by
the doc side of the gutter -- a `.cc-line-number` holding the number of the
doc block's first line. */
.cc-fragment-indent {
/* Discard the `pre` styling of any theme; see [above](cc-fragment-font). */
all: revert;
/* `all` also drops the page-wide `box-sizing`; put it back. */
box-sizing: inherit;
/* Take exactly the width of the gutter plus the whitespace it contains,
rather than expanding or shrinking as a flex item otherwise would. */
flex: 0 0 auto;
white-space: pre;
tab-size: 4;
/* A `pre` carries vertical margins of its own, which would push this out of
line with the code it must align to. */
margin: 0;
/* Match `.cc-fragment-code`; see [above](cc-fragment-font). */
font: var(--cc-fragment-font);
}
/* <span id="cc-fragment-doc-contents">The contents of that doc block</span>,
which the
[rules in CodeChatEditorBase.css](CodeChatEditorBase.css#remove-space) trim
to the height of its text: a gathered doc block sits directly against the code
block above and below it, exactly as it does in the source. */
.cc-fragment-doc-contents {
flex-grow: 1;
}
/* One code block of a rendered fragment. */
.cc-fragment-code {
/* Discard the `pre` styling of any theme; see [above](cc-fragment-font). */
all: revert;
/* `all` also drops the page-wide `box-sizing`; put it back. */
box-sizing: inherit;
/* The code is reproduced exactly, newlines and all. */
white-space: pre;
tab-size: 4;
/* A `pre` carries vertical margins of its own, which would open a gap
between this and the doc block above or below it -- a gap the source
doesn't have. */
margin: 0;
/* Match `.cc-fragment-indent`; see [above](cc-fragment-font). */
font: var(--cc-fragment-font);
}
/* The line number which fills the gutter: one preceding each line of a code
block, and one preceding the indent of each doc block. Since this is generated
content rather than part of the source, it's excluded from what a selection
copies and dimmed to keep it from competing with the source itself. */
.cc-line-number {
/* Right-align the number in the gutter, so that every line of code begins
in the same column regardless of how many digits precede it. Use
`min-width`, not `width`: a line number too long for the gutter must
widen it rather than overflow onto the code. */
display: inline-block;
min-width: var(--cc-gutter-width);
padding-right: 1ch;
text-align: right;
opacity: 0.5;
}