├── .gitignore ├── CHANGELOG.md ├── LICENSE.md ├── README.md ├── base-2018 ├── README.md ├── css │ ├── bulma.css │ └── theme.css ├── index.twig ├── js │ ├── app.js │ └── normalizeBrightness.js ├── listing.twig ├── not-found.twig ├── page.twig ├── partials │ ├── _aside.twig │ ├── _footer.twig │ ├── _fresh_install.twig │ ├── _header.twig │ ├── _master.twig │ ├── _navbar.twig │ ├── _no_content.twig │ ├── _record_meta.twig │ ├── _recordfooter.twig │ ├── _sub_menu.twig │ ├── _sub_menu_footer.twig │ ├── _sub_recent_records.twig │ └── _sub_taxonomylinks.twig ├── record.twig ├── search.twig ├── source │ ├── gulpfile.js │ ├── javascript │ │ └── app.js │ ├── package-lock.json │ ├── package.json │ └── scss │ │ ├── _breakpointdebug.scss │ │ ├── _settings.scss │ │ ├── _typography.scss │ │ ├── bulma.scss │ │ └── theme.scss ├── theme.yaml └── wireframes │ ├── Base-2018 detail.monopic │ ├── Base-2018 detail.png │ ├── Base-2018 homepage.monopic │ ├── Base-2018 homepage.png │ ├── Base-2018 homepage_widgets.monopic │ ├── Base-2018 homepage_widgets.png │ ├── Base-2018 listing.monopic │ ├── Base-2018 listing.png │ ├── Base-2018 search results.monopic │ ├── Base-2018 search results.png │ ├── Base-2018 showcase.monopic │ └── Base-2018 showcase.png ├── base-2021 ├── README.md ├── css │ ├── base-2021.css │ └── tailwind │ │ └── base-2021.css ├── img │ ├── hero.png │ └── logo.svg ├── index.twig ├── js │ └── app.js ├── listing.twig ├── macros.twig ├── package-lock.json ├── package.json ├── partials │ ├── _block_header.twig │ ├── _contact_form_extension.twig │ ├── _contact_form_static.twig │ ├── _footer.twig │ ├── _index_3_column_block.twig │ ├── _index_3_column_block_images.twig │ ├── _index_CTA.twig │ ├── _index_contact_with_map.twig │ ├── _index_divider_bottom.twig │ ├── _index_divider_top.twig │ ├── _index_hero.twig │ ├── _index_home_block.twig │ ├── _index_pricing_block.twig │ ├── _index_team.twig │ ├── _index_vertical_block.twig │ ├── _latest_few_of_everything.twig │ ├── _master.twig │ ├── _menu.twig │ ├── _navigation.twig │ ├── _record_author.twig │ ├── _record_divider_top.twig │ ├── _record_header_author.twig │ ├── _record_newsletter_sub.twig │ ├── _record_prev_next.twig │ └── _socials.twig ├── postcss.config.js ├── record.twig ├── tailwind.config.js ├── theme.yaml └── yarn.lock ├── composer.json ├── screenshots ├── screenshot1.png ├── screenshot2.png └── screenshot3.png └── skeleton ├── README.md ├── css └── simple.css ├── index.twig ├── listing.twig ├── partials ├── _aside.twig ├── _footer.twig ├── _fresh_install.twig ├── _header.twig ├── _image.twig ├── _master.twig ├── _recordfooter.twig ├── _sub_menu.twig ├── _sub_menu_header.twig └── _sub_taxonomylinks.twig ├── record.twig ├── search.twig └── theme.yaml /.gitignore: -------------------------------------------------------------------------------- 1 | composer.lock 2 | vendor/ 3 | node_modules/ 4 | bower_components/ 5 | .DS_Store 6 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | 4 | Version 2.0.0, 2018-03-14 5 | 6 | - Added 'base-2018' theme 7 | - Updating a handful of dependencies in 'base-2018', move from NPM to Yarn 8 | - Updating a handful of dependencies in 'skeleton' 9 | 10 | Version 1.0.4, 2017-11-14 11 | 12 | - Tiny fix for imagelists in 'fields'. 13 | 14 | Version 1.0.3, 2017-11-01 15 | 16 | - Change: Handle new blocks types 17 | 18 | Version 1.0.2, 2017-10-14 19 | 20 | - Improve the usage of the `_sub_fields.twig` partial for repeaters 21 | 22 | Version 1.0.1, 2017-10-03 23 | 24 | - Fix 404-ing link 25 | - Some extra safeguards against exceptions in "strict" mode. 26 | - Add spacing to control and output structures to aide readability 27 | - Comment out parameters that override config 28 | 29 | Version 1.0, 2017-07-14 30 | 31 | - Updating a handful of dependencies in 'base-2016' 32 | - Added 'skeleton' theme 33 | - Move to bolt/themes repo. 34 | 35 | Previous versions, as Base 2016 36 | ------------------------------ 37 | 38 | Version 2.2 39 | 40 | - Replaced `gulp-minify-css` with `cssnano`. 41 | - Updated Foundation for Sites to 6.3.1. 42 | 43 | Version 2.1 44 | 45 | - `partials/_sub_fields.twig` is now included 46 | 47 | Version 2.0 48 | 49 | - Updated for Foundation 6.3 50 | 51 | Version 1.0 52 | 53 | - Initial release. 54 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | # The MIT License (MIT) 2 | 3 | Copyright (c) 2017 Bolt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in 13 | all copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 21 | THE SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | Bolt Themes 2 | =========== 3 | 4 | This is a Bolt-specific base package for the default theme templates. This 5 | package gets installed with Bolt by default, so there should be no need to pull 6 | it in manually. 7 | -------------------------------------------------------------------------------- /base-2018/README.md: -------------------------------------------------------------------------------- 1 | Bolt Base-2018 Theme 2 | ==================== 3 | 4 | Base-2018 is a clean theme for Bolt, built on top of [Bulma][bulma]. 5 | To learn more about specific Bulma components, check out the 6 | [Bulma Documentation][bulma-docs]. 7 | 8 | Features included with Base-2018 9 | -------------------------------- 10 | 11 | Base-2018 comes with all of the great features that are found in Bolt, the 12 | Bulma framework, and a few things more. Simply put, if it works in Bulma, 13 | it will work in Bulma for Bolt. The theme also includes: 14 | 15 | - Sass(scss) or CSS Versions 16 | - Optional Yarn and Gulp Support 17 | - And much, much more! 18 | 19 | Requirements for Base-2018 20 | -------------------------- 21 | 22 | You can use whatever you want – seriously. You can use Gulp, Yarn, Codekit or 23 | nothing at all. It’s completely up to you how you decide to build your theme – 24 | Bulma for Bolt will stay out of your workflow as much as possible. 25 | 26 | This theme does include Sass, Javascript and Gulp files, and is optimized for a 27 | Gulp-based workflow. To get the most out of this theme, Gulp is highly 28 | recommended. However, if you're not using Gulp yet, you can also modify the 29 | compiled CSS files as is. 30 | 31 | File Structure 32 | -------------- 33 | 34 | These are the most important files, included in this theme. 35 | 36 | ``` 37 | . 38 | ├── css/ 39 | │   ├── bulma.css - The compiled Bulma CSS framework 40 | │   └── theme.css - Theme-specific CSS 41 | ├── js/ 42 | │   ├── app.js - Theme-specific Javascript 43 | │   └── normalizeBrightness.js - A required javascript file 44 | ├── partials/ 45 | │   ├── _aside.twig - Partial for the sidebar. With fixed content, or widgets 46 | │   ├── _footer.twig - Partial for the footer below every page 47 | │   ├── _fresh_install.twig - Partial that's shown on fresh installs with some instructions 48 | │   ├── _header.twig - Partial for the header banner with the site title 49 | │   ├── _master.twig - Twig template, that is uses to 'extend' all pages (See 'template inheritance') 50 | │   ├── _navbar.twig - Partial with the navigation bar shown on top of every page 51 | │   ├── _no_content.twig - Partial that's shown when there is no homepage present 52 | │   ├── _record_meta.twig - Partial with meta-information shown at the top of a page or entry 53 | │   ├── _recordfooter.twig - Partial with meta-information below a page or entry 54 | │   ├── _sub_field_blocks.twig - Partial with blocks, used by `_sub_fields.twig` 55 | │   ├── _sub_fields.twig - Partial used to render contenttypes with an undertermined amount of fields 56 | │   ├── _sub_menu.twig - Partial with macro for rendering the drop-down menu 57 | │   ├── _sub_menu_footer.twig - Partial with macro for rendering the menu in the footer 58 | │   ├── _sub_pager.twig - Partial with the markup for the pagination ([1|2|3|…]) 59 | │   ├── _sub_recent_records.twig - Partial for the "latest records" block 60 | │   └── _sub_taxonomylinks.twig - Partial with the markup for the links to taxonomies like categories and tags 61 | ├── source/ 62 | │   ├── javascript/ 63 | │   │   └── app.js - Source app.js file 64 | │   ├── node_modules/ 65 | │   ├── scss/ 66 | │   │   ├── _breakpointdebug.scss 67 | │   │   ├── _settings.scss 68 | │   │   ├── _typography.scss 69 | │   │   ├── bulma.scss 70 | │   │   └── theme.scss 71 | │   ├── gulpfile.js - Build task script for Gulp. 72 | │   ├── package.json - Configuration for used Node / Gulp packages. 73 | │   └── yarn.lock 74 | ├── README.md 75 | ├── index.twig 76 | ├── listing.twig 77 | ├── not-found.twig 78 | ├── page.twig 79 | ├── record.twig 80 | ├── search.twig 81 | └── theme.yaml 82 | ``` 83 | 84 | Installation 85 | ------------ 86 | 87 | No need to install anything. This theme comes with Bolt. Don't forget to set 88 | `theme: base-2018` in your `config.yaml` file, if it doesn't show up already. 89 | 90 | Getting Started 91 | --------------- 92 | 93 | This theme was developed to be as "tinker friendly" as possible. Depending on 94 | your area of expertise and experience with different front-end development 95 | techniques, you can modify the CSS of this theme on different 'levels': 96 | 97 | - If you're familiar with Bulma and Gulp, you can finetune which parts of 98 | Bulma are included, as well as all their settings. See the 99 | `source/scss/bulma.scss` and `source/gulpfile.js` files. 100 | - If you do know a bit of SCSS, you can work in `source/scss/theme.scss` and 101 | `source/scss/_settings.scss` files. 102 | - Otherwise you can just make your changes in the compiled css at `css/theme.css`. 103 | 104 | The templates themselves are the `.twig` files in the root of the theme folder, 105 | as well as the additional helper files in the `partials` folder. 106 | 107 | Modifying the HTML of the theme 108 | ------------------------------- 109 | 110 | All HTML parts of the theme are made in Twig. If you're not familiar with Twig 111 | yet, be sure to read the Bolt documentation on Twig, as well as the official 112 | Twig documentation. 113 | 114 | This theme uses a concept called 'template inheritance'. From other themes or 115 | CMS'es, you might be familiar with seeing each page 'include' a header and a 116 | 'footer'. Instead, we have one 'master' template, which are extended by each of 117 | the different templates. You can read more about this concept on the 118 | [Twig site - Template Inheritance][inheritance] or here: 119 | [Dealing With Themes And Layouts With Twig][theme-twig] 120 | 121 | For example, take a look at one of the simpler templates, `record.twig`: 122 | 123 | ```twig 124 | {% extends 'partials/_master.twig' %} 125 | 126 | {% block main %} 127 | 128 |

{{ record.title }}

129 | 130 | {{ block('sub_fields', 'partials/_sub_fields.twig') }} 131 | 132 | {{ include('partials/_recordfooter.twig', { 'record': record }) }} 133 | 134 | {% endblock main %} 135 | ``` 136 | 137 | You'll notice the first line that states that the template 'extends' the 138 | `_master.twig` partial. The rest of the template is the `{% block %}`, which 139 | overrides the 'main' block in the master template. Inside the block is just an 140 | `

