Edgewall Software

Changes between Version 3 and Version 4 of TracDev/Proposals/ThemePlugins


Ignore:
Timestamp:
Apr 14, 2007, 10:25:29 PM (17 years ago)
Author:
Armin Ronacher
Comment:

wohoo. that could be *the* solution

Legend:

Unmodified
Added
Removed
Modified
  • TracDev/Proposals/ThemePlugins

    v3 v4  
    1313To create a list of generic classes an analysis of the current css files and genshi templates would be required.
    1414
    15 == A CSS Preprocessor ==
    16 
    17 CSS does not allow variables and constants unfortunately. Because of that a CSS preprocessor is the only way to use a value twice in a file. If a request in a chrome folder goes to `foo.css` and the `foo.css` file does not exist the chrome system would look for a `foo.css.tmpl`. If that file exists trac loads it as python text template (`string.Template`) and executes it.
    18 
    19 Such a template would have access to the current theme provider described below.
    20 
    21 > cmlenz is not happy with this solution because it breaks static file serving over apache. Maybe there are better ways.
    22 
    23 Implementing this is probably not needed if the CSS classes are generic enough and plugins/the trac core just uses them. The actual themes then style those classes.
    24 
    25 == A Theme Provider ==
    26 
    27 The most important part of a theme would be the theme provider. Because trac supports plugins which can add their own css files it's pretty hard to keep a global style without overriding the css files of the plugins too.
    28 
     15== Theme Provider ==
    2916{{{
    3017#!python
    31 class IThemeProvider(Interface):
     18class MyTheme(Component):
     19    implements(IThemeProvider, ITemplateProvider)
    3220
    33     def get_theme_color(name):
    34         """
    35         Return the hexadecimal value for a given name. The actual color
    36         names should be specified on a wiki page in the trac.edgewall.org
    37         wiki so that plugin developers could get informations about the
    38         allowed colors.
     21    # IThemeProvider
     22    def get_theme_htdocs_id(self):
     23        return 'mytheme'
    3924
    40         If a name is not overriden by the theme it has to return a
    41         default color. (for example ``#000000``)
    42         """
     25    def get_theme_site_template(self):
     26        return 'mytheme/site.html'
     27
     28    # ITemplateProvider methods
     29    def get_templates_dirs(self):
     30        from pkg_resources import resource_filename
     31        return [resource_filename(__name__, 'templates')]
     32
     33    def get_htdocs_dirs(self):
     34        from pkg_resources import resource_filename
     35        return [('mytheme', resource_filename(__name__, 'htdocs'))]
    4336}}}
    4437
    45 == site.html ==
    46 At the moment trac instances have a `htdocs/` and a `template/` folder. Both will stay, but the `site.html` in the template folder goes.
     38There will also be a `UserTheme` component class which uses the `site.html` from the trac instance folder and the template/htdocs folder in the instance. It's one of the both default themes:
     39 * `trac` - the trac default theme
     40 * `custom` - a special theme that forwards the htdocs/template lookups to the instance folders and uses the normal `site.html` as template.
    4741
    48 The `site.html` file will be part of a theme. If a theme implements not only the `IThemeProvider` but also the `ITemplateProvider` it can add a `htdocs` and `template` folder to the searchpath. In the latter would now be the `site.html` file.
    49 
    50 As long as the `layout.html` file does not change you can override nearly everything in the `site.html` file by using XPATH:
     42== Themes ==
     43A theme looks like the theme defined above. So this could be the `mytheme/site.html`:
    5144
    5245{{{
     
    5851    <!-- load the default header stuff including the layout and plugin css files -->
    5952    ${select('*')}
    60     <!-- load own css files. not sure if get_css_url would be
    61           possible, maybe use the env stuff -->
    62     <link rel="stylesheet" href="${theme.get_css_url('style.css')}" />
    63     <link rel="stylesheet" href="${theme.get_css_url('print.css')}" media="print" />
     53    <!-- include theme css files -->
     54    <link rel="stylesheet" href="${theme.get_chrome_url('style/style.css')}" />
     55    <link rel="stylesheet" href="${theme.get_chrome_url('style/print.css')}" media="print" />
    6456  </head>
    6557  <body py:match="body">
    66     <!-- here a very complex example -->
    67     <div id="project-content">
    68       <div id="project-header">
    69         <h1>Project Trac</h1>
     58    <!-- normal design used by the project webpage -->
     59    <div id="header">
     60      <h1>Project Trac</h1>
     61    </div>
     62    <div id="navigation">
     63      <li><a href="/">Index</a></li>
     64      <li><a href="/downloads">Downloads</a></li>
     65      <li><a href="/wiki/">Wiki</a></li>
     66      <li class="active"><a href="/trac/">Development</a></li>
     67    </div>
     68
     69    <!-- embbed the trac -->
     70    <div id="body">
     71      <div id="x-trac">
     72        <div class="sidebar">
     73          <!-- combine all three navigation bars into one -->
     74          <ul class="navigation">
     75            <!-- include main navigation -->
     76            ${select('ul[@id="mainnav"]/*')}
     77            <!-- include meta nav -->
     78            ${select('ul[@id="metanav"]/*')}
     79            <!-- include ctx nav -->
     80            ${select('ul[@id="ctxtnav"]/*')}
     81          </ul>
     82            <li>Search
     83              ${select('div[@id="banner"]/form[@id="search"]')}
     84            </li>
     85          </ul>
     86          <!-- search box -->
     87          ${select('form[@id="search"]')}
     88        </div>
     89        <div class="trac-body">
     90          ${select('div[@id="main"]/*')}
     91        </div>
    7092      </div>
    71       <div id="project-sidebar">
    72         <!-- combine all three navigation bars into one -->
    73         <ul><li><ul>
    74           <!-- include main navigation -->
    75           ${select('div[@id="mainnav"]/ul/*')}
    76           <li><a href="http://www.example.org/">Project Webpage</a></ul></li>
    77           <li>User<ul>
    78             ${select('div[@id="metanav"]/ul/*')}
    79           </ul></li>
    80           <!-- this is a bit hackish, there should be a nicer way for it -->
    81           <li py:if="unicode(select('div[@id=\'main\']/div[@id=\'ctxtnav\']/ul/*'))">
    82             Actions<ul>
    83             ${select('div[@id="main"]/div[@id="ctxtnav"]/ul/*')}
    84           </ul></li>
    85           <li>Search
    86             ${select('div[@id="banner"]/form[@id="search"]')}
    87           </li>
    88         </ul>
    89       </div>
    90       <div id="project-body">
    91         <!-- include trac body output -->
    92         ${select('div[@id="main"]/*[@id!="ctxtnav"]')}
    93       </div>
    94       <div id="project-footer">
    95         <a href="http://www.example.org/">Project</a> is open source software licensed
    96         under the <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>,
    97         development page powered by <a href="http://trac.edgewall.org/">Trac</a>.
    98       </div>
     93    </div>
     94
     95    <!-- project webpage footer -->
     96    <div id="footer">
     97      <a href="http://www.example.org/">Project</a> is open source software licensed
     98      under the <a href="http://www.gnu.org/copyleft/gpl.html">GPL</a>,
     99      development page powered by <a href="http://trac.edgewall.org/">Trac</a>.
    99100    </div>
    100101  </body>
     
    102103}}}
    103104
    104 That of course requires that the `layout.html` and css classes/ids don't change after a trac update.
     105As you can see the idea is that the default layout.html does not include *any* style elements. It just wraps the content elements in divs and uls. (navigation bars, content etc). The default css files have all their rules prefixed with `#x-trac` in order to avoid clashes with included css files from project webpages. The idea is that you just have to add a div with the idea `#x-trac` where the trac should appear, select everything there and there you go. Additionally you can of course as shown above, move the navigation bars around thanks to the ass-kicking genshi xpath support.
     106
     107`theme.get_chrome_url()` creates an url to the chrome folder of the current theme.