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