` element with the record title, a `sub_fields` block (defined in 141 | `partials/_sub_fields.twig`) that will output the fields that are defined for 142 | this ContentType, and it closes with an include of `_recordfooter.twig` to 143 | display some meta data, like the author, date and permalink. 144 | 145 | As you can see, we can still use 'include' for small blocks of HTML, even though 146 | we're using template inheritance. This way we can keep our themes very 147 | structured and organized. 148 | 149 | ### Showing all fields without defining them 150 | 151 | Because this is a general purpose theme, we try to make it work without problems 152 | for any defined ContentType. This means we'll need to render all available 153 | fields in the template without knowledge of which fields are defined exactly. 154 | To do this, we're using the `_sub_fields.twig` partial. Simply said, this 155 | partial goes over all fields in the ContentType, and outputs them in a generic 156 | way. It's used like this: 157 | 158 | ```twig 159 | {% with { 'record': record, 'common': true, 'extended': true, 'repeaters': true } %} 160 | {{ block('sub_fields', 'partials/_sub_fields.twig') }} 161 | {% endwith %} 162 | ``` 163 | 164 | The `with` tag is used to scope variables: This way they will be available 165 | within the block, but not outside. The partial has a few "options" you can set 166 | this way: 167 | 168 | | Option | Description | 169 | |------------------|-------------| 170 | | `record` | The Record to use in the display. Defaults to `record` | 171 | | `common` | Whether or not to include common fields like 'text', 'html', 'textarea', 'image' and 'video' in the output. Defaults to `true` | 172 | | `extended` | Whether or not to include all other regular fields (like 'date', 'select' and others) in the output. Defaults to `false` | 173 | | `repeaters` | Whether or not to include repeater fields in the output. Defaults to `false` | 174 | | `exclude` | field names to exclude, even though they might otherwise be included | 175 | | `skip_uses` | By default the field that's used as the slug is skipped, under the assumption that it corresponds to the title of the page. To disable this, set `'skipuses': false` | 176 | 177 | Note: `templatefields` are included in `common` and `extended`, where applicable. 178 | 179 | Theme structure 180 | --------------- 181 | 182 | In the diagram below, you'll see the wat most pages are structured. In this case, 183 | `index.twig`. In the HTML, you will see it extends `_master.twig`, which can be found in 184 | the `partials/` folder. Inside this file, the global structure of all pages is laid out: 185 | The basic HTML structure, and a handful of other included partials. 186 | 187 | ``` 188 | index.twig structure _topbar.twig 189 | 190 | │ 191 | ├─────────────────────────┴────────────────────────────────┤ 192 | 193 | ┌────────────────────────────────────────────┬───────────────┐ 194 | _sub_menu.twig ──▶ │ Home link1 link2 link3 │______ [Search]│ ◀── _search.twig 195 | ├────────────────────────────────────────────┴───────────────┤ 196 | │••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••│ 197 | │•••••••••••••••••••••••(header image)•••••••••••••••••••••••│ ◀── _header.twig 198 | │•••••••••••••••••••••••(name of site)•••••••••••••••••••••••│ 199 | │••••••••••••••••••••••••••••••••••••••••••••••••••••••••••••│ 200 | │ ┌──────────────────(main content)─┐ ┌────────────(aside)─┐ │ 201 | │ │Lorem ipsum dolor sit amet │ │Lorem ipsum dolor │ │ 202 | │ │ │ │sit amet. Consec- │ │ 203 | │ │Consectetur adipiscing elit. Nunc│ │tetur adipiscing. │ │ 204 | │ │omni virtuti vitium contrario │ │ │ │ 205 | │ │nominehgpponitur. Non enim, si │ │Latest X │ │ 206 | │ │malum est dolor, carere eo malo │ │ - intellegetur │ │ 207 | │ │satis est ad bene vivendum. Duo │ │ - Expectoque │ │ 208 | │ │Reges: constructio interrete. │ │ - videantur │ │ ◀── _aside.twig 209 | │ │ │ │ │ │ 210 | │ └─────────────────────────────────┘ │Latest Y │ │ 211 | │ ┌─────────────────────────────────┐ │ - intellegetur │ │ 212 | │ │Lorem ipsum dolor sit amet │ │ - Expectoque │ │ 213 | │ │ │ │ - videantur │ │ 214 | │ │Consectetur adipiscing elit. Nunc│ │ │ │ 215 | │ │omni virtuti vitium contrario │ │ │ │ 216 | ┬ ├─┴─────────────────────────────────┴─┴────────────────────┴─┤ 217 | _footer.twig ──┤ │ (C) 2016 Home link1 link2 link3 │ ◀── _sub_menu.twig 218 | ┴ └────────────────────────────────────────────────────────────┘ 219 | 220 | ├────────────────────────────┬─────────────────────────────────┤ 221 | │ 222 | 223 | _master.twig 224 | ``` 225 | 226 | Options in `theme.yaml` 227 | ----------------------- 228 | 229 | This theme comes with its own configuration file, named `theme.yaml`. In this 230 | file you can set certain specific options for the theme, such as the default 231 | images for the header, the position of the 'aside' sidebar, and the global 232 | layout. 233 | 234 | Finally, the last section defines the settings for which templates are used for 235 | which types of pages. The templates you will set in this config file will 236 | override the ones in the global `config/bolt/config.yaml`, so beware! 237 | 238 | ``` 239 | # maintenance_template: maintenance_default.twig 240 | homepage_template: index.twig 241 | record_template: record.twig 242 | listing_template: listing.twig 243 | search_results_template: search.twig 244 | notfound: notfound.twig 245 | ``` 246 | 247 | For details on which page is used when, see the next section in this document. 248 | 249 | Working with the `.twig` files 250 | ------------------------------ 251 | 252 | You are free to do what you want, when it comes to the .twig files. Out-of-the- 253 | box, this theme comes with a handful of templates, that correspond to 254 | the default ContentTypes when you have a fresh install of Bolt. 255 | 256 | Most of the templates will be pretty straightforward, especially if you're 257 | familiar with the concept of Template Inheritance. The main templates are: 258 | 259 | - `index.twig`: Used as the frontpage or homepage of the site. 260 | - `listing.twig`: This template is used for listing overviews of all kind, like 261 | `/pages` for all records in the 'pages ContentType' or `category/movies` for 262 | all records that have the 'movies' category assigned to them. Note that 263 | 'search' uses its own template, though. 264 | - `not-found.twig`: This template is used as the template that's shown when the 265 | visitor hits a non-existing page on the website. 266 | - `page.twig`: The detail page for a single record of the 'pages' ContentType. 267 | Automatically picked up by Bolt, if the name matches. 268 | - `record.twig`: The "generic" detail page for a single record page. This is 269 | used as the fallback, if there's no specific template set for a single record 270 | page. 271 | - `search.twig`: This page displays the search results and a search box, to 272 | search again. 273 | 274 | Working with the `.scss` files 275 | ------------------------------ 276 | 277 | This theme uses Node, NPM and Gulp to run the tasks to compile and minify the 278 | Sass and Javascript files. If you don't have Node, NPM and Gulp yet, install 279 | them from [Nodejs.org](https://nodejs.org) and [Gulpjs.com](https://gulpjs.com). 280 | 281 | To install the theme's dependencies, run the following in the source directory: 282 | 283 | ``` 284 | npm install 285 | ``` 286 | 287 | Now you can simply run `npm run start` to compile the javascript and sass 288 | files. This will build the files, and it will continue to monitor changes to 289 | the `.scss` files. If you make a change, the compiled files will be updated 290 | immediately. When you're ready to deploy, and put the site in production, be 291 | sure to build the files and minify them: 292 | 293 | ``` 294 | npm run build 295 | ``` 296 | 297 | This will build the files that you can deploy, or put into your versioning 298 | system. 299 | 300 | If you're interested to learn more about the process, these two tutorials on 301 | Gulp (which is what we use under the hood) might be of interest to you: 302 | 303 | - https://markgoodyear.com/2014/01/getting-started-with-gulp/ 304 | - https://travismaynard.com/writing/getting-started-with-gulp 305 | 306 | [bulma]: http://bulma.io/ 307 | [bulma-docs]: https://bulma.io/documentation/overview/start/ 308 | [inheritance]: http://twig.sensiolabs.org/doc/tags/extends.html 309 | [theme-twig]: http://hugogiraudel.com/2013/11/12/themes-layouts-twig/ 310 | -------------------------------------------------------------------------------- /base-2018/css/theme.css: -------------------------------------------------------------------------------- 1 | h1,h2,h3,h4,h5,h6{font-family:Bitter,serif}li a,p a{text-decoration:underline} 2 | 3 | /*! 4 | * baguetteBox.js 5 | * @author feimosi 6 | * @version %%INJECT_VERSION%% 7 | * @url https://github.com/feimosi/baguetteBox.js 8 | */#baguetteBox-overlay{display:none;opacity:0;position:fixed;overflow:hidden;top:0;left:0;width:100%;height:100%;z-index:2;background-color:#222;background-color:rgba(0,0,0,.8);transition:opacity .5s ease}#baguetteBox-overlay.visible{opacity:1}#baguetteBox-overlay .full-image{display:inline-block;position:relative;width:100%;height:100%;text-align:center}#baguetteBox-overlay .full-image figure{display:inline;margin:0;height:100%}#baguetteBox-overlay .full-image img{display:inline-block;width:auto;height:auto;max-height:100%;max-width:100%;vertical-align:middle;box-shadow:0 0 8px rgba(0,0,0,.6)}#baguetteBox-overlay .full-image figcaption{display:block;position:absolute;bottom:0;width:100%;text-align:center;line-height:1.8;white-space:normal;color:#ccc;background-color:#000;background-color:rgba(0,0,0,.6);font-family:sans-serif}#baguetteBox-overlay .full-image:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}#baguetteBox-slider{position:absolute;left:0;top:0;height:100%;width:100%;white-space:nowrap;transition:left .4s ease,transform .4s ease}#baguetteBox-slider.bounce-from-right{animation:a .4s ease-out}#baguetteBox-slider.bounce-from-left{animation:b .4s ease-out}@keyframes a{0%{margin-left:0}50%{margin-left:-30px}to{margin-left:0}}@keyframes b{0%{margin-left:0}50%{margin-left:30px}to{margin-left:0}}.baguetteBox-button#next-button,.baguetteBox-button#previous-button{top:50%;top:calc(50% - 30px);width:44px;height:60px}.baguetteBox-button{position:absolute;cursor:pointer;outline:none;padding:0;margin:0;border:0;border-radius:15%;background-color:#323232;background-color:rgba(50,50,50,.5);color:#ddd;font:1.6em sans-serif;transition:background-color .4s ease}.baguetteBox-button:focus,.baguetteBox-button:hover{background-color:rgba(50,50,50,.9)}.baguetteBox-button#next-button{right:2%}.baguetteBox-button#previous-button{left:2%}.baguetteBox-button#close-button{top:20px;right:2%;right:calc(2% + 6px);width:30px;height:30px}.baguetteBox-button svg{position:absolute;left:0;top:0}.baguetteBox-spinner{width:40px;height:40px;display:inline-block;position:absolute;top:50%;left:50%;margin-top:-20px;margin-left:-20px}.baguetteBox-double-bounce1,.baguetteBox-double-bounce2{width:100%;height:100%;border-radius:50%;background-color:#fff;opacity:.6;position:absolute;top:0;left:0;animation:c 2s infinite ease-in-out}.baguetteBox-double-bounce2{animation-delay:-1s}@keyframes c{0%,to{transform:scale(0)}50%{transform:scale(1)}}code[class*=language-],pre[class*=language-]{color:#000;background:none;text-shadow:0 1px #fff;font-family:Consolas,Monaco,Andale Mono,Ubuntu Mono,monospace;font-size:1em;text-align:left;white-space:pre;word-spacing:normal;word-break:normal;word-wrap:normal;line-height:1.5;-moz-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}code[class*=language-]::selection,code[class*=language-] ::selection,pre[class*=language-]::selection,pre[class*=language-] ::selection{text-shadow:none;background:#b3d4fc}@media print{code[class*=language-],pre[class*=language-]{text-shadow:none}}pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre[class*=language-]{background:#f5f2f0}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#708090}.token.punctuation{color:#999}.token.namespace{opacity:.7}.token.boolean,.token.constant,.token.deleted,.token.number,.token.property,.token.symbol,.token.tag{color:#905}.token.attr-name,.token.builtin,.token.char,.token.inserted,.token.selector,.token.string{color:#690}.language-css .token.string,.style .token.string,.token.entity,.token.operator,.token.url{color:#9a6e3a;background:hsla(0,0%,100%,.5)}.token.atrule,.token.attr-value,.token.keyword{color:#07a}.token.class-name,.token.function{color:#dd4a68}.token.important,.token.regex,.token.variable{color:#e90}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.visually-hidden:not(:focus):not(:active){position:absolute!important;height:1px;width:1px;overflow:hidden;clip:rect(1px,1px,1px,1px)}.skip-link{position:absolute;top:60px;z-index:1}.navbar-brand .navbar-item,.skip-link{font-family:Bitter,serif;font-size:1.5rem;font-weight:700}.navbar-end{align-items:center}@media screen and (max-width:768px){.navbar-end form{padding:1rem}.navbar-end form .control:first-child{width:100%}}.notification ul{margin:.5em 1.4em;list-style-type:disc}.teaser{font-weight:700;margin-bottom:1rem}.card,.card-content{display:flex;flex-direction:column;height:100%}.card-content .button:last-child{margin-top:auto}.card-content p{height:100%}.section-latest-entries .buttons{margin-top:1.5rem}.tags{margin-top:3rem}.tags .label{margin-right:.5em}.section-record .image{margin-top:3rem;margin-bottom:3rem}.button{text-decoration:none}p.meta{margin-top:1rem;color:#777;font-size:90%}@media screen and (max-width:768px){.media{flex-direction:column}}.media-right{flex-shrink:1;margin-left:0}@media screen and (max-width:768px){.media-right{order:-1;width:100%;margin-bottom:1rem}}.imageholder img{width:100%}.notification>.delete{right:.5rem;top:.5rem}.hero-image{background-repeat:no-repeat;background-position:50%;background-size:cover;margin-top:52px}.hero.is-large .hero-body{padding-bottom:4rem;padding-top:4rem}.hero.is-large .hero-body h1.title,.hero.is-large .hero-body h2.subtitle{text-shadow:2px 2px 15px rgba(0,0,0,.4)}.hero.is-large .hero-body h1.title{font-size:2rem;font-weight:700}.hero.is-large .hero-body h2.subtitle{font-size:1.5rem}@media print,screen and (min-width:769px){.hero.is-large .hero-body{padding-bottom:12rem;padding-top:12rem}.hero.is-large .hero-body h1.title{font-size:2.5rem}.hero.is-large .hero-body h2.subtitle{font-size:1.875rem}}@media screen and (min-width:1024px){.hero.is-large .hero-body{padding-bottom:16rem;padding-top:16rem}.hero.is-large .hero-body h1.title{font-size:3rem}.hero.is-large .hero-body h2.subtitle{font-size:2.25rem}}.footer{padding:2rem 1.5rem}[data-background-image]{position:relative}[data-background-image] .dark-overlay{content:"";display:block;position:absolute;top:0;left:0;width:100%;height:100%;background-color:#000}pre .tag{margin:0;padding:0;background-color:transparent;display:inherit;font-size:inherit}pre .number{font-size:1em} -------------------------------------------------------------------------------- /base-2018/index.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 |
6 |
7 |
8 |
9 | 10 | {# Remove this include if you don't need it anymore. #} 11 | {{ include('partials/_fresh_install.twig') }} 12 | 13 | {% setcontent homepage = "homepage" limit 1 returnsingle %} 14 | {% if homepage %} 15 |
16 |

{{ homepage.title }}

17 |
{{ homepage.teaser }}
18 | {{ homepage.content }} 19 | 20 | {% include 'partials/_record_meta.twig' with {'record': homepage } %} 21 |
22 | {% else %} 23 | {# Remove this include if you don't need it anymore. #} 24 | {{ include('partials/_no_content.twig') }} 25 | {% endif %} 26 |
27 |
28 | {{ include('partials/_aside.twig') }} 29 |
30 |
31 |
32 |
33 | 34 | {# Pages section #} 35 | 36 |
37 |
38 |

Pages

39 |
40 | {% setcontent pages = 'pages' latest limit 3 %} 41 | {% for page in pages %} 42 |
43 |
44 |
45 |
46 | {{ popup(page|image, 480, 320) }} 47 |
48 |
49 | 56 |
57 |
58 | {% else %} 59 |
60 |

{{ __("general.phrase.no-content-found") }}

61 |
62 | {% endfor %} 63 |
64 |
65 |
66 | 67 | {# Latest entries #} 68 | 69 |
70 |
71 |

Latest Entries

72 | {% setcontent entries = 'entries' latest limit 3 %} 73 | {% for entry in entries %} 74 |
75 |
76 |
77 |

{{ entry|title }}

78 | {{ entry.teaser }} 79 | {% include 'partials/_record_meta.twig' with {'extended': true, 'record': entry} %} 80 |
81 |
82 |
83 |
84 | {{ popup(entry|image, 480, 320) }} 85 |
86 |
87 |
88 | {% else %} 89 |

{{ __("general.phrase.no-content-found") }}

90 | {% endfor %} 91 | 94 |
95 |
96 | 97 | {% include "partials/_sub_recent_records.twig" %} 98 | 99 | {% endblock main %} 100 | -------------------------------------------------------------------------------- /base-2018/js/normalizeBrightness.js: -------------------------------------------------------------------------------- 1 | // From: https://github.com/antoningrele/img-brightness-normalization 2 | 3 | function normalizeBrightness(coeff=1.25) { 4 | 5 | document.querySelectorAll('[data-background-image]').forEach(function(div) { 6 | 7 | /* Get the div's image background url and apply to the style */ 8 | var imageUrl = div.dataset.backgroundImage; 9 | div.style.background = "url('" + imageUrl + "')"; 10 | 11 | /* Prepare a dom image for canvas manipulation*/ 12 | var background = new Image(); 13 | background.src = imageUrl; 14 | 15 | /* When the dom image loads, proceed with the calculations */ 16 | background.onload = function() { 17 | 18 | var brightness = getBrightness(background); 19 | div.dataset.brightness = brightness; 20 | 21 | /* The more opaque the overlay, the darker the image. 22 | A coefficient of 1 will equate the overlay's opacity with the image's brightness. 23 | A higher coefficient will leave more room for differences between the images, but 24 | will avoid darkening your images too much. */ 25 | var darkOverlayOpacity = brightness / coeff; 26 | div.style.background = ` 27 | linear-gradient(rgba(0,0,0,${darkOverlayOpacity}), 28 | rgba(0,0,0,${darkOverlayOpacity})), 29 | url(${imageUrl}) 30 | `; 31 | div.style.backgroundSize = "cover"; 32 | div.style.backgroundPosition = "center"; 33 | } 34 | }) 35 | } 36 | 37 | 38 | function getBrightness(img) { 39 | 40 | /* Returns a brightness value between 0 and 1 based on the image's brightness */ 41 | 42 | var rgb = getAverageColor(img) 43 | var brightness255 = (rgb.r * 2 + rgb.g *3 + rgb.b) / 6 44 | var brightness = brightness255 / 255 45 | return brightness 46 | 47 | } 48 | 49 | function getAverageColor(img) { 50 | 51 | /* Returns an RGB object of an image's average color */ 52 | 53 | var canvas = document.createElement('canvas'); 54 | var ctx = canvas.getContext('2d'); 55 | var width = canvas.width = img.naturalWidth; 56 | var height = canvas.height = img.naturalHeight; 57 | 58 | ctx.drawImage(img, 0, 0); 59 | 60 | var imageData = ctx.getImageData(0, 0, width, height); 61 | var data = imageData.data; 62 | var r = 0; 63 | var g = 0; 64 | var b = 0; 65 | 66 | for (var i = 0; i < data.length; i += 4) { 67 | r += data[i]; 68 | g += data[i+1]; 69 | b += data[i+2]; 70 | } 71 | 72 | r = Math.floor(r / (data.length / 4)); 73 | g = Math.floor(g / (data.length / 4)); 74 | b = Math.floor(b / (data.length / 4)); 75 | 76 | return { r: r, g: g, b: b }; 77 | 78 | } -------------------------------------------------------------------------------- /base-2018/listing.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 |
5 |
6 | {# This template is used for 'listings': Generic pages that list a number of 7 | records from a certain contenttype. These records are available as an array 8 | called 'records'. In the for-loop below, we iterate over the records that 9 | are on this page. It can be used for overview pages like 'all entries', or 10 | 'all records tagged with kittens'. #} 11 | 12 | {# If used for listing a taxonomy, we add a heading #} 13 | {% if taxonomy is defined %} 14 |
15 |

16 | {{ __('general.phrase.overview-for', {'%slug%': taxonomy.options[slug]|default(slug) }) }} 17 |

18 |
19 | {% else %} 20 |

{{ contenttype.name }}

21 | {% endif %} 22 | 23 | {% for record in records %} 24 |
25 |
26 |
27 |

{{ record|title }}

28 | 29 | {# display something introduction-like.. #} 30 | {% if record.introduction %} 31 | {{ record.introduction }} 32 | {% elseif record.teaser %} 33 | {{ record.teaser }} 34 | {% else %} 35 |

{{ record.excerpt(300, false, search|default('')) }}

36 | {% endif %} 37 | 38 | {% include 'partials/_record_meta.twig' with {'extended': true} %} 39 | 40 |
41 |
42 | {% if record|image %} 43 |
44 |
45 | 46 | {{ (record|image).alt|default(record|title) }} 47 | 48 |
49 |
50 | {% endif %} 51 | 52 |
53 | {% else %} 54 |
55 |
56 |

{{ __('general.phrase.no-content-found') }}

57 | 58 |

59 | {{ __("Unfortunately, no content could be found. Try another page, or go to the homepage.", {'%paths_root%': path('homepage')} ) }} 60 |

61 |
62 |
63 | {% endfor %} 64 | 65 | {# If there are more records than will fit on one page, the pager is shown. #} 66 | {{ pager(records, template = 'helpers/_pager_bulma.html.twig') }} 67 |
68 |
69 | {% endblock main %} 70 | -------------------------------------------------------------------------------- /base-2018/not-found.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% setcontent record = 'blocks/404-not-found' %} 4 | 5 | {% block main %} 6 | 7 |
8 |
9 |
10 | {% if record %} 11 |

{{ record.title|default('404 not found') }}

12 | {{ record.content|default('

The requested page was not found.

')|raw }} 13 | {% else %} 14 |

404 not found

15 |

16 | The requested page was not found. 17 |

18 | 19 |
20 | {# #} 21 | Add a Blocks record with slug '404-not-found' to customize this message. 22 | If it's not showing up here, doublecheck that the slug is correct, and that the Block is published. 23 |
24 | {% endif %} 25 |
26 | 27 |
28 | 29 |
30 | 31 |
32 |
33 | 34 |
35 |
36 | 37 |
38 |
39 | {% endblock main %} 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /base-2018/page.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 |
6 |
7 |
8 |
9 |
10 |

{{ record.title }}

11 | 12 | {% include 'partials/_record_meta.twig' with {'extended': true} %} 13 | 14 | {{ record.teaser }} 15 | 16 | {% if record|image %} 17 |
18 | {{ record.values.image.alt|default() }} 19 | {# #} 20 |
21 | {{ record|image.alt|default() }} 22 | {# Figure 1: Some beautiful placeholders #} 23 |
24 |
25 | 26 | {% endif %} 27 | 28 | {{ record.body }} 29 | 30 | {# If there are repeaters, we should output them. #} 31 | {% with { 'record': record, 'common': false, 'repeaters': true, 'blocks': true, 'exclude': ['teaser', 'body', 'image'] } %} 32 | {{ block('sub_fields', 'helpers/_fields.twig') }} 33 | {% endwith %} 34 | 35 | {# Uncomment this if you wish to dump the entire record to the client, for debugging purposes. 36 | {{ dump(record) }} 37 | #} 38 | 39 | {{ include('partials/_recordfooter.twig') }} 40 |
41 |
42 |
43 | {{ include('partials/_aside.twig') }} 44 |
45 |
46 |
47 |
48 | 49 | {% endblock main %} 50 | -------------------------------------------------------------------------------- /base-2018/partials/_aside.twig: -------------------------------------------------------------------------------- 1 | {# Sidebar #} 2 | 42 | {# End Sidebar #} 43 | -------------------------------------------------------------------------------- /base-2018/partials/_footer.twig: -------------------------------------------------------------------------------- 1 | {# Footer #} 2 | 24 | 25 | 26 | 27 | -------------------------------------------------------------------------------- /base-2018/partials/_fresh_install.twig: -------------------------------------------------------------------------------- 1 | {% if user %} 2 |
3 | 4 |

Welcome to the Bolt Base-2018 theme.

5 |

This is a minimal theme, with a modular structure. It is well suited to build your own themes on top of.

6 | 11 | Note: Only registered users will see this. This piece of content is hidden from regular visitors. 12 |
13 | {% endif %} 14 | -------------------------------------------------------------------------------- /base-2018/partials/_header.twig: -------------------------------------------------------------------------------- 1 | {% if record.contenttype.slug|default() not in ['showcases', 'entries'] %} 2 | {% setcontent homepage = "homepage" limit 1 returnsingle %} 3 |
8 |
9 |
10 |

{{ config.get('general/sitename') }}

11 | {% if config.get('general/payoff') %} 12 |

{{ config.get('general/payoff') }}

13 | {% endif %} 14 |
15 |
16 |
17 | {% endif %} 18 | -------------------------------------------------------------------------------- /base-2018/partials/_master.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | {# make sure we always display a proper title: The record's title if there is one, appended with the 7 | sitename. If there is no title, we append the sitename with the payoff, if there is one. #} 8 | 9 | {%- if record.title is defined %}{{ record.title|striptags }} | {% endif -%} 10 | {{ config.get('general/sitename') -}} 11 | {% if record.title is not defined and config.get('general/payoff') %} | {{ config.get('general/payoff') }}{% endif -%} 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | {% block body %} 21 | 22 | 26 | 27 | {{ widgets('main_top') }} 28 | 29 | 30 | {% block main %} 31 | {% endblock main %} 32 | 33 | {{ widgets('main_bottom') }} 34 | 35 | {% endblock body %} 36 | 37 | {{ include('partials/_footer.twig') }} 38 | 39 | 40 | 41 | 42 | 43 | -------------------------------------------------------------------------------- /base-2018/partials/_navbar.twig: -------------------------------------------------------------------------------- 1 | {# Navbar #} 2 | 37 | -------------------------------------------------------------------------------- /base-2018/partials/_no_content.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 |

{{ __("general.phrase.no-content-found") }}

4 |

5 | {{ __("page.dashboard.empty-database") }} 6 |

7 |
8 | -------------------------------------------------------------------------------- /base-2018/partials/_record_meta.twig: -------------------------------------------------------------------------------- 1 |

2 | {% if record.link() and (record.link != global.request.server.get('REQUEST_URI')) %} 3 | 4 | {{ __('general.phrase.read-more') }} 5 | 6 | {% elseif record.contentlink %} 7 | 8 | {{ __('general.phrase.read-more') }} 9 | 10 | {% endif %} 11 | {% if record.editlink() %} 12 | 13 | 14 | {{ __('general.phrase.edit') }} 15 | 16 | 17 | {% endif %} 18 |

19 | {% if extended|default() %} 20 |

21 | {{ __('general.phrase.written-by-on', { 22 | '%name%': record.author.displayname|default(__('Unknown')), 23 | '%date%': record.datepublish|localdate("l F j, Y") 24 | }) }} 25 |

26 | {% endif %} 27 | -------------------------------------------------------------------------------- /base-2018/partials/_recordfooter.twig: -------------------------------------------------------------------------------- 1 | {# This file is inserted as the 'footer' of each listed record. #} 2 | 3 | {# include the 'default' links to taxonomies. Check the documentation for ways to modify and customize 4 | what is output to the browser: https://docs.bolt.cm/contenttypes/taxonomies#displaying-taxonomies-in-templates #} 5 | {{ include('partials/_sub_taxonomylinks.twig', { record: record }) }} 6 | 7 | {% set previous = record|previous('id') %} 8 | {% set next = record|next('id') %} 9 | {% if previous or next %} 10 | 18 | {% endif %} 19 | 20 | {% set relatedrecords = record.related() %} 21 | {% if relatedrecords is not empty %} 22 |

23 |

{{ __('general.phrase.related-content') }}

24 | 29 |

30 | {% endif %} 31 | 32 | -------------------------------------------------------------------------------- /base-2018/partials/_sub_menu.twig: -------------------------------------------------------------------------------- 1 | {# This file might seem a little complex, because of the high density of tags. 2 | It uses Twig macros and ternary selectors. Read up on them, if required: 3 | macros: http://twig.sensiolabs.org/doc/templates.html#macros 4 | ternary operators: http://twig.sensiolabs.org/doc/templates.html#other-operators 5 | #} 6 | 7 | {# Make sure the setting for the submenus is defined. #} 8 | {% if withsubmenus is not defined %} 9 | {% set withsubmenus = true %} 10 | {% endif %} 11 | 12 | {# The 'recursive' macro, for inserting one menu item. If it has a submenu, it 13 | invokes itself to insert the items of the submenus. #} 14 | {% macro display_menu_item(item, loop, withsubmenus) %} 15 | {% from _self import display_menu_item %} 16 | {% apply spaceless %} 17 | {% set with_submenu = withsubmenus and item.submenu is not empty %} 18 | 19 | {% if item.submenu and withsubmenus %} 20 | 32 | {% else %} 33 | 34 | {{- item.label|default(item.title) -}} 35 | 36 | {% endif %} 37 | 38 | {% endapply %} 39 | {% endmacro %} 40 | 41 | {# Make the macro available for use #} 42 | {% from _self import display_menu_item %} 43 | 44 | {# The main menu loop: Iterates over the items, calling `display_menu_item` #} 45 | {% for item in menu %} 46 | {% if item.label is defined %} 47 | {{ display_menu_item(item, loop, withsubmenus) }} 48 | {% endif %} 49 | {% endfor %} 50 | -------------------------------------------------------------------------------- /base-2018/partials/_sub_menu_footer.twig: -------------------------------------------------------------------------------- 1 | {# This file might seem a little complex, because of the high density of tags. 2 | It uses Twig macros and ternary selectors. Read up on them, if required: 3 | macros: http://twig.sensiolabs.org/doc/templates.html#macros 4 | ternary operators: http://twig.sensiolabs.org/doc/templates.html#other-operators 5 | #} 6 | 7 | {# Make sure the setting for the submenus is defined. #} 8 | {% if withsubmenus is not defined %} 9 | {% set withsubmenus = true %} 10 | {% endif %} 11 | 12 | {# The 'recursive' macro, for inserting one menu item. If it has a submenu, it 13 | invokes itself to insert the items of the submenus. #} 14 | {% macro display_menu_item(item, loop, extraclass, withsubmenus) %} 15 | {% from _self import display_menu_item %} 16 | {% apply spaceless %} 17 |

18 | 19 | {{- item.label|default('-') -}} 20 | 21 |

22 | {% endapply %} 23 | {% endmacro %} 24 | 25 | {# Make the macro available for use #} 26 | {% from _self import display_menu_item %} 27 | 28 | {# The main menu loop: Iterates over the items, calling `display_menu_item` #} 29 | {% for item in menu %} 30 | {% if item.label is defined %} 31 | {{ display_menu_item(item, loop, '', withsubmenus) }} 32 | {% endif %} 33 | {% endfor %} 34 | -------------------------------------------------------------------------------- /base-2018/partials/_sub_recent_records.twig: -------------------------------------------------------------------------------- 1 | {# The next section iterates over all of the contenttypes, and prints a list 2 | of the five latest records of each of them. The 'magic' happens in the 3 | setcontent tag.. `ct.slug` is set to each of the (visible) contenttypes, 4 | and `latest limit 5` ensures we grab the 5 latest published records. 5 | #} 6 |
7 |
8 |
9 | {% for ct in config.get('contenttypes')|filter(ct => not ct.viewless and not ct.singleton) %} 10 | {% setcontent records = ct.slug latest limit 5 %} 11 | {% if records|length %} 12 |
13 |
14 |
15 |

{{ __('contenttypes.generic.recent', {'%contenttypes%': ct.name}) }}

16 |
    17 | {% for record in records %} 18 |
  • {{ record|title }}
  • 19 | {% else %} 20 |
  • {{ __('contenttypes.generic.no-recent', {'%contenttype%': ct.slug}) }}
  • 21 | {% endfor %} 22 |
23 | {{ __('contenttypes.generic.overview',{'%contenttypes%': ct.name}) }} 24 |
25 |
26 |
27 | {% endif %} 28 | {% endfor %} 29 |
30 |
31 |
32 | -------------------------------------------------------------------------------- /base-2018/partials/_sub_taxonomylinks.twig: -------------------------------------------------------------------------------- 1 |
2 | {% for type, taxonomies in record|taxonomies %} 3 | 4 | {% if taxonomies|length == 1 %} 5 | {{ config.get('taxonomies')[type].singular_name }}: 6 | {% elseif taxonomies|length > 1 %} 7 | {{ config.get('taxonomies')[type].name }}: 8 | {% endif %} 9 | 10 | {% for taxonomy in taxonomies %} 11 | {{ taxonomy.name }} 12 | {% else %} 13 | {{ __('general.phrase.none') }} 14 | {% endfor %} 15 | {% endfor %} 16 |
17 | -------------------------------------------------------------------------------- /base-2018/record.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 |
6 |
7 | {% if record|image %} 8 |
9 | {{ record|image.alt|default() }} 10 |
11 | {{ record|image.alt|default() }} 12 |
13 |
14 | {% endif %} 15 | 16 |
17 |
18 |
19 |

{{ record|title }}

20 | 21 | {% include 'partials/_record_meta.twig' %} 22 | 23 | {# Output all fields, in the order as defined in the contenttype. 24 | To change the generated html and configure the options, see: 25 | https://docs.bolt.cm/templating #} 26 | {% with { 'record': record, 'exclude': [record|image.fieldname|default()] } %} 27 | {{ block('sub_fields', 'helpers/_fields.twig') }} 28 | {% endwith %} 29 | 30 | {# Uncomment this if you wish to dump the entire record to the client, for debugging purposes. 31 | {{ dump(record) }} 32 | #} 33 | 34 | {{ include('partials/_recordfooter.twig', { 'record': record, 'extended': true }) }} 35 |
36 |
37 |
38 |
39 |
40 | 41 | {% include "partials/_sub_recent_records.twig" %} 42 | 43 | {% endblock main %} 44 | -------------------------------------------------------------------------------- /base-2018/search.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 |
5 |
6 | {# This template is used for search results. If 'search' is defined, 7 | we display an appropriate title. The 'records' array contains all of the 8 | records matching the current query. If there are no results, the 9 | code in the 'else' part of the for-loop is used. #} 10 | 11 |

12 | {% if search is not empty %} 13 | {{ __('general.phrase.search-results-for-variable', { '%search%': search }) }} 14 | {% else %} 15 | {{ __('general.phrase.search') }} 16 | {% endif %} 17 |

18 | 19 | {# Perhaps we post a small teaser, stored in the 'block' named 'Search teaser' #} 20 | {% setcontent block = "block/search-teaser" %} 21 | 22 | {# check if we have 'content'. If so, we know we have have a teaser to display. #} 23 | {% if block.content is defined %} 24 |
25 | {{ block.content }} 26 |
27 | {% endif %} 28 | 29 |
30 | 31 |
32 | 33 |
34 |
35 | 36 |
37 |
38 |
39 |
40 | 41 |
42 |
43 | {% for record in records %} 44 |
45 |
46 |
47 |

{{ record|title }}

48 | 49 |

50 | {% if record|edit_link %} 51 | Edit • 52 | {% endif %} 53 | {{ __('general.phrase.permalink') }} • 54 | {{ __('general.phrase.written-by-on', { 55 | '%name%': record.author.displayname|default(__('Unknown')), 56 | '%date%': record.datepublish|localdate("l F j, Y") 57 | }) }} 58 |

59 | 60 | {# display something introduction-like.. #} 61 |

{{ record|excerpt(300, false, search|default('')) }}

62 |
63 |
64 | {% if record|image %} 65 |
66 |
67 | 68 | {{ (record|image).alt|default(record|title) }} 69 | 70 |
71 |
72 | {% endif %} 73 |
74 | 75 | {% else %} 76 | 77 |
78 |

79 | {% if searchTerm is not empty %} 80 | {{ __('general.phrase.no-search-results-for', { '%search%': searchTerm|escape }) }} 81 | {% else %} 82 | {{ __('general.phrase.no-search-term-provided') }} 83 | {% endif %} 84 |

85 |
86 | 87 | {% endfor %} 88 | 89 | {# If there are more records than will fit on one page, the pager is shown. #} 90 | {{ pager(records, template = 'helpers/_pager_bulma.html.twig') }} 91 | 92 |
93 |
94 | {% endblock main %} 95 | -------------------------------------------------------------------------------- /base-2018/source/gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var $ = require('gulp-load-plugins')(); 3 | var argv = require('yargs').argv; 4 | 5 | // Check for --production flag 6 | var PRODUCTION = !!(argv.production); 7 | 8 | // Define base paths for Sass and Javascript. 9 | // File paths to various assets are defined here. 10 | var PATHS = { 11 | sass: [ 12 | 'node_modules', 13 | ] 14 | }; 15 | 16 | var javascriptFiles = [ 17 | 'javascript/app.js', 18 | 'node_modules/baguettebox.js/src/baguetteBox.js', 19 | 'node_modules/prismjs/prism.js', 20 | 'node_modules/prismjs/components/prism-php.js', 21 | 'node_modules/prismjs/components/prism-json.js', 22 | 'node_modules/prismjs/components/prism-yaml.js', 23 | 'node_modules/prismjs/components/prism-bash.js', 24 | 'node_modules/prismjs/components/prism-markup-templating.js', 25 | 'node_modules/prismjs/plugins/line-numbers/prism-line-numbers.js', 26 | 'node_modules/prismjs/plugins/line-highlight/prism-line-highlight.js' 27 | ]; 28 | 29 | // Compile Foundation Sass into CSS. In production, the CSS is compressed 30 | gulp.task('bulma-sass', function() { 31 | 32 | return gulp.src('scss/bulma.scss') 33 | .pipe($.sourcemaps.init()) 34 | .pipe($.sass({ 35 | includePaths: PATHS.sass 36 | }) 37 | .on('error', $.sass.logError)) 38 | .pipe($.autoprefixer()) 39 | .pipe($.if(PRODUCTION, $.cssnano())) 40 | .pipe($.if(!PRODUCTION, $.sourcemaps.write())) 41 | .pipe(gulp.dest('../css')); 42 | }); 43 | 44 | // Compile Theme Sass into CSS. Not compressed. 45 | gulp.task('theme-sass', function() { 46 | 47 | return gulp.src('scss/theme.scss') 48 | .pipe($.sourcemaps.init()) 49 | .pipe($.sass({ 50 | includePaths: PATHS.sass 51 | }) 52 | .on('error', $.sass.logError)) 53 | .pipe($.autoprefixer()) 54 | // If you _do_ want to compress this file on 'production', uncomment the the lines below. 55 | .pipe($.if(PRODUCTION, $.cssnano())) 56 | .pipe($.if(!PRODUCTION, $.sourcemaps.write())) 57 | .pipe(gulp.dest('../css')); 58 | }); 59 | 60 | // Set up 'compress' task. 61 | gulp.task('compress', function() { 62 | return gulp.src(javascriptFiles) 63 | .pipe($.if(PRODUCTION, $.uglify())) 64 | .pipe($.concat('app.js')) 65 | .pipe(gulp.dest('../js')); 66 | }); 67 | 68 | gulp.task('setproduction', function(done) { 69 | PRODUCTION = true; 70 | done(); 71 | }); 72 | 73 | // Set up 'default' task, with watches. 74 | gulp.task('default', gulp.series(gulp.parallel('compress', 'bulma-sass', 'theme-sass'), function watch() { 75 | gulp.watch(['scss/**/*.scss'], gulp.series('theme-sass', 'bulma-sass')); 76 | gulp.watch(['javascript/**/*.js'], gulp.series('compress')); 77 | })); 78 | 79 | // Set up 'build' task, without watches and force 'production'. 80 | gulp.task('build', gulp.series(gulp.parallel('setproduction', 'compress', 'bulma-sass', 'theme-sass'))); 81 | 82 | -------------------------------------------------------------------------------- /base-2018/source/javascript/app.js: -------------------------------------------------------------------------------- 1 | document.addEventListener('DOMContentLoaded', function () { 2 | 3 | // Get all "navbar-burger" elements 4 | var $navbarBurgers = Array.prototype.slice.call(document.querySelectorAll('.navbar-burger'), 0); 5 | 6 | // Check if there are any navbar burgers 7 | if ($navbarBurgers.length > 0) { 8 | 9 | // Add a click event on each of them 10 | $navbarBurgers.forEach(function ($el) { 11 | $el.addEventListener('click', function () { 12 | 13 | // Get the target from the "data-target" attribute 14 | var target = $el.dataset.target; 15 | var $target = document.getElementById(target); 16 | 17 | // Toggle the class on both the "navbar-burger" and the "navbar-menu" 18 | $el.classList.toggle('is-active'); 19 | $target.classList.toggle('is-active'); 20 | 21 | }); 22 | }); 23 | } 24 | baguetteBox.run('.container'); 25 | 26 | normalizeBrightness(); 27 | 28 | document.querySelector('.notification > button.delete').addEventListener('click', function(e) { 29 | e.target.parentElement.style.display = 'none'; 30 | }, false); 31 | }); 32 | -------------------------------------------------------------------------------- /base-2018/source/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bolt-base-2018-theme", 3 | "description": "Base 2018", 4 | "version": "0.1.0", 5 | "license": "MIT", 6 | "private": false, 7 | "repository": { 8 | "type": "git", 9 | "url": "https://github.com/bolt/themes" 10 | }, 11 | "bugs": { 12 | "url": "https://github.com/bolt/themes/issues", 13 | "email": "bob@twokings.nl" 14 | }, 15 | "main": "gulpfile.js", 16 | "dependencies": { 17 | "baguettebox.js": "^1.11.1", 18 | "bulma": "^0.9.0", 19 | "gulp-concat": "^2.6.1", 20 | "prismjs": "^1.27.0" 21 | }, 22 | "devDependencies": { 23 | "gulp": "^4.0.2", 24 | "gulp-autoprefixer": "^7.0.1", 25 | "gulp-cssnano": "^2.1.3", 26 | "gulp-if": "^3.0.0", 27 | "gulp-load-plugins": "^2.0.4", 28 | "gulp-sass": "^4.1.0", 29 | "node-sass": "^4.14.1", 30 | "gulp-sourcemaps": "^2.6.5", 31 | "gulp-uglify": "^3.0.2", 32 | "yargs": "^15.4.1" 33 | }, 34 | "scripts": { 35 | "start": "gulp", 36 | "build": "gulp build" 37 | }, 38 | "browserslist": [ 39 | "last 1 version", 40 | "> 1%" 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /base-2018/source/scss/_breakpointdebug.scss: -------------------------------------------------------------------------------- 1 | @if ($debug-breakpoint==true) { 2 | body:before { 3 | content: 'mobile'; 4 | position: fixed; 5 | text-align: center; 6 | bottom: 0; 7 | left: 0; 8 | width: auto; 9 | background: rgba(0, 0, 0, 0.85); 10 | color: #FFF; 11 | font-weight: bold; 12 | z-index: 999; 13 | padding: 0.5em 2em; 14 | 15 | @include tablet { 16 | content: 'tablet'; 17 | } 18 | 19 | @include desktop { 20 | content: 'desktop'; 21 | } 22 | 23 | @include widescreen { 24 | content: 'widescreen'; 25 | } 26 | 27 | @include fullhd { 28 | content: 'fullhd'; 29 | } 30 | 31 | } 32 | 33 | } -------------------------------------------------------------------------------- /base-2018/source/scss/_settings.scss: -------------------------------------------------------------------------------- 1 | // Show the current breakpoints in the lower left corner. 2 | $debug-breakpoint: false; 3 | 4 | // ------------ Settings for Bulma --------------- 5 | 6 | // 1. Import the initial variables 7 | @import "../node_modules/bulma/sass/utilities/initial-variables"; 8 | @import "../node_modules/bulma/sass/utilities/functions"; 9 | 10 | // 2. Set your own initial variables 11 | 12 | // Colors 13 | $light: rgb(240, 239, 239); 14 | $dark: #444; 15 | $medium: #777; 16 | 17 | // Fonts 18 | $font-sans-serif : 'Roboto', sans-serif; // Base font 19 | $font-serif : 'Bitter', serif; // Headings 20 | 21 | // 3. Set the derived variables 22 | 23 | // Option 1: https://color.adobe.com/ims-construction-colors-color-theme-10555392/ 24 | $link: #DF1C31; 25 | $info: #1B2A3F; 26 | $primary: #2873A4; 27 | $success: #F1A42C; 28 | 29 | // Option 2: https://color.adobe.com/mapa-laranja-color-theme-10556928/ 30 | // $primary: #C97B5C; 31 | // $info: #3F3430; 32 | // $link: #3F271D; 33 | // $success: #8B7368; 34 | 35 | // Option 3: https://color.adobe.com/WASD-color-theme-10551808/ 36 | // $primary: #0D6545; 37 | // $info: #373B3A; 38 | // $link: #0E724E; 39 | // $success: #8B7368; 40 | 41 | // Option 4: https://color.adobe.com/Palette-de-couleurs-1-color-theme-10564608/ 42 | // $primary: darken(#9FD4F1, 10); 43 | // $info: #9B8D1F; 44 | // $link: #385681; 45 | // $success: #9C8754; 46 | 47 | // Option 5: Black & White 48 | // $primary: #444; 49 | // $info: #888; 50 | // $link: #385691; 51 | // $success: #777; 52 | 53 | $pre-background: $grey-lighter; 54 | $family-primary: $font-sans-serif; 55 | 56 | // Generic variables 57 | $body-background-color: $white; 58 | $body-weight: $weight-light; 59 | $column-gap: 1.5rem; 60 | 61 | // Title 62 | $title-color: $black; 63 | $title-weight: $weight-normal; 64 | $title-size: 2rem; 65 | $subtitle-size: 1.5rem; 66 | 67 | // Box 68 | $box-radius: 0; 69 | $box-shadow: 0; 70 | 71 | // 4. Setup your Custom Colors 72 | $linkedin: #0077b5; 73 | $linkedin-invert: findColorInvert($linkedin); 74 | $twitter: #55acee; 75 | $twitter-invert: findColorInvert($twitter); 76 | $github: #333; 77 | $github-invert: findColorInvert($github); 78 | 79 | // 5. Import the rest of the "utilities". 80 | @import "../node_modules/bulma/sass/utilities/all"; 81 | -------------------------------------------------------------------------------- /base-2018/source/scss/_typography.scss: -------------------------------------------------------------------------------- 1 | h1, h2, h3, h4, h5, h6 { 2 | font-family: $font-serif; 3 | } 4 | 5 | p a, 6 | li a { 7 | text-decoration: underline; 8 | } 9 | -------------------------------------------------------------------------------- /base-2018/source/scss/bulma.scss: -------------------------------------------------------------------------------- 1 | // 6. Import the rest of Bulma with settings. 2 | 3 | @import 'settings'; 4 | @import '../node_modules/bulma/bulma'; 5 | 6 | // Some overrides to set a good default for Symfony Forms / Boltforms styles 7 | .boltform { 8 | & label { 9 | @extend .label; 10 | line-height: 2em; 11 | } 12 | 13 | & input { 14 | @extend .input; 15 | } 16 | 17 | & textarea { 18 | @extend .textarea; 19 | } 20 | 21 | & select { 22 | @extend .select; 23 | } 24 | 25 | & input[type='checkbox'] { 26 | @extend .checkbox; 27 | } 28 | 29 | & input[type='radio'] { 30 | @extend .radio; 31 | } 32 | 33 | & button { 34 | @extend .button; 35 | @extend .is-primary; 36 | } 37 | 38 | } 39 | 40 | 41 | /* Default pagerfanta styles, for pagination */ 42 | .pagination { 43 | } 44 | 45 | .pagination a, 46 | .pagination span { 47 | display: inline-block; 48 | background: #f4f9fa; 49 | border: 1px solid #96c4cc; 50 | color: #2c8898; 51 | margin-right: .2em; 52 | padding: .4em .35em; 53 | } 54 | 55 | .pagination a { 56 | text-decoration: none; 57 | } 58 | 59 | .pagination a:hover { 60 | background: #c0dbe0; 61 | color: #982c61; 62 | } 63 | 64 | .pagination .dots { 65 | border-width: 0; 66 | } 67 | 68 | .pagination .current { 69 | background: #c0dbe0; 70 | font-weight: bold; 71 | } 72 | 73 | .pagination .disabled { 74 | border-color: #c0dbe0; 75 | color: #abcfd6; 76 | } 77 | -------------------------------------------------------------------------------- /base-2018/source/scss/theme.scss: -------------------------------------------------------------------------------- 1 | // Theme specific styling. 2 | 3 | @import 'settings'; 4 | @import 'typography'; 5 | @import 'breakpointdebug'; 6 | @import 'node_modules/baguettebox.js/src/baguetteBox'; 7 | @import 'node_modules/prismjs/themes/prism'; 8 | 9 | .visually-hidden:not(:focus):not(:active) { 10 | position: absolute !important; 11 | height: 1px; 12 | width: 1px; 13 | overflow: hidden; 14 | clip: rect(1px, 1px, 1px, 1px); 15 | } 16 | .skip-link { 17 | font-family: $font-serif; 18 | font-size: $size-large; 19 | font-weight: bold; 20 | position: absolute; 21 | top: 60px; 22 | z-index: 1; 23 | } 24 | 25 | .navbar-brand { 26 | .navbar-item { 27 | font-family: $font-serif; 28 | font-size: $size-large; 29 | font-weight: bold; 30 | } 31 | } 32 | 33 | .navbar-end { 34 | align-items: center; 35 | @include mobile { 36 | form { 37 | padding: 1rem; 38 | .control:first-child { 39 | width: 100%; 40 | } 41 | } 42 | } 43 | } 44 | 45 | .notification { 46 | ul { 47 | margin: 0.5em 1.4em; 48 | list-style-type: disc; 49 | } 50 | } 51 | 52 | .teaser { 53 | font-weight: bold; 54 | margin-bottom: 1rem; 55 | } 56 | 57 | .card { 58 | display: flex; 59 | flex-direction: column; 60 | height: 100%; 61 | } 62 | 63 | .card-content { 64 | display: flex; 65 | flex-direction: column; 66 | height: 100%; 67 | 68 | .button:last-child { 69 | margin-top: auto; 70 | } 71 | 72 | p { 73 | height: 100%; 74 | } 75 | } 76 | 77 | .section-latest-entries { 78 | .buttons { 79 | margin-top: 1.5rem; 80 | } 81 | } 82 | 83 | .tags { 84 | margin-top: 3rem; 85 | .label { 86 | margin-right: .5em; 87 | } 88 | } 89 | 90 | .section-record { 91 | .image { 92 | margin-top: 3rem; 93 | margin-bottom: 3rem; 94 | } 95 | } 96 | 97 | .button { 98 | text-decoration: none; 99 | } 100 | 101 | p.meta { 102 | margin-top: 1rem; 103 | color: $medium; 104 | font-size: 90%; 105 | } 106 | 107 | .media { 108 | @include mobile { 109 | flex-direction: column; 110 | } 111 | } 112 | .media-right { 113 | flex-shrink: 1; 114 | margin-left: 0; 115 | @include mobile { 116 | order: -1; 117 | width: 100%; 118 | margin-bottom: 1rem; 119 | } 120 | } 121 | 122 | .imageholder { 123 | img { 124 | width: 100%; 125 | } 126 | } 127 | 128 | .notification > .delete { 129 | right: .5rem; 130 | top: .5rem; 131 | } 132 | 133 | 134 | .hero-image { 135 | background-repeat: no-repeat; 136 | background-position: center center; 137 | background-size: cover; 138 | margin-top: 52px; 139 | } 140 | 141 | .hero.is-large .hero-body { 142 | padding-bottom: 4rem; 143 | padding-top: 4rem; 144 | h1.title, 145 | h2.subtitle { 146 | text-shadow: 2px 2px 15px rgba(0, 0, 0, 0.4); 147 | } 148 | h1.title { 149 | font-size: $title-size; 150 | font-weight: bold; 151 | } 152 | h2.subtitle { 153 | font-size: $subtitle-size; 154 | } 155 | @include tablet { 156 | padding-bottom: 12rem; 157 | padding-top: 12rem; 158 | h1.title { 159 | font-size: $title-size * 1.25; 160 | } 161 | h2.subtitle { 162 | font-size: $subtitle-size * 1.25; 163 | } 164 | } 165 | @include desktop { 166 | padding-bottom: 16rem; 167 | padding-top: 16rem; 168 | h1.title { 169 | font-size: $title-size * 1.5; 170 | } 171 | h2.subtitle { 172 | font-size: $subtitle-size * 1.5; 173 | } 174 | } 175 | 176 | } 177 | 178 | .footer { 179 | padding: 2rem 1.5rem 180 | } 181 | 182 | // https://antoningrele.github.io/img-brightness-normalization/normalizeBrightness.css 183 | [data-background-image] { position: relative; } 184 | 185 | [data-background-image] .dark-overlay { 186 | /* This is the element that is going to darken the background image 187 | By default, it's entirely black, but the JS code will give it 188 | some transparency by setting its opacity to a calculated value. 189 | The brighter the image, the higher the opacity, to compensate ! */ 190 | 191 | content: ""; 192 | display: block; 193 | position: absolute; 194 | top: 0; left: 0; 195 | width: 100%; height: 100%; 196 | background-color: black; 197 | } 198 | 199 | pre { 200 | // Fix tags in PrismJS. 201 | .tag { 202 | margin: 0; 203 | padding: 0; 204 | background-color: transparent; 205 | display: inherit; 206 | font-size: inherit; 207 | } 208 | .number { 209 | font-size: 1em; 210 | } 211 | } -------------------------------------------------------------------------------- /base-2018/theme.yaml: -------------------------------------------------------------------------------- 1 | # Optional config file for the theme. 2 | 3 | # Variables that are in this file, can be used in your twig template like {{ theme.foo }} 4 | 5 | # Template filenames. If you're creating a theme for distribution, you can specify 6 | # the filenames of the templates here. The templates you will set in this config 7 | # file will override the ones in the global app/config/config.yml, so beware! 8 | # maintenance_template: maintenance_default.twig 9 | # homepage_template: index.twig 10 | # record_template: record.twig 11 | # listing_template: listing.twig 12 | # search_results_template: search.twig 13 | # notfound: not-found.twig 14 | 15 | # Optional overrides. These override the ones in config.yml, but can be set in 16 | # either place. 17 | # taxonomy_sort: DESC 18 | # homepage: page/1 19 | # listing_sort: datepublish DESC 20 | # listing_records: 6 21 | # search_results_records: 10 22 | 23 | # Aliases can be set to restrict images to a specific set of available 24 | # resolutions or to decouple image sizes from template files. 25 | thumbnails: 26 | aliases: 27 | myimageformat: 28 | size: [400,300] 29 | cropping: crop 30 | -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 detail.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 detail.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 detail.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 detail.png -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 homepage.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 homepage.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 homepage.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 homepage.png -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 homepage_widgets.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 homepage_widgets.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 homepage_widgets.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 homepage_widgets.png -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 listing.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 listing.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 listing.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 listing.png -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 search results.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 search results.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 search results.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 search results.png -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 showcase.monopic: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 showcase.monopic -------------------------------------------------------------------------------- /base-2018/wireframes/Base-2018 showcase.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2018/wireframes/Base-2018 showcase.png -------------------------------------------------------------------------------- /base-2021/README.md: -------------------------------------------------------------------------------- 1 | Bolt 4 - Base-2021 theme 2 | ======================== 3 | 4 | This is the base theme that comes with the installation of Bolt 5. 5 | 6 | Bolt CMS is an open source, adaptable platform for building and running modern 7 | websites. Built on PHP, Symfony and more. [Read the site](https://boltcms.io) 8 | for more info. 9 | 10 | To check out Bolt and set up your first Bolt installation, read [Installing Bolt][installation]. 11 | 12 | --- 13 | 14 | 1 Tailwind CSS 15 | -------------- 16 | 17 | This theme is based on the framework [Tailwind CSS](https://tailwindcss.com/). 18 | Tailwind CSS is a highly customizable, low-level CSS framework that gives you 19 | all of the building blocks you need to build bespoke designs without any 20 | opinionated styles you have to fight to override. 21 | 22 | 1.1 Development 23 | --------------- 24 | 25 | The raw Tailwind-flavoured CSS-file lives in `css/tailwind/`. In this setup the 26 | CSS will be processed, purged and minified by default. You can disable purging 27 | by setting `purge.enabled`to `false` in `tailwind.config.js` and minification by 28 | commenting out all `cssnano`-related lines in `postcss.config.js`. 29 | 30 | Read more about the process in the [Tailwind CSS / Optimizing for Production][opt] docs. 31 | 32 | During development you can use `yarn watch` to automatically regenerate all css 33 | files. When purging is enabled, this process scrapes all `.twig` files in the 34 | theme folder and tries to find all used selectors. In doing so, all unused 35 | selectors are purged and the final size of tailwind reduces from a couple of 36 | megabytes to some kilobytes. 37 | 38 | 2 Resources 39 | ----------- 40 | 41 | - [Tailwind Cheat Sheet](https://nerdcave.com/tailwind-cheat-sheet) 42 | - [Tailwind components](https://tailwindcomponents.com/) 43 | - [Tailwind Toolbox](https://www.tailwindtoolbox.com/) 44 | - [Awsome Tailwind CSS - Large resource of links](https://github.com/aniftyco/awesome-tailwindcss) 45 | - [Bolt CMS documentation](https://docs.bolt.cm/4.0/getting-started/introduction) 46 | - [Twig documentation](https://twig.symfony.com/) 47 | 48 | 3 Editing this theme 49 | -------------------- 50 | 51 | The base-2021 theme consists of: 52 | 53 | - Homepage (index.twig) 54 | - Record page (record.twig) 55 | - Listing page (listing.twig) 56 | 57 | You can edit these files to your liking. The themes come with the development 58 | build of Tailwind CSS which is 2380.4kB. 59 | These makes the development as productive as possible, but when you are ready 60 | for production, make sure you 'purge' the CSS. 61 | See the Tailwind documentation for information about [controling the file size](https://tailwindcss.com/docs/controlling-file-size). 62 | 63 | ``` 64 | **Important note** 65 | In the folder "tailwind css" is the base css file for generating the Tailwind CSS. 66 | In this file are also some custom CSS rules for the record template. 67 | ``` 68 | 69 | [opt]: https://tailwindcss.com/docs/optimizing-for-production 70 | [installation]: https://docs.bolt.cm/installation/installation 71 | -------------------------------------------------------------------------------- /base-2021/css/base-2021.css: -------------------------------------------------------------------------------- 1 | /*! tailwindcss v2.2.4 | MIT License | https://tailwindcss.com*/ 2 | 3 | /*! modern-normalize v1.1.0 | MIT License | https://github.com/sindresorhus/modern-normalize */html{-webkit-text-size-adjust:100%;line-height:1.15;-moz-tab-size:4;-o-tab-size:4;tab-size:4}body{font-family:system-ui,-apple-system,Segoe UI,Roboto,Helvetica,Arial,sans-serif,Apple Color Emoji,Segoe UI Emoji;margin:0}hr{color:inherit;height:0}code{font-family:ui-monospace,SFMono-Regular,Consolas,Liberation Mono,Menlo,monospace;font-size:1em}button,input,textarea{font-family:inherit;font-size:100%;line-height:1.15;margin:0}button{text-transform:none}[type=button],[type=submit],button{-webkit-appearance:button}progress{vertical-align:baseline}[type=search]{-webkit-appearance:textfield;outline-offset:-2px}h1,h2,h3,hr,p{margin:0}button{background-color:transparent;background-image:none}ul{list-style:none;margin:0;padding:0}html{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji;line-height:1.5}body{font-family:inherit;line-height:inherit}*,:after,:before{border:0 solid;box-sizing:border-box}hr{border-top-width:1px}img{border-style:solid}textarea{resize:vertical}input::-moz-placeholder,textarea::-moz-placeholder{color:#9ca3af;opacity:1}input:-ms-input-placeholder,textarea:-ms-input-placeholder{color:#9ca3af;opacity:1}input::placeholder,textarea::placeholder{color:#9ca3af;opacity:1}button{cursor:pointer}h1,h2,h3{font-size:inherit;font-weight:inherit}a{color:inherit;text-decoration:inherit}button,input,textarea{color:inherit;line-height:inherit;padding:0}code{font-family:ui-monospace,SFMono-Regular,Menlo,Monaco,Consolas,Liberation Mono,Courier New,monospace}embed,iframe,img,svg{display:block;vertical-align:middle}img{height:auto;max-width:100%}*,:after,:before{--tw-border-opacity:1;border-color:rgba(229,231,235,var(--tw-border-opacity))}html{font-size:18px}a,a:hover{text-decoration:underline}a.rounded,a.rounded-full,nav a{text-decoration:inherit}a.pencil-editlink{font-size:75%;opacity:.7;text-decoration:none}a.pencil-editlink:hover{opacity:1}.container{width:100%}@media (min-width:640px){.container{max-width:640px}}@media (min-width:768px){.container{max-width:768px}}@media (min-width:1024px){.container{max-width:1024px}}@media (min-width:1280px){.container{max-width:1280px}}@media (min-width:1536px){.container{max-width:1536px}}.fixed{position:fixed}.absolute{position:absolute}.relative{position:relative}.inset-0{bottom:0;left:0;right:0;top:0}.top-0{top:0}.right-0{right:0}.bottom-0{bottom:0}.left-0{left:0}.z-0{z-index:0}.z-10{z-index:10}.z-20{z-index:20}.z-30{z-index:30}.z-40{z-index:40}.z-50{z-index:50}.order-first{order:-9999}.m-8{margin:2rem}.-m-4{margin:-1rem}.mx-4{margin-left:1rem;margin-right:1rem}.mx-auto{margin-left:auto;margin-right:auto}.my-0{margin-bottom:0;margin-top:0}.my-2{margin-bottom:.5rem;margin-top:.5rem}.my-3{margin-bottom:.75rem;margin-top:.75rem}.my-4{margin-bottom:1rem;margin-top:1rem}.my-6{margin-bottom:1.5rem;margin-top:1.5rem}.my-12{margin-bottom:3rem;margin-top:3rem}.mt-1{margin-top:.25rem}.mt-2{margin-top:.5rem}.mt-3{margin-top:.75rem}.mt-4{margin-top:1rem}.mt-8{margin-top:2rem}.mt-16{margin-top:4rem}.mt-auto{margin-top:auto}.-mt-12{margin-top:-3rem}.mr-2{margin-right:.5rem}.mr-3{margin-right:.75rem}.mr-4{margin-right:1rem}.mb-1{margin-bottom:.25rem}.mb-2{margin-bottom:.5rem}.mb-3{margin-bottom:.75rem}.mb-4{margin-bottom:1rem}.mb-5{margin-bottom:1.25rem}.mb-6{margin-bottom:1.5rem}.mb-8{margin-bottom:2rem}.mb-10{margin-bottom:2.5rem}.mb-12{margin-bottom:3rem}.ml-1{margin-left:.25rem}.ml-3{margin-left:.75rem}.ml-auto{margin-left:auto}.block{display:block}.inline{display:inline}.flex{display:flex}.inline-flex{display:inline-flex}.hidden{display:none}.h-1{height:.25rem}.h-4{height:1rem}.h-5{height:1.25rem}.h-6{height:1.5rem}.h-10{height:2.5rem}.h-20{height:5rem}.h-32{height:8rem}.h-auto{height:auto}.h-full{height:100%}.w-4{width:1rem}.w-5{width:1.25rem}.w-6{width:1.5rem}.w-10{width:2.5rem}.w-20{width:5rem}.w-64{width:16rem}.w-1\/6{width:16.666667%}.w-5\/6{width:83.333333%}.w-full{width:100%}.max-w-sm{max-width:24rem}.max-w-3xl{max-width:48rem}.max-w-4xl{max-width:56rem}.max-w-5xl{max-width:64rem}.max-w-full{max-width:100%}.max-w-screen-xl{max-width:1280px}.flex-1{flex:1 1 0%}.flex-none{flex:none}.flex-shrink-0{flex-shrink:0}.flex-shrink{flex-shrink:1}.flex-grow{flex-grow:1}.transform{--tw-translate-x:0;--tw-translate-y:0;--tw-rotate:0;--tw-skew-x:0;--tw-skew-y:0;--tw-scale-x:1;--tw-scale-y:1;transform:translateX(var(--tw-translate-x)) translateY(var(--tw-translate-y)) rotate(var(--tw-rotate)) skewX(var(--tw-skew-x)) skewY(var(--tw-skew-y)) scaleX(var(--tw-scale-x)) scaleY(var(--tw-scale-y))}.origin-top-right{transform-origin:top right}.rotate-0{--tw-rotate:0deg}.rotate-180{--tw-rotate:180deg}.scale-95{--tw-scale-x:.95;--tw-scale-y:.95}.scale-100{--tw-scale-x:1;--tw-scale-y:1}.resize-none{resize:none}.list-none{list-style-type:none}.appearance-none{-webkit-appearance:none;-moz-appearance:none;appearance:none}.flex-row{flex-direction:row}.flex-col{flex-direction:column}.flex-col-reverse{flex-direction:column-reverse}.flex-wrap{flex-wrap:wrap}.content-center{align-content:center}.items-start{align-items:flex-start}.items-end{align-items:flex-end}.items-center{align-items:center}.justify-start{justify-content:flex-start}.justify-end{justify-content:flex-end}.justify-center{justify-content:center}.justify-between{justify-content:space-between}.overflow-hidden{overflow:hidden}.break-normal{overflow-wrap:normal;word-break:normal}.rounded-none{border-radius:0}.rounded{border-radius:.25rem}.rounded-md{border-radius:.375rem}.rounded-lg{border-radius:.5rem}.rounded-full{border-radius:9999px}.rounded-t-none{border-top-left-radius:0;border-top-right-radius:0}.rounded-t{border-top-left-radius:.25rem;border-top-right-radius:.25rem}.rounded-b-none{border-bottom-left-radius:0;border-bottom-right-radius:0}.rounded-b{border-bottom-left-radius:.25rem;border-bottom-right-radius:.25rem}.border-0{border-width:0}.border-2{border-width:2px}.border{border-width:1px}.border-b-2{border-bottom-width:2px}.border-b-4{border-bottom-width:4px}.border-b{border-bottom-width:1px}.border-none{border-style:none}.border-gray-200{--tw-border-opacity:1;border-color:rgba(229,231,235,var(--tw-border-opacity))}.border-gray-400{--tw-border-opacity:1;border-color:rgba(156,163,175,var(--tw-border-opacity))}.focus\:border-indigo-500:focus{--tw-border-opacity:1;border-color:rgba(99,102,241,var(--tw-border-opacity))}.bg-transparent{background-color:transparent}.bg-white{--tw-bg-opacity:1;background-color:rgba(255,255,255,var(--tw-bg-opacity))}.bg-gray-100{--tw-bg-opacity:1;background-color:rgba(243,244,246,var(--tw-bg-opacity))}.bg-gray-200{--tw-bg-opacity:1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.bg-gray-300{--tw-bg-opacity:1;background-color:rgba(209,213,219,var(--tw-bg-opacity))}.hover\:bg-gray-200:hover{--tw-bg-opacity:1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.hover\:bg-indigo-600:hover{--tw-bg-opacity:1;background-color:rgba(79,70,229,var(--tw-bg-opacity))}.focus\:bg-gray-200:focus{--tw-bg-opacity:1;background-color:rgba(229,231,235,var(--tw-bg-opacity))}.object-cover{-o-object-fit:cover;object-fit:cover}.object-center{-o-object-position:center;object-position:center}.p-1{padding:.25rem}.p-3{padding:.75rem}.p-4{padding:1rem}.p-6{padding:1.5rem}.p-8{padding:2rem}.p-10{padding:2.5rem}.px-2{padding-left:.5rem;padding-right:.5rem}.px-3{padding-left:.75rem;padding-right:.75rem}.px-4{padding-left:1rem;padding-right:1rem}.px-5{padding-left:1.25rem;padding-right:1.25rem}.px-6{padding-left:1.5rem;padding-right:1.5rem}.px-8{padding-left:2rem;padding-right:2rem}.py-0{padding-bottom:0;padding-top:0}.py-1{padding-bottom:.25rem;padding-top:.25rem}.py-2{padding-bottom:.5rem;padding-top:.5rem}.py-3{padding-bottom:.75rem;padding-top:.75rem}.py-4{padding-bottom:1rem;padding-top:1rem}.py-6{padding-bottom:1.5rem;padding-top:1.5rem}.py-8{padding-bottom:2rem;padding-top:2rem}.py-12{padding-bottom:3rem;padding-top:3rem}.py-24{padding-bottom:6rem;padding-top:6rem}.pt-4{padding-top:1rem}.pt-6{padding-top:1.5rem}.pt-12{padding-top:3rem}.pt-20{padding-top:5rem}.pt-24{padding-top:6rem}.pr-0{padding-right:0}.pr-3{padding-right:.75rem}.pb-0{padding-bottom:0}.pb-4{padding-bottom:1rem}.pb-6{padding-bottom:1.5rem}.pb-12{padding-bottom:3rem}.pb-20{padding-bottom:5rem}.text-left{text-align:left}.text-center{text-align:center}.text-right{text-align:right}.align-middle{vertical-align:middle}.font-sans{font-family:ui-sans-serif,system-ui,-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,Helvetica Neue,Arial,Noto Sans,sans-serif,Apple Color Emoji,Segoe UI Emoji,Segoe UI Symbol,Noto Color Emoji}.text-xs{font-size:.75rem;line-height:1rem}.text-sm{font-size:.875rem;line-height:1.25rem}.text-base{font-size:1rem;line-height:1.5rem}.text-lg{font-size:1.125rem}.text-lg,.text-xl{line-height:1.75rem}.text-xl{font-size:1.25rem}.text-2xl{font-size:1.5rem;line-height:2rem}.text-3xl{font-size:1.875rem;line-height:2.25rem}.text-5xl{font-size:3rem;line-height:1}.font-normal{font-weight:400}.font-medium{font-weight:500}.font-semibold{font-weight:600}.font-bold{font-weight:700}.uppercase{text-transform:uppercase}.leading-none{line-height:1}.leading-tight{line-height:1.25}.leading-normal{line-height:1.5}.leading-relaxed{line-height:1.625}.tracking-normal{letter-spacing:0}.tracking-wide{letter-spacing:.025em}.tracking-widest{letter-spacing:.1em}.text-black{--tw-text-opacity:1;color:rgba(0,0,0,var(--tw-text-opacity))}.text-white{--tw-text-opacity:1;color:rgba(255,255,255,var(--tw-text-opacity))}.text-gray-200{--tw-text-opacity:1;color:rgba(229,231,235,var(--tw-text-opacity))}.text-gray-400{--tw-text-opacity:1;color:rgba(156,163,175,var(--tw-text-opacity))}.text-gray-500{--tw-text-opacity:1;color:rgba(107,114,128,var(--tw-text-opacity))}.text-gray-600{--tw-text-opacity:1;color:rgba(75,85,99,var(--tw-text-opacity))}.text-gray-700{--tw-text-opacity:1;color:rgba(55,65,81,var(--tw-text-opacity))}.text-gray-800{--tw-text-opacity:1;color:rgba(31,41,55,var(--tw-text-opacity))}.text-gray-900{--tw-text-opacity:1;color:rgba(17,24,39,var(--tw-text-opacity))}.text-indigo-500{--tw-text-opacity:1;color:rgba(99,102,241,var(--tw-text-opacity))}.focus\:text-gray-900:focus,.hover\:text-gray-900:hover{--tw-text-opacity:1;color:rgba(17,24,39,var(--tw-text-opacity))}.underline{text-decoration:underline}.no-underline{text-decoration:none}.hover\:underline:hover{text-decoration:underline}.hover\:no-underline:hover{text-decoration:none}.opacity-0{opacity:0}.opacity-25{opacity:.25}.opacity-100{opacity:1}*,:after,:before{--tw-shadow:0 0 #0000}.shadow{--tw-shadow:0 1px 3px 0 rgba(0,0,0,0.1),0 1px 2px 0 rgba(0,0,0,0.06)}.shadow,.shadow-md{box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.shadow-md{--tw-shadow:0 4px 6px -1px rgba(0,0,0,0.1),0 2px 4px -1px rgba(0,0,0,0.06)}.shadow-lg{--tw-shadow:0 10px 15px -3px rgba(0,0,0,0.1),0 4px 6px -2px rgba(0,0,0,0.05);box-shadow:var(--tw-ring-offset-shadow,0 0 #0000),var(--tw-ring-shadow,0 0 #0000),var(--tw-shadow)}.focus\:outline-none:focus{outline:2px solid transparent;outline-offset:2px}*,:after,:before{--tw-ring-inset:var(--tw-empty,/*!*/ /*!*/);--tw-ring-offset-width:0px;--tw-ring-offset-color:#fff;--tw-ring-color:rgba(59,130,246,0.5);--tw-ring-offset-shadow:0 0 #0000;--tw-ring-shadow:0 0 #0000}.filter{--tw-blur:var(--tw-empty,/*!*/ /*!*/);--tw-brightness:var(--tw-empty,/*!*/ /*!*/);--tw-contrast:var(--tw-empty,/*!*/ /*!*/);--tw-grayscale:var(--tw-empty,/*!*/ /*!*/);--tw-hue-rotate:var(--tw-empty,/*!*/ /*!*/);--tw-invert:var(--tw-empty,/*!*/ /*!*/);--tw-saturate:var(--tw-empty,/*!*/ /*!*/);--tw-sepia:var(--tw-empty,/*!*/ /*!*/);--tw-drop-shadow:var(--tw-empty,/*!*/ /*!*/);filter:var(--tw-blur) var(--tw-brightness) var(--tw-contrast) var(--tw-grayscale) var(--tw-hue-rotate) var(--tw-invert) var(--tw-saturate) var(--tw-sepia) var(--tw-drop-shadow)}.grayscale{--tw-grayscale:grayscale(100%)}.transition{transition-duration:.15s;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,-webkit-backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter;transition-property:background-color,border-color,color,fill,stroke,opacity,box-shadow,transform,filter,backdrop-filter,-webkit-backdrop-filter;transition-timing-function:cubic-bezier(.4,0,.2,1)}.transition-transform{transition-duration:.15s;transition-property:transform;transition-timing-function:cubic-bezier(.4,0,.2,1)}.duration-75{transition-duration:75ms}.duration-100{transition-duration:.1s}.duration-200{transition-duration:.2s}.ease-in{transition-timing-function:cubic-bezier(.4,0,1,1)}.ease-out{transition-timing-function:cubic-bezier(0,0,.2,1)}.article>p{margin:1rem 0}.article>p,.article>ul{font-size:clamp(1.1rem,1.1vw,1.6rem)}.article>ul{list-style-position:inside;list-style-type:disc}.article h1{font-size:clamp(1.875rem,2.5vw,2.25rem)}.article h2{font-size:clamp(1.5rem,2vw,1.875rem)}.article h3{font-size:clamp(1.25rem,1.75vw,1.5rem);font-weight:700}@media (min-width:640px){.sm\:my-4{margin-bottom:1rem;margin-top:1rem}.sm\:mt-0{margin-top:0}.sm\:-mt-6{margin-top:-1.5rem}.sm\:mr-4{margin-right:1rem}.sm\:mr-10{margin-right:2.5rem}.sm\:ml-6{margin-left:1.5rem}.sm\:ml-auto{margin-left:auto}.sm\:w-1\/2{width:50%}.sm\:flex-row{flex-direction:row}.sm\:justify-start{justify-content:flex-start}}@media (min-width:768px){.md\:mt-0{margin-top:0}.md\:-mt-1{margin-top:-.25rem}.md\:mb-0{margin-bottom:0}.md\:mb-2{margin-bottom:.5rem}.md\:ml-0{margin-left:0}.md\:ml-4{margin-left:1rem}.md\:ml-auto{margin-left:auto}.md\:inline-block{display:inline-block}.md\:inline{display:inline}.md\:flex{display:flex}.md\:hidden{display:none}.md\:h-36{height:9rem}.md\:w-48{width:12rem}.md\:w-64{width:16rem}.md\:w-auto{width:auto}.md\:w-1\/2{width:50%}.md\:w-1\/3{width:33.333333%}.md\:flex-grow{flex-grow:1}.md\:flex-row{flex-direction:row}.md\:items-center{align-items:center}.md\:justify-start{justify-content:flex-start}.md\:justify-end{justify-content:flex-end}.md\:justify-between{justify-content:space-between}.md\:px-4{padding-left:1rem;padding-right:1rem}.md\:py-8{padding-bottom:2rem;padding-top:2rem}.md\:pb-0{padding-bottom:0}.md\:text-left{text-align:left}.md\:text-sm{font-size:.875rem;line-height:1.25rem}.md\:text-base{font-size:1rem;line-height:1.5rem}.md\:text-xl{font-size:1.25rem;line-height:1.75rem}.md\:text-3xl{font-size:1.875rem;line-height:2.25rem}}@media (min-width:1024px){.lg\:mx-0{margin-left:0;margin-right:0}.lg\:mt-0{margin-top:0}.lg\:mt-2{margin-top:.5rem}.lg\:-mt-24{margin-top:-6rem}.lg\:mr-0{margin-right:0}.lg\:mb-0{margin-bottom:0}.lg\:ml-auto{margin-left:auto}.lg\:h-48{height:12rem}.lg\:w-1\/2{width:50%}.lg\:w-1\/3{width:33.333333%}.lg\:w-2\/3{width:66.666667%}.lg\:w-1\/4{width:25%}.lg\:flex-wrap{flex-wrap:wrap}.lg\:rounded-l-lg{border-bottom-left-radius:.5rem;border-top-left-radius:.5rem}.lg\:text-5xl{font-size:3rem;line-height:1}}@media (min-width:1280px){.xl\:mt-0{margin-top:0}.xl\:mr-4{margin-right:1rem}} -------------------------------------------------------------------------------- /base-2021/css/tailwind/base-2021.css: -------------------------------------------------------------------------------- 1 | @tailwind base; 2 | @tailwind components; 3 | @tailwind utilities; 4 | 5 | @layer base { 6 | html { 7 | font-size: 18px; 8 | } 9 | 10 | a, a:hover { 11 | text-decoration: underline; 12 | } 13 | 14 | nav a, 15 | a.rounded, 16 | a.rounded-full { 17 | text-decoration: inherit; 18 | } 19 | 20 | a.pencil-editlink { 21 | text-decoration: none; 22 | opacity: 0.7; 23 | font-size: 75%; 24 | } 25 | 26 | a.pencil-editlink:hover { 27 | opacity: 1.0; 28 | } 29 | } 30 | 31 | /* Default grid, as used by the Article field type */ 32 | .article-grid { 33 | display: grid; 34 | grid-template-columns: repeat(12, 1fr); 35 | grid-column-gap: 2rem; 36 | grid-row-gap: 0rem; 37 | } 38 | 39 | .article-grid + .article-grid { 40 | margin-top: 1rem; 41 | } 42 | 43 | .article-grid figure, .article-grid img { 44 | margin: 0; 45 | width: 100%; 46 | max-width: 100%; 47 | } 48 | 49 | .article-grid .col-1 { grid-column: span 1; } 50 | .article-grid .col-2 { grid-column: span 2; } 51 | .article-grid .col-3 { grid-column: span 3; } 52 | .article-grid .col-4 { grid-column: span 4; } 53 | .article-grid .col-5 { grid-column: span 5; } 54 | .article-grid .col-6 { grid-column: span 6; } 55 | .article-grid .col-7 { grid-column: span 7; } 56 | .article-grid .col-8 { grid-column: span 8; } 57 | .article-grid .col-9 { grid-column: span 9; } 58 | .article-grid .col-10 { grid-column: span 10; } 59 | .article-grid .col-11 { grid-column: span 11; } 60 | .article-grid .col-12 { grid-column: span 12; } 61 | 62 | .article-grid div p { 63 | margin-top: 0; 64 | } 65 | 66 | @media only screen and (max-width: 600px) { 67 | .article-grid { 68 | grid-template-columns: repeat(1, 1fr); 69 | } 70 | 71 | .article-grid .col-1, 72 | .article-grid .col-2, 73 | .article-grid .col-3, 74 | .article-grid .col-4, 75 | .article-grid .col-5, 76 | .article-grid .col-6, 77 | .article-grid .col-7, 78 | .article-grid .col-8, 79 | .article-grid .col-9, 80 | .article-grid .col-10, 81 | .article-grid .col-11, 82 | .article-grid .col-12 { 83 | grid-column: span 1; 84 | margin-bottom: 1rem; 85 | } 86 | } 87 | 88 | @layer utilities { 89 | @responsive { 90 | 91 | .article>p { 92 | margin: 1rem 0; 93 | font-size: clamp(1.1rem, 1.1vw, 1.6rem); 94 | } 95 | 96 | .article > ol { 97 | list-style-type: decimal; 98 | list-style-position: inside; 99 | font-size: clamp(1.1rem, 1.1vw, 1.6rem); 100 | } 101 | 102 | .article > ul { 103 | list-style-type: disc; 104 | list-style-position: inside; 105 | font-size: clamp(1.1rem, 1.1vw, 1.6rem); 106 | } 107 | .article h1 { 108 | font-size: clamp(1.875rem, 2.5vw, 2.25rem) 109 | } 110 | .article h2 { 111 | font-size: clamp(1.5rem, 2vw, 1.875rem) 112 | } 113 | .article h3 { 114 | font-size: clamp(1.25rem, 1.75vw, 1.5rem); 115 | font-weight: 700; 116 | } 117 | .article h4 { 118 | font-size: clamp(1.125rem, 1.5vw, 1.25rem) 119 | } 120 | .article h5 { 121 | font-size: 1rem; 122 | font-weight: 700; 123 | } 124 | .article h6 { 125 | font-size: 1rem; 126 | font-weight: 600; 127 | } 128 | 129 | .article blockquote>p { 130 | border-left-width: 4px; 131 | border-color: #b2f5ea; 132 | font-style: italic; 133 | margin-top: 2rem; 134 | margin-bottom: 2rem; 135 | padding-left: 2rem; 136 | font-size: clamp(1.875rem, 2.5vw, 2.25rem); 137 | } 138 | 139 | } 140 | } 141 | /* Base grid for "Article" powered Fields */ 142 | -------------------------------------------------------------------------------- /base-2021/img/hero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/base-2021/img/hero.png -------------------------------------------------------------------------------- /base-2021/img/logo.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | 7 | 9 | 10 | -------------------------------------------------------------------------------- /base-2021/index.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 | {% include 'partials/_index_hero.twig' with { content: 'blocks/hero-section' } %} 6 | 7 | {% include 'partials/_index_divider_top.twig' %} 8 | 9 | {% include 'partials/_index_home_block.twig' with { content: 'homepage/1' } %} 10 | 11 | {% include 'partials/_index_vertical_block.twig' with { content: 'blocks/introduction', contenttype: 'pages' } %} 12 | 13 | {% include 'partials/_index_3_column_block_images.twig' with { contenttype: 'entries' } %} 14 | 15 | {% if 'people' in config.get('contenttypes').keys() %} 16 | {% include 'partials/_index_team.twig' with { content: 'blocks/people', contenttype: 'people' } %} 17 | {% endif %} 18 | 19 | {% if 'products' in config.get('contenttypes').keys() %} 20 | {% include 'partials/_index_pricing_block.twig' with { content: 'blocks/products', contenttype: 'products' } %} 21 | {% endif %} 22 | 23 | {% if 'pages' in config.get('contenttypes').keys() %} 24 | {% include 'partials/_index_3_column_block.twig' with { content: 'blocks/about', contenttype: 'pages' } %} 25 | {% endif %} 26 | 27 | {% include 'partials/_index_divider_bottom.twig' with { background: '#FFF' } %} 28 | 29 | {% include 'partials/_index_CTA.twig' with { content: 'blocks/call-to-action' } %} 30 | 31 | {% include 'partials/_index_divider_top.twig' with { background: '#f8fafc' } %} 32 | 33 | {% include 'partials/_index_contact_with_map.twig' %} 34 | 35 | {% endblock main %} 36 | -------------------------------------------------------------------------------- /base-2021/js/app.js: -------------------------------------------------------------------------------- 1 | 2 | /*Toggle header colours*/ 3 | var scrollpos = window.scrollY; 4 | var header = document.getElementById("header"); 5 | var navcontent = document.getElementById("nav-content"); 6 | var navaction = document.getElementById("navAction"); 7 | var brandname = document.getElementById("brandname"); 8 | var toToggle = document.querySelectorAll(".toggleColour"); 9 | 10 | document.addEventListener('scroll', function() { 11 | 12 | /*Apply classes for slide in bar*/ 13 | scrollpos = window.scrollY; 14 | 15 | if(scrollpos > 10){ 16 | header.classList.add("bg-white"); 17 | header.classList.remove("text-white"); 18 | header.classList.add("text-black"); 19 | //Use to switch toggleColour colours 20 | for (var i = 0; i < toToggle.length; i++) { 21 | toToggle[i].classList.add("text-black"); 22 | toToggle[i].classList.remove("text-white"); 23 | } 24 | header.classList.add("shadow"); 25 | 26 | } 27 | else { 28 | header.classList.remove("bg-white"); 29 | header.classList.remove("text-black"); 30 | header.classList.add("text-white"); 31 | 32 | //Use to switch toggleColour colours 33 | for (var i = 0; i < toToggle.length; i++) { 34 | toToggle[i].classList.add("text-white"); 35 | toToggle[i].classList.remove("text-gray-800"); 36 | } 37 | 38 | header.classList.remove("shadow"); 39 | 40 | 41 | } 42 | 43 | }); 44 | 45 | 46 | 47 | /*Toggle dropdown list*/ 48 | /*https://gist.github.com/slavapas/593e8e50cf4cc16ac972afcbad4f70c8*/ 49 | 50 | var navMenuDiv = document.getElementById("nav-content"); 51 | var navMenu = document.getElementById("nav-toggle"); 52 | 53 | document.onclick = check; 54 | function check(e){ 55 | var target = (e && e.target) || (event && event.srcElement); 56 | 57 | //Nav Menu 58 | if (!checkParent(target, navMenuDiv) && navMenuDiv) { 59 | // click NOT on the menu 60 | if (checkParent(target, navMenu)) { 61 | // click on the link 62 | if (navMenuDiv.classList.contains("hidden")) { 63 | navMenuDiv.classList.remove("hidden"); 64 | } else { 65 | navMenuDiv.classList.add("hidden"); 66 | } 67 | } else { 68 | // click both outside link and outside menu, hide menu 69 | navMenuDiv.classList.add("hidden"); 70 | } 71 | } 72 | } 73 | function checkParent(t, elm) { 74 | while(t.parentNode) { 75 | if( t == elm ) {return true;} 76 | t = t.parentNode; 77 | } 78 | return false; 79 | } 80 | 81 | 82 | /* Progress bar */ 83 | //Source: https://alligator.io/js/progress-bar-javascript-css-variables/ 84 | var h = document.documentElement, 85 | b = document.body, 86 | st = 'scrollTop', 87 | sh = 'scrollHeight', 88 | progress = document.querySelector('#progress'), 89 | scroll; 90 | var scrollpos = window.scrollY; 91 | var header = document.getElementById("header"); 92 | var navcontent = document.getElementById("nav-content"); 93 | 94 | document.addEventListener('scroll', function () { 95 | if(progress) { 96 | /*Refresh scroll % width*/ 97 | scroll = (h[st] || b[st]) / ((h[sh] || b[sh]) - h.clientHeight) * 100; 98 | progress.style.setProperty('--scroll', scroll + '%'); 99 | 100 | /*Apply classes for slide in bar*/ 101 | scrollpos = window.scrollY; 102 | if (scrollpos > 10) { 103 | header.classList.add("bg-white"); 104 | header.classList.add("shadow"); 105 | } else { 106 | header.classList.remove("bg-white"); 107 | header.classList.remove("shadow"); 108 | } 109 | } 110 | }); 111 | -------------------------------------------------------------------------------- /base-2021/listing.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 |
5 | {# This template is used for 'listings': Generic pages that list a number of 6 | records from a certain content type. These records are available as an array 7 | called 'records'. In the for-loop below, we iterate over the records that 8 | are on this page. It can be used for overview pages like 'all entries', or 9 | 'all records tagged with kittens'. #} 10 | 11 | 12 | 13 |
14 | {# If used for listing a taxonomy, we add a heading #} 15 | {% if taxonomy is defined %} 16 |
17 |

18 | {{ __('general.phrase.overview-for', {'%slug%': taxonomy.options[slug]|default(slug) }) }} 19 |

20 |
21 | {% endif %} 22 | 23 | {% if search is defined %} 24 |
25 |

26 | {% if search is not empty %} 27 | {{ __('general.phrase.search-results-for-variable', { '%search%': search }) }} 28 | {% else %} 29 | {{ __('general.phrase.search') }} 30 | {% endif %} 31 |

32 |
33 | {% endif %} 34 | 35 |
36 | 37 | {% for record in records %} 38 | 39 |
40 |
41 | 42 | {% for type, taxonomies in record|taxonomies %} 43 | {% for taxonomy in taxonomies %} 44 | {{ taxonomy.name }} 45 | {% endfor %} 46 | {% endfor %} 47 | 48 | {{ record.publishedAt|date("d M Y")}} 49 | 50 |
51 | 52 |
53 |

{{ record|title }}

54 |

55 | {{ record|excerpt(300, false, search|default('')) }} 56 |

57 | 58 | 59 | {{ __('general.phrase.read-more') }} » 60 | 61 |
62 | 63 |
64 | {% if record|image %} 65 | 66 | {% endif %} 67 |
68 | 69 |
70 | 71 | {% else %} 72 | 73 |

{{ __('general.phrase.no-content-found') }}

74 |

75 | {{ __("Unfortunately, no content could be found. Try another page, or go to the homepage.", {'%paths_root%': path('homepage')} ) }} 76 |

77 | 78 |
79 | 82 | 85 |
86 | 87 | {% endfor %} 88 | 89 |
90 | 91 | {{ pager(records, template='helpers/_pager_tailwind.html.twig') }} 92 |
93 |
94 | {% endblock main %} 95 | -------------------------------------------------------------------------------- /base-2021/macros.twig: -------------------------------------------------------------------------------- 1 | {% macro edit(content, label = "✏️") %}{% apply spaceless %} 2 | {% if content|edit_link %} 3 | {% set title = __('general.phrase.edit') ~ ' ' ~ content.definition.singular_name ~ ' "' ~ content|title ~ '"' %} 4 | {{ label }} 5 | {% endif %} 6 | {% endapply %}{% endmacro %} 7 | -------------------------------------------------------------------------------- /base-2021/package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "current", 3 | "version": "1.0.0", 4 | "scripts": { 5 | "build-tailwind": "postcss css/tailwind/*.css -d css/", 6 | "watch": "chokidar '*.config.js' 'css/tailwind/*.css' '**/*.twig' -i 'node_modules' -c 'yarn build-tailwind' --initial" 7 | }, 8 | "license": "ISC", 9 | "devDependencies": { 10 | "autoprefixer": "^10.2.6", 11 | "chokidar-cli": "^2.1.0", 12 | "cssnano": "^5.0.6", 13 | "postcss-cli": "^8.3.1", 14 | "tailwindcss": "^2.2.2" 15 | } 16 | } -------------------------------------------------------------------------------- /base-2021/partials/_block_header.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 |

{{ block|title }} {{ edit(block) }}

4 |
5 |
6 |
7 |
8 |
9 | {{ block|excerpt(300) }} 10 |
11 |
12 | -------------------------------------------------------------------------------- /base-2021/partials/_contact_form_extension.twig: -------------------------------------------------------------------------------- 1 | {# We've put this in a separate partial, because this is needed for correct 2 | behaviour: The Twig parser parses the entire document, and _then_ executes it. 3 | This means we can't parse a template that checks if a tag might exist or not. 4 | By putting this in a separate file, we circumvent that limitation. #} 5 | {{ boltforms('contact') }} -------------------------------------------------------------------------------- /base-2021/partials/_contact_form_static.twig: -------------------------------------------------------------------------------- 1 | 4 | 7 | 10 | -------------------------------------------------------------------------------- /base-2021/partials/_footer.twig: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /base-2021/partials/_index_3_column_block.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/people" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | {# The name of `contenttype` is passed in from the index, i.e. "people" #} 7 | {% setcontent records = (contenttype) limit 3 random %} 8 | 9 | 10 |
{# no `border-b` (border-bottom) #} 11 | 43 |
44 | -------------------------------------------------------------------------------- /base-2021/partials/_index_3_column_block_images.twig: -------------------------------------------------------------------------------- 1 | {# The name of `contenttype` is passed in from the index, i.e. "entries" #} 2 | {% setcontent records = (contenttype) limit 3 latest %} 3 | 4 | 5 |
6 |
7 |
8 | 9 | {% for record in records %} 10 |
11 |
12 | {% if record|image %} 13 | {{ record|image.title|default('-') }} 15 | {% endif %} 16 |
17 |

18 | {% for taxonomy in record|taxonomies['categories']|default([]) %} 19 | {{ taxonomy.name }} 20 | {%- if not loop.last %}, {% endif %} 21 | {% endfor %} 22 |

23 |

24 | {{ record|title }} 25 |

26 |

27 | {{ record|excerpt(200) }} 28 |

29 |
30 | 31 | {{ __('general.phrase.read-more') }} » 32 | 33 | 34 | 35 | {{ record.author }} 36 | 37 |
38 |
39 |
40 |
41 | 42 | {% endfor %} 43 | 44 |
45 |
46 |
47 | -------------------------------------------------------------------------------- /base-2021/partials/_index_CTA.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/people" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | 7 |
8 |

{{ block|title }}

9 |
10 |
11 |
12 |

{{ block|excerpt }}

13 | 15 | Action! 16 | 17 |
18 | -------------------------------------------------------------------------------- /base-2021/partials/_index_contact_with_map.twig: -------------------------------------------------------------------------------- 1 | {# Configure the address and location of the map in `public/theme/base-2021/theme.yaml`. #} 2 | 3 | 4 |
5 |
6 |
8 | 12 |
13 |
14 |

ADDRESS

15 |

{{ config.get('theme/location/address')|nl2br }}

16 |
17 | 23 |
24 |
25 | 26 |
27 |

Feedback

28 | {% if extension_exists('bolt/forms') %} 29 | {% include 'partials/_contact_form_extension.twig' %} 30 | {% else %} 31 | {% include 'partials/_contact_form_static.twig' %} 32 | {% endif %} 33 |
34 |
35 |
36 | -------------------------------------------------------------------------------- /base-2021/partials/_index_divider_bottom.twig: -------------------------------------------------------------------------------- 1 | {% set background = background|default('#f8fafc') %} 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /base-2021/partials/_index_divider_top.twig: -------------------------------------------------------------------------------- 1 | {% set background = background|default('#f8fafc') %} 2 | 3 | 4 |
5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 |
-------------------------------------------------------------------------------- /base-2021/partials/_index_hero.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/hero" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | 7 |
8 |
9 | 10 |
11 |

{{ block|title }} {{ edit(block) }}

12 |

{{ block.teaser|default(block|excerpt) }}

13 | 15 | {{ __('general.phrase.read-more') }} 16 | 17 |
18 | 19 |
20 | 21 |
22 |
23 |
24 | -------------------------------------------------------------------------------- /base-2021/partials/_index_home_block.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "homepage/1" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | 7 |
8 |
9 | 10 |
11 | 12 |
13 |

{{ block|title }} {{ edit(block) }}

14 | {{ block.introduction }} 15 | 16 |
17 | 18 | {% if record|image %} 19 |
20 | {{ record|image.title }} 22 |
23 | {% endif %} 24 | 25 |
26 | {{ block.content }} 27 |
28 |
29 | 30 |
31 |
32 | -------------------------------------------------------------------------------- /base-2021/partials/_index_pricing_block.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/products" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | {# The name of `contenttype` is passed in from the index, i.e. "people" #} 7 | {% setcontent records = (contenttype) limit 3 %} 8 | 9 | 10 |
11 |
12 | {% include 'partials/_block_header.twig' %} 13 | 14 |
15 | 16 | {% for record in records %} 17 | {% if loop.index == 2 %} 18 |
19 |
20 |
{{ record|title }} {{ edit(block) }}
21 |
22 |
    23 |
  • ✅ {{ record.feature_1 }}
  • 24 |
  • ✅ {{ record.feature_2 }}
  • 25 |
  • ✅ {{ record.feature_3 }}
  • 26 |
27 |
28 |
29 | {{ record|excerpt(100, wrap=true) }} 30 |
31 | {{ record.price|default('unknown')}} 32 | per month 33 |
34 |
35 | 38 |
39 |
40 |
41 | {% else %} 42 |
43 |
44 |
{{ record|title }}
45 |
    46 |
  • ✅ {{ record.feature_1 }}
  • 47 |
  • ✅ {{ record.feature_2 }}
  • 48 |
  • ✅ {{ record.feature_3 }}
  • 49 |
50 |
51 |
52 | {{ record|excerpt(100, wrap=true) }} 53 |
54 | {{ record.price|default('unknown')}} 55 | per month 56 |
57 |
58 | 61 |
62 |
63 |
64 | {% endif %} 65 | {% endfor %} 66 | 67 |
68 |
69 |
70 | -------------------------------------------------------------------------------- /base-2021/partials/_index_team.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/people" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | {# The name of `contenttype` is passed in from the index, i.e. "people" #} 7 | {% setcontent records = (contenttype) limit 4 random returnmultiple %} 8 | 9 | 10 |
11 |
12 | {% include 'partials/_block_header.twig' %} 13 | 14 |
15 | 16 | {% for record in records %} 17 |
18 |
19 | {{ record.name }} - {{ record.description }} 22 |
23 |

{{ record.name }} {{ edit(block) }}

24 |

{{ record.description }}

25 |

{{ record|excerpt(100) }}

26 | 27 | 28 | 29 | {{ __('general.phrase.read-more') }} 30 | 31 | 32 | 33 | {% if record.contentlink %} 34 | 35 | 36 | Link 37 | 38 | 39 | {% endif %} 40 | 41 |
42 |
43 |
44 | {% endfor %} 45 | 46 |
47 |
48 |
49 | -------------------------------------------------------------------------------- /base-2021/partials/_index_vertical_block.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {# The name of the `content` is passed in from the index, i.e. "blocks/introduction" #} 4 | {% setcontent block = (content) returnsingle %} 5 | 6 | {# The name of `contenttype` is passed in from the index, i.e. "pages" #} 7 | {% setcontent records = (contenttype) limit 4 %} 8 | 9 | 10 |
11 |
12 | {% include 'partials/_block_header.twig' %} 13 | 14 | {% for record in records %} 15 |
16 | {% if loop.index is odd and record|image %} 17 |
18 | {{ record|image.title }} 20 |
21 | {% endif %} 22 | 23 |
24 |

{{ record|title }} {{ edit(block) }}

25 | {{ record|excerpt(300, wrap=true) }} 26 | 27 | 28 | {{ __('general.phrase.read-more') }} » 29 | 30 | 31 |
32 | {% if loop.index is even and record|image %} 33 |
34 | {{ record|image.title }} 36 |
37 | {% endif %} 38 |
39 | {% endfor %} 40 | 41 |
42 |
43 | -------------------------------------------------------------------------------- /base-2021/partials/_latest_few_of_everything.twig: -------------------------------------------------------------------------------- 1 | {% for ct in config.get('contenttypes')|filter(ct => not ct.viewless and not ct.singleton) %} 2 | 3 | {% setcontent records = ct.slug latest limit 3 %} 4 | 5 |
6 |

{{ ct.name|upper }}

7 | 8 | {% if records|length %} 9 | 16 |

17 | 18 | {{ __('contenttypes.generic.overview',{'%contenttypes%': ct.name}) }} » 19 | 20 |

21 | {% else %} 22 |

{{ __('contenttypes.generic.no-recent', {'%contenttype%': ct.slug}) }}

23 | {% endif %} 24 | 25 |
26 | {% endfor %} 27 | -------------------------------------------------------------------------------- /base-2021/partials/_master.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {# make sure we always display a proper title: The record's title if there is one, appended with the 8 | sitename. If there is no title, we append the sitename with the payoff, if there is one. #} 9 | 10 | {%- if record|default and record.title -%} 11 | {{- record.title ~ ' | ' -}} 12 | {%- endif -%} 13 | {{- config.get('general/sitename') -}} 14 | {%- if record|default == null and config.has('general/payoff') -%} 15 | {{- ' | ' ~ config.get('general/payoff') -}} 16 | {%- endif -%} 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 34 | 35 | 36 | 37 | 38 | {% include 'partials/_navigation.twig' %} 39 | 40 | {% block main %} 41 | (This is block main) 42 | {% endblock main %} 43 | 44 | {% include 'partials/_footer.twig' %} 45 | 46 | 47 | 48 | 49 | 50 | -------------------------------------------------------------------------------- /base-2021/partials/_menu.twig: -------------------------------------------------------------------------------- 1 | {% macro display_submenu(item) %} 2 |
3 | 9 |
15 |
16 | {% for item in item.submenu %} 17 | {{ item.label|default(item.title) }} 19 | {% endfor %} 20 |
21 |
22 |
23 | {% endmacro %} 24 | 25 | {% macro display_main(item) %} 26 | 33 | {{ item.label|default(item.title) }} 34 | 35 | {% endmacro %} 36 | 37 | 50 | -------------------------------------------------------------------------------- /base-2021/partials/_navigation.twig: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /base-2021/partials/_record_author.twig: -------------------------------------------------------------------------------- 1 | {% set author = record|related('people')|first %} 2 | 3 | {% if author %} 4 | 5 |
6 | Avatar of Author 8 |
9 |

{{ author.name }}

10 |

{{ author.description }}

11 |
12 | 17 |
18 | 19 | {% endif %} -------------------------------------------------------------------------------- /base-2021/partials/_record_divider_top.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 | 5 | 6 | 7 | 10 | 13 | 16 | 17 | 18 | 20 | 21 | 22 | 23 | 24 |
-------------------------------------------------------------------------------- /base-2021/partials/_record_header_author.twig: -------------------------------------------------------------------------------- 1 | {% set author = record|related('people')|first %} 2 | 3 | {% if author %} 4 |
5 | {% if author|image %} 6 | 7 | {% endif %} 8 | 9 |
10 |

By {{ author.name }}

11 |

{{ record.publishedAt|date("d M")}}

12 |
13 |
14 | {% endif %} -------------------------------------------------------------------------------- /base-2021/partials/_record_newsletter_sub.twig: -------------------------------------------------------------------------------- 1 |
2 | 3 | 4 |
5 |
6 |

Subscribe to my Newsletter

7 |

Get the latest posts delivered right 8 | to your inbox

9 |
10 |
11 |
12 | 14 | 16 |
17 |
18 |
19 |
20 |
21 | -------------------------------------------------------------------------------- /base-2021/partials/_record_prev_next.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | {% set previous = record|previous('id') %} 4 | {% set next = record|next('id') %} 5 | {% if previous or next %} 6 |
7 |
8 | {% if previous %} 9 | « Previous {{ record.definition.singular_name }}
10 |

12 | {{ previous|title|excerpt(44) }} 13 |

14 | {% endif %} 15 |
16 |
17 | {% if next %} 18 | Next {{ record.definition.singular_name }} »
19 |

21 | {{ next|title|excerpt(44) }} 22 |

23 | {% endif %} 24 |
25 |
26 | {% endif %} 27 | 28 | -------------------------------------------------------------------------------- /base-2021/partials/_socials.twig: -------------------------------------------------------------------------------- 1 | 2 | {% if config.get('theme/socials/facebook') %} 3 | 4 | 6 | 7 | 8 | 9 | {% endif %} 10 | 11 | {% if config.get('theme/socials/twitter') %} 12 | 13 | 15 | 16 | 17 | 18 | 19 | {% endif %} 20 | 21 | {% if config.get('theme/socials/youtube') %} 22 | 23 | 25 | 26 | 27 | {% endif %} 28 | 29 | {% if config.get('theme/socials/instagram') %} 30 | 31 | 33 | 34 | 35 | 36 | 37 | {% endif %} 38 | 39 | {% if config.get('theme/socials/linkedin') %} 40 | 41 | 43 | 45 | 46 | 47 | 48 | {% endif %} -------------------------------------------------------------------------------- /base-2021/postcss.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | plugins: { 3 | tailwindcss: {}, 4 | autoprefixer: {}, 5 | cssnano: { 6 | preset: "default", 7 | }, 8 | }, 9 | }; 10 | -------------------------------------------------------------------------------- /base-2021/record.twig: -------------------------------------------------------------------------------- 1 | {% from 'macros.twig' import edit as edit %} 2 | 3 | {% extends 'partials/_master.twig' %} 4 | 5 | {% block main %} 6 | 7 | 8 | 9 |
10 | 11 |
12 |
14 |
15 | {% if record|image %} 16 | 17 | {% endif %} 18 | 19 |
20 |
21 |

22 | {{ record|title }} 23 |

24 | {% include 'partials/_record_header_author.twig' %} 25 |
26 |
27 | 28 | {% include 'partials/_record_divider_top.twig' %} 29 | 30 |
31 | 32 |
33 | 34 |
35 | 36 | 37 | 38 |
39 |

{{ record|title }} {{ edit(record) }}

40 | 41 | {% with { 'record': record, 'exclude': [record|image.fieldname|default(), 'teaser'] } %} 42 | {{ block('sub_fields', 'helpers/_fields.twig') }} 43 | {% endwith %} 44 |
45 | 46 | 47 | 48 |
49 | 50 | 51 |
52 | {% for type, taxonomies in record|taxonomies %} 53 | {{ config.get('taxonomies/' ~ type).name }}: 54 | {% for taxonomy in taxonomies %} 55 | {{ taxonomy.name }} 56 | {%- if not loop.last %}, {% endif %} 57 | {% endfor %} 58 |
59 | {% endfor %} 60 |
61 | 62 | 63 | {# If you have a newsletter, uncomment the following, to insert the subscription block #} 64 | {# {% include 'partials/_record_newsletter_sub.twig' %} #} 65 | 66 | 67 | {% include 'partials/_record_author.twig' %} 68 | 69 | 70 |
71 | 72 | {% include 'partials/_record_prev_next.twig' %} 73 | 74 |
75 |
76 | 77 | 78 | {% endblock main %} 79 | -------------------------------------------------------------------------------- /base-2021/tailwind.config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | purge: { 3 | mode: "all", 4 | enabled: true, 5 | preserveHtmlElements: false, 6 | options: { 7 | keyframes: true, 8 | }, 9 | content: ["./**/*.twig"], 10 | }, 11 | darkMode: false, 12 | theme: { 13 | extend: {}, 14 | }, 15 | variants: { 16 | extend: {}, 17 | }, 18 | plugins: [], 19 | }; 20 | -------------------------------------------------------------------------------- /base-2021/theme.yaml: -------------------------------------------------------------------------------- 1 | # location for the embedded map 2 | location: 3 | map_query: "Two Kings, the Hague" 4 | address: | 5 | Prins Hendrikstraat 91 6 | 2518 HL The Hague 7 | Netherlands 8 | email: support@example.org 9 | phone: "+31 1-123456789" 10 | 11 | socials: 12 | facebook: ~ 13 | twitter: https://twitter.com/twokings 14 | instagram: https://www.instagram.com/bopp 15 | linkedin: https://www.linkedin.com/company/two-kings 16 | youtube: ~ 17 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "bolt/themes", 3 | "description": "🎨 Starter themes for Bolt", 4 | "type": "bolt-theme", 5 | "homepage": "https://boltcms.io", 6 | "keywords": [ 7 | "CMS", 8 | "Twig" 9 | ], 10 | "license": "MIT", 11 | "require": { 12 | "php": ">=7.2.9", 13 | "twig/twig": "^2.12 | ^3.0" 14 | }, 15 | "require-dev": { 16 | "bolt/core": "^4.1 || ^5.0" 17 | }, 18 | "extra": { 19 | "screenshots": [ 20 | "screenshots/screenshot1.png", 21 | "screenshots/screenshot2.png", 22 | "screenshots/screenshot3.png" 23 | ], 24 | "themes": [ 25 | "skeleton", 26 | "base-2018", 27 | "base-2021" 28 | ] 29 | } 30 | } 31 | -------------------------------------------------------------------------------- /screenshots/screenshot1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/screenshots/screenshot1.png -------------------------------------------------------------------------------- /screenshots/screenshot2.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/screenshots/screenshot2.png -------------------------------------------------------------------------------- /screenshots/screenshot3.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/bolt/themes/205f78a1b2999cb08b4570816bcb2185d3dbd3a2/screenshots/screenshot3.png -------------------------------------------------------------------------------- /skeleton/README.md: -------------------------------------------------------------------------------- 1 | Bolt Skeleton Theme 2 | =================== 3 | 4 | Skeleton is a minimal theme for Bolt. It has the bare bones functionality of 5 | what you'd commonly expect from a template, without all the bells and whistles. 6 | 7 | Features: 8 | 9 | - Simple design, function over form. 10 | - Uses [Simple.css](https://simplecss.org/) as a minimal CSS theme. 11 | - No Javascript. 12 | 13 | Aw yiss. 14 | -------------------------------------------------------------------------------- /skeleton/css/simple.css: -------------------------------------------------------------------------------- 1 | /* Global variables. */ 2 | :root { 3 | /* Set sans-serif & mono fonts */ 4 | --sans-font: -apple-system, BlinkMacSystemFont, "Avenir Next", Avenir, 5 | "Nimbus Sans L", Roboto, "Noto Sans", "Segoe UI", Arial, Helvetica, 6 | "Helvetica Neue", sans-serif; 7 | --mono-font: Consolas, Menlo, Monaco, "Andale Mono", "Ubuntu Mono", monospace; 8 | 9 | /* Body font size. By default, effectively 18.4px, based on 16px as 'root em' */ 10 | --base-fontsize: 1.15rem; 11 | 12 | /* Major third scale progression - see https://type-scale.com/ */ 13 | --header-scale: 1.25; 14 | 15 | /* Line height is set to the "Golden ratio" for optimal legibility */ 16 | --line-height: 1.618; 17 | 18 | /* Default (light) theme */ 19 | --bg: #fff; 20 | --accent-bg: #f5f7ff; 21 | --text: #212121; 22 | --text-light: #585858; 23 | --border: #898EA4; 24 | --accent: #0d47a1; 25 | --code: #d81b60; 26 | --preformatted: #444; 27 | --marked: #ffdd33; 28 | --disabled: #efefef; 29 | } 30 | 31 | /* Dark theme */ 32 | @media (prefers-color-scheme: dark) { 33 | :root { 34 | color-scheme: dark; 35 | --bg: #212121; 36 | --accent-bg: #2b2b2b; 37 | --text: #dcdcdc; 38 | --text-light: #ababab; 39 | --accent: #ffb300; 40 | --code: #f06292; 41 | --preformatted: #ccc; 42 | --disabled: #111; 43 | } 44 | /* Add a bit of transparency so light media isn't so glaring in dark mode */ 45 | img, 46 | video { 47 | opacity: 0.8; 48 | } 49 | } 50 | 51 | /* Reset box-sizing */ 52 | *, *::before, *::after { 53 | box-sizing: border-box; 54 | } 55 | 56 | /* Reset default appearance */ 57 | textarea, 58 | select, 59 | input, 60 | progress { 61 | appearance: none; 62 | -webkit-appearance: none; 63 | -moz-appearance: none; 64 | } 65 | 66 | html { 67 | /* Set the font globally */ 68 | font-family: var(--sans-font); 69 | scroll-behavior: smooth; 70 | } 71 | 72 | /* Make the body a nice central block */ 73 | body { 74 | color: var(--text); 75 | background-color: var(--bg); 76 | font-size: var(--base-fontsize); 77 | line-height: var(--line-height); 78 | display: grid; 79 | grid-template-columns: 1fr min(45rem, 90%) 1fr; 80 | margin: 0; 81 | } 82 | body > * { 83 | grid-column: 2; 84 | } 85 | 86 | /* Make the header bg full width, but the content inline with body */ 87 | body > header { 88 | background-color: var(--accent-bg); 89 | border-bottom: 1px solid var(--border); 90 | text-align: center; 91 | padding: 0 0.5rem 2rem 0.5rem; 92 | grid-column: 1 / -1; 93 | } 94 | 95 | body > header h1 { 96 | max-width: 1200px; 97 | margin: 1rem auto; 98 | } 99 | 100 | body > header p { 101 | max-width: 40rem; 102 | margin: 1rem auto; 103 | } 104 | 105 | /* Add a little padding to ensure spacing is correct between content and header > nav */ 106 | main { 107 | padding-top: 1.5rem; 108 | } 109 | 110 | body > footer { 111 | background: var(--accent-bg); 112 | border-top: 1px solid var(--border); 113 | margin-top: 4rem; 114 | padding: 2rem 1rem 1.5rem 1rem; 115 | color: var(--text-light); 116 | font-size: 0.9rem; 117 | text-align: center; 118 | border-top: 1px solid var(--border); 119 | } 120 | 121 | /* Format headers */ 122 | h1 { 123 | font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale) * var(--header-scale)); 124 | margin-top: calc(var(--line-height) * 1.5rem); 125 | } 126 | 127 | h2 { 128 | font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale) * var(--header-scale)); 129 | margin-top: calc(var(--line-height) * 1.5rem); 130 | } 131 | 132 | h3 { 133 | font-size: calc(var(--base-fontsize) * var(--header-scale) * var(--header-scale)); 134 | margin-top: calc(var(--line-height) * 1.5rem); 135 | } 136 | 137 | h4 { 138 | font-size: calc(var(--base-fontsize) * var(--header-scale)); 139 | margin-top: calc(var(--line-height) * 1.5rem); 140 | } 141 | 142 | h5 { 143 | font-size: var(--base-fontsize); 144 | margin-top: calc(var(--line-height) * 1.5rem); 145 | } 146 | 147 | h6 { 148 | font-size: calc(var(--base-fontsize) / var(--header-scale)); 149 | margin-top: calc(var(--line-height) * 1.5rem); 150 | } 151 | 152 | /* Prevent long strings from overflowing container */ 153 | p, h1, h2, h3, h4, h5, h6 { 154 | overflow-wrap: break-word; 155 | } 156 | 157 | /* Fix line height when title wraps */ 158 | h1, 159 | h2, 160 | h3 { 161 | line-height: 1.1; 162 | } 163 | 164 | /* Format links & buttons */ 165 | a, 166 | a:visited { 167 | color: var(--accent); 168 | } 169 | 170 | a:hover { 171 | text-decoration: none; 172 | } 173 | 174 | button, 175 | [role="button"], 176 | input[type="submit"], 177 | input[type="reset"], 178 | input[type="button"], 179 | label[type="button"] { 180 | border: none; 181 | border-radius: 5px; 182 | background-color: var(--accent); 183 | font-size: 1rem; 184 | color: var(--bg); 185 | padding: 0.7rem 0.9rem; 186 | margin: 0.5rem 0; 187 | } 188 | 189 | button[disabled], 190 | [role="button"][aria-disabled="true"], 191 | input[type="submit"][disabled], 192 | input[type="reset"][disabled], 193 | input[type="button"][disabled], 194 | input[type="checkbox"][disabled], 195 | input[type="radio"][disabled], 196 | select[disabled] { 197 | cursor: not-allowed; 198 | } 199 | 200 | input:disabled, 201 | textarea:disabled, 202 | select:disabled, 203 | button[disabled] { 204 | cursor: not-allowed; 205 | background-color: var(--disabled); 206 | color: var(--text-light) 207 | } 208 | 209 | input[type="range"] { 210 | padding: 0; 211 | } 212 | 213 | /* Set the cursor to '?' on an abbreviation and style the abbreviation to show that there is more information underneath */ 214 | abbr[title] { 215 | cursor: help; 216 | text-decoration-line: underline; 217 | text-decoration-style: dotted; 218 | } 219 | 220 | button:enabled:hover, 221 | [role="button"]:not([aria-disabled="true"]):hover, 222 | input[type="submit"]:enabled:hover, 223 | input[type="reset"]:enabled:hover, 224 | input[type="button"]:enabled:hover, 225 | label[type="button"]:hover { 226 | filter: brightness(1.4); 227 | cursor: pointer; 228 | } 229 | 230 | button:focus-visible:where(:enabled, [role="button"]:not([aria-disabled="true"])), 231 | input:enabled:focus-visible:where( 232 | [type="submit"], 233 | [type="reset"], 234 | [type="button"] 235 | ) { 236 | outline: 2px solid var(--accent); 237 | outline-offset: 1px; 238 | } 239 | 240 | /* Format navigation */ 241 | header > nav { 242 | font-size: 1rem; 243 | line-height: 2; 244 | padding: 1rem 0 0 0; 245 | } 246 | 247 | /* Use flexbox to allow items to wrap, as needed */ 248 | header > nav ul, 249 | header > nav ol { 250 | align-content: space-around; 251 | align-items: center; 252 | display: flex; 253 | flex-direction: row; 254 | flex-wrap: wrap; 255 | justify-content: center; 256 | list-style-type: none; 257 | margin: 0; 258 | padding: 0; 259 | } 260 | 261 | /* List items are inline elements, make them behave more like blocks */ 262 | header > nav ul li, 263 | header > nav ol li { 264 | display: inline-block; 265 | } 266 | 267 | header > nav a, 268 | header > nav a:visited { 269 | margin: 0 0.5rem 1rem 0.5rem; 270 | border: 1px solid var(--border); 271 | border-radius: 5px; 272 | color: var(--text); 273 | display: inline-block; 274 | padding: 0.1rem 1rem; 275 | text-decoration: none; 276 | } 277 | 278 | header > nav a:hover { 279 | border-color: var(--accent); 280 | color: var(--accent); 281 | cursor: pointer; 282 | } 283 | 284 | /* Reduce nav side on mobile */ 285 | @media only screen and (max-width: 720px) { 286 | header > nav a { 287 | border: none; 288 | padding: 0; 289 | text-decoration: underline; 290 | line-height: 1; 291 | } 292 | } 293 | 294 | /* Consolidate box styling */ 295 | aside, details, pre, progress { 296 | background-color: var(--accent-bg); 297 | border: 1px solid var(--border); 298 | border-radius: 5px; 299 | margin-bottom: 1rem; 300 | } 301 | 302 | aside { 303 | font-size: 1rem; 304 | padding: 0 15px; 305 | } 306 | 307 | .main aside { 308 | width: 30%; 309 | float: right; 310 | margin-left: 15px; 311 | } 312 | 313 | /* Make aside full-width on mobile */ 314 | @media only screen and (max-width: 720px) { 315 | aside { 316 | width: 100%; 317 | float: none; 318 | margin-left: 0; 319 | } 320 | } 321 | 322 | fieldset { 323 | border: 1px solid var(--border); 324 | padding: 1rem; 325 | border-radius: 5px; 326 | margin-bottom: 1rem; 327 | } 328 | 329 | article h2:first-child, 330 | section h2:first-child { 331 | margin-top: 1rem; 332 | } 333 | 334 | section { 335 | border-top: 1px solid var(--border); 336 | border-bottom: 1px solid var(--border); 337 | padding: 2rem 1rem; 338 | margin: 3rem 0; 339 | } 340 | 341 | /* Don't double separators when chaining sections */ 342 | section + section, 343 | section:first-child { 344 | border-top: 0; 345 | padding-top: 0; 346 | } 347 | 348 | section:last-child { 349 | border-bottom: 0; 350 | padding-bottom: 0; 351 | } 352 | 353 | details { 354 | padding: 0.7rem 1rem; 355 | } 356 | 357 | summary { 358 | cursor: pointer; 359 | font-weight: bold; 360 | padding: 0.7rem 1rem; 361 | margin: -0.7rem -1rem; 362 | word-break: break-all; 363 | } 364 | 365 | details[open] > summary + * { 366 | margin-top: 0; 367 | } 368 | 369 | details[open] > summary { 370 | margin-bottom: 0.5rem; 371 | } 372 | 373 | details[open] > :last-child { 374 | margin-bottom: 0; 375 | } 376 | 377 | /* Format tables */ 378 | table { 379 | border-collapse: collapse; 380 | display: block; 381 | margin: 1.5rem 0; 382 | overflow: auto; 383 | width: 100%; 384 | } 385 | 386 | td, 387 | th { 388 | border: 1px solid var(--border); 389 | text-align: left; 390 | padding: 0.5rem; 391 | } 392 | 393 | th { 394 | background-color: var(--accent-bg); 395 | font-weight: bold; 396 | } 397 | 398 | tr:nth-child(even) { 399 | /* Set every other cell slightly darker. Improves readability. */ 400 | background-color: var(--accent-bg); 401 | } 402 | 403 | table caption { 404 | font-weight: bold; 405 | margin-bottom: 0.5rem; 406 | } 407 | 408 | /* Format forms */ 409 | textarea, 410 | select, 411 | input { 412 | font-size: inherit; 413 | font-family: inherit; 414 | padding: 0.5rem; 415 | margin-bottom: 0.5rem; 416 | color: var(--text); 417 | background-color: var(--bg); 418 | border: 1px solid var(--border); 419 | border-radius: 5px; 420 | box-shadow: none; 421 | max-width: 100%; 422 | display: inline-block; 423 | } 424 | label { 425 | display: block; 426 | } 427 | textarea:not([cols]) { 428 | width: 100%; 429 | } 430 | 431 | /* Add arrow to drop-down */ 432 | select:not([multiple]) { 433 | background-image: linear-gradient(45deg, transparent 49%, var(--text) 51%), 434 | linear-gradient(135deg, var(--text) 51%, transparent 49%); 435 | background-position: calc(100% - 15px), calc(100% - 10px); 436 | background-size: 5px 5px, 5px 5px; 437 | background-repeat: no-repeat; 438 | padding-right: 25px; 439 | } 440 | 441 | /* checkbox and radio button style */ 442 | input[type="checkbox"], 443 | input[type="radio"] { 444 | vertical-align: middle; 445 | position: relative; 446 | width: min-content; 447 | } 448 | 449 | input[type="checkbox"] + label, 450 | input[type="radio"] + label { 451 | display: inline-block; 452 | } 453 | 454 | input[type="radio"] { 455 | border-radius: 100%; 456 | } 457 | 458 | input[type="checkbox"]:checked, 459 | input[type="radio"]:checked { 460 | background-color: var(--accent); 461 | } 462 | 463 | input[type="checkbox"]:checked::after { 464 | /* Creates a rectangle with colored right and bottom borders which is rotated to look like a check mark */ 465 | content: " "; 466 | width: 0.18em; 467 | height: 0.32em; 468 | border-radius: 0; 469 | position: absolute; 470 | top: 0.05em; 471 | left: 0.17em; 472 | background-color: transparent; 473 | border-right: solid var(--bg) 0.08em; 474 | border-bottom: solid var(--bg) 0.08em; 475 | font-size: 1.8em; 476 | transform: rotate(45deg); 477 | } 478 | input[type="radio"]:checked::after { 479 | /* creates a colored circle for the checked radio button */ 480 | content: " "; 481 | width: 0.25em; 482 | height: 0.25em; 483 | border-radius: 100%; 484 | position: absolute; 485 | top: 0.125em; 486 | background-color: var(--bg); 487 | left: 0.125em; 488 | font-size: 32px; 489 | } 490 | 491 | /* Makes input fields wider on smaller screens */ 492 | @media only screen and (max-width: 720px) { 493 | textarea, 494 | select, 495 | input { 496 | width: 100%; 497 | } 498 | } 499 | 500 | /* Set a height for color input */ 501 | input[type="color"] { 502 | height: 2.5rem; 503 | padding: 0.2rem; 504 | } 505 | 506 | /* do not show border around file selector button */ 507 | input[type="file"] { 508 | border: 0; 509 | } 510 | 511 | /* Misc body elements */ 512 | hr { 513 | border: none; 514 | height: 1px; 515 | background: var(--border); 516 | margin: 1rem auto; 517 | } 518 | 519 | mark { 520 | padding: 2px 5px; 521 | border-radius: 4px; 522 | background-color: var(--marked); 523 | } 524 | 525 | img, 526 | video { 527 | max-width: 100%; 528 | height: auto; 529 | border-radius: 5px; 530 | } 531 | 532 | figure { 533 | margin: 0; 534 | text-align: center; 535 | } 536 | 537 | figcaption { 538 | font-size: 0.9rem; 539 | color: var(--text-light); 540 | margin-bottom: 1rem; 541 | } 542 | 543 | blockquote { 544 | margin: 2rem 0 2rem 2rem; 545 | padding: 0.4rem 0.8rem; 546 | border-left: 0.35rem solid var(--accent); 547 | color: var(--text-light); 548 | font-style: italic; 549 | } 550 | 551 | cite { 552 | font-size: 0.9rem; 553 | color: var(--text-light); 554 | font-style: normal; 555 | } 556 | 557 | dt { 558 | color: var(--text-light); 559 | } 560 | 561 | /* Use mono font for code elements */ 562 | code, 563 | pre, 564 | pre span, 565 | kbd, 566 | samp { 567 | font-family: var(--mono-font); 568 | color: var(--code); 569 | } 570 | 571 | kbd { 572 | color: var(--preformatted); 573 | border: 1px solid var(--preformatted); 574 | border-bottom: 3px solid var(--preformatted); 575 | border-radius: 5px; 576 | padding: 0.1rem 0.4rem; 577 | } 578 | 579 | pre { 580 | padding: 1rem 1.4rem; 581 | max-width: 100%; 582 | overflow: auto; 583 | color: var(--preformatted); 584 | } 585 | 586 | /* Fix embedded code within pre */ 587 | pre code { 588 | color: var(--preformatted); 589 | background: none; 590 | margin: 0; 591 | padding: 0; 592 | } 593 | 594 | /* Progress bars */ 595 | /* Declarations are repeated because you */ 596 | /* cannot combine vendor-specific selectors */ 597 | progress { 598 | width: 100%; 599 | } 600 | 601 | progress:indeterminate { 602 | background-color: var(--accent-bg); 603 | } 604 | 605 | progress::-webkit-progress-bar { 606 | border-radius: 5px; 607 | background-color: var(--accent-bg); 608 | } 609 | 610 | progress::-webkit-progress-value { 611 | border-radius: 5px; 612 | background-color: var(--accent); 613 | } 614 | 615 | progress::-moz-progress-bar { 616 | border-radius: 5px; 617 | background-color: var(--accent); 618 | transition-property: width; 619 | transition-duration: 0.3s; 620 | } 621 | 622 | progress:indeterminate::-moz-progress-bar { 623 | background-color: var(--accent-bg); 624 | } 625 | 626 | 627 | 628 | /* CSS Rules below are added for Bolt's Skeleton theme */ 629 | 630 | .callout { 631 | border: 2px dashed rgba(0, 0, 0, 0.2); 632 | background-color: rgba(0, 0, 0, 0.05); 633 | padding: 0.5rem 1rem; 634 | margin: 1rem 0; 635 | } 636 | 637 | 638 | .meta { 639 | color: #888; 640 | font-size: 0.9em; 641 | } 642 | 643 | /* Default pagerfanta styles, for pagination */ 644 | .pagination { 645 | text-align: center; 646 | } 647 | 648 | .pagination li { 649 | display: inline-block; 650 | background: var(--accent-bg); 651 | border: 1px solid var(--accent-light); 652 | color: var(--accent); 653 | padding: 0; 654 | border-radius: 4px; 655 | font-size: 1rem; 656 | } 657 | 658 | .pagination li.active { 659 | background: var(--accent-light); 660 | } 661 | 662 | .pagination a { 663 | text-decoration: none; 664 | display: inline-block; 665 | padding: .25em .6em; 666 | } 667 | 668 | .pagination a:hover { 669 | background: var(--accent-light); 670 | color: var(--accent); 671 | } 672 | 673 | .pagination .dots { 674 | border-width: 0; 675 | } 676 | 677 | .pagination .current { 678 | background: #c0dbe0; 679 | font-weight: bold; 680 | } 681 | 682 | .pagination .disabled { 683 | border-color: #c0dbe0; 684 | color: #abcfd6; 685 | } 686 | 687 | /* Some tweaks to keep Symfony dumps in check */ 688 | .sf-dump { 689 | font-size: 1rem !important; 690 | line-height: 1.4rem !important; 691 | } 692 | .sf-minitoolbar button { 693 | margin: 0; 694 | } -------------------------------------------------------------------------------- /skeleton/index.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 | {% if record|default %} 6 | 7 |

{{ record|title }}

8 | 9 | {# Remove this block if you don't need it anymore. #} 10 | {{ include('partials/_fresh_install.twig') }} 11 | 12 | {# Output the `introduction` field. If it doesn't exist, 'default' to 13 | the full excerpt of the current Record #} 14 | {{ record.introduction|default(record|excerpt) }} 15 | 16 | {% include 'partials/_image.twig' with ({'image': record|image}) %} 17 | 18 | {{ record.content }} 19 | 20 | {{ include('partials/_recordfooter.twig', { 'record': record }) }} 21 | 22 | {% endif %} 23 | 24 | {% endblock main %} 25 | 26 | {% block aside %} 27 | 28 | {{ include('partials/_aside.twig') }} 29 | 30 | {% endblock aside %} 31 | -------------------------------------------------------------------------------- /skeleton/listing.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 | {# This template is used for 'listings': Generic pages that list a number of 6 | records from a certain content type. These records are available as an array 7 | called 'records'. In the for-loop below, we iterate over the records that 8 | are on this page. It can be used for overview pages like 'all entries', or 9 | 'all records tagged with kittens'. #} 10 | 11 | {# If used for listing a taxonomy, we add a heading #} 12 | {% if taxonomy is defined %} 13 |

14 | {{ __('general.phrase.overview-for', {'%slug%': taxonomy.options[slug]|default(slug) }) }} 15 |

16 | {% endif %} 17 | 18 | {% for record in records %} 19 |
20 | 21 |

{{ record|title }}

22 | 23 | {% if record|image %} 24 | 25 | {{ record|image.alt|default() }} 26 | 27 | {% endif %} 28 | 29 |

{{ record|excerpt(300, false, search|default('')) }}

30 | 31 | {% include 'partials/_recordfooter.twig' with { 'record': record } %} 32 | 33 |
34 | 35 | {% if not loop.last %} 36 |
37 | {% endif %} 38 | 39 | {% else %} 40 |
41 | 42 |

{{ __('general.phrase.no-content-found') }}

43 | 44 |

45 | {{ __("Unfortunately, no content could be found. Try another page, or go to the homepage.", {'%paths_root%': path('homepage')} ) }} 46 |

47 | 48 |
49 | {% endfor %} 50 | 51 | {# If there are more records than will fit on one page, the pager is shown. #} 52 | {{ pager(records, template = 'helpers/_pager_basic.html.twig') }} 53 | 54 | {% endblock main %} 55 | -------------------------------------------------------------------------------- /skeleton/partials/_aside.twig: -------------------------------------------------------------------------------- 1 | 2 | 70 | 71 | -------------------------------------------------------------------------------- /skeleton/partials/_footer.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 | 4 |

{{ __('Menu') }}

5 | {{ menu(template = 'partials/_sub_menu.twig') }} 6 | 7 |
8 | 9 |

{{ __('general.phrase.search') }}

10 | 11 |
12 | 13 | 14 |
15 | 16 |

17 | {{ __('general.phrase.built-with-bolt') }} 18 |

19 | 20 | {{ widgets('footer') }} 21 | 22 |
23 | -------------------------------------------------------------------------------- /skeleton/partials/_fresh_install.twig: -------------------------------------------------------------------------------- 1 | {% if user %} 2 |
3 |

Welcome to the Bolt Skeleton theme.

4 |

This is a minimal theme, with a modular structure. It is well suited to build your own themes on top of.

5 | 9 | Note: Only currently logged-on users will see this. This piece of content is hidden from regular visitors. 10 |
11 | {% endif %} 12 | -------------------------------------------------------------------------------- /skeleton/partials/_header.twig: -------------------------------------------------------------------------------- 1 | 2 |
3 | {# the values in the 'config' object are taken directly from the file app/config/config.yml #} 4 |

{{ config.get('general/sitename') }}

5 | {% if config.has('general/payoff') and record is defined and record|feature == 'homepage' %} 6 |

{{ config.get('general/payoff') }}

7 | {% endif %} 8 | 9 | {{ menu( 10 | name = 'main', 11 | template = 'partials/_sub_menu_header.twig', 12 | withsubmenus = false 13 | ) }} 14 |
15 | -------------------------------------------------------------------------------- /skeleton/partials/_image.twig: -------------------------------------------------------------------------------- 1 | {% if image %} 2 |
3 | 4 | {{ (record|image).alt|default(record|title) }} 5 | 6 | {% if image.alt|default() %} 7 |
{{ image.alt }}
8 | {% endif %} 9 |
10 | {% endif %} 11 | -------------------------------------------------------------------------------- /skeleton/partials/_master.twig: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | {# make sure we always display a proper title: The record's title if there is one, appended with the 8 | sitename. If there is no title, we append the sitename with the payoff, if there is one. #} 9 | 10 | {%- if record|default and record.title -%} 11 | {{- record.title ~ ' | ' -}} 12 | {%- endif -%} 13 | {{- config.get('general/sitename') -}} 14 | {%- if record|default == null and config.has('general/payoff') -%} 15 | {{- ' | ' ~ config.get('general/payoff') -}} 16 | {%- endif -%} 17 | 18 | 19 | 20 | 21 | {{ include('partials/_header.twig') }} 22 | 23 |
24 | {% block body %} 25 | 26 | 27 | {{ widgets('main_top') }} 28 | 29 | {% block main %} 30 | {% endblock main %} 31 | 32 | {{ widgets('main_bottom') }} 33 | 34 | {% endblock body %} 35 |
36 | 37 | {% block aside %} 38 | {% endblock aside %} 39 | 40 | {{ include('partials/_footer.twig') }} 41 | 42 | 43 | 44 | -------------------------------------------------------------------------------- /skeleton/partials/_recordfooter.twig: -------------------------------------------------------------------------------- 1 | {# This file is inserted as the 'footer' of each listed record. #} 2 |

3 | {% if user %} 4 | {{ __('general.phrase.edit') }} - 5 | {% endif %} 6 | {{ __('general.phrase.written-by-on', { 7 | '%name%': record.author.displayName|default(__('Unknown')), 8 | '%date%': record.publishedAt|localdate("l F j, Y") 9 | }) }} 10 |

11 | 12 | {% if extended|default %} 13 |

14 | {{ __('general.phrase.permalink') }} - 15 | {# include the 'default' links to taxonomies. Check the documentation for ways to modify and customize 16 | what is output to the browser: https://docs.bolt.cm/contenttypes/taxonomies#displaying-taxonomies-in-templates #} 17 | {{ include('partials/_sub_taxonomylinks.twig', { record: record }) }} 18 |

19 | 20 | {% set previous = previous_record(record, byColumn='id') %} 21 | {% set next = next_record(record, byColumn='id') %} 22 | 23 | {% if previous or next %} 24 |

25 | {% if previous %} 26 | « {{ previous|title }} 27 | {% endif %} 28 | {% if previous and next %} 29 | - 30 | {% endif %} 31 | {% if next %} 32 | {{ next|title }} » 33 | {% endif %} 34 |

35 | {% endif %} 36 | 37 | {% set related_content_types = record|related_by_type %} 38 | 39 | {% if related_content_types is not empty %} 40 |

{{ __('general.phrase.related-content') }}

41 | {% for content_type, related_records in related_content_types %} 42 |

Related {{ config.get('contenttypes/' ~ content_type ~ '/name') }}

43 | 48 | {% endfor %} 49 | {% endif %} 50 | 51 | {% endif %} 52 | -------------------------------------------------------------------------------- /skeleton/partials/_sub_menu.twig: -------------------------------------------------------------------------------- 1 | {# This file might seem a little complex, because of the high density of tags. 2 | It uses Twig macros and ternary selectors. Read up on them, if required: 3 | macros: http://twig.sensiolabs.org/doc/templates.html#macros 4 | ternary operators: http://twig.sensiolabs.org/doc/templates.html#other-operators 5 | #} 6 | 7 | {# The 'recursive' macro, for inserting one menu item. If it has a submenu, it 8 | invokes itself to insert the items of the submenus. #} 9 | {% macro display_menu_item(item, loop, withsubmenus) %} 10 | {% from _self import display_menu_item %} 11 | {% apply spaceless %} 12 | {% set with_submenu = withsubmenus and item.submenu is not empty %} 13 |
  • 18 | 19 | 20 | {{- item.label|default(item.title) -}} 21 | 22 | 23 | {% if with_submenu %} 24 | 29 | {% endif %} 30 |
  • 31 | {% endapply %} 32 | {% endmacro %} 33 | 34 | {# Make the macro available for use #} 35 | {% from _self import display_menu_item %} 36 | 37 | {# The main menu loop: Iterates over the items, calling `display_menu_item` #} 38 | 45 | 46 | -------------------------------------------------------------------------------- /skeleton/partials/_sub_menu_header.twig: -------------------------------------------------------------------------------- 1 | {# This file might seem a little complex, because of the high density of tags. 2 | It uses Twig macros and ternary selectors. Read up on them, if required: 3 | macros: http://twig.sensiolabs.org/doc/templates.html#macros 4 | ternary operators: http://twig.sensiolabs.org/doc/templates.html#other-operators 5 | #} 6 | 7 | {# The 'recursive' macro, for inserting one menu item. If it has a submenu, it 8 | invokes itself to insert the items of the submenus. #} 9 | {% macro display_menu_item(item, loop, withsubmenus) %} 10 | {% from _self import display_menu_item %} 11 | {% apply spaceless %} 12 | 15 | {{- item.label -}} 16 | 17 | {% endapply %} 18 | {% endmacro %} 19 | 20 | {# Make the macro available for use #} 21 | {% from _self import display_menu_item %} 22 | 23 | {# The main menu loop: Iterates over the items, calling `display_menu_item` #} 24 | 32 | 33 | -------------------------------------------------------------------------------- /skeleton/partials/_sub_taxonomylinks.twig: -------------------------------------------------------------------------------- 1 | {% for type, taxonomies in record|taxonomies %} 2 | 3 | {% if taxonomies|length == 1 %} 4 | {{ config.get('taxonomies')[type].singular_name }}: 5 | {% elseif taxonomies|length > 1 %} 6 | {{ config.get('taxonomies')[type].name }}: 7 | {% endif %} 8 | 9 | {% for taxonomy in taxonomies %} 10 | {{ taxonomy.name }}{% if not loop.last %}, {% endif %} 11 | {% else %} 12 | {{ __('general.phrase.none') }} 13 | {% endfor %} 14 | {% if not loop.last %} - {% endif %} 15 | {% endfor %} 16 | -------------------------------------------------------------------------------- /skeleton/record.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 |

    {{ record|title }}

    6 | 7 | {% include 'partials/_image.twig' with ({'image': record|image}) %} 8 | 9 | {# Output all fields, in the order as defined in the content type. 10 | To change the generated html and configure the options, see: 11 | https://docs.bolt.cm/templating #} 12 | {% with { 'record': record, 'exclude': [record|image.fieldname|default()] } %} 13 | {{ block('sub_fields', 'helpers/_fields.twig') }} 14 | {% endwith %} 15 | 16 | {# Uncomment this if you wish to dump the entire record to the client, for debugging purposes. 17 | {{ dump(record) }} 18 | #} 19 | 20 | 21 | {% include 'partials/_recordfooter.twig' with { 'record': record, 'extended': true } %} 22 | 23 | {% endblock main %} 24 | -------------------------------------------------------------------------------- /skeleton/search.twig: -------------------------------------------------------------------------------- 1 | {% extends 'partials/_master.twig' %} 2 | 3 | {% block main %} 4 | 5 | {# This template is used for search results. If 'search' is defined, 6 | we display an appropriate title. The 'records' array contains all of the 7 | records matching the current query. If there are no results, the 8 | code in the 'else' part of the for-loop is used. #} 9 |

    10 | {% if searchTerm is not empty %} 11 | {{ __('general.phrase.search-results-for', { '%search%': searchTerm }) }} 12 | {% else %} 13 | {{ __('general.phrase.search') }} 14 | {% endif %} 15 |

    16 | 17 | {# Perhaps we post a small teaser, stored in the 'block' named 'Search teaser' #} 18 | {% setcontent block = "block/search-teaser" %} 19 | 20 | {# check if we have 'content'. If so, we know we have have a teaser to display. #} 21 | {% if block and block.content %} 22 | {{ block.content }} 23 | {% endif %} 24 | 25 |
    26 | 27 | 28 |
    29 | 30 | {% for record in records %} 31 |
    32 | 33 |

    {{ record|title }}

    34 | 35 | {% if record|image %} 36 | 37 | {{ (record|image).alt|default(record|title) }} 38 | 39 | {% endif %} 40 | 41 | {# display something introduction-like.. #} 42 |

    {{ record|excerpt(300, false, search|default('')) }}

    43 | 44 |
    45 | 46 | {% if not loop.last %} 47 |
    48 | {% endif %} 49 | 50 | {% else %} 51 | 52 |

    53 | {% if searchTerm is not empty %} 54 | {{ __('general.phrase.no-search-results-for', { '%search%': searchTerm|escape }) }} 55 | {% else %} 56 | {{ __('general.phrase.no-search-term-provided') }} 57 | {% endif %} 58 |

    59 | 60 | {% endfor %} 61 | 62 | {# If there are more records than will fit on one page, the pager is shown. #} 63 | {{ pager(records, template = 'helpers/_pager_basic.html.twig') }} 64 | 65 | {% endblock main %} 66 | -------------------------------------------------------------------------------- /skeleton/theme.yaml: -------------------------------------------------------------------------------- 1 | # Optional config file for the theme. 2 | 3 | # Variables that are in this file, can be used in your twig template like {{ theme.foo }} 4 | 5 | # Template filenames. If you 're creating a theme for distribution, you can specify 6 | # the filenames of the templates here. The templates you will set in this config 7 | # file will override the ones in the global app/config/config.yml, so beware! 8 | # maintenance_template: maintenance_default.twig 9 | # homepage_template: index.twig 10 | # record_template: record.twig 11 | # listing_template: listing.twig 12 | # search_results_template: search.twig 13 | # notfound: notfound.twig 14 | --------------------------------------------------------------------------------