Fossil SCM

fossil-scm / www / customskin.md
1
# Skinning the Fossil Web Interface
2
3
The Fossil web interface comes with a pre-configured look and feel. The default
4
look and feel works fine in many situations. However, you may want to change
5
the look and feel (the "skin") of Fossil to better suite your own individual tastes.
6
This document provides background information to aid you in that task.
7
8
## <a id="builtin"></a>Built-in Skins
9
10
Fossil comes with [multiple built-in skins](/skins). If the default skin does not
11
suite your tastes, perhaps one of the other built-in skins will work better.
12
If nothing else, the built-in skins can serve as examples or templates that
13
you can use to develop your own custom skin.
14
15
The sources to these built-ins can
16
be found in the Fossil source tree under the skins/ folder. The
17
[skins/](/dir?ci=trunk&name=skins)
18
folder contains a separate subfolder for each built-in skin, with each
19
subfolders holding at least these five files:
20
21
* css.txt
22
* details.txt
23
* footer.txt
24
* header.txt
25
* js.txt
26
27
Try out the built-in skins by using the --skin option on the
28
[fossil ui](/help/ui) or [fossil server](/help/server) commands.
29
30
## <a id="sharing"></a>Sharing Skins
31
32
The skin of a repository is not part of the versioned state and does not
33
"push" or "pull" like checked-in files. The skin is local to the
34
repository. However, skins can be shared between repositories using
35
the [fossil config](/help/configuration) command.
36
The "fossil config push skin" command will send the local skin to a remote
37
repository and the "fossil config pull skin" command will import a skin
38
from a remote repository. The "fossil config export skin FILENAME"
39
will export the skin for a repository into a file FILENAME. This file
40
can then be imported into a different repository using the
41
"fossil config import FILENAME" command. Unlike "push" and "pull",
42
the "export" and "import" commands are able to move skins between
43
repositories for different projects. So, for example, if you have a
44
group of related repositories, you can develop a skin for one of them,
45
then get a consistent look across all the repositories by exporting
46
the skin from the first repository and importing into all the others.
47
48
The file generated by "fossil config export" could be checked into
49
one of your repositories and versioned, if desired. This will not
50
automatically change the skin when looking backwards in time, but it
51
will provide an historical record of what the skin used to be and
52
allow the historical look of the repositories to be recreated if
53
necessary.
54
55
When cloning a repository, the skin of the new repository is initialized to
56
the skin of the repository from which it was cloned.
57
58
# Structure Of A Fossil Web Page
59
60
Every HTML page generated by Fossil has the same basic structure:
61
62
| Fossil-Generated HTML Header |
63
| Skin Header |
64
| Fossil-Generated Content |
65
| Skin Footer |
66
| Fossil-Generated HTML Footer |
67
68
By default, Fossil starts every generated HTML page with this:
69
70
<html>
71
<head>
72
<base href="...">
73
<meta http-equiv="Content-Security-Policy" content="....">
74
<meta name="viewport" content="width=device-width, initial-scale=1.0">
75
<title>....</title>
76
<link rel="stylesheet" href="..." type="text/css">
77
</head>
78
<body class="FEATURE">
79
80
Fossil used to require a static version of this in every skin’s Header
81
area, but over time, we have found good cause to generate multiple
82
elements at runtime.
83
84
One such is the `FEATURE` element, being either the top-level HTTP
85
request routing element (e.g. `doc`) or an aggregate feature class that
86
groups multiple routes under a single name. A prime example is `forum`,
87
which groups the `/forummain`, `/forumpost`, and `/forume2` routes,
88
allowing per-feature CSS. For instance, to style `<blockquote>` tags
89
specially for forum posts written in Markdown, leaving all other block
90
quotes alone, you could say:
91
92
body.forum div.markdown blockquote {
93
margin-left: 10px;
94
}
95
96
You can [override this generated HTML header](#override) by including a
97
“`<body>`” tag somewhere in the Header area of the skin, but it is
98
almost always best to limit a custom skin’s Header section to something
99
like this:
100
101
<div class="sidebar" id="version-2.24">Prior to Fossil 2.24, we used
102
generic `<div>` elements to mark up these sections of the header, but we
103
switched to these semantic tag names to give browser accessibility
104
features more freedom to do intelligent things with the page content.
105
Those who made custom skins based on the old way of doing things will
106
need to track this change when upgrading, else the corresponding CSS
107
will mistarget the page header elements. Also, if you’re using Fossil’s
108
chat feature, failing to track this change will cause it to miscalculate
109
the message area size, resulting in double scrollbars. Simply diffing
110
your custom header in the skin editor against the stock version should
111
be sufficient to show what you need to change.</div>
112
113
114
<header>
115
...
116
</header>
117
<nav class="mainmenu" title="Main Menu">
118
...
119
</nav>
120
<nav id="hbdrop" class="hbdrop" title="sitemap"></nav>
121
122
See the stock skins’ headers for ideas of what to put in place of the
123
ellipses.
124
125
The Fossil-generated Content section immediately follows this Header.
126
It will look like this:
127
128
<div class="content">
129
... Fossil-generated content here ...
130
</div>
131
132
After the Content is the custom Skin Footer section which should
133
follow this template:
134
135
<footer>
136
... skin-specific stuff here ...
137
</footer>
138
139
As with the `<header>` change called out above, this, too, is a breaking
140
change in Fossil 2.24.
141
142
Finally, Fossil always adds its own footer (unless overridden)
143
to close out the generated HTML:
144
145
</body>
146
</html>
147
148
## <a id="mainmenu"></a>Changing the Main Menu Contents
149
150
The actual text content of the skin’s main menu is not
151
part of the skin proper if you’re using one of the stock skins.
152
If you look at the Header section of the skin, you’ll find a
153
`<div class="mainmenu">` element whose contents are set by a short
154
[TH1](./th1.md) script from the contents of the **Main Menu** section of
155
the Setup → Configuration screen.
156
157
This feature allows the main menu contents to stay the same across
158
different skins, so you no longer have to reapply menu customizations
159
when trying different skins.
160
161
See the [`capexpr`](./th1.md#capexpr) section of the TH1 docs for help
162
on interpreting the default contents of this block.
163
164
165
## <a id="override"></a>Overriding the HTML Header and Footer
166
167
Notice that the `<html>`, `<head>`, and opening `<body>`
168
elements at the beginning of the document,
169
and the closing `</body>` and `</html>` elements at the end are automatically
170
generated by Fossil. This is recommended.
171
172
However, for maximum design flexibility, Fossil allows those elements to be
173
supplied as part of the configurable Skin Header and Skin Footer.
174
If the Skin Header contains the text "`<body`", then Fossil assumes that
175
the Skin Header and Skin Footer will handle all of the `<html>`,
176
`<head>`, and `<body>` text itself, and the Fossil-generated header and
177
footer will be blank.
178
179
When overriding the HTML Header in this way, you will probably want to use some
180
of the [TH1 variables documented below](#vars) such as `$stylesheet_url`
181
to avoid hand-writing code that Fossil can generate for you.
182
183
# Designing, Debugging, and Installing A Custom Skin
184
185
It is possible to develop a new skin from scratch. But a better and easier
186
approach is to use one of the existing built-in skins as a baseline and
187
make incremental modifications, testing after each step, to obtain the
188
desired result.
189
190
The skin is controlled by five files:
191
192
<dl>
193
<dt><b>css.txt</b></dt>
194
195
<dd>The css.txt file is the text of the CSS for Fossil.
196
Fossil might add additional CSS elements after
197
the css.txt file, if it sees that the css.txt omits some
198
CSS components that Fossil needs. But for the most part,
199
the content of the css.txt is the CSS for the page.</dd>
200
201
<dt><b>details.txt</b><dt>
202
203
<dd>The details.txt file is short list of settings that control
204
the look and feel, mostly of the timeline. The default
205
details.txt file looks like this:
206
207
<pre>
208
pikchr-background: ""
209
pikchr-fontscale: ""
210
pikchr-foreground: ""
211
pikchr-scale: ""
212
timeline-arrowheads: 1
213
timeline-circle-nodes: 1
214
timeline-color-graph-lines: 1
215
white-foreground: 0
216
</pre>
217
218
The three "timeline-" settings in details.txt control the appearance
219
of certain aspects of the timeline graph. The number on the
220
right is a boolean - "1" to activate the feature and "0" to
221
disable it. The "white-foreground:" setting should be set to
222
"1" if the page color has light-color text on a darker background,
223
and "0" if the page has dark text on a light-colored background.
224
225
If the "pikchr-foreground" setting
226
is defined and is not an empty string then it specifies a
227
foreground color to use for [pikchr diagrams](./pikchr.md). The
228
default pikchr foreground color is black, or white if the
229
"white-foreground" boolean is set. The "pikchr-background"
230
settings does the same for the pikchr diagram background color.
231
If the "pikchr-fontscale" and "pikchr-scale" values are not
232
empty strings, then they should be floating point values (close
233
to 1.0) that specify relative scaling of the fonts in pikchr
234
diagrams and other elements of the diagrams, respectively.
235
</dd>
236
237
<dt><b>footer.txt</b> and <b>header.txt</b></dt>
238
239
<dd>The footer.txt and header.txt files contain the Skin Footer
240
and Skin Header respectively. Of these, the Skin Header is
241
the most important, as it contains the markup used to generate
242
the banner and menu bar for each page.
243
244
Both the footer.txt and header.txt file are
245
[processed using TH1](#headfoot) prior to being output as
246
part of the overall web page.</dd>
247
248
<dt><b>js.txt</b></dt>
249
250
<dd>The js.txt file is optional. It is intended to be javascript.
251
The complete text of this javascript might be inserted into
252
the Skin Footer, after being processed using TH1, using
253
code like the following in the "footer.txt" file:
254
255
<pre>
256
&lt;script nonce="$nonce"&gt;
257
&lt;th1&gt;styleScript&lt;/th1&gt;
258
&lt;/script&gt;
259
</pre>
260
261
The js.txt file was originally used to insert javascript
262
that controls the hamburger menu in the default skin. More
263
recently, the javascript for the hamburger menu was moved into
264
a separate built-in file. Skins that use the hamburger menu
265
typically cause the javascript to be loaded by including the
266
following TH1 code in the "header.txt" file:
267
268
<pre>
269
&lt;th1&gt;builtin_request_js hbmenu.js&lt;/th1&gt;
270
</pre>
271
272
The difference between `styleScript` and `builtin_request_js`
273
is that the `styleScript` command interprets the file
274
using TH1 and injects the content directly into the output
275
stream, whereas the `builtin_request_js` command inserts the
276
Javascript verbatim and does so at some unspecified future time
277
down inside the Fossil-generated footer.
278
You can use either
279
approach in custom skins that you create.
280
281
Note that the "js.txt" file is *not* automatically inserted into
282
the generate HTML for a page. You, the skin designer, must
283
cause the javascript to be inserted by issuing appropriate
284
TH1 commands in the "header.txt" or "footer.txt" files.</dd>
285
</dl>
286
287
Developing a new skin is simply a matter of creating appropriate
288
versions of these five control files.
289
290
### Skin Development Using The Web Interface
291
292
Users with admin privileges can use the Admin/Skin configuration page
293
on the web interface to develop a new skin. The development of a new
294
skin occurs without disrupting the existing skin. So you can work on
295
a new skin for a Fossil instance while the existing skin is still in
296
active use.
297
298
The new skin is a "draft" skin. You initialize one of 9 draft skins
299
to either the current skin or to one of the built-in skins. Then
300
use forms to edit the 5 control files described above. The new
301
skin can be tested after each edit. Finally, once the new skin is
302
working as desired, the draft skin is "published" and becomes the
303
new live skin that most users see.
304
305
### Skin Development Using A Local Text Editor
306
307
An alternative approach is to copy the five control files for your
308
baseline skin into a temporary working directory (here called
309
"./newskin") and then launch the [fossil ui](/help/ui) command
310
with the "--skin ./newskin" option. If the argument to the --skin
311
option contains a "/" character, then the five control files are
312
read out of the directory named. You can then edit the control
313
files in the ./newskin folder using you favorite text editor, and
314
press "Reload" on your browser to see the effects.
315
316
317
### Disabling The Web Browser Cache During Development
318
319
Fossil is aggressive about asking the web browser to cache
320
resources. While developing a new skin, it is often helpful to
321
put your web browser into developer mode and disable the cache.
322
If you fail to do this, then you might make some change to your skin
323
under development and press "Reload" only to find that the display
324
did not change. After you have finished work your skin, the
325
caches should synchronize with your new design and you can reactivate
326
your web browser's cache and take it out of developer mode.
327
328
## <a id="headfoot"></a>Header and Footer Processing
329
330
The `header.txt` and `footer.txt` control files of a skin are the HTML text
331
of the Skin Header and Skin Footer, except that before being inserted
332
into the output stream, the text is run through a
333
[TH1 interpreter](./th1.md) that might adjust the text as follows:
334
335
* All text within &lt;th1&gt;...&lt;/th1&gt; is omitted from the
336
output and is instead run as a TH1 script. That TH1
337
script has the opportunity to insert new text in place of itself,
338
or to inhibit or enable the output of subsequent text.
339
340
* Text of the form "$NAME" or "$&lt;NAME&gt;" is replaced with
341
the value of the TH1 variable NAME. See the [TH1 Variables](#vars)
342
section for more information on the two possible variable formats.
343
344
For example, first few lines of a typical Skin Header will look
345
like this:
346
347
<div class="header">
348
<div class="title"><h1>$<project_name></h1>$<title>/div>
349
350
After variables are substituted by TH1, that will look more like this:
351
352
<div class="header">
353
<div class="title"><h1>Project Name</h1>Page Title</div>
354
355
As you can see, two TH1 variable substitutions were done.
356
357
The same TH1 interpreter is used for both the header and the footer
358
and for all scripts contained within them both. Hence, any global
359
TH1 variables that are set by the header are available to the footer.
360
361
## <a id="menu"></a>Customizing the ≡ Hamburger Menu
362
363
The menu bar of the default skin has an entry to open a drop-down menu with
364
additional navigation links, represented by the ≡ button (hence the name
365
"hamburger menu"). The Javascript logic to open and close the hamburger menu
366
when the button is clicked is usually handled by a script named
367
"hbmenu.js" that is one of the [built-in resource files](/test-builtin-files)
368
that are part of Fossil.
369
370
The ≡ button for the hamburger menu is added to the menu bar by the following
371
TH1 commands in the `header.txt` file, right before the menu bar links:
372
373
html "<a id='hbbtn' href='$home/sitemap'>&#9776;</a>"
374
builtin_request_js hbmenu.js
375
376
The hamburger button can be repositioned between the other menu links (but the
377
drop-down menu is always left-aligned with the menu bar), or it can be removed
378
by deleting the above statements. The "html" statement inserts the appropriate
379
`<a>` for the hamburger menu button (some skins require something slightly
380
different - for example the ardoise skins wants "`<li><a>`"). The
381
"builtin_request_js hbmenu.js" asks Fossil to include the "hbmenu.js"
382
resource files in the Fossil-generated footer.
383
384
The hbmenu.js script requires
385
the following `<div>` element somewhere in your header, in which to build
386
the hamburger menu.
387
388
<div id='hbdrop'></div>
389
390
Out of the box, the contents of the panel is populated with the [Site
391
Map](/sitemap), but only if the panel does not already contain any HTML
392
elements (that is, not just comments, plain text or non-presentational white
393
space). So the hamburger menu can be customized by replacing the empty `<div
394
id='hbdrop'></div>` element with a menu structure knitted according to the
395
following template:
396
397
<div id="hbdrop" data-anim-ms="400">
398
<ul class="columns" style="column-width: 20em; column-count: auto">
399
<!-- NEW GROUP WITH HEADING LINK -->
400
<li>
401
<a href="$home$index_page">Link: Home</a>
402
<ul>
403
<li><a href="$home/timeline">Link: Timeline</a></li>
404
<li><a href="$home/dir?ci=tip">Link: File List</a></li>
405
</ul>
406
</li>
407
<!-- NEW GROUP WITH HEADING TEXT -->
408
<li>
409
Heading Text
410
<ul>
411
<li><a href="$home/doc/trunk/www/customskin.md">Link: Theming</a></li>
412
<li><a href="$home/doc/trunk/www/th1.md">Link: TH1 Scripts</a></li>
413
</ul>
414
</li>
415
<!-- NEXT GROUP GOES HERE -->
416
</ul>
417
</div>
418
419
The custom `data-anim-ms` attribute can be added to the panel element to direct
420
the Javascript logic to override the default menu animation duration of 400 ms.
421
A faster animation duration of 80-200 ms may be preferred for smaller menus. The
422
animation is disabled by setting the attribute to `"0"`.
423
424
425
## <a id="vars"></a>TH1 Variables
426
427
Before expanding the TH1 within the header and footer, Fossil first
428
initializes a number of TH1 variables to values that depend on
429
repository settings and the specific page being generated.
430
431
Variables holding text that is loaded from "external, potentially untrusted"
432
sources (including the repository settings) are treated as [tainted strings]
433
(./th1.md#taint) and must be noted in the `$<NAME>` form, instead of `$NAME`,
434
or they may trigger an error (see the linked document for details). The
435
`$<NAME>` form corresponds to the TH1 statement `puts [ htmlize "$NAME" ]`,
436
where the [htmlize](./th1.md#htmlize) function escapes the tainted string,
437
making it safe for output in HTML code.
438
439
440
* **`project_name`** - The project_name variable is filled with the
441
name of the project as configured under the Admin/Configuration
442
menu. This is a [tainted string](./th1.md#taint) variable and must
443
be used as `$<project_name>`.
444
445
* **`project_description`** - The project_description variable is
446
filled with the description of the project as configured under
447
the Admin/Configuration menu. This is a [tainted string]
448
(./th1.md#taint) variable and must be used as `$<project_description>`.
449
450
* **`mainmenu`** - The mainmenu variable contains a TCL list with the main
451
menu entries. See the [mainmenu](/help/mainmenu) setting for details.
452
453
* **`title`** - The title variable holds the title of the page being
454
generated.
455
456
The title variable is special in that it is deleted after
457
the header script runs and before the footer script. This is
458
necessary to avoid a conflict with a variable by the same name used
459
in my ticket-screen scripts.
460
461
* **`baseurl`** - The root of the URL namespace for this server.
462
463
* **`secureurl`** - The same as $baseurl except that if the scheme is
464
"http:" it is changed to "https:"
465
466
* **`home`** - The $baseurl without the scheme and hostname. For example,
467
if the $baseurl is "http://projectX.com/cgi-bin/fossil" then the
468
$home will be just "/cgi-bin/fossil".
469
470
* **`index_page`** - The landing page URI as
471
specified by the Admin/Configuration setup page.
472
473
* **`current_page`** - The name of the page currently being processed,
474
without the leading "/" and without query parameters.
475
Examples: "timeline", "doc/trunk/README.txt", "wiki".
476
477
* **`current_checkin`** - The [check-in name](./checkin_names.wiki) to
478
which the current
479
[/ci](/help/www/ci),
480
[/dir](/help/www/dir),
481
[/tree](/help/www/tree),
482
[/timeline](/help/www/timeline) or
483
[/vinfo](/help/www/vinfo)
484
page refers, or undefined for all other pages. This variable is
485
derived from query parameters and is therefore a [tainted string]
486
(./th1.md#taint).
487
488
* **`csrf_token`** - A token used to prevent cross-site request forgery.
489
490
* **`default_csp`** - [Fossil’s default CSP](./defcsp.md) unless
491
[overridden by custom TH1 code](./defcsp.md#th1). Useful within
492
the skin for inserting the CSP into a `<meta>` tag within [a
493
custom `<head>` element](#headfoot).
494
495
* **`nonce`** - The value of the cryptographic nonce for the request
496
being processed.
497
498
* **`release_version`** - The release version of Fossil. Ex: "1.31"
499
500
* **`manifest_version`** - A prefix on the check-in hash of the
501
specific version of fossil that is running. Ex: "\[47bb6432a1\]"
502
503
* **`manifest_date`** - The date of the source-code check-in for the
504
version of fossil that is running.
505
506
* **`compiler_name`** - The name and version of the compiler used to
507
build the fossil executable.
508
509
* **`login`** - This variable only exists if the user has logged in.
510
The value is the username of the user.
511
512
* **`stylesheet_url`** - A URL for the internal style-sheet maintained
513
by Fossil.
514
515
* **`logo_image_url`** - A URL for the logo image for this project, as
516
configured on the Admin/Logo page.
517
518
* **`background_image_url`** - A URL for a background image for this
519
project, as configured on the Admin/Logo page.
520
521
All of the above are variables in the sense that either the header or the
522
footer is free to change or erase them. But they should probably be treated
523
as constants. New predefined values are likely to be added in future
524
releases of Fossil.
525
526
527
## <a id="procedure"></a>Suggested Skin Customization Procedure
528
529
Developers are free, of course, to develop new skins using any method they
530
want, but the following is a technique that has worked well in the past and
531
can serve as a starting point for future work:
532
533
1. Select a built-in skin that is closest to the desired look. Make
534
copies of the css, footer, and header into files name "css.txt",
535
"details.txt",
536
"footer.txt", and "header.txt" in some temporary directory.
537
538
If the Fossil source code is available, then these three files can
539
be copied directly out of one of the subdirectories under skins. If
540
sources are not easily at hand, then a copy/paste out of the
541
CSS, footer, and header editing screens under the Admin menu will
542
work just as well. The important point is that the three files
543
be named exactly "css.txt", "footer.txt", and "header.txt" and that
544
they all be in the same directory.
545
546
2. Run the [fossil ui](/help/ui) command with an extra
547
option "--skin SKINDIR" where SKINDIR is the name of the directory
548
in which the three txt files were stored in step 1. This will bring
549
up the Fossil website using the tree files in SKINDIR.
550
551
3. Edit the *.txt files in SKINDIR. After making each small change,
552
press Reload on the web browser to see the effect of that change.
553
Iterate until the desired look is achieved.
554
555
4. Copy/paste the resulting css.txt, details.txt,
556
header.txt, and footer.txt files
557
into the CSS, details, header, and footer configuration screens
558
under the Admin/Skins menu. Alternately, import them using the
559
process described below.
560
561
An alternative to step 4 is to convert the skin files into a form
562
which can be imported into a repository using `fossil config import`.
563
It requires compiling [a small tool from the fossil source
564
tree](/file/tools/skintxt2config.c):
565
566
>
567
```
568
$ cc -o s2c /path/to/fossil/checkout/tools/skintxt2config.c
569
```
570
571
With that in place, the custom skin files can be converted with:
572
573
>
574
```
575
$ ./s2c yourskin/*.txt > skin.config
576
```
577
578
It can be imported into an arbitrary fossil repository with:
579
580
>
581
```
582
$ fossil config import skin.config
583
```
584
585
And it can be pushed to a remote repository with:
586
587
>
588
```
589
$ fossil config push skin
590
```
591
592
That approach has proven to be an effective way to locally develop
593
skin changes then push them to a "live" site.
594
595
596
## See Also
597
598
* [Customizing the Timeline Graph](customgraph.md)
599

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button