--- I have extended the starter layout with advanced topics, especially the sorter, grouper and tagger plugins. Content is updated. Navigation, code styling and text readability are improved.main
| @@ -154,7 +154,7 @@ class TaggerPlugin(Plugin): | |||
| if not 'template' in config: | |||
| raise self.template.exception_class( | |||
| "No Template sepecified in tagger configuration.") | |||
| "No Template specified in tagger configuration.") | |||
| source = content.node_from_relative_path(config.get('source', '')) | |||
| target = self.site.config.deploy_root_path.child_folder( | |||
| config.get('target', 'tags')) | |||
| @@ -0,0 +1,49 @@ | |||
| --- | |||
| index: 3 | |||
| title_ending: "| Grouping" | |||
| tags: | |||
| - sort | |||
| - group | |||
| learning_order: 2 | |||
| --- | |||
| Grouping | |||
| ======== | |||
| Content is very often grouped by theme, size, location or any other | |||
| conceivable measure. Groups can be traversed in a few ways in Hyde, and | |||
| [sorted](sorter.html) at the same time. Here are two common ways: | |||
| Walking all groups and subgroups | |||
| -------------------------------- | |||
| {# Resources are sorted by defining a sorter in the configuration file. #} | |||
| {% for grp, res_walker in site.content.walk_level_groups() %} | |||
| *{{ grp.description }}* | |||
| {% for res in res_walker %} | |||
| * [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) \ | |||
| ({{ res.name }}) | |||
| {% endfor %} | |||
| {% endfor %} | |||
| {# The above code layout is not arbitrary. Remember that we're building | |||
| a Markdown page so every space or line ending has a purpose. | |||
| #} | |||
| Listing only the specific (sub)group | |||
| ------------------------------------ | |||
| {% for res in site.content.walk_resources_grouped_by_advanced() %} | |||
| * [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) \ | |||
| ({{ res.name }}) | |||
| {% endfor %} | |||
| {# You can also call the top level group "level" to get all resources that | |||
| are in the group. Or you can list all resources of the same group in the | |||
| current node with "resource.node.walk_resource_grouped_by_advanced()". | |||
| #} | |||
| {{ macros.render_bottom_article_nav() }} | |||
| @@ -0,0 +1,3 @@ | |||
| extends: base.j2 | |||
| default_block: content | |||
| level: advanced | |||
| @@ -0,0 +1,44 @@ | |||
| --- | |||
| index: 1 | |||
| title_ending: "| Advanced topics" | |||
| tags: | |||
| - sort | |||
| - group | |||
| - tag | |||
| learning_order: 4 | |||
| --- | |||
| More advanced topics | |||
| ==================== | |||
| If you have read and understood all basic topics covered in | |||
| {% for res in site.content.walk_resources_grouped_by_basic()|reverse %} | |||
| [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) | |||
| {% endfor %} | |||
| then you are ready for some more advanced features. They are explained in | |||
| the same way as the basic part, building on the knowledge of the previous, | |||
| so it is recommended that you follow them in the listed order. | |||
| {# List all resources from a group, sort them by index and list their tags. #} | |||
| {% for res in resource.node.walk_resources_sorted_by_learning_order() %} | |||
| {{ loop.index }}. \ | |||
| [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) \ | |||
| {% if res.name == "overview.html" %}*(this file)*{% endif %} \ | |||
| {# | |||
| Sometimes you'll have to add HTML tags to a Markdown file for styling | |||
| or adding some special features, and Markdown is OK with that. | |||
| #} | |||
| <span class="tags">tags: | |||
| {% for tag in res.meta.tags %} | |||
| {# | |||
| After wring the tag name, check if that is the last tag in the list. If | |||
| it is, don't append the comma at the end. | |||
| #} | |||
| {{ tag }}{% if tag != res.meta.tags[-1] %},{% endif %} | |||
| {% endfor %} | |||
| </span> | |||
| {% endfor %} | |||
| {{ macros.render_bottom_article_nav() }} | |||
| @@ -0,0 +1,53 @@ | |||
| --- | |||
| index: 2 | |||
| title_ending: "| Sorting" | |||
| tags: | |||
| - sort | |||
| learning_order: 1 | |||
| --- | |||
| Sorting | |||
| ======= | |||
| There will come a time when you will need to list and sort resources. Hyde | |||
| allows you to walk the site tree and sort the resources by the predefined | |||
| settings in your configuration file. | |||
| You can list and sort by name all your content files. | |||
| {# With every sorter defined in the configuration file, nodes get a method | |||
| to call. Notice that in the first and last example the method is called | |||
| on the whole content of the site, while the second example shows how to | |||
| invoke it only on one specific node (in this case the current one). | |||
| Also, some new Jinja filters were used to style the output. | |||
| #} | |||
| {% for res in site.content.walk_resources_sorted_by_name() %} | |||
| * [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) \ | |||
| ({{ res.name }}) | |||
| {% endfor %} | |||
| Or list only those in the current node (folder). In this case that would be | |||
| all advanced topics. | |||
| {# Have in mind that using the next example in a content page (like here) or | |||
| using it in a layout (Jinja template that is extended or include by | |||
| content pages) will yield very different results. | |||
| In this case it will be called only once, for this resource, and shown | |||
| only on this page. If it was in a layout, it would be called for EVERY | |||
| resource that uses that layout. In that case the context would be | |||
| different, the parent node of the resource could be different and the | |||
| results will probably be different too. | |||
| #} | |||
| {% for res in resource.node.walk_resources_sorted_by_index() %} | |||
| {{ loop.index }}. [{{ res.slug|capitalize }}]({{ res.full_url }}) | |||
| {% endfor %} | |||
| Or sort files by type and then by size. | |||
| {% for res in site.content.walk_resources_sorted_by_file_type() %} | |||
| * [{{ res.source_file.kind|upper }}] {{ res.name }} | |||
| {% endfor %} | |||
| {{ macros.render_bottom_article_nav() }} | |||
| @@ -0,0 +1,51 @@ | |||
| --- | |||
| index: 4 | |||
| title_ending: "| Tagging" | |||
| tags: | |||
| - sort | |||
| - tag | |||
| learning_order: 3 | |||
| --- | |||
| Tagging | |||
| ======= | |||
| It seems that human beings want to tag everything. You can do it with | |||
| Hyde also. In this example **tags** are used to represent technologies | |||
| used to build a particular advanced page. So you can see that the | |||
| **sorting** was needed for all advanced topics, but **grouping** was | |||
| used only for overview and grouping pages. | |||
| Listing by tags | |||
| --------------- | |||
| {# You can grab the list of all tags ... #} | |||
| {% for tag, meta in site.tagger.tags %} | |||
| *{{ tag }}* | |||
| {# ... and get all resurces tagged with that node. #} | |||
| {% for res in resource.node.walk_resources_tagged_with(tag) %} | |||
| * [{{ res.slug|capitalize|replace("-"," ") }}]({{ res.full_url }}) \ | |||
| ({{ res.name }}) | |||
| {% endfor %} | |||
| {% endfor %} | |||
| {# Another way to walk through resources tagged with a specific tag is | |||
| to use a method that contains that tag's name. | |||
| {% for res in resource.node.walk_resources_tagged_with_sort() %} | |||
| {% endfor %} | |||
| #} | |||
| Tag combination | |||
| --------------- | |||
| You can also search for combination of tags. If you search for a | |||
| resource that has **sort**, **tag** and **group** tags, only an | |||
| {% for res in resource.node.walk_resources_tagged_with('sort+tag+group') -%} | |||
| [{{ res.slug }}]({{ res.full_url }}) | |||
| {%- endfor %} | |||
| will be returned. | |||
| {{ macros.render_bottom_article_nav() }} | |||
| @@ -1,6 +1,6 @@ | |||
| --- | |||
| extends: base.j2 | |||
| title_ending: "| What next" | |||
| title_ending: "| First steps" | |||
| --- | |||
| {# In-file metadata. Supplements data from the site's configuration file | |||
| and node (folder) level data in "meta.yaml" files. | |||
| @@ -11,8 +11,8 @@ title_ending: "| What next" | |||
| #} | |||
| {% block content %} | |||
| There and back again | |||
| ==================== | |||
| Walk this way if you're a beginner | |||
| ================================== | |||
| This template was created to look at its code. So you should spend about | |||
| 5% of your time looking at the web from the outside and the other 95% | |||
| @@ -29,24 +29,24 @@ previous one. | |||
| ---------------------------------------- | |||
| The site is made of two folders and a [Hyde configuration][hyde_config] | |||
| file. The folders are _content_ and _layout_. | |||
| file. The folders are **content** and **layout**. | |||
| _content_ contains all your page content, blog articles, pictures and | |||
| **content** contains all your page content, blog articles, pictures and | |||
| resources like CSS and JavaScript. Everything that is unique is here. | |||
| _layout_ contains templates and macros. Everything that you'll want to | |||
| **layout** contains templates and macros. Everything that you'll want to | |||
| reuse is here. | |||
| 2. Jinja2 template | |||
| ------------------ | |||
| _base.j2_ is a very short and simple Jinja2 template. This way you can | |||
| **base.j2** is a very short and simple Jinja2 template. This way you can | |||
| concentrate on some of the basic features. Notice meta and context | |||
| variables invocation inside curly braces, dynamic media path generation | |||
| and running all content through the Markdown filter. | |||
| _macros.j2_ contains a macro for generating the main menu. | |||
| **macros.j2** contains macros for common and repetitive tasks. | |||
| For more information or to try something new, visit the extensive [Jinja2 | |||
| documentation][jinja2_docs]. | |||
| @@ -55,19 +55,31 @@ documentation][jinja2_docs]. | |||
| 3. Content | |||
| ---------- | |||
| Look at the three files in this order: _index.html_, _what-next.html_ | |||
| and _about.html_. | |||
| Look at the three files in this order: [index.html](index.html), | |||
| [first-steps.html](first-steps.html) and [about.html](about.html). | |||
| _Index_ extends the base layout in the classic Jinja way and fills the | |||
| content block with some simple Markdown data. | |||
| [Index](index.html) extends the base layout in the classic Jinja way and | |||
| fills the content block with some simple Markdown data. | |||
| _What next_ goes a step furher. It introduces the in-file metadata that | |||
| plugins will use to extend and fill the layout. It also uses some new | |||
| Markdown features. | |||
| [First steps](first-steps.html) goes a step furher. It introduces the | |||
| in-file metadata that plugins will use to extend and fill the layout. It | |||
| also uses some new Markdown features. | |||
| _About_ has a _default_block_ metadata and mixes Markdown content with | |||
| Jinja templates. | |||
| [About](about.html) has a **default_block** metadata and mixes Markdown | |||
| content with Jinja templates. | |||
| [hyde_config]: http://hyde.github.com/config.html "Hyde configuration" | |||
| [jinja2_docs]: http://jinja.pocoo.org/docs/templates/ "Jinja2 documentation" | |||
| 4. Advanced sections | |||
| -------------------- | |||
| While searching and navigating this template you'll find more files and | |||
| sections than mentioned on this page (something like **meta.yaml** | |||
| files, the **content/advanced** folder or other Jinja templates). They | |||
| are files needed for the [advanced topics](advanced/overview.html) so | |||
| just ignore them at the beginning. They will start to make sense while | |||
| you're working through the template or will be explicitly explained when | |||
| the right time comes. | |||
| {% endblock %} | |||
| @@ -18,4 +18,6 @@ technologies step by step. Those are: | |||
| * Jinja templates | |||
| * Markdown | |||
| * basic metadata and plugins | |||
| Are you ready for your [first steps](first-steps.html)? | |||
| {% endblock %} | |||
| @@ -4,7 +4,7 @@ | |||
| } | |||
| html, body { | |||
| color: #fafafa; | |||
| color: #ddd; | |||
| background-color: black; | |||
| } | |||
| @@ -20,6 +20,10 @@ body { | |||
| font-family: Tahoma, sans-serif; | |||
| } | |||
| strong { | |||
| color: white; | |||
| } | |||
| a { | |||
| color: #f1ee00; | |||
| } | |||
| @@ -28,11 +32,11 @@ a:hover, a:focus { | |||
| text-decoration: none; | |||
| } | |||
| p, ul { | |||
| p, ul, ol { | |||
| margin-bottom: 1.6em; | |||
| } | |||
| ul { | |||
| ul, ol { | |||
| margin-left: 2em; | |||
| } | |||
| @@ -49,6 +53,7 @@ header h1 { | |||
| font-size: 50px; | |||
| font-weight: normal; | |||
| text-shadow: -1px 2px 1px black; | |||
| color: white; | |||
| } | |||
| header h1 span { | |||
| @@ -60,13 +65,14 @@ header h2 { | |||
| font-weight: normal; | |||
| letter-spacing: 11px; | |||
| text-shadow: -1px 2px 1px black; | |||
| color: white; | |||
| } | |||
| nav { | |||
| position: absolute; | |||
| top: 340px; | |||
| right: 120px; | |||
| width: 200px; | |||
| width: 250px; | |||
| text-align: right; | |||
| font-family: Anton, Tahoma, sans-serif; | |||
| } | |||
| @@ -74,7 +80,7 @@ nav { | |||
| nav a, | |||
| nav a:visited { | |||
| text-decoration: none; | |||
| color: #fafafa; | |||
| color: white; | |||
| text-transform: uppercase; | |||
| font-size: 2.8em; | |||
| } | |||
| @@ -121,6 +127,7 @@ nav, aside { | |||
| font-family: Anton, Tahoma, sans-serif; | |||
| text-transform: uppercase; | |||
| margin-bottom: 0.8em; | |||
| color: white; | |||
| } | |||
| #content h2 { | |||
| @@ -128,6 +135,8 @@ nav, aside { | |||
| font-size: 1.2em; | |||
| font-family: Tahoma, sans-serif; | |||
| margin-bottom: 1.33em; | |||
| color: white; | |||
| border-bottom: 1px dashed #888; | |||
| } | |||
| #content code { | |||
| @@ -142,3 +151,19 @@ nav, aside { | |||
| border-bottom: 1px solid #222; | |||
| border-left: 1px solid #111; | |||
| } | |||
| #content .tags { | |||
| font-size: 0.8em; | |||
| color: #888; | |||
| } | |||
| #content .bottom_article_nav { | |||
| border-top: 1px dashed #888; | |||
| overflow: hidden; | |||
| margin-top: 40px; | |||
| padding-top: 10px; | |||
| } | |||
| #content .bottom_article_nav .next { | |||
| float: right; | |||
| } | |||
| @@ -0,0 +1,2 @@ | |||
| level: basic | |||
| @@ -22,8 +22,8 @@ | |||
| way it can be used to generate the list many times, in | |||
| a footer, etc. | |||
| #} | |||
| {% from "macros.j2" import render_main_menu with context %} | |||
| {{ render_main_menu() }} | |||
| {% import "macros.j2" as macros with context %} | |||
| {{ macros.render_main_menu() }} | |||
| </nav> | |||
| <article id="content"> | |||
| {# Main content block. Notice it has to pass through the | |||
| @@ -38,5 +38,15 @@ | |||
| <p>Created by <a href="{{ author.url}}">{{ author.name}}</a> | |||
| for <a href="{{ project.url }}">{{ project.name }}</a></p> | |||
| </aside> | |||
| {# Some parts of the web are not needed for development and can | |||
| wait for production (ex. analytics). They can be included in | |||
| the final production build. Create a new config file, extend | |||
| the original one and override the "mode" property; then build | |||
| the site with the new "production configuration". | |||
| #} | |||
| {% if site.config.mode == "production" -%} | |||
| {% include "ga.j2" %} | |||
| {%- endif %} | |||
| </body> | |||
| </html> | |||
| @@ -0,0 +1,13 @@ | |||
| <script type="text/javascript"> | |||
| var _gaq = _gaq || []; | |||
| _gaq.push(['_setAccount', '{{ site.meta.ga_tracking_code }}']); | |||
| _gaq.push(['_trackPageview']); | |||
| (function() { | |||
| var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true; | |||
| ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js'; | |||
| var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s); | |||
| })(); | |||
| </script> | |||
| @@ -1,7 +1,35 @@ | |||
| {% macro render_main_menu() -%} | |||
| {# Set menu item selected if the current resource matches the item in the | |||
| site's config file or set "Advanced topics" selected for any resources | |||
| that have the "advanced" folder as their parent. | |||
| #} | |||
| <ul> | |||
| {% for menu_item in menu -%} | |||
| <li><a {% if menu_item.url == resource.url %}class="selected"{% endif %} href="{{ menu_item.url }}">{{ menu_item.title }}</a></li> | |||
| <li><a {% if (menu_item.url == resource.full_url) or | |||
| (menu_item.title == "Advanced topics" | |||
| and resource.node.name == "advanced") | |||
| %}class="selected"{% endif %} | |||
| href="{{ menu_item.url }}">{{ menu_item.title }}</a></li> | |||
| {%- endfor %} | |||
| </ul> | |||
| {%- endmacro %} | |||
| {# Advanced topics macro. Renders navigation at the end of the article. #} | |||
| {% macro render_bottom_article_nav() %} | |||
| <div class="bottom_article_nav"> | |||
| {% if resource.next_by_index is not none -%} | |||
| <div class="next"><a href="{{ resource.next_by_index.full_url }}"> | |||
| {{ resource.next_by_index.meta.title_ending|replace("| ", "") }}</a> | |||
| ></div> | |||
| {%- endif %} | |||
| {% if resource.prev_by_index is not none -%} | |||
| <div class="prev">< <a href="{{ resource.prev_by_index.full_url }}"> | |||
| {{ resource.prev_by_index.meta.title_ending|replace("| ", "") }}</a> | |||
| </div> | |||
| {%- endif %} | |||
| </div> | |||
| {% endmacro %} | |||
| @@ -1,11 +1,14 @@ | |||
| mode: learning | |||
| media_root: media | |||
| media_url: media # will use relative path, prepend "/" for absolute path | |||
| media_url: /media | |||
| template: hyde.ext.templates.jinja.Jinja2Template | |||
| plugins: | |||
| - hyde.ext.plugins.meta.MetaPlugin | |||
| - hyde.ext.plugins.auto_extend.AutoExtendPlugin | |||
| - hyde.ext.plugins.syntext.SyntextPlugin | |||
| # Plugins needed for the advances section. | |||
| - hyde.ext.plugins.sorter.SorterPlugin | |||
| - hyde.ext.plugins.grouper.GrouperPlugin | |||
| - hyde.ext.plugins.tagger.TaggerPlugin | |||
| context: | |||
| data: | |||
| author: | |||
| @@ -20,8 +23,66 @@ context: | |||
| install: "http://hyde.github.com/install.html" | |||
| menu: | |||
| - title: Home | |||
| url: index.html | |||
| - title: What next | |||
| url: what-next.html | |||
| url: /index.html | |||
| - title: First steps | |||
| url: /first-steps.html | |||
| - title: Advanced topics | |||
| url: /advanced/overview.html | |||
| - title: About | |||
| url: about.html | |||
| url: /about.html | |||
| ### Advanced part ### | |||
| # This defines meta data on the whole site. | |||
| meta: | |||
| # 'nodemeta' will tell Hyde what file to look for inside a folder from | |||
| # which to apply meta data to all files (resources) inside it. This is | |||
| # a great way of simply adding or modifying properties of a very large | |||
| # number of files. | |||
| nodemeta: meta.yaml | |||
| ga_tracking_code: XX-XXXXXXXX-X | |||
| sorter: | |||
| name: # the name of the sorter (no pun intended) | |||
| attr: name # by which attributes will resources be sorted | |||
| filters: | |||
| source_file.kind: html | |||
| # You can include only files from a certain folder. | |||
| #resource.node: (name of the folder) | |||
| #reverse: True # if you need the list backwards | |||
| file_type: | |||
| attr: | |||
| - source_file.kind | |||
| - source_file.size | |||
| index: | |||
| attr: meta.index | |||
| filters: | |||
| source_file.kind: html | |||
| learning_order: | |||
| attr: meta.learning_order | |||
| filters: | |||
| source_file.kind: html | |||
| grouper: | |||
| level: | |||
| sorter: name | |||
| description: Difficulty levels | |||
| groups: | |||
| - name: basic | |||
| description: Basic | |||
| - name: advanced | |||
| description: Advanced | |||
| # You can have more than one group section, depending on your needs. | |||
| # For example: "categories", "menu sections", etc. | |||
| #category: | |||
| # description: To which category a blog post belongs to. | |||
| # groups: | |||
| # - name: software | |||
| # description: Software engineering | |||
| # - name: web | |||
| # description: Web technologies | |||
| # - name: seo | |||
| # description: Search Engine Optimization | |||
| tagger: | |||
| sorter: name | |||