By Tim Sutton and QGIS Contributors.
This web site is a static site built using Hugo.
If you want to understand Hugo and the other technologies we used to build this site, there is some recommended reading for you below:
-
Read this article on templates if you are looking to understand how templates work.
-
Read this article on hugo pipes, minifying content etc.
-
Read this article to see how you can use Hugo variables in your SCSS.
-
Read this article to see the general process of customizing bulma with SASS. Note that in addition to this workflow, we also generate our SASS primary file (bulma.sass) from a Hugo template.
-
This theme uses the Bulma CSS framework, which you should familiarise yourself with if you want to change the theme.
-
View the website design QGIS website figma
-
The relationship between some of the key concepts in Hugo is shown below:
The following key skills are needed for theme developers (DEV) and content creators (CC):
Term | Description |
---|---|
content | Top level folder for your user created web site content |
section | Any subfolder of content containing an _index.md file. e.g. the section content/about/ would have within it a file called content/about/_index.md making it a section and resolvable at the URL https://your domain/about/ . |
nested section | As above, creating a subsection, for example content/about/staff/_index.md . Note that if the subsection contains only a single page, it will will be navigable as a page at e.g. https://your domain/about/staff/ |
section template | By default a section with nested subfolders of content will render as a list. If you want to customize the section (i.e. not render as a list) you can make a section template in layouts/-section name-/section.html |
The QGIS.org web site receives a lot of traffic so our website is designed to be fast, privacy respecting and open source, like the rest of QGIS.
- ๐จ Fast: all pages are statically generated, there is no database, no bulky javascript or CSS frameworks etc.
- ๐ Privacy respecting: as much as possible we avoid things that can be used to track you - no resources loaded from other web sites, no cookies, no trackers, no sessions etc.
- ๐๏ธOpen source: This repository is covered by two licenses:
- The HUGO Project and QGIS theme provided here are published under a permissive ๐ MIT License.
- The actual content of the web site is ยฉ QGIS.ORG amd Contributors and is made available under the Creative Commons-NonCommercial-Share-Alike-4.0 license. We chose this license to prevent third parties from hosting their own, possibly maliciously altered versions of the QGIS.org web site.
๐ A quick acknowledgement: The starting point for this site was the web site created by the community around jupiterbroadcasting.com . you can find their GitHub Repo here - although we have made so many changes, there probably isn't much left of the site we derived from in this repo.
Navigate to your development directory
git clone https://github.com/qgis/qgis-hugo.git
First install hugo for your local machine:
๐ Note: we need to install the 'extended' hugo version which includes a SASS compiler. If you don't install the extended version you will get errors like this when compiling:
ERROR 2022/12/11 07:33:37 Rebuild failed: TOCSS: failed to transform
"css/style.scss" (text/x-scss). Check your Hugo installation; you need
the extended version to build SCSS/SASS.: this feature is not available
in your current Hugo version, see https://goo.gl/YMrWcn for more information
You can find the extended version in the releases page.
Download the deb above and then do
sudo dpkg -i hugo_extended_0.107.0_linux-amd64.deb
If you are using VSCode, I recommend the following extensions:
- Hugo Language and Syntax Support
- Color Highlight
Clone the repo:
git clone https://github.com/qgis/qgis-hugo.git
Run the site:
Press Ctl-Shift-D
then choose the following runner:
'Run dev using locally installed Hugo'
the click the green triangle next to the runner to start it.
Once the site is running, you can open it at:
The site will automatically refresh any page you have open if you edit it and save your work. Magical eh?
Test files are located in test/e2e
.
You need to have these extras installed:
pip install pytest pytest-base-url playwright
These tests exist to make sure code changes to this repository do not break how the site currently functions. They are intended to run on each commit to verify the site is working in expected order.
Read more on testing here.
- Navigate to the e2e test folder which is located in
test/e2e
. - Create or edit a test file for the page or section you want to test and get coding, test files should start with the name test follow by the file name, example
test_about_page.py
.
We can enable built in pytest support in VSCode.
Note: Before running the tests, you need to install the dependencies listed in REQUIREMENTS.txt:
pip install -r REQUIREMENTS.txt
And playwright:
pip install playwright
These should be set up by default when you open this project under VSCode, but if needed you can configure the VSCode settings to set the base-url (search for @id:python.testing.pytestArgs Testing in the settings filter):
Start the live debug server:
Now open the test explorer and run your tests:
Any failed tests will be marked in red as shown above.
pytest --base-url=http://localhost:1313
- Start the hugo server in a terminal window
make dev
. - Run test in terminal window
make tests
Note: To run the tests as described above, you need to have docker installed on your machine and the appropriate permissions to run docker commands.
There is a github action that will run the tests automatically on PR submission, merge.
See .github/workflows/e2e.yml
You can harvest data from various feeds using the fetch_feeds.py script. By default flickr harvesting is disabled in this script so run it manually and review the content to see if it is suitable for publication on our site.
./fetch_feeds.py --flickr=yes
This script is run nightly as a github action (see .github/workflows/update-feeds.yml).
The search functionality uses both FuseJS and MarkJS.
The search functionality code is based on this Blog Post and GitHub Gist by Eddie Webb.
Content folders need to be excluded from search, by making them headless bundles - which we have done for the sustaining member and flagship user folders in content/. To make other content folders which are not rendered and included in search results, add an index.md
file with the following content: headless = true
.
The site needs to work in production, where the links of the site are all below the root URL, and in staging, where the site is deployed to GitHub pages in a subpath. To ensure both deployment strategies work, please use the following method of constructing URLs in templates.
<a class="button is-primary" href="{{ "donate/" | absURL }}">
Note: We do not use a leading slash, only an ending slash.
- Separate words in file names with hyphens e.g. windows-download.md
- Avoid abbreviations in the words of your files
- Write file names in lower case only
- No spaces in file names
We welcome your contributions! All contributors are expected to sign a contributor license agreement (CLA) which you can see here. This process is automatically enabled when you create your first pull request via https://cla-assistant.io/.
Page type | Path |
---|---|
Landing Page | themes/qgis/layouts/index.html |
Top Level Pages | themes/qgis/layouts/_default/single.html |
The content/_index.md
is the content for the landing page. Just edit whatever you like there. The blocks shortcodes are described below.
Content pages are stored in the content
folder. The top level documents there will be rendered with the top level page theming.
For example to add an about page, create content/about.md
The page will be accessible then at /about/
Place images and media in static/img
. Everything in static
is referenced
from the top level of the site e.g. static/img/foo.png
would be referenced in
markdown as /img/foo.png
.
There are two menus, the primary (1) menu which appears at the top of the page, and the secondary menu (2) which may appear beneath it depending on context.
For pages to appear in the top menu, you need to add an entry to
config.toml
for example the menu for the above about page will be:
[[menu.main]]
name = "About"
url = "/about/"
weight = -110
# pre = "<i class='fa-solid fa-clipboard-question mr-1'></i>"
Note: The pre
item is commented out. If you uncomment it, it will place a font awesome icon before the text of the menu item.
For pages to appear in the secondary menu, you need to add an entry to
config.toml
for example the menu for the documentation page will be:
[[menu.learning]]
name = "Documentation"
url = "/documentation/documentation-overview/"
weight = -110
#pre = "<i class='fa-solid fa-clipboard-question mr-1'></i>"
[menu.learning.params]
submenu = "documentation"
Use the submenu
parameter to define which submenu the menu entry should be shown in. You can create as many submenu terms as you like, and then associate pages to these submenus in the front matter of your markdown documents.
In order for a secondary menu to be displayed, your content page needs to specify the submenu name in the front matter e.g.:
Example front matter listing:
---
type: "page"
title: "Documentation Overview"
subtitle: "QGIS Documentation Resources"
draft: false
heroImage: "img/banners/banner2.png"
submenus: documentation
---
Note: Despite the pluralised name, you should only specify one submenu name.
All of the menu entries specified in config.toml with a matching submenus term will be shown in the secondary menu when you add this to the front matter. If you specify no submenus= entry in the front matter, the secondary menu will not be rendered.
The primary menu template is implemented in themes/qgis/layouts/partials/menu.html
.
The secondary menu template is implemented in themes/qgis/layouts/partials/submenu.html
.
Note: You typically will not need to edit the above files unless you are a developer.
Blocks span the page from left to right and contain sub elements for title, description, link etc.
Blocks are defined in themes/qgis/layouts/shortcodes/block
. To use a block, simply add it to your markdown as per this example:
{{< block
title="Block with more content"
subtitle="Unleash your creativity and experience first
class cartographic design capabilities and design great
maps for digital and print. "
>}}
If you want to include markdown content inside the block you can do it as inner content like this:
{{< block
title="Block with more content"
subtitle="Unleash your creativity and experience first
class cartographic design capabilities and design great
maps for digital and print. "
>}}
More details khdkjhksj dhjfhs dkj hsfdjkh fsd
{{< /block >}}
The options for a block are:
Name | Description |
---|---|
title | Title for the block |
subtitle | Subtitled for the block |
link | Optional: URL to have a link to at the bottom left of the block |
link-text | Mandatory if link provided: Text to show with the hyperlink. |
link-class | Optional and only used if link provided: Bulma class (e.g. is-primary) for the link button. |
class | defaults to is-primary. Use this to set the bulma class for the block. |
animate | defaults to false. Experimental support for animating blocks into place as they enter the viewport. |
sub-block-side | defaults to 'cover'. Choose which side (left, right) or cover. Use cover to span the content across the whole block. If an image is set, the image will cover the block or be placed left or right as indicated here. |
image | optional. Place your images into the same folder as the markdown file (so that they are 'bundle resources in hugo terminology') and then reference by the file name only e.g. "some-image.png". |
Note: Do not include a leading slash in the image path!
We carry over the idea of boxes and columns from bulma. They can be used to arrange content in a side by side fashion or a grid of content boxes.
First a simple example:
{{< columns-start >}}
{{< column-start >}}
{{< box-start >}}
# Box 1
Normal markdown text....
{{< box-end >}}
{{< box-start >}}
# Box 2
Normal markdown text....
{{< box-end >}}
{{< column-end >}}
{{< columns-end >}}
Will render like this:
To render the blocks side by side, we can make a small tweak like this:
{{< columns-start >}}
{{< column-start>}}
{{< box-start >}}
# Box 1
Normal markdown text....
{{< box-end >}}
{{< column-end >}}
{{< column-start>}}
{{< box-start >}}
# Box 2
Normal markdown text....
{{< box-end >}}
{{< column-end >}}
{{< columns-end >}}
Above you can see we close each column before setting the nextWill render like this:
One last column arrangement example shows how we can use the bulma column sizes to define specific column sizes:
{{< columns-start >}}
{{< column-start class="is-one-third">}}
{{< box-start >}}
# Box 1
Normal markdown text....
{{< box-end >}}
{{< column-end >}}
{{< column-start class="is-two-thirds">}}
{{< box-start >}}
# Box 2
Normal markdown text....
{{< box-end >}}
{{< column-end >}}
{{< columns-end >}}
Above you can see we use the is-one-third / is-two-thirds classes on each column so they render like this:
The content you write within boxes can be normal markdown and can use any of the shortcode components described in this readme. Here is an example from the download page showing a QR code block and a content card side by side in the grid.
Before starting your markdown content, start a card using the box-start
shortcode so it lays out nicely in our grid:
{{< box-start >}}
This is the all-in-one stable release installer. The software
you receive with the free download link and the download and
donate link is identical. For other Windows installer variants
see here.
A box-start
shortcode can take the following parameters:
Name | Description |
---|---|
header | A short piece of text to display in the card header |
classes | (Optional) Any bulma classes you want to have applied to the internal content section of the card. |
ribbon | A word or two to display at the top left of the box. |
ribbon-classes | A bulma class such as is-primary to set the style of the ribbon. See also the Bulma Ribbon page for other modifier classes that can be used. |
Here is an example of a box with ribbon set:
{{< box-start ribbon="Note!" ribbon-class="is-success">}}
Acceptance of sustaining members shall be subject to the discretion and approval of The Board,
who reserve the right to accept or reject applications for sustaining membership and
ongoing support memberships as deemed appropriate.
{{< box-end >}}
When you are done writing your content, end a box using the box-end
shortcode:
{{< box-end >}}
A box-end
shortcode takes no parameters:
The image shortcode can be used to place an image on the page occupying the same amount of space as a block:
Sample useage:
{{< image
image="soufriere.png"
>}}
If you prefer, you can supply a GIF and it will display animated. The image will be anchored to the left top of the block and then cropped according to the block dimensions.
There is a special option whereby you can combine both a static image preview and an animated GIF that will be visible when you mouse over the image. To do this you need to have two images, a PNG image and an GIF image. Typically you might record the GIF using an application like Peek. Once you have a GIF, you can extract the first frame like this (using ImageMagick):
convert 'image.gif[0]' image.png
To include the mouse over version, add an image element referencing the PNG, and then add gif=true as a parameter:
{{< image
image="soufriere.png"
gif=true
>}}
Note: The image names must have the same base name and you must use PNG and GIF images.
If you are writing plain markdown, you can also wrap it in content shortcodes (instead of the card shortcode described above) like this:
{{< content-start classes="notification is-light" >}}
# Markdown header
Markdown content
{{< content-end >}}
Name | Description |
---|---|
classes | (Optional) Any bulma classes you want to have applied to the internal content section of the card. |
The button
shortcode is a way to put a single button link element onto your page:
{{< button
fullwidth = "true"
icon = "fa-solid fa-calendar"
class = "is-success"
link = "showcase/user-group-events"
text = "User Group News" >}}
Note: We do not use a leading slash for internal links, only an ending slash. If you want the link to open in a new tab, start the link with https: or mailto:
The info-bar
shortcode is a way to put a infographic style element onto your page:
{{< info-bar
"20+:years"
"100%:open source"
"450k+:Daily users" >}}
To use info-bar, pass it a collection of key-value pairs separated by :
colons as
illustrated above.
The info-icons
shortcode is a way to put a row of circular fontawesome icon elements onto your page:
{{< info-icons
"Linux:fa-brands fa-linux"
"macOS:fa-brands fa-apple"
"Windows:fa-brands fa-windows" >}}
To use icon-bar, pass it a collection of key-value pairs separated by :
colons as illustrated above. The second value should be a fontawesome image name.
The image-bar
shortcode is a way to put a row of circular image elements onto your page:
{{< image-bar
"Cartography:/img/map1.png"
"Analysis:/img/map2.png"
"Print:/img/map3.png" >}}
To use image-bar, pass it a collection of key-value pairs separated by :
colons as
illustrated above. The second value should be a path to an image.
The button-bar
shortcode is a way to put a row of button link elements onto your page:
{{< button-bar
"fa-brands fa-windows mr-1:Windows:downloads/windows/"
"fa-brands fa-apple mr-1:macOS:downloads/macos/"
"fa-brands fa-linux mr-1:Linux:downloads/linux/"
>}}
Note: We do not use a leading slash for internal links, only an ending slash. If you want the link to open in a new tab, start the link with https: or mailto:
To use button-bar, pass it a collection of key-value triplets separated by :
colons as
illustrated above.
- The first value should be a fontawesome image name.
- The second value should be the label for the button.
- The third value should be the link that clicking the button will lead to.
You can add as many buttons as you like to the bar, and they will be distributed evenly across the page.
The steps-bar
shortcode is a way to put a row of steps onto your page:
{{< steps-bar
"fa-solid fa-hand-holding-heart:Choose if you want to support the project:true"
"fa-sharp fa-solid fa-solar-system:Choose your operating system:false"
"fa-solid fa-download:Download:false"
>}}
To use steps-bar, pass it a collection of key-value triplets separated by :
colons as
illustrated above.
- The first value should be a fontawesome image name.
- The second value should be the label for the step.
- The third value should be true or false indicating which step is active.
You can add as many steps as you like to the bar, and they will be distributed evenly across the page.
{{< image-bar
"Cartography:map1.png"
"Analysis:map1.png"
"Print:map1.png" >}}
{{< info-icons
"Linux:fa-brands fa-linux"
"macOS:fa-brands fa-apple"
"Windows:fa-brands fa-windows" >}}
{{< info-bar
"20+:years"
"100%:open source"
"450k+:Daily users" >}}
Brand colours are established in config.toml
.
These are compiled into the SASS theme when Hugo builds the site. You can further
modify the branding by overriding bulma variables. To do this, edit themes/qgis/assets/sass/bulma.sass
and add your variables. Each bulma page includes a list of variables at the bottom of the page which can be used to override the default bulma styling for the various elements they provide. For example, we can to the variable list for bulma buttons and choose a property to modify:
Next, set a value for that variable in themes/qgis/assets/sass/bulma.sass
:
Finally, to rather use the parameter defined in config.toml
, you can use this syntax:
$navbar-background-color: {{ .Param "light2" }};
We use various bulma css framework extension. If you need to add more, place them with the others in themes/qgis/assets/sass
and then reference the addition in themes/qgis/assets/sass/bulma.sass
(as shown in the example below). Always use the SASS version so that the them branding is properly applied. More bulma extensions can be found in
/* Extensions */
/* Steps - see https://github.com/aramvisser/bulma-steps */
@import "bulma-steps.sass"
/* Pricing table - see https://github.com/Wikiki/bulma-pricingtable */
@import "bulma-pricing-table.sass"
/* Badge - see https://github.com/CreativeBulma/bulma-badge/ */
@import "bulma-pricing-table.sass"
Put your customizations in themes/qgis/assets/css/custom.css
.
We use a hugo minification and combining workflow - see the header layout in themes/qgis/layouts/partials/header.html
.