├── .eslintignore ├── .eslintrc ├── .github └── workflows │ └── test.yml ├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── assets ├── fonts │ ├── Roboto-Medium.woff │ ├── Roboto-Medium.woff2 │ ├── Roboto-Regular.woff │ ├── Roboto-Regular.woff2 │ ├── Roboto-RegularItalic.woff │ ├── Roboto-RegularItalic.woff2 │ ├── fa-brands-400.eot │ ├── fa-brands-400.svg │ ├── fa-brands-400.ttf │ ├── fa-brands-400.woff │ ├── fa-brands-400.woff2 │ ├── fa-regular-400.eot │ ├── fa-regular-400.svg │ ├── fa-regular-400.ttf │ ├── fa-regular-400.woff │ ├── fa-regular-400.woff2 │ ├── fa-solid-900.eot │ ├── fa-solid-900.svg │ ├── fa-solid-900.ttf │ ├── fa-solid-900.woff │ ├── fa-solid-900.woff2 │ ├── lg.eot │ ├── lg.svg │ ├── lg.ttf │ └── lg.woff ├── img │ ├── fa-brands-400.svg │ ├── fa-regular-400.svg │ ├── fa-solid-900.svg │ ├── lg.svg │ ├── loading.gif │ ├── photo-1523980669340-3d154e47d5fd.jpg │ ├── sven-scheuermeier-178631-unsplash.jpg │ ├── video-play.png │ ├── vimeo-play.png │ └── youtube-play.png ├── scripts │ ├── grid.js │ ├── main-vendors.js │ ├── main-vendors.js.LICENSE.txt │ ├── main.js │ └── post.js └── styles │ ├── main.css │ └── post.css ├── author.hbs ├── babel.config.js ├── default.hbs ├── error-404.hbs ├── error.hbs ├── index.hbs ├── package.json ├── page.hbs ├── partials ├── byline-multiple.hbs ├── byline-single.hbs ├── feed-card.hbs ├── floating-header.hbs ├── footer.hbs ├── google_adsense.hbs ├── google_analytics.hbs ├── header.hbs ├── icons │ ├── avatar.hbs │ ├── facebook.hbs │ ├── ghost-logo.hbs │ ├── infinity.hbs │ ├── location.hbs │ ├── point.hbs │ ├── rss.hbs │ ├── twitter.hbs │ └── website.hbs ├── navigation.hbs ├── pagination.hbs ├── post-card.hbs ├── search.hbs ├── share-post.hbs ├── site-nav.hbs ├── spinkit.hbs └── subscribe_form.hbs ├── post.hbs ├── renovate.json ├── src ├── build │ ├── postcss.config.js │ ├── webpack.config.dev.js │ ├── webpack.config.js │ └── webpack.config.prod.js ├── img │ ├── credits.txt │ ├── photo-1523980669340-3d154e47d5fd.jpg │ └── sven-scheuermeier-178631-unsplash.jpg ├── scripts │ ├── app.ts │ ├── createScrollManager.ts │ ├── grid.ts │ ├── particles.json │ ├── post.ts │ └── search.ts ├── styles │ ├── _settings.scss │ ├── components │ │ ├── ads.scss │ │ ├── error.scss │ │ ├── fonts.scss │ │ ├── footer.scss │ │ ├── general.scss │ │ ├── header.scss │ │ ├── koenig.scss │ │ ├── lightbox.scss │ │ ├── main-content.scss │ │ ├── mixins.scss │ │ ├── pagination.scss │ │ ├── placeholder.scss │ │ ├── post-feed.scss │ │ ├── posts-list.scss │ │ ├── prismjs.scss │ │ ├── search.scss │ │ ├── spinkit.scss │ │ ├── tags.scss │ │ └── top-bar.scss │ ├── main.scss │ └── post.scss └── typings │ ├── @tryghost │ ├── content-api │ │ └── index.d.ts │ └── index.d.ts │ ├── colorthief │ └── index.d.ts │ ├── custom │ └── index.d.ts │ ├── ghost-search │ └── index.d.ts │ ├── ghost │ └── index.d.ts │ ├── lightgallery │ └── index.d.ts │ └── particles.js │ └── index.d.ts ├── tag.hbs ├── tsconfig.json └── yarn.lock /.eslintignore: -------------------------------------------------------------------------------- 1 | build/ 2 | babel.config.js -------------------------------------------------------------------------------- /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "parser": "@typescript-eslint/parser", 3 | "parserOptions": { 4 | "ecmaFeatures": { 5 | "jsx": false 6 | }, 7 | "ecmaVersion": 6, 8 | "tsconfigRootDir": ".", 9 | "project": "./tsconfig.json" 10 | }, 11 | "env": { 12 | "es6": true, 13 | "node": true, 14 | "browser": true, 15 | "jquery": true 16 | }, 17 | "plugins": ["@typescript-eslint", "prettier"], 18 | "extends": [ 19 | "jquery", 20 | "airbnb-base", 21 | "plugin:@typescript-eslint/recommended", 22 | "plugin:import/typescript", 23 | "plugin:prettier/recommended", 24 | "prettier/@typescript-eslint" 25 | ], 26 | "rules": { 27 | "indent": [ 28 | "error", 29 | 4 30 | ], 31 | "no-console": 0, 32 | "no-param-reassign": 0, 33 | "no-plusplus": [ 34 | "error", 35 | { 36 | "allowForLoopAfterthoughts": true 37 | } 38 | ], 39 | "spaced-comment": ["error", "always", { 40 | "line": { 41 | "markers": ["/"], 42 | "exceptions": ["-", "+"] 43 | }, 44 | "block": { 45 | "markers": ["!"], 46 | "exceptions": ["*"], 47 | "balanced": true 48 | } 49 | }], 50 | "no-unused-expressions": ["warn", { 51 | "allowShortCircuit": true, 52 | "allowTernary": true 53 | }], // https://eslint.org/docs/rules/no-unused-expressions 54 | "no-trailing-spaces": [2, { "skipBlankLines": true }], 55 | "prefer-template": 0, 56 | "import/extensions": 0, 57 | "lines-between-class-members": 0, 58 | "@typescript-eslint/prefer-interface": "off", // also want to use "type" 59 | "@typescript-eslint/explicit-function-return-type": "off", // annoying to force return type 60 | "@typescript-eslint/explicit-member-accessibility": "off", 61 | "@typescript-eslint/no-non-null-assertion": "off", 62 | "@typescript-eslint/no-var-requires": "off", 63 | "@typescript-eslint/ban-ts-ignore": "off" 64 | } 65 | } -------------------------------------------------------------------------------- /.github/workflows/test.yml: -------------------------------------------------------------------------------- 1 | name: Test 2 | on: 3 | pull_request: 4 | push: 5 | branches: 6 | - master 7 | 8 | jobs: 9 | build: 10 | runs-on: ubuntu-latest 11 | strategy: 12 | matrix: 13 | node: [ '12' ] 14 | name: Node ${{ matrix.node }} 15 | steps: 16 | - uses: actions/checkout@v1 17 | - name: Cache node modules 18 | uses: actions/cache@v1 19 | with: 20 | path: node_modules 21 | key: ${{ runner.OS }}-build-${{ hashFiles('**/yarn.lock') }} 22 | restore-keys: | 23 | ${{ runner.OS }}-build-${{ env.cache-name }}- 24 | ${{ runner.OS }}-build- 25 | ${{ runner.OS }}- 26 | - name: Setup node 27 | uses: actions/setup-node@v1 28 | with: 29 | node-version: ${{ matrix.node }} 30 | - run: npm install yarn 31 | - run: yarn install 32 | - run: yarn lint 33 | - run: yarn build 34 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Cruft 2 | *~ 3 | *# 4 | .#* 5 | .DS_Store 6 | 7 | # Logs 8 | logs 9 | *.log 10 | npm-debug.log* 11 | yarn-debug.log* 12 | yarn-error.log* 13 | 14 | # Runtime data 15 | pids 16 | *.pid 17 | *.seed 18 | *.pid.lock 19 | .firebase 20 | 21 | # dependencies 22 | /node_modules 23 | /.pnp 24 | .pnp.js 25 | 26 | # testing 27 | tests/__coverage__/ 28 | tests/**/*.jsx 29 | 30 | # production 31 | /dist 32 | /build 33 | /scenarios 34 | src/**/*.jsx 35 | 36 | # misc 37 | .DS_Store 38 | .env.local 39 | .env.development.local 40 | .env.test.local 41 | .env.production.local 42 | 43 | npm-debug.log* 44 | yarn-debug.log* 45 | yarn-error.log* 46 | package-lock.json 47 | 48 | # Editor 49 | .idea/ 50 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | assets/ 2 | src/build/ 3 | node_modules/ 4 | package-lock.json 5 | yarn.lock 6 | package.json 7 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "trailingComma": "es5", 3 | "tabWidth": 4, 4 | "singleQuote": true, 5 | "htmlWhitespaceSensitivity": "css", 6 | "jsxBracketSameLine": true, 7 | "overrides": [ 8 | { 9 | "files": "*.css", 10 | "options": { 11 | "tabWidth": 2 12 | } 13 | } 14 | ] 15 | } 16 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 William Díaz 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 all 13 | 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 THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # CUSCA 2 | 3 | [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT) 4 | [![Build Status](https://github.com/wdiazux/cusca/workflows/Test/badge.svg)](https://github.com/wdiazux/cusca/actions?query=workflow%3ATest) 5 | [![Donate](https://img.shields.io/badge/donate-paypal-blue.svg?style=flat-square)](https://paypal.me/wdiazux) 6 | 7 | A responsive theme for [Ghost 3.x](https://ghost.org). 8 | 9 | **What that mean CUSCA?** 10 | 11 | Is the abbreviation for Cuscatlán, it was the name of El Salvador before the conquest and means "the land of precious things" in Nahuatl. 12 | 13 | --- 14 | 15 | ## Introduction 16 | 17 | Cusca was development using [Foundation](http://foundation.zurb.com) as base, the style is generated with 18 | [Sass](https://sass-lang.com) and the javascript is generated with [Typescript](https://www.typescriptlang.org) and 19 | other cool stuff that comes from different libraries: 20 | 21 | - [Shuffle](https://vestride.github.io/Shuffle/) 22 | - [LightGallery.js](https://sachinchoolur.github.io/lightgallery.js/) 23 | - [FontAwesome](http://fontawesome.io) 24 | - [Prism.js](http://prismjs.com) 25 | - [Color Thief](https://lokeshdhakar.com/projects/color-thief/) 26 | - [Particles.js](https://vincentgarreau.com/particles.js/) 27 | - [Ghost Search](https://github.com/HauntedThemes/ghost-search) 28 | 29 | All the help to contribute to the development or improvement of the theme is welcomed. 30 | 31 | ## Installation 32 | 33 | Inside the Ghost themes folder (content/themes) you have to clone the repository or download the last version: 34 | 35 | :anchor: [Last release](https://github.com/wdiazux/cusca/releases/latest) 36 | 37 | ```bash 38 | git clone https://github.com/wdiazux/cusca.git 39 | ``` 40 | 41 | ## Setup 42 | 43 | ### Disqus 44 | 45 | Inside the `post.hbs` file you need to replace `[your-disqus-name]` with your Disqus name: 46 | 47 | ```javascript 48 | (function() { // DON'T EDIT BELOW THIS LINE 49 | var d = document, s = d.createElement('script'); 50 | s.async = true; 51 | s.src = 'https://[your-disqus-name].disqus.com/embed.js'; 52 | s.setAttribute('data-timestamp', +new Date()); 53 | (d.head || d.body).appendChild(s); 54 | })(); 55 | ``` 56 | 57 | Do the same for `partials/loop.hbs`: 58 | 59 | ```html 60 | 61 | ``` 62 | 63 | ### Search 64 | 65 | The new release of the Ghost API v3, require extra steps that are **NECESSARY** for the 66 | search functionality: 67 | 68 | - Go in your Ghost's dashboard -> Integrations -> Add custom integration 69 | - Set a name: Themes Search 70 | - Get the `Content API Key` and replace the demo key with this one 71 | - Do the same with the `API URL` 72 | 73 | The file to modify with this credentials is `src/scripts/app.ts` 74 | and at the end of the document is the Search section, and the parameter you 75 | need to change are the URL and Key from the GhostSearch class. 76 | 77 | ```javascript 78 | const ghostSearch = new GhostSearch({ 79 | url: 'http://localhost:2368', 80 | key: '4f1476d8df3a9cd277b2273b6e', 81 | }); 82 | ``` 83 | 84 | You will need to rebuild the theme to make it work after modifying the parameters. In 85 | the end of this page you will find the commands that you need to do it. 86 | 87 | ### Social Icons 88 | 89 | Inside the `partials/footer.hbs` file replace `[your-user]` with your user names for each social network: 90 | 91 | ```html 92 |
  • 93 | 94 |
  • 95 |
  • 96 | 97 |
  • 98 |
  • 99 | 100 |
  • 101 |
  • 102 | 103 |
  • 104 |
  • 105 | 106 |
  • 107 |
  • 108 | 109 |
  • 110 | ``` 111 | 112 | ### Google Analytics 113 | 114 | Inside the `partials/google_analytics.hbs` file replace `[your-ga-id]` with your google analytics id: 115 | 116 | ```javascript 117 | window.ga=window.ga||function(){(ga.q=ga.q||[]).push(arguments)};ga.l=+new Date; 118 | ga('create', '[your-ga-id]', 'auto'); 119 | ga('send', 'pageview'); 120 | ``` 121 | 122 | ## Modify the theme 123 | 124 | You need to run a ghost instance in the port 2368 it is the default ghost port, 125 | the theme was development using Webpack, so first you need to install it and 126 | their dependencies with this command: 127 | 128 | ``` bash 129 | npm install 130 | ``` 131 | 132 | You also can use yarn instead of npm: 133 | ``` bash 134 | yarn install 135 | ``` 136 | 137 | Then you have four commands provided by the Webpack configuration file: 138 | * `npm run dev` to compile files in development. 139 | * `npm run start` for live development. 140 | * `npm run build` to build a production environment. 141 | * `npm run test` to test the theme with gscan. 142 | 143 | If you are using yarn: 144 | * `yarn dev` to compile files in development. 145 | * `yarn start` for live development. 146 | * `yarn build` to build a production environment. 147 | * `yarn test` to test the theme with gscan. 148 | 149 | If you are looking to modify the style or something in the scripts, the source 150 | files are in the `src` directory `assets` is the destination directory and it 151 | shouldn't be modified. 152 | This version use Typescript for javascript and SASS to generate CSS. 153 | 154 | ## Copyright & License 155 | 156 | - Copyright (c) 2017-2020 William Diaz - Released under the [MIT license](LICENSE). 157 | This version is using the MIT license and the libraries are also MIT or compatibles with it. 158 | -------------------------------------------------------------------------------- /assets/fonts/Roboto-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-Medium.woff -------------------------------------------------------------------------------- /assets/fonts/Roboto-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-Medium.woff2 -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-Regular.woff -------------------------------------------------------------------------------- /assets/fonts/Roboto-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-Regular.woff2 -------------------------------------------------------------------------------- /assets/fonts/Roboto-RegularItalic.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-RegularItalic.woff -------------------------------------------------------------------------------- /assets/fonts/Roboto-RegularItalic.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/Roboto-RegularItalic.woff2 -------------------------------------------------------------------------------- /assets/fonts/fa-brands-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-brands-400.eot -------------------------------------------------------------------------------- /assets/fonts/fa-brands-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-brands-400.ttf -------------------------------------------------------------------------------- /assets/fonts/fa-brands-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-brands-400.woff -------------------------------------------------------------------------------- /assets/fonts/fa-brands-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-brands-400.woff2 -------------------------------------------------------------------------------- /assets/fonts/fa-regular-400.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-regular-400.eot -------------------------------------------------------------------------------- /assets/fonts/fa-regular-400.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-regular-400.ttf -------------------------------------------------------------------------------- /assets/fonts/fa-regular-400.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-regular-400.woff -------------------------------------------------------------------------------- /assets/fonts/fa-regular-400.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-regular-400.woff2 -------------------------------------------------------------------------------- /assets/fonts/fa-solid-900.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-solid-900.eot -------------------------------------------------------------------------------- /assets/fonts/fa-solid-900.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-solid-900.ttf -------------------------------------------------------------------------------- /assets/fonts/fa-solid-900.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-solid-900.woff -------------------------------------------------------------------------------- /assets/fonts/fa-solid-900.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/fa-solid-900.woff2 -------------------------------------------------------------------------------- /assets/fonts/lg.eot: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/lg.eot -------------------------------------------------------------------------------- /assets/fonts/lg.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | { 8 | "fontFamily": "lg", 9 | "majorVersion": 1, 10 | "minorVersion": 0, 11 | "fontURL": "https://github.com/sachinchoolur/lightgallery.js", 12 | "copyright": "sachin", 13 | "license": "MLT", 14 | "licenseURL": "http://opensource.org/licenses/MIT", 15 | "version": "Version 1.0", 16 | "fontId": "lg", 17 | "psName": "lg", 18 | "subFamily": "Regular", 19 | "fullName": "lg", 20 | "description": "Font generated by IcoMoon." 21 | } 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | 33 | 34 | 35 | 36 | 37 | 38 | 39 | 40 | 41 | 42 | 43 | 44 | 45 | 46 | 47 | -------------------------------------------------------------------------------- /assets/fonts/lg.ttf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/lg.ttf -------------------------------------------------------------------------------- /assets/fonts/lg.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/fonts/lg.woff -------------------------------------------------------------------------------- /assets/img/fa-brands-400.svg: -------------------------------------------------------------------------------- 1 | export default "../../assets/fonts/fa-brands-400.svg"; -------------------------------------------------------------------------------- /assets/img/fa-regular-400.svg: -------------------------------------------------------------------------------- 1 | export default "../../assets/fonts/fa-regular-400.svg"; -------------------------------------------------------------------------------- /assets/img/fa-solid-900.svg: -------------------------------------------------------------------------------- 1 | export default "../../assets/fonts/fa-solid-900.svg"; -------------------------------------------------------------------------------- /assets/img/lg.svg: -------------------------------------------------------------------------------- 1 | export default "../../assets/fonts/lg.svg"; -------------------------------------------------------------------------------- /assets/img/loading.gif: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/loading.gif -------------------------------------------------------------------------------- /assets/img/photo-1523980669340-3d154e47d5fd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/photo-1523980669340-3d154e47d5fd.jpg -------------------------------------------------------------------------------- /assets/img/sven-scheuermeier-178631-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/sven-scheuermeier-178631-unsplash.jpg -------------------------------------------------------------------------------- /assets/img/video-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/video-play.png -------------------------------------------------------------------------------- /assets/img/vimeo-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/vimeo-play.png -------------------------------------------------------------------------------- /assets/img/youtube-play.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/assets/img/youtube-play.png -------------------------------------------------------------------------------- /assets/scripts/main-vendors.js.LICENSE.txt: -------------------------------------------------------------------------------- 1 | /*! 2 | * Sizzle CSS Selector Engine v2.3.5 3 | * https://sizzlejs.com/ 4 | * 5 | * Copyright JS Foundation and other contributors 6 | * Released under the MIT license 7 | * https://js.foundation/ 8 | * 9 | * Date: 2020-03-14 10 | */ 11 | 12 | /*! 13 | * jQuery JavaScript Library v3.5.0 14 | * https://jquery.com/ 15 | * 16 | * Includes Sizzle.js 17 | * https://sizzlejs.com/ 18 | * 19 | * Copyright JS Foundation and other contributors 20 | * Released under the MIT license 21 | * https://jquery.org/license 22 | * 23 | * Date: 2020-04-10T15:07Z 24 | */ 25 | -------------------------------------------------------------------------------- /assets/styles/post.css: -------------------------------------------------------------------------------- 1 | .sk-cube-grid{position:absolute;width:40px;height:40px;left:0;right:0;margin:0 auto;opacity:1;transition:opacity .6s ease}.sk-cube-grid .sk-cube{width:33%;height:33%;background-color:#1a2940;float:left;-webkit-animation:sk-cubeGridScaleDelay 1.3s ease-in-out infinite;animation:sk-cubeGridScaleDelay 1.3s ease-in-out infinite}.sk-cube-grid .sk-cube1{-webkit-animation-delay:.2s;animation-delay:.2s}.sk-cube-grid .sk-cube2{-webkit-animation-delay:.3s;animation-delay:.3s}.sk-cube-grid .sk-cube3{-webkit-animation-delay:.4s;animation-delay:.4s}.sk-cube-grid .sk-cube4{-webkit-animation-delay:.1s;animation-delay:.1s}.sk-cube-grid .sk-cube5{-webkit-animation-delay:.2s;animation-delay:.2s}.sk-cube-grid .sk-cube6{-webkit-animation-delay:.3s;animation-delay:.3s}.sk-cube-grid .sk-cube7{-webkit-animation-delay:0s;animation-delay:0s}.sk-cube-grid .sk-cube8{-webkit-animation-delay:.1s;animation-delay:.1s}.sk-cube-grid .sk-cube9{-webkit-animation-delay:.2s;animation-delay:.2s}.post-feed .sk-cube-grid{position:absolute;top:4rem;left:0;right:0;margin:0 auto}.post-full-image .sk-cube-grid{top:50%;transform:translateY(-50%)}.loaded .sk-cube-grid{opacity:0}@-webkit-keyframes sk-cubeGridScaleDelay{0%,70%,to{transform:scaleX(1)}35%{transform:scale3D(0,0,1)}}@keyframes sk-cubeGridScaleDelay{0%,70%,to{transform:scaleX(1)}35%{transform:scale3D(0,0,1)}}.read-next .post-card{display:flex;position:relative;margin:0 0 2rem;flex:1 1 250px;flex-direction:column}@media print,screen and (min-width:40em){.read-next .post-card:first-child{margin:0 2rem 2rem 0}.read-next .post-card:last-child{margin:0 0 2rem}}@media print,screen and (min-width:64em){.read-next .post-card{margin:0 2rem 2rem 0}.read-next .post-card:last-child{margin:0 0 2rem}}.read-next .post-card-content,.read-next .post-card-inner{display:flex;flex-grow:1;flex-direction:column;justify-content:space-between}.read-next .post-card-featured-image:focus .post-card-image img,.read-next .post-card-featured-image:hover .post-card-image img{transform:matrix(1.2,0,0,1.2,0,0) translateY(-50%)}.read-next .post-card-featured-image .tags{max-height:calc(100% - 10px)}.read-next .post-card-image{height:135px}.read-next .post-card-image img{position:absolute;top:50%;transform:translateY(-50%)}.read-next-card{color:#fefefe;border-radius:5px;overflow:hidden}.read-next-card:before{content:"";position:absolute;top:0;right:0;bottom:0;left:0;display:block;background:linear-gradient(135deg,rgba(26,41,64,.95),rgba(26,41,64,.85))}.read-next-card .post-card-inner{background:none}.read-next-card a,.read-next-card a:focus,.read-next-card a:hover{color:#fefefe}.related-articles{display:flex;flex-flow:row wrap}.read-next-card-header-title{text-align:center;text-transform:uppercase;font-weight:500}.read-next-card-header-title i{font-size:70%}.read-next-card-content ul{margin:0;list-style:none}.read-next-card-content ul>li a{display:block;max-width:86%;margin-left:7%;padding:.91912rem 0;text-align:center;font-weight:500;border-bottom:1px solid hsla(0,0%,100%,.3);white-space:nowrap;overflow:hidden;text-overflow:ellipsis}.read-next-card-footer{position:relative;margin:.91912rem 0 .18382rem;text-align:center}@font-face{font-family:lg;src:url(../../assets/fonts/lg.eot);src:url(../../assets/fonts/lg.eot?#iefixn1z373) format("embedded-opentype"),url(../../assets/fonts/lg.woff) format("woff"),url(../../assets/fonts/lg.ttf) format("truetype"),url(../../assets/img/lg.svg#lg) format("svg");font-weight:400;font-style:normal}.lg-icon{font-family:lg;speak:none;font-style:normal;font-weight:400;font-variant:normal;text-transform:none;line-height:1;-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.lg-actions .lg-next,.lg-actions .lg-prev{background-color:rgba(0,0,0,.45);border-radius:2px;color:#999;cursor:pointer;display:block;font-size:22px;margin-top:-10px;padding:8px 10px 9px;position:absolute;top:50%;z-index:1080}.lg-actions .lg-next.disabled,.lg-actions .lg-prev.disabled{pointer-events:none;opacity:.5}.lg-actions .lg-next:hover,.lg-actions .lg-prev:hover{color:#fff}.lg-actions .lg-next{right:20px}.lg-actions .lg-next:before{content:"\e095"}.lg-actions .lg-prev{left:20px}.lg-actions .lg-prev:after{content:"\e094"}@-webkit-keyframes lg-right-end{0%{left:0}50%{left:-30px}to{left:0}}@keyframes lg-right-end{0%{left:0}50%{left:-30px}to{left:0}}@-webkit-keyframes lg-left-end{0%{left:0}50%{left:30px}to{left:0}}@keyframes lg-left-end{0%{left:0}50%{left:30px}to{left:0}}.lg-outer.lg-right-end .lg-object{-webkit-animation:lg-right-end .3s;animation:lg-right-end .3s;position:relative}.lg-outer.lg-left-end .lg-object{-webkit-animation:lg-left-end .3s;animation:lg-left-end .3s;position:relative}.lg-toolbar{z-index:1082;left:0;position:absolute;top:0;width:100%;background-color:rgba(0,0,0,.45)}.lg-toolbar .lg-icon{color:#999;cursor:pointer;float:right;font-size:24px;height:47px;line-height:27px;padding:10px 0;text-align:center;width:50px;text-decoration:none!important;outline:medium none;transition:color .2s linear}.lg-toolbar .lg-icon:hover{color:#fff}.lg-toolbar .lg-close:after{content:"\e070"}.lg-toolbar .lg-download:after{content:"\e0f2"}.lg-sub-html{background-color:rgba(0,0,0,.45);bottom:0;color:#eee;font-size:16px;left:0;padding:10px 40px;position:fixed;right:0;text-align:center;z-index:1080}.lg-sub-html h4{margin:0;font-size:13px;font-weight:700}.lg-sub-html p{font-size:12px;margin:5px 0 0}#lg-counter{color:#999;display:inline-block;font-size:16px;padding-left:20px;padding-top:12px;vertical-align:middle}.lg-next,.lg-prev,.lg-toolbar{opacity:1;transition:transform .35s cubic-bezier(0,0,.25,1) 0s,opacity .35s cubic-bezier(0,0,.25,1) 0s,color .2s linear}.lg-hide-items .lg-prev{opacity:0;transform:translate3d(-10px,0,0)}.lg-hide-items .lg-next{opacity:0;transform:translate3d(10px,0,0)}.lg-hide-items .lg-toolbar{opacity:0;transform:translate3d(0,-10px,0)}body:not(.lg-from-hash) .lg-outer.lg-start-zoom .lg-object{transform:scale3d(.5,.5,.5);opacity:0;transition:transform .25s cubic-bezier(0,0,.25,1) 0s,opacity .25s cubic-bezier(0,0,.25,1)!important;transform-origin:50% 50%}body:not(.lg-from-hash) .lg-outer.lg-start-zoom .lg-item.lg-complete .lg-object{transform:scaleX(1);opacity:1}.lg-outer .lg-thumb-outer{background-color:#0d0a0a;bottom:0;position:absolute;width:100%;z-index:1080;max-height:350px;transform:translate3d(0,100%,0);transition:transform .25s cubic-bezier(0,0,.25,1) 0s}.lg-outer .lg-thumb-outer.lg-grab .lg-thumb-item{cursor:-webkit-grab;cursor:-o-grab;cursor:-ms-grab;cursor:grab}.lg-outer .lg-thumb-outer.lg-grabbing .lg-thumb-item{cursor:move;cursor:-webkit-grabbing;cursor:-o-grabbing;cursor:-ms-grabbing;cursor:grabbing}.lg-outer .lg-thumb-outer.lg-dragging .lg-thumb{transition-duration:0s!important}.lg-outer.lg-thumb-open .lg-thumb-outer{transform:translateZ(0)}.lg-outer .lg-thumb{padding:10px 0;height:100%;margin-bottom:-5px}.lg-outer .lg-thumb-item{border-radius:5px;cursor:pointer;float:left;overflow:hidden;height:100%;border:2px solid #fff;border-radius:4px;margin-bottom:5px}@media (min-width:1025px){.lg-outer .lg-thumb-item{transition:border-color .25s ease}}.lg-outer .lg-thumb-item.active,.lg-outer .lg-thumb-item:hover{border-color:#a90707}.lg-outer .lg-thumb-item img{width:100%;height:100%;-o-object-fit:cover;object-fit:cover}.lg-outer.lg-has-thumb .lg-item{padding-bottom:120px}.lg-outer.lg-can-toggle .lg-item{padding-bottom:0}.lg-outer.lg-pull-caption-up .lg-sub-html{transition:bottom .25s ease}.lg-outer.lg-pull-caption-up.lg-thumb-open .lg-sub-html{bottom:100px}.lg-outer .lg-toggle-thumb{background-color:#0d0a0a;border-radius:2px 2px 0 0;color:#999;cursor:pointer;font-size:24px;height:39px;line-height:27px;padding:5px 0;position:absolute;right:20px;text-align:center;top:-39px;width:50px}.lg-outer .lg-toggle-thumb:after{content:"\e1ff"}.lg-outer .lg-toggle-thumb:hover{color:#fff}.lg-outer .lg-video-cont{display:inline-block;vertical-align:middle;max-width:1140px;max-height:100%;width:100%;padding:0 5px}.lg-outer .lg-video{width:100%;height:0;padding-bottom:56.25%;overflow:hidden;position:relative}.lg-outer .lg-video .lg-object{display:inline-block;position:absolute;top:0;left:0;width:100%!important;height:100%!important}.lg-outer .lg-video .lg-video-play{width:84px;height:59px;position:absolute;left:50%;top:50%;margin-left:-42px;margin-top:-30px;z-index:1080;cursor:pointer}.lg-outer .lg-has-vimeo .lg-video-play{background:url(../../assets/img/vimeo-play.png) no-repeat scroll 0 0 transparent}.lg-outer .lg-has-vimeo:hover .lg-video-play{background:url(../../assets/img/vimeo-play.png) no-repeat scroll 0 -58px transparent}.lg-outer .lg-has-html5 .lg-video-play{background:transparent url(../../assets/img/video-play.png) no-repeat scroll 0 0;height:64px;margin-left:-32px;margin-top:-32px;width:64px;opacity:.8}.lg-outer .lg-has-html5:hover .lg-video-play{opacity:1}.lg-outer .lg-has-youtube .lg-video-play{background:url(../../assets/img/youtube-play.png) no-repeat scroll 0 0 transparent}.lg-outer .lg-has-youtube:hover .lg-video-play{background:url(../../assets/img/youtube-play.png) no-repeat scroll 0 -60px transparent}.lg-outer .lg-video-object{width:100%!important;height:100%!important;position:absolute;top:0;left:0}.lg-outer .lg-has-video .lg-video-object{visibility:hidden}.lg-outer .lg-has-video.lg-video-playing .lg-object,.lg-outer .lg-has-video.lg-video-playing .lg-video-play{display:none}.lg-outer .lg-has-video.lg-video-playing .lg-video-object{visibility:visible}.lg-progress-bar{background-color:#333;height:5px;left:0;position:absolute;top:0;width:100%;z-index:1083;opacity:0;transition:opacity .08s ease 0s}.lg-progress-bar .lg-progress{background-color:#a90707;height:5px;width:0}.lg-progress-bar.lg-start .lg-progress{width:100%}.lg-show-autoplay .lg-progress-bar{opacity:1}.lg-autoplay-button:after{content:"\e01d"}.lg-show-autoplay .lg-autoplay-button:after{content:"\e01a"}.lg-outer.lg-css3.lg-zoom-dragging .lg-item.lg-complete.lg-zoomable .lg-image,.lg-outer.lg-css3.lg-zoom-dragging .lg-item.lg-complete.lg-zoomable .lg-img-wrap{transition-duration:0s}.lg-outer.lg-use-transition-for-zoom .lg-item.lg-complete.lg-zoomable .lg-img-wrap{transition:transform .3s cubic-bezier(0,0,.25,1) 0s}.lg-outer.lg-use-left-for-zoom .lg-item.lg-complete.lg-zoomable .lg-img-wrap{transition:left .3s cubic-bezier(0,0,.25,1) 0s,top .3s cubic-bezier(0,0,.25,1) 0s}.lg-outer .lg-item.lg-complete.lg-zoomable .lg-img-wrap{transform:translateZ(0);-webkit-backface-visibility:hidden;backface-visibility:hidden}.lg-outer .lg-item.lg-complete.lg-zoomable .lg-image{transform:scaleX(1);transition:transform .3s cubic-bezier(0,0,.25,1) 0s,opacity .15s!important;transform-origin:0 0;-webkit-backface-visibility:hidden;backface-visibility:hidden}#lg-zoom-in:after{content:"\e311"}#lg-actual-size{font-size:20px}#lg-actual-size:after{content:"\e033"}#lg-zoom-out{opacity:.5;pointer-events:none}#lg-zoom-out:after{content:"\e312"}.lg-zoomed #lg-zoom-out{opacity:1;pointer-events:auto}.lg-outer .lg-pager-outer{bottom:60px;left:0;position:absolute;right:0;text-align:center;z-index:1080;height:10px}.lg-outer .lg-pager-outer.lg-pager-hover .lg-pager-cont{overflow:visible}.lg-outer .lg-pager-cont{cursor:pointer;display:inline-block;overflow:hidden;position:relative;vertical-align:top;margin:0 5px}.lg-outer .lg-pager-cont:hover .lg-pager-thumb-cont{opacity:1;transform:translateZ(0)}.lg-outer .lg-pager-cont.lg-pager-active .lg-pager{box-shadow:inset 0 0 0 2px #fff}.lg-outer .lg-pager-thumb-cont{background-color:#fff;color:#fff;bottom:100%;height:83px;left:0;margin-bottom:20px;margin-left:-60px;opacity:0;padding:5px;position:absolute;width:120px;border-radius:3px;transition:opacity .15s ease 0s,transform .15s ease 0s;transform:translate3d(0,5px,0)}.lg-outer .lg-pager-thumb-cont img{width:100%;height:100%}.lg-outer .lg-pager{background-color:hsla(0,0%,100%,.5);border-radius:50%;box-shadow:inset 0 0 0 8px hsla(0,0%,100%,.7);display:block;height:12px;transition:box-shadow .3s ease 0s;width:12px}.lg-outer .lg-pager:focus,.lg-outer .lg-pager:hover{box-shadow:inset 0 0 0 8px #fff}.lg-outer .lg-caret{border-left:10px solid transparent;border-right:10px solid transparent;border-top:10px dashed;bottom:-10px;display:inline-block;height:0;left:50%;margin-left:-5px;position:absolute;vertical-align:middle;width:0}.lg-fullscreen:after{content:"\e20c"}.lg-fullscreen-on .lg-fullscreen:after{content:"\e20d"}.lg-outer #lg-dropdown-overlay{background-color:rgba(0,0,0,.25);bottom:0;cursor:default;left:0;position:fixed;right:0;top:0;z-index:1081;opacity:0;visibility:hidden;transition:visibility 0s linear .18s,opacity .18s linear 0s}.lg-outer.lg-dropdown-active #lg-dropdown-overlay,.lg-outer.lg-dropdown-active .lg-dropdown{transition-delay:0s;transform:translateZ(0);opacity:1;visibility:visible}.lg-outer.lg-dropdown-active #lg-share{color:#fff}.lg-outer .lg-dropdown{background-color:#fff;border-radius:2px;font-size:14px;list-style-type:none;margin:0;padding:10px 0;position:absolute;right:0;text-align:left;top:50px;opacity:0;visibility:hidden;transform:translate3d(0,5px,0);transition:transform .18s linear 0s,visibility 0s linear .5s,opacity .18s linear 0s}.lg-outer .lg-dropdown:after{content:"";display:block;height:0;width:0;position:absolute;border:8px solid transparent;border-bottom-color:#fff;right:16px;top:-16px}.lg-outer .lg-dropdown>li:last-child{margin-bottom:0}.lg-outer .lg-dropdown>li:hover .lg-icon,.lg-outer .lg-dropdown>li:hover a{color:#333}.lg-outer .lg-dropdown a{color:#333;display:block;white-space:pre;padding:4px 12px;font-family:Open Sans,Helvetica Neue,Helvetica,Arial,sans-serif;font-size:12px}.lg-outer .lg-dropdown a:hover{background-color:rgba(0,0,0,.07)}.lg-outer .lg-dropdown .lg-dropdown-text{display:inline-block;line-height:1;margin-top:-3px;vertical-align:middle}.lg-outer .lg-dropdown .lg-icon{color:#333;display:inline-block;float:none;font-size:20px;height:auto;line-height:1;margin-right:8px;padding:0;vertical-align:middle;width:auto}.lg-outer #lg-share{position:relative}.lg-outer #lg-share:after{content:"\e80d"}.lg-outer #lg-share-facebook .lg-icon{color:#3b5998}.lg-outer #lg-share-facebook .lg-icon:after{content:"\e901"}.lg-outer #lg-share-twitter .lg-icon{color:#00aced}.lg-outer #lg-share-twitter .lg-icon:after{content:"\e904"}.lg-outer #lg-share-googleplus .lg-icon{color:#dd4b39}.lg-outer #lg-share-googleplus .lg-icon:after{content:"\e902"}.lg-outer #lg-share-pinterest .lg-icon{color:#cb2027}.lg-outer #lg-share-pinterest .lg-icon:after{content:"\e903"}.group{*zoom:1}.group:after,.group:before{display:table;content:"";line-height:0}.group:after{clear:both}.lg-outer{width:100%;height:100%;position:fixed;top:0;left:0;z-index:1050;opacity:0;transition:opacity .15s ease 0s}.lg-outer *{box-sizing:border-box}.lg-outer.lg-visible{opacity:1}.lg-outer.lg-css3 .lg-item.lg-current,.lg-outer.lg-css3 .lg-item.lg-next-slide,.lg-outer.lg-css3 .lg-item.lg-prev-slide{transition-duration:inherit!important;transition-timing-function:inherit!important}.lg-outer.lg-css3.lg-dragging .lg-item.lg-current,.lg-outer.lg-css3.lg-dragging .lg-item.lg-next-slide,.lg-outer.lg-css3.lg-dragging .lg-item.lg-prev-slide{transition-duration:0s!important;opacity:1}.lg-outer.lg-grab img.lg-object{cursor:-webkit-grab;cursor:-o-grab;cursor:-ms-grab;cursor:grab}.lg-outer.lg-grabbing img.lg-object{cursor:move;cursor:-webkit-grabbing;cursor:-o-grabbing;cursor:-ms-grabbing;cursor:grabbing}.lg-outer .lg{height:100%;width:100%;position:relative;overflow:hidden;margin-left:auto;margin-right:auto;max-width:100%;max-height:100%}.lg-outer .lg-inner{width:100%;height:100%;position:absolute;left:0;top:0;white-space:nowrap}.lg-outer .lg-item{background:url(../../assets/img/loading.gif) no-repeat scroll 50% transparent;display:none!important}.lg-outer.lg-css3 .lg-current,.lg-outer.lg-css3 .lg-next-slide,.lg-outer.lg-css3 .lg-prev-slide,.lg-outer.lg-css .lg-current{display:inline-block!important}.lg-outer .lg-img-wrap,.lg-outer .lg-item{display:inline-block;text-align:center;position:absolute;width:100%;height:100%}.lg-outer .lg-img-wrap:before,.lg-outer .lg-item:before{content:"";display:inline-block;height:50%;width:1px;margin-right:-1px}.lg-outer .lg-img-wrap{position:absolute;padding:0 5px;left:0;right:0;top:0;bottom:0}.lg-outer .lg-item.lg-complete{background-image:none}.lg-outer .lg-item.lg-current{z-index:1060}.lg-outer .lg-image{display:inline-block;vertical-align:middle;max-width:100%;max-height:100%;width:auto!important;height:auto!important}.lg-outer.lg-show-after-load .lg-item .lg-object,.lg-outer.lg-show-after-load .lg-item .lg-video-play{opacity:0;transition:opacity .15s ease 0s}.lg-outer.lg-show-after-load .lg-item.lg-complete .lg-object,.lg-outer.lg-show-after-load .lg-item.lg-complete .lg-video-play{opacity:1}.lg-outer .lg-empty-html,.lg-outer.lg-hide-download #lg-download{display:none}.lg-backdrop{position:fixed;top:0;left:0;right:0;bottom:0;z-index:1040;background-color:#000;opacity:0;transition:opacity .15s ease 0s}.lg-backdrop.in{opacity:1}.lg-css3.lg-no-trans .lg-current,.lg-css3.lg-no-trans .lg-next-slide,.lg-css3.lg-no-trans .lg-prev-slide{transition:none 0s ease 0s!important}.lg-css3.lg-use-css3 .lg-item,.lg-css3.lg-use-left .lg-item{-webkit-backface-visibility:hidden;backface-visibility:hidden}.lg-css3.lg-fade .lg-item{opacity:0}.lg-css3.lg-fade .lg-item.lg-current{opacity:1}.lg-css3.lg-fade .lg-item.lg-current,.lg-css3.lg-fade .lg-item.lg-next-slide,.lg-css3.lg-fade .lg-item.lg-prev-slide{transition:opacity .1s ease 0s}.lg-css3.lg-slide.lg-use-css3 .lg-item{opacity:0}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-prev-slide{transform:translate3d(-100%,0,0)}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-next-slide{transform:translate3d(100%,0,0)}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-current{transform:translateZ(0);opacity:1}.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-current,.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-next-slide,.lg-css3.lg-slide.lg-use-css3 .lg-item.lg-prev-slide{transition:transform 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s}.lg-css3.lg-slide.lg-use-left .lg-item{opacity:0;position:absolute;left:0}.lg-css3.lg-slide.lg-use-left .lg-item.lg-prev-slide{left:-100%}.lg-css3.lg-slide.lg-use-left .lg-item.lg-next-slide{left:100%}.lg-css3.lg-slide.lg-use-left .lg-item.lg-current{left:0;opacity:1}.lg-css3.lg-slide.lg-use-left .lg-item.lg-current,.lg-css3.lg-slide.lg-use-left .lg-item.lg-next-slide,.lg-css3.lg-slide.lg-use-left .lg-item.lg-prev-slide{transition:left 1s cubic-bezier(0,0,.25,1) 0s,opacity .1s ease 0s}.lightbox{display:inline-block;max-width:100%}.lightbox img{flex-shrink:0;cursor:pointer;cursor:zoom-in}pre[data-line]{position:relative;padding:1em 0 1em 3em}.line-highlight{position:absolute;left:0;right:0;padding:inherit 0;margin-top:1em;background:rgba(153,122,102,.08);background:linear-gradient(90deg,rgba(153,122,102,.1) 70%,rgba(153,122,102,0));pointer-events:none;line-height:inherit;white-space:pre}.line-highlight:before,.line-highlight[data-end]:after{content:attr(data-start);position:absolute;top:.4em;left:.6em;min-width:1em;padding:0 .5em;background-color:rgba(153,122,102,.4);color:#f5f2f0;font:700 65%/1.5 sans-serif;text-align:center;vertical-align:.3em;border-radius:999px;text-shadow:none;box-shadow:0 1px #fff}.line-highlight[data-end]:after{content:attr(data-end);top:auto;bottom:.4em}.line-numbers .line-highlight:after,.line-numbers .line-highlight:before{content:none}code[class*=language-],pre:not([class*=language-]),pre[class*=language-]{color:#ccc;background:none;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;-o-tab-size:4;tab-size:4;-webkit-hyphens:none;-ms-hyphens:none;hyphens:none}pre:not([class*=language-]),pre[class*=language-]{padding:1em;margin:.5em 0;overflow:auto}:not(pre)>code[class*=language-],pre:not([class*=language-]),pre[class*=language-]{background:#2d2d2d}:not(pre)>code[class*=language-]{padding:.1em;border-radius:.3em;white-space:normal}.token.block-comment,.token.cdata,.token.comment,.token.doctype,.token.prolog{color:#999}.token.punctuation{color:#ccc}.token.attr-name,.token.deleted,.token.namespace,.token.tag{color:#e2777a}.token.function-name{color:#6196cc}.token.boolean,.token.function,.token.number{color:#f08d49}.token.class-name,.token.constant,.token.property,.token.symbol{color:#f8c555}.token.atrule,.token.builtin,.token.important,.token.keyword,.token.selector{color:#cc99cd}.token.attr-value,.token.char,.token.regex,.token.string,.token.variable{color:#7ec699}.token.entity,.token.operator,.token.url{color:#67cdcc}.token.bold,.token.important{font-weight:700}.token.italic{font-style:italic}.token.entity{cursor:help}.token.inserted{color:green}pre:not([class*=language-]),pre[class*=language-]{margin-top:0}pre:not([class*=language-]){padding:.73529rem .98039rem;font-family:inherit}pre:not([class*=language-]) code{background-color:transparent;color:inherit}pre>code{font-size:90%;padding:0}:not(pre)>code{word-break:break-word;font-size:90%}.comments,.read-next{background:#f0f0f0}.read-next{padding:2rem}.comments{padding-bottom:3rem}.post-full-image:after,.post-full-image:before{position:absolute;content:"";top:0;z-index:1;background:hsla(0,0%,100%,.05);border:1px solid hsla(0,0%,100%,.1)}.post-full-image{display:block;position:relative;margin-bottom:2rem;width:100%;height:500px;overflow:hidden;text-align:center;border-top-left-radius:5px;border-top-right-radius:5px;background:#f1f1f1}.post-full-image:before{width:250px;height:250px;left:6%;transform:rotate(45deg)}.post-full-image:after{width:250px;height:250px;left:12%;transform:rotate(135deg)}@media print,screen and (min-width:40em){.post-full-image:after,.post-full-image:before{width:350px;height:350px}}@media print,screen and (min-width:64em){.post-full-image:after,.post-full-image:before{width:500px;height:500px}}.post-full-image img{position:absolute;max-width:90%;max-height:87%;top:50%;left:0;right:0;margin:0 auto;border-radius:10px;z-index:4;transform:translateY(-40%)}.post-full-image.loaded img{transform:translateY(-53%)}@media print,screen and (max-width:63.99875em){.post-full-image{height:350px}}@media print,screen and (max-width:39.99875em){.post-full-image{height:250px}}.post-full-image .post-full-image-background,.post-full-image .post-full-meta-feature,.post-full-image img{opacity:0;transition-property:transform,opacity;transition-duration:.6s;transition-timing-function:ease-in}.post-full-image.loaded .post-full-image-background,.post-full-image.loaded .post-full-meta-feature,.post-full-image.loaded img{opacity:1}.post-full-image-background{display:block;position:absolute;width:100%;height:100%;top:0;left:0;background:hsla(0,0%,100%,0)}.post-full-meta,.post-full-meta-feature{display:flex;padding:.30637rem .61275rem;width:100%;font-size:85%;text-align:left;font-weight:500;flex-flow:row wrap;justify-content:space-between}.post-full-meta-feature .post-date,.post-full-meta .post-date{margin-right:.91912rem}.post-full-meta-feature .post-full-meta-date,.post-full-meta .post-full-meta-date{text-transform:uppercase}.post-full-meta{position:relative;margin-bottom:1.53186rem;background:#f7f7f9}.post-full-meta .fa,.post-full-meta .far,.post-full-meta .fas{font-size:80%}.post-full-meta .meta-tag{text-transform:uppercase;color:#292929}.post-full-meta-feature{position:absolute;bottom:0;left:0;color:#fefefe;background:rgba(0,0,0,.8);z-index:20}.post-full-meta-feature .fa,.post-full-meta-feature .far,.post-full-meta-feature .fas{font-size:80%}.post-full-meta-feature .meta-tag{text-transform:uppercase;color:#fefefe}.post-full-meta-feature .meta-tag:focus,.post-full-meta-feature .meta-tag:hover{color:#fefefe}.post-full-title{text-align:center;margin-bottom:2rem}@media print,screen and (min-width:40em){.comments-container,.post-content,.post-full-footer,.post-full-meta,.title-wrapper{flex:0 0 auto;width:calc(81.81818% - 1.83824rem);margin-right:.91912rem;margin-left:calc(8.33333% + .91912rem)}}@media print,screen and (min-width:64em){.comments-container,.post-content,.post-full-footer,.post-full-meta,.title-wrapper{flex:0 0 auto;width:calc(66.66667% - 1.83824rem);margin-right:.91912rem;margin-left:calc(16.66667% + .91912rem)}}.post-full-image+.post-full-content .kg-content :first-child .kg-image{width:100%}.post-content .kg-width-full .kg-image,.post-content .kg-width-wide .kg-image{max-width:100%}.kg-gallery-container{display:flex;flex-direction:column;max-width:100%}.kg-gallery-row{display:flex;flex-direction:row;justify-content:center}.kg-gallery-row:not(:first-of-type){margin:.75em 0 0}.kg-gallery-image img{display:block;margin:0;width:100%;height:100%}.kg-gallery-image:not(:first-of-type){margin:0 0 0 .75em}.kg-card{margin:0 0 .98039rem}.kg-card>*{margin:0 auto!important}.post-full-footer{display:flex;align-items:center;justify-content:center;margin-top:4rem}.post-full-container{display:inline-flex;position:relative;padding:.36765rem .18382rem .18382rem;flex-flow:row wrap;background:#f0f0f0;max-height:70px}.post-full-container .author-list-item,.post-full-container>section:first-child{margin-right:.61275rem}.post-full-container:before{left:-70px;border-left:70px solid transparent}.post-full-container:after,.post-full-container:before{display:block;position:absolute;content:" ";width:0;height:0;top:0;border-bottom:70px solid #f0f0f0}.post-full-container:after{right:-70px;border-right:70px solid transparent}.author-list li:last-child{margin-right:0}.author-card .author-profile-image,.share-icon{display:inline-block;position:relative;width:50px;height:50px;border-radius:50%;overflow:hidden;background:#cc4b37;text-align:center}.author-card a{border-bottom:none}.share-icon{color:#fefefe;font-size:1.53186rem}.share-icon>i{padding:.73529rem}.open-share{display:block;position:absolute;width:100%;height:100%;top:0;left:0;cursor:pointer;background:hsla(0,0%,100%,0)}.share-post{position:relative}.share-post:focus .share-post-ct,.share-post:hover .share-post-ct{opacity:1;visibility:visible}.share-post-ct{position:absolute;flex-flow:row nowrap;bottom:125%;left:50%;opacity:0;visibility:hidden;transform:translateX(-50%);transition:visibility .2s linear,opacity .2s linear;z-index:80}.share-icons{position:relative;flex-flow:row nowrap;padding:.75rem;border-radius:0;background-color:#0a0a0a}.share-icons:before{display:block;position:absolute;content:" ";width:0;height:0;top:100%;left:0;right:0;margin:0 auto;bottom:auto;border-color:#0a0a0a transparent transparent;border-style:solid inset inset;border-width:.75rem .75rem 0}.share-icons>li:not(:last-child){margin-right:.42892rem}.social-icon{display:inline-block;position:relative;padding:.36765rem;width:35px;height:35px;border-radius:50%;overflow:hidden;text-align:center;cursor:pointer}.social-icon,.social-icon:focus,.social-icon:hover{color:#fefefe}.icon-twitter{background-color:#56adee}.icon-twitter:focus,.icon-twitter:hover{background-color:#147cca}.icon-facebook{background-color:#4862a2}.icon-facebook:focus,.icon-facebook:hover{background-color:#29375b}.icon-google-plus{background-color:#db4437}.icon-google-plus:focus,.icon-google-plus:hover{background-color:#92241a}.icon-reddit{background-color:#ff4500}.icon-reddit:focus,.icon-reddit:hover{background-color:#992900}.icon-linkedin{background-color:#0071ad}.icon-linkedin:focus,.icon-linkedin:hover{background-color:#00507a}.icon-flipboard{background-color:#ff2a31}.icon-flipboard:focus,.icon-flipboard:hover{background-color:#c30006}.tooltip{z-index:80} -------------------------------------------------------------------------------- /author.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | {{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}} 3 | 4 | {{#author}} 5 | {{!-- Everything inside the #author tags pulls data from the author --}} 6 | {{#contentFor "styles"}} 7 | 52 | {{/contentFor}} 53 | {{/author}} 54 | 55 | 56 | {{#contentFor "author_header"}} 57 | 58 | {{#author}} 59 |

    {{name}}

    60 |
    61 | 89 |
    90 | {{/author}} 91 | {{/contentFor}} 92 | 93 |
    94 |
    95 |
    96 |
    97 | {{#foreach posts}} 98 | {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}} 99 | {{> "post-card"}} 100 | {{/foreach}} 101 |
    102 | {{pagination}} 103 |
    104 |
    105 | 106 | {{#contentFor "scripts"}} 107 | 108 | {{/contentFor}} 109 | -------------------------------------------------------------------------------- /babel.config.js: -------------------------------------------------------------------------------- 1 | module.exports = function(api) { 2 | api.cache(true); 3 | 4 | const presets = [ 5 | '@babel/preset-typescript', 6 | [ 7 | '@babel/preset-env', 8 | { 9 | useBuiltIns: 'usage', 10 | corejs: 3, 11 | targets: { 12 | ie: 11, 13 | }, 14 | }, 15 | ], 16 | ]; 17 | const plugins = [ 18 | '@babel/plugin-transform-runtime' 19 | ]; 20 | 21 | return { 22 | presets, 23 | plugins, 24 | }; 25 | }; 26 | -------------------------------------------------------------------------------- /default.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | {{!-- Document Settings --}} 6 | 7 | 8 | 9 | {{!-- Base Meta --}} 10 | {{meta_title}} 11 | 12 | 13 | 14 | {{!-- Styles'n'Scripts --}} 15 | 16 | {{{block "styles"}}} 17 | 18 | {{!-- This tag outputs SEO meta+structured data and other important settings --}} 19 | {{ghost_head}} 20 | 21 | 22 | 23 | 24 |
    25 | 26 | {{> header}} 27 | 28 | {{!-- All the main content gets inserted here, index.hbs, post.hbs, etc --}} 29 |
    30 | {{{body}}} 31 |
    32 | 33 | {{!-- The footer at the very bottom of the screen --}} 34 | {{> footer}} 35 | 36 |
    37 | 38 | {{> search}} 39 | 40 | {{!-- jQuery + Fitvids, which makes all video embeds responsive --}} 41 | 42 | 43 | 44 | {{!-- The #block helper will pull in data from the #contentFor other template files. In this case, there's some JavaScript which we only want to use in post.hbs, but it needs to be included down here, after jQuery has already loaded. --}} 45 | {{{block "scripts"}}} 46 | 47 | {{!-- Ghost outputs important scripts and data with this tag - it should always be the very last thing before the closing body tag --}} 48 | {{ghost_foot}} 49 | 50 | {{!-- Google Analytics --}} 51 | {{> "google_analytics"}} 52 | 53 | 54 | -------------------------------------------------------------------------------- /error-404.hbs: -------------------------------------------------------------------------------- 1 | {{!-- 2 | This error template is used for all 404 errors, which might occur on your site. 3 | It's a good idea to keep this template as minimal as possible in terms of both file size and complexity. 4 | --}} 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | {{meta_title}} 13 | 14 | 15 | 16 | {{!-- Styles'n'Scripts --}} 17 | 18 | {{{block "styles"}}} 19 | 20 | 21 | 22 |
    23 | 24 | {{> header}} 25 | 26 |
    27 |
    28 |
    29 |

    {{statusCode}}

    30 |

    {{message}}

    31 | Go to the front page → 32 |
    33 | 34 |
    35 |
    36 |
    37 | {{#get "posts" limit="3"}} 38 | {{#foreach posts}} 39 | {{> "post-card"}} 40 | {{/foreach}} 41 | {{/get}} 42 |
    43 |
    44 |
    45 |
    46 | 47 | {{!-- The footer at the very bottom of the screen --}} 48 | {{> footer}} 49 | 50 |
    51 | 52 | {{> search}} 53 | 54 | {{!-- jQuery + Fitvids, which makes all video embeds responsive --}} 55 | 56 | 57 | 58 | 59 | 60 | 61 | -------------------------------------------------------------------------------- /error.hbs: -------------------------------------------------------------------------------- 1 | {{!-- 2 | This error template is used for all 400/500 errors, except 404, which might occur on your site. 3 | It's a good idea to keep this template as minimal as possible in terms of both file size and complexity. 4 | You'll notice that we *don't* use any JavsScript, or ghost_head / ghost_foot in this file. 5 | --}} 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | {{meta_title}} 14 | 15 | 16 | 17 | {{!-- Styles'n'Scripts --}} 18 | 19 | {{{block "styles"}}} 20 | 21 | 22 | 23 |
    24 |
    25 |
    26 |
    27 |

    {{statusCode}}

    28 |

    {{message}}

    29 | Go to the front page → 30 |
    31 | 32 | {{#if errorDetails}} 33 |
    34 |

    Theme errors

    35 |
      36 | {{#foreach errorDetails}} 37 |
    • 38 | {{{rule}}} 39 | 40 | {{#foreach failures}} 41 |

      Ref: {{ref}}

      42 |

      Message: {{message}}

      43 | {{/foreach}} 44 |
    • 45 | {{/foreach}} 46 |
    47 |
    48 | {{/if}} 49 |
    50 |
    51 |
    52 | 53 | 54 | 55 | 56 | -------------------------------------------------------------------------------- /index.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | {{!-- The tag above means: insert everything in this file 3 | into the {body} of the default.hbs template --}} 4 | 5 | {{#contentFor "styles"}} 6 | 51 | {{/contentFor}} 52 | 53 | {{!-- The main content area --}} 54 | 55 |
    56 |
    57 |
    58 |
    59 | {{#foreach posts}} 60 | {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}} 61 | {{> "post-card"}} 62 | {{/foreach}} 63 |
    64 | {{pagination}} 65 |
    66 |
    67 | 68 | 69 | {{#contentFor "scripts"}} 70 | 71 | {{/contentFor}} 72 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "cusca", 3 | "description": "A clean theme for Ghost publishing platform.", 4 | "demo": "https://wdiaz.org", 5 | "version": "2.0.5", 6 | "engines": { 7 | "ghost": ">=3.0.0", 8 | "ghost-api": "v3" 9 | }, 10 | "license": "MIT", 11 | "screenshots": { 12 | "desktop": "assets/screenshot-desktop.jpg", 13 | "mobile": "assets/screenshot-mobile.jpg" 14 | }, 15 | "scripts": { 16 | "dev": "./node_modules/.bin/webpack --progress --colors -d --config src/build/webpack.config.js", 17 | "build": "./node_modules/.bin/webpack --progress --colors -p --config src/build/webpack.config.js", 18 | "start": "./node_modules/.bin/webpack --hide-modules --colors -d --watch --config src/build/webpack.config.js", 19 | "lint": "eslint src/scripts/ --ext .ts --ignore-path src/scripts/particles.json", 20 | "test": "gscan --v3 ." 21 | }, 22 | "author": { 23 | "name": "William Diaz", 24 | "email": "wdiazux@gmail.com", 25 | "url": "https://www.wdiaz.org" 26 | }, 27 | "gpm": { 28 | "type": "theme", 29 | "categories": [ 30 | "Minimal", 31 | "Magazine" 32 | ] 33 | }, 34 | "keywords": [ 35 | "ghost", 36 | "theme", 37 | "ghost-theme", 38 | "responsive", 39 | "foundation" 40 | ], 41 | "repository": { 42 | "type": "git", 43 | "url": "git+https://github.com/wdiazux/cusca.git" 44 | }, 45 | "bugs": { 46 | "url": "https://github.com/wdiazux/cusca/issues" 47 | }, 48 | "contributors": [ 49 | "https://github.com/wdiazux/cusca/graphs/contributors" 50 | ], 51 | "devDependencies": { 52 | "@babel/cli": "7.8.4", 53 | "@babel/core": "7.9.6", 54 | "@babel/plugin-transform-runtime": "7.9.6", 55 | "@babel/preset-env": "7.9.6", 56 | "@babel/preset-typescript": "7.9.0", 57 | "@types/webpack-env": "1.15.3", 58 | "@typescript-eslint/eslint-plugin": "2.31.0", 59 | "@typescript-eslint/parser": "2.31.0", 60 | "autoprefixer": "9.8.6", 61 | "awesome-typescript-loader": "5.2.1", 62 | "babel-loader": "8.1.0", 63 | "browser-sync": "2.26.13", 64 | "browser-sync-webpack-plugin": "2.2.2", 65 | "clean-webpack-plugin": "3.0.0", 66 | "copy-webpack-plugin": "5.1.2", 67 | "css-loader": "3.5.3", 68 | "cssnano": "4.1.10", 69 | "eslint": "7.0.0", 70 | "eslint-config-airbnb": "18.1.0", 71 | "eslint-config-jquery": "3.0.0", 72 | "eslint-config-prettier": "6.11.0", 73 | "eslint-loader": "4.0.2", 74 | "eslint-plugin-import": "2.20.2", 75 | "eslint-plugin-prettier": "3.1.4", 76 | "file-loader": "6.0.0", 77 | "gscan": "3.5.7", 78 | "mini-css-extract-plugin": "0.9.0", 79 | "node-sass": "4.14.1", 80 | "optimize-css-assets-webpack-plugin": "5.0.4", 81 | "postcss": "7.0.36", 82 | "postcss-flexbugs-fixes": "4.2.1", 83 | "postcss-loader": "3.0.0", 84 | "postcss-preset-env": "6.7.0", 85 | "precss": "4.0.0", 86 | "prettier": "2.0.5", 87 | "promise-polyfill": "8.1.3", 88 | "sass-loader": "8.0.2", 89 | "style-loader": "1.2.1", 90 | "terser-webpack-plugin": "3.0.8", 91 | "typescript": "3.8.3", 92 | "webpack": "4.43.0", 93 | "webpack-cli": "3.3.12", 94 | "webpack-merge": "4.2.2", 95 | "worker-loader": "2.0.0" 96 | }, 97 | "config": { 98 | "posts_per_page": 12, 99 | "image_sizes": { 100 | "xxs": { 101 | "width": 30 102 | }, 103 | "xs": { 104 | "width": 100 105 | }, 106 | "s": { 107 | "width": 300 108 | }, 109 | "m": { 110 | "width": 600 111 | }, 112 | "l": { 113 | "width": 1000 114 | }, 115 | "xl": { 116 | "width": 2000 117 | } 118 | } 119 | }, 120 | "homepage": "https://github.com/wdiazux/cusca#readme", 121 | "dependencies": { 122 | "@babel/runtime": "7.9.6", 123 | "@fortawesome/fontawesome-free": "5.13.1", 124 | "@tryghost/content-api": "1.4.11", 125 | "@types/jquery": "3.3.38", 126 | "@types/prismjs": "1.16.2", 127 | "colorthief": "2.3.2", 128 | "core-js": "3.6.5", 129 | "foundation-sites": "6.6.3", 130 | "fuzzysort": "1.1.4", 131 | "jquery": "3.5.1", 132 | "lg-zoom.js": "1.2.0", 133 | "lightgallery.js": "1.2.0", 134 | "particles.js": "2.0.0", 135 | "prismjs": "1.20.0", 136 | "roboto-fontface": "0.10.0", 137 | "shufflejs": "5.2.3", 138 | "tern": "0.24.3", 139 | "typeface-montserrat": "0.0.75", 140 | "what-input": "5.2.10" 141 | } 142 | } 143 | -------------------------------------------------------------------------------- /page.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | {{!-- The tag above means: insert everything in this file 3 | into the {body} of the default.hbs template --}} 4 | 5 | {{#contentFor "styles"}} 6 | 7 | {{/contentFor}} 8 | 9 | {{!-- Everything inside the #post tags pulls data from the post --}} 10 | {{#post}} 11 | 12 |
    13 |
    14 | 15 |
    16 | 17 |
    18 |
    19 | {{#if feature_image}} 20 |
    21 |
    22 | 23 |
    24 |
    25 |
    26 |
    27 |
    28 |
    29 |
    30 |
    31 |
    32 |
    33 |
    34 | 35 |
    36 | {{/if}} 37 | 38 |
    39 |

    {{title}}

    40 |
    41 |
    42 | 43 |
    44 |
    45 | {{content}} 46 |
    47 |
    48 | 49 |
    50 | 51 |
    52 |
    53 | 54 | {{/post}} 55 | 56 | {{!-- The #contentFor helper here will send everything inside it up to the matching #block helper found in default.hbs --}} 57 | {{#contentFor "scripts"}} 58 | 59 | {{/contentFor}} 60 | -------------------------------------------------------------------------------- /partials/byline-multiple.hbs: -------------------------------------------------------------------------------- 1 |
    2 | 3 | 18 | 19 |
    20 | -------------------------------------------------------------------------------- /partials/byline-single.hbs: -------------------------------------------------------------------------------- 1 | {{!-- Everything inside the #author tags pulls data from the author --}} 2 | {{#primary_author}} 3 |
    4 | 5 | {{#if profile_image}} 6 | 7 | {{else}} 8 | {{> "icons/avatar"}} 9 | {{/if}} 10 | 11 |
    12 | {{/primary_author}} 13 | -------------------------------------------------------------------------------- /partials/feed-card.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{#if feature_image}} 4 |
    5 | 6 |
    7 | {{title}} 13 |
    14 |
    15 | {{#if tags}} 16 |
      17 | {{#foreach tags}} 18 |
    • #{{name}}
    • 19 | {{/foreach}} 20 |
    21 | {{/if}} 22 |
    23 | {{/if}} 24 | 25 |
    26 |
    27 | 28 |

    {{title}}

    29 |
    30 |
    31 | 32 |
    33 |

    {{excerpt words="15"}}[...]

    34 |
    35 | 36 | 73 |
    74 |
    75 |
    76 | -------------------------------------------------------------------------------- /partials/floating-header.hbs: -------------------------------------------------------------------------------- 1 | 23 | -------------------------------------------------------------------------------- /partials/footer.hbs: -------------------------------------------------------------------------------- 1 | 98 | -------------------------------------------------------------------------------- /partials/google_adsense.hbs: -------------------------------------------------------------------------------- 1 | 2 | 12 | -------------------------------------------------------------------------------- /partials/google_analytics.hbs: -------------------------------------------------------------------------------- 1 | 6 | 7 | -------------------------------------------------------------------------------- /partials/header.hbs: -------------------------------------------------------------------------------- 1 | {{!-- The big featured header, it uses blog cover image as a BG if available --}} 2 | 3 | 69 | -------------------------------------------------------------------------------- /partials/icons/avatar.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/facebook.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/ghost-logo.hbs: -------------------------------------------------------------------------------- 1 | Ghost Logo 2 | -------------------------------------------------------------------------------- /partials/icons/infinity.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/location.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/point.hbs: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /partials/icons/rss.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/twitter.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/icons/website.hbs: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /partials/navigation.hbs: -------------------------------------------------------------------------------- 1 | 11 | -------------------------------------------------------------------------------- /partials/pagination.hbs: -------------------------------------------------------------------------------- 1 | 5 | 6 | 20 | -------------------------------------------------------------------------------- /partials/post-card.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | {{#if feature_image}} 4 |
    5 | 6 |
    7 | {{title}} 13 |
    14 |
    15 | {{#if tags}} 16 |
      17 | {{#foreach tags}} 18 |
    • #{{name}}
    • 19 | {{/foreach}} 20 |
    21 | {{/if}} 22 | 23 | 24 |
    25 | {{/if}} 26 | 27 |
    28 |
    29 | 30 |

    {{title}}

    31 |
    32 |
    33 | 34 |
    35 |

    {{excerpt words="33"}}

    36 |
    37 | 38 | 75 | 76 |
    77 |
    78 |
    79 |
    80 |
    81 |
    82 |
    83 |
    84 |
    85 |
    86 |
    87 |
    88 |
    89 | -------------------------------------------------------------------------------- /partials/search.hbs: -------------------------------------------------------------------------------- 1 | 18 | -------------------------------------------------------------------------------- /partials/share-post.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 |
    6 | 7 |
    8 | 45 |
    46 | 47 |
    48 | -------------------------------------------------------------------------------- /partials/site-nav.hbs: -------------------------------------------------------------------------------- 1 | {{#if @site.navigation}} 2 | {{navigation}} 3 | {{/if}} 4 | -------------------------------------------------------------------------------- /partials/spinkit.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 |
    4 |
    5 |
    6 |
    7 |
    8 |
    9 |
    10 |
    11 |
    12 | -------------------------------------------------------------------------------- /partials/subscribe_form.hbs: -------------------------------------------------------------------------------- 1 |
    2 |
    3 | 4 |
    5 | 6 |
    7 |
    8 |
    9 | Great! Check your inbox and click the link to confirm your subscription. 10 |
    11 |
    12 | Please enter a valid email address! 13 |
    14 |
    15 | -------------------------------------------------------------------------------- /post.hbs: -------------------------------------------------------------------------------- 1 | {{!< default}} 2 | 3 | {{!-- The tag above means: insert everything in this file 4 | into the {body} of the default.hbs template --}} 5 | 6 | {{#contentFor "styles"}} 7 | 8 | {{/contentFor}} 9 | 10 | 11 | {{!-- Everything inside the #post tags pulls data from the post --}} 12 | {{#post}} 13 | 14 |
    15 |
    16 | 17 |
    18 |
    19 | {{#if feature_image}} 20 |
    21 |
    22 | 23 | 24 | {{> "spinkit"}} 25 | 26 |
    27 | 30 | {{#primary_tag}} 31 |
    32 | {{name}} 33 |
    34 | {{/primary_tag}} 35 |
    36 |
    37 | {{/if}} 38 | 39 |
    40 |

    {{title}}

    41 |
    42 | 43 | {{#unless feature_image}} 44 |
    45 | 48 | {{#primary_tag}} 49 |
    50 |
    {{name}} 51 |
    52 | {{/primary_tag}} 53 |
    54 | {{/unless}} 55 |
    56 | 57 | 58 |
    59 |
    60 | {{content}} 61 |
    62 |
    63 | 64 | 81 |
    82 | 83 |
    84 |
    85 | 86 | {{!-- Links to Previous/Next posts --}} 87 | 144 | 145 | {{!-- Comments --}} 146 |
    147 |
    148 |
    149 |

    Comments:

    150 | 151 |
    152 | 165 | 166 |
    167 | 168 |
    169 |
    170 | 171 | {{/post}} 172 | 173 | {{!-- The #contentFor helper here will send everything inside it up to the matching #block helper found in default.hbs --}} 174 | {{#contentFor "scripts"}} 175 | 176 | {{/contentFor}} 177 | -------------------------------------------------------------------------------- /renovate.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": [ 3 | "config:base" 4 | ], 5 | "node": { 6 | "supportPolicy": ["lts"] 7 | }, 8 | "separateMinorPatch": true, 9 | "patch": { 10 | "automerge": true 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /src/build/postcss.config.js: -------------------------------------------------------------------------------- 1 | 2 | module.exports = { 3 | plugins: [ 4 | require('postcss-flexbugs-fixes'), 5 | require('postcss-preset-env')({ 6 | stage: 4, 7 | autoprefixer: false, 8 | }), 9 | require('autoprefixer'), 10 | require('cssnano') 11 | ] 12 | }; -------------------------------------------------------------------------------- /src/build/webpack.config.dev.js: -------------------------------------------------------------------------------- 1 | const BrowserSyncPlugin = require('browser-sync-webpack-plugin'); 2 | 3 | // Webpack Development Configuration 4 | 5 | const config = { 6 | plugins: [ 7 | new BrowserSyncPlugin( 8 | { 9 | host: 'localhost', 10 | port: 3000, 11 | cors: true, 12 | proxy: { 13 | target: 'http://localhost:2368', 14 | proxyReq: { 15 | function (proxyReq) { 16 | proxyReq.setHeader('Access-Control-Allow-Origin', '*'); 17 | } 18 | } 19 | }, 20 | files: [ 21 | { 22 | match: [ 23 | '**/*.hbs', 24 | './src/*.*' 25 | ] 26 | } 27 | ] 28 | }, 29 | { 30 | reload: true 31 | } 32 | ) 33 | ], 34 | }; 35 | 36 | module.exports = config; 37 | -------------------------------------------------------------------------------- /src/build/webpack.config.js: -------------------------------------------------------------------------------- 1 | const eslint = require('eslint'); 2 | const webpack = require('webpack'); 3 | const path = require('path'); 4 | const merge = require('webpack-merge'); 5 | const { CleanWebpackPlugin } = require('clean-webpack-plugin'); 6 | const CopyWebpackPlugin = require('copy-webpack-plugin'); 7 | const { CheckerPlugin } = require('awesome-typescript-loader'); 8 | const MiniCssExtractPlugin = require("mini-css-extract-plugin"); 9 | 10 | // Detect Node Environment Variable and load corresponding webpack config-extras 11 | const prod = process.argv.indexOf('-p') !== -1 || process.env.NODE_ENV === 'production'; 12 | const ENV_CONF = prod ? require('./webpack.config.prod') : require('./webpack.config.dev'); 13 | 14 | // Webpack Base Configuration 15 | const config = { 16 | // Tell Webpack where to start looking for your files. 17 | context: path.resolve(__dirname, '../'), 18 | // We are looking at the Bootstrap files you installed with NPM. 19 | entry: { 20 | 'main' : [ 21 | './scripts/app.ts', 22 | './styles/main.scss' 23 | ], 24 | 'post' : [ 25 | './scripts/post.ts', 26 | './styles/post.scss' 27 | ], 28 | 'grid': [ 29 | './scripts/grid.ts' 30 | ] 31 | }, 32 | // This next line generates source maps to help with debugging. 33 | // Don't want source maps? Get rid of it. 34 | devtool: prod ? false : 'source-map', 35 | // Here we're defining the output of our bundled JS. 36 | output: { 37 | filename: 'scripts/[name].js', 38 | // Everything gets initially output to this directory. 39 | // /js and /fonts are odd because of how Font Awesome builds. 40 | path: path.resolve(__dirname, '../../assets/') 41 | }, 42 | // This is the extra rules that we have to handle our SCSS and ES2015. 43 | module: { 44 | rules: [ 45 | { 46 | enforce: 'pre', 47 | test: /\.ts$/, 48 | loader: 'eslint-loader', 49 | exclude: /(node_modules)/, 50 | options: { 51 | formatter: eslint.CLIEngine.getFormatter('stylish'), 52 | emitWarning: process.env.NODE_ENV !== 'production', 53 | }, 54 | }, 55 | { 56 | test: /\.js$/, 57 | exclude: /(node_modules)/, 58 | loader: 'babel-loader', 59 | }, 60 | { 61 | test: /\.ts$/, 62 | use: { 63 | loader: 'awesome-typescript-loader', 64 | options: { 65 | useBabel: true, 66 | configFileName: 'tsconfig.json', 67 | babelOptions: { 68 | babelrc: true, 69 | }, 70 | babelCore: '@babel/core' 71 | } 72 | }, 73 | }, 74 | { 75 | test: /\.(sa|sc|c)ss$/, 76 | use: [ 77 | MiniCssExtractPlugin.loader, 78 | 'css-loader', 79 | { 80 | loader: 'postcss-loader', 81 | options: { 82 | sourceMap: true, 83 | config: { path: path.resolve(__dirname, './postcss.config.js') } 84 | } 85 | }, 86 | { 87 | loader: 'sass-loader', 88 | options: { 89 | sourceMap: true, 90 | sassOptions: { 91 | includePaths: [ 92 | './node_modules/foundation-sites/scss/', 93 | ] 94 | } 95 | }, 96 | } 97 | ] 98 | }, 99 | { 100 | test: /\.(jpg|png|gif|svg)$/, 101 | use: [ 102 | { 103 | loader: 'file-loader', 104 | options: { 105 | name: '[name].[ext]', 106 | outputPath: 'img/', 107 | publicPath: '../../assets/img/' 108 | } 109 | } 110 | ] 111 | }, 112 | { 113 | test: /\.(ttf|otf|eot|svg|woff(2)?)(\?[a-z0-9]+)?$/, 114 | exclude: /img/, 115 | use: [ 116 | { 117 | loader: 'file-loader', 118 | options: { 119 | name: '[name].[ext]', 120 | outputPath: 'fonts/', 121 | publicPath: '../../assets/fonts/' 122 | } 123 | } 124 | ] 125 | }, 126 | { 127 | test: /\.worker.js$/, 128 | loader: 'worker-loader', 129 | options: { publicPath: '/assets/' } 130 | } 131 | ] 132 | }, 133 | optimization: { 134 | splitChunks: { 135 | automaticNameDelimiter: '-', 136 | name: true, 137 | cacheGroups: { 138 | vendors: { 139 | test: /[\\/]node_modules[\\/](jquery|foundation-sites|particles.js)[\\/]/, 140 | chunks: 'all', 141 | name: 'main-vendors', 142 | priority: 1 143 | } 144 | } 145 | } 146 | }, 147 | resolve: { 148 | modules: ['src/scripts', 'node_modules'], 149 | extensions: ['*', '.js', '.ts'], 150 | }, 151 | plugins: [ 152 | new CleanWebpackPlugin(), 153 | new MiniCssExtractPlugin({ 154 | filename: 'styles/[name].css', 155 | chunkFilename: 'styles/[id].css', 156 | }), 157 | new CopyWebpackPlugin([ 158 | { from: 'fonts/**/', to: 'fonts' } 159 | ], { copyUnmodified: true }), 160 | new webpack.ProvidePlugin({ 161 | $: 'jquery', 162 | jQuery: 'jquery', 163 | }), 164 | new CheckerPlugin() 165 | ] 166 | }; 167 | 168 | // Export a merge of base- and dev/prod- config 169 | module.exports = env => { 170 | return merge(config, ENV_CONF); 171 | }; 172 | -------------------------------------------------------------------------------- /src/build/webpack.config.prod.js: -------------------------------------------------------------------------------- 1 | const TerserPlugin = require('terser-webpack-plugin'); 2 | const OptimizeCSSAssetsPlugin = require("optimize-css-assets-webpack-plugin"); 3 | 4 | // Webpack Development Configuration 5 | const config = { 6 | optimization: { 7 | minimizer: [ 8 | new TerserPlugin({ 9 | parallel: true, 10 | cache: true, 11 | sourceMap: true, 12 | terserOptions: { 13 | warnings: false, 14 | output: { 15 | comments: false, 16 | }, 17 | } 18 | }), 19 | new OptimizeCSSAssetsPlugin({ 20 | cssProcessor: require('cssnano'), 21 | cssProcessorPluginOptions: { 22 | preset: ['default', { discardComments: { removeAll: true } }], 23 | } 24 | }) 25 | ] 26 | } 27 | }; 28 | 29 | module.exports = config; 30 | -------------------------------------------------------------------------------- /src/img/credits.txt: -------------------------------------------------------------------------------- 1 | Sven Scheuermeier 2 | @sveninho 3 | https://unsplash.com/photos/YhdEgF-qWlI 4 | 5 | Missy Stinson 6 | @missystinson 7 | https://unsplash.com/photos/_uFakEUIAno 8 | -------------------------------------------------------------------------------- /src/img/photo-1523980669340-3d154e47d5fd.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/src/img/photo-1523980669340-3d154e47d5fd.jpg -------------------------------------------------------------------------------- /src/img/sven-scheuermeier-178631-unsplash.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/wdiazux/cusca/463d64b5c9bd39c4d140c880f474770de150388b/src/img/sven-scheuermeier-178631-unsplash.jpg -------------------------------------------------------------------------------- /src/scripts/app.ts: -------------------------------------------------------------------------------- 1 | import 'core-js/proposals/url'; 2 | import 'foundation-sites'; 3 | import 'particles.js'; 4 | import particlesJSON from './particles.json'; 5 | import GhostSearch from './search'; 6 | import createScrollManager from './createScrollManager'; 7 | 8 | // Here, we're requiring all images inside JS in order to use the webpack 9 | // fileloader even on images that are not otherwise required in js 10 | const images = require.context('../img/', false, /\.(png|gif|jpe?g|svg)$/); 11 | images.keys().map(images); 12 | 13 | $(document).foundation(); 14 | 15 | // Pagination 16 | // ---------- 17 | 18 | document.addEventListener('DOMContentLoaded', () => { 19 | const pagination = (currentPage: number, pageCount: number) => { 20 | const range: (string | number)[] = []; 21 | const delta = 2; 22 | 23 | for ( 24 | let i = Math.max(2, currentPage - delta); 25 | i <= Math.min(pageCount - 1, currentPage + delta); 26 | i++ 27 | ) { 28 | range.push(i); 29 | } 30 | 31 | if (currentPage - delta > 2) range.unshift('...'); 32 | if (currentPage + delta < pageCount - 1) range.push('...'); 33 | 34 | range.unshift(1); 35 | range.push(pageCount); 36 | 37 | return range; 38 | }; 39 | 40 | const createPagination = () => { 41 | let url: string = window.location.href; 42 | const currPageElm: HTMLDivElement | null = document.querySelector( 43 | '.curr-page' 44 | ); 45 | const totalPagesElm: HTMLDivElement | null = document.querySelector( 46 | '.total-pages' 47 | ); 48 | if (!currPageElm || !totalPagesElm) return; 49 | const currentPage: number = Number.parseInt( 50 | currPageElm!.textContent!, 51 | 10 52 | ); 53 | const totalPages: number = Number.parseInt( 54 | totalPagesElm!.textContent!, 55 | 10 56 | ); 57 | const paginationElm: HTMLElement | null = document.querySelector( 58 | '.pagination' 59 | ); 60 | const paginationPrev: HTMLDivElement | null = document.querySelector( 61 | '.pagination-previous' 62 | ); 63 | 64 | if (totalPages > 1) { 65 | const paginationItems: string[] = []; 66 | const paginationArr: (string | number)[] = pagination( 67 | currentPage, 68 | totalPages 69 | ); 70 | 71 | paginationArr.forEach((pagElm: number | string): void => { 72 | const urlArray = url.split('/'); 73 | 74 | if (pagElm === currentPage) { 75 | paginationItems.push(`
  • ${pagElm}
  • `); 76 | } else if (typeof pagElm === 'number') { 77 | if (urlArray[urlArray.length - 3] === 'page') { 78 | url = url.replace(/\/page\/.*$/, '') + '/'; 79 | } 80 | paginationItems.push( 81 | `
  • ${pagElm}
  • ` 82 | ); 83 | } else { 84 | paginationItems.push('
  • '); 85 | } 86 | }); 87 | 88 | if (paginationPrev?.parentNode) 89 | paginationPrev.insertAdjacentHTML( 90 | 'afterend', 91 | paginationItems.join('') 92 | ); 93 | } else if (paginationElm != null) { 94 | paginationElm.style.display = 'none'; 95 | } 96 | }; 97 | createPagination(); 98 | }); 99 | 100 | // Top bar 101 | // ------- 102 | 103 | const siteHeader: HTMLDivElement | null = document.querySelector( 104 | '.site-header' 105 | ); 106 | const siteHeaderBg: HTMLDivElement | null = document.querySelector( 107 | '.site-header-bg' 108 | ); 109 | 110 | createScrollManager().add((pageScroll) => { 111 | if (!siteHeader || !siteHeaderBg) return; 112 | const lastHeaderHeight = siteHeader.offsetHeight; 113 | 114 | if (pageScroll! - siteHeaderBg.scrollTop - lastHeaderHeight! >= -240) { 115 | siteHeader.classList.add('bg'); 116 | siteHeaderBg.style.opacity = '0.3'; 117 | } else { 118 | siteHeader.classList.remove('bg'); 119 | siteHeaderBg!.style.opacity = '1'; 120 | } 121 | }); 122 | 123 | if (siteHeaderBg) { 124 | window.particlesJS('site-header-bg', particlesJSON); 125 | } else if (siteHeader) { 126 | siteHeader.classList.add('bg'); 127 | } 128 | 129 | document.addEventListener('DOMContentLoaded', () => { 130 | // Search 131 | // ------ 132 | const openSearchElm = document.querySelectorAll('[data-open-search]'); 133 | const closeSearchElm = document.querySelectorAll('[data-close-search]'); 134 | 135 | const ghostSearch = new GhostSearch({ 136 | url: 'http://localhost:2368', 137 | key: '4f1476d8df3a9cd277b2273b6e', 138 | }); 139 | 140 | openSearchElm.forEach((elm): void => { 141 | elm.addEventListener('click', ghostSearch.openSearch); 142 | }); 143 | closeSearchElm.forEach((elm): void => { 144 | elm.addEventListener('click', ghostSearch.closeSearch); 145 | }); 146 | }); 147 | -------------------------------------------------------------------------------- /src/scripts/createScrollManager.ts: -------------------------------------------------------------------------------- 1 | const createScrollManager = () => { 2 | let callbacks: { (data?: number): void }[] = []; 3 | let scrollPosition = -1; 4 | let animatedKilled = false; 5 | let eventsAdded = false; 6 | 7 | const animate = () => { 8 | // eslint-disable-next-line @typescript-eslint/no-use-before-define 9 | requestAnimationFrame(onScroll); 10 | }; 11 | 12 | const addEvents = (): void => { 13 | window.addEventListener( 14 | 'scroll', 15 | () => { 16 | // eslint-disable-next-line @typescript-eslint/no-use-before-define 17 | onScroll(); 18 | }, 19 | { 20 | capture: true, 21 | passive: true, 22 | } 23 | ); 24 | }; 25 | 26 | const onScroll = () => { 27 | if (animatedKilled) return; 28 | 29 | if (scrollPosition !== window.pageYOffset) { 30 | scrollPosition = window.pageYOffset; 31 | callbacks.forEach((cb) => cb(scrollPosition)); 32 | animate(); 33 | } else if (!eventsAdded) { 34 | addEvents(); 35 | eventsAdded = true; 36 | } 37 | }; 38 | 39 | animate(); 40 | 41 | return { 42 | add: (cb: (data?: number) => void) => { 43 | callbacks = [...callbacks, cb]; 44 | }, 45 | remove: (cb: () => {}): void => { 46 | callbacks = callbacks.filter((value) => value !== cb); 47 | }, 48 | destroy: (): void => { 49 | animatedKilled = true; 50 | window.removeEventListener('scroll', animate); 51 | }, 52 | }; 53 | }; 54 | 55 | export default createScrollManager; 56 | -------------------------------------------------------------------------------- /src/scripts/grid.ts: -------------------------------------------------------------------------------- 1 | // Polyfill 2 | // -------- 3 | 4 | import 'core-js/es/array'; 5 | 6 | const Shuffle = require('shufflejs').default; 7 | 8 | if (window.NodeList && !NodeList.prototype.forEach) { 9 | // @ts-ignore 10 | NodeList.prototype.forEach = Array.prototype.forEach; 11 | } 12 | const onImagesLoaded = (container: string, callback?: () => void) => { 13 | const containerElm: HTMLElement | null = document.querySelector(container); 14 | if (!container) return; 15 | 16 | const images: HTMLCollectionOf = containerElm!.getElementsByTagName( 17 | 'img' 18 | ); 19 | let loaded: number = images.length; 20 | 21 | if (loaded === 0 && callback) { 22 | callback(); 23 | return; 24 | } 25 | 26 | Array.from(images).forEach((image) => { 27 | if (image.complete) { 28 | // eslint-disable-next-line no-plusplus 29 | loaded -= 1; 30 | if (loaded === 0 && callback) callback(); 31 | } else { 32 | image.addEventListener('load', () => { 33 | // eslint-disable-next-line no-plusplus 34 | loaded -= 1; 35 | if (loaded === 0 && callback) callback(); 36 | }); 37 | } 38 | }); 39 | }; 40 | 41 | // Grid 42 | // ---- 43 | const postFeed: HTMLDivElement | null = document.querySelector('.post-feed'); 44 | const shuffleInstance = new Shuffle(postFeed, { 45 | itemSelector: '.post-card', 46 | sizer: '.post-card-ex', 47 | buffer: 1, 48 | }); 49 | 50 | const postCard: NodeListOf | null = document.querySelectorAll( 51 | '.post-card' 52 | ); 53 | if (postCard) { 54 | postCard.forEach((card: HTMLDivElement): void => { 55 | let cardHeight = 220; 56 | const line2 = card.querySelector('.placeholder-text2'); 57 | const line3 = card.querySelector('.placeholder-text3'); 58 | const placeholderCt: HTMLDivElement | null = card.querySelector( 59 | '.placeholder-content-ct' 60 | ); 61 | const postCardMeta: HTMLDivElement | null = card.querySelector( 62 | '.post-card-meta' 63 | ); 64 | 65 | if (postCardMeta) { 66 | cardHeight = postCardMeta.offsetTop + postCardMeta.offsetHeight; 67 | } 68 | if (cardHeight < 119) { 69 | card.style.minHeight = '0'; 70 | if (line2?.parentNode) line2.parentNode.removeChild(line2); 71 | if (line3?.parentNode) line3.parentNode.removeChild(line3); 72 | if (placeholderCt) placeholderCt.style.minHeight = '0'; 73 | } 74 | }); 75 | } 76 | 77 | const shuffleCards = (): void => { 78 | if (postFeed) { 79 | // Remove placeholder class in parent 80 | postFeed.classList.remove('loading-cards'); 81 | 82 | // Add class "loaded" to feed post container 83 | postFeed.classList.add('loaded'); 84 | 85 | shuffleInstance.on(Shuffle.EventType.LAYOUT, () => { 86 | const placeholderCt: NodeListOf = document.querySelectorAll( 87 | '.placeholder-content-ct' 88 | ); 89 | const placeholderImg: NodeListOf = document.querySelectorAll( 90 | '.placeholder-featured-image' 91 | ); 92 | 93 | placeholderCt.forEach((placeHolder: HTMLElement): void => { 94 | if (placeHolder?.parentElement) 95 | placeHolder.parentElement.removeChild(placeHolder); 96 | }); 97 | 98 | placeholderImg.forEach((placeHolder: HTMLElement): void => { 99 | if (placeHolder?.parentElement) 100 | placeHolder.parentElement.removeChild(placeHolder); 101 | }); 102 | }); 103 | } 104 | }; 105 | 106 | onImagesLoaded('.post-feed', shuffleCards); 107 | -------------------------------------------------------------------------------- /src/scripts/particles.json: -------------------------------------------------------------------------------- 1 | { 2 | "particles": { 3 | "number": { 4 | "value": 60, 5 | "density": { 6 | "enable": true, 7 | "value_area": 1420 8 | } 9 | }, 10 | "color": { 11 | "value": [ 12 | "#aa73ff", 13 | "#f8c210", 14 | "#83d238", 15 | "#33b1f8" 16 | ] 17 | }, 18 | "shape": { 19 | "type": "triangle", 20 | "stroke": { 21 | "width": 0, 22 | "color": "#000000" 23 | }, 24 | "polygon": { 25 | "nb_sides": 5 26 | } 27 | }, 28 | "opacity": { 29 | "value": 0.5, 30 | "random": false, 31 | "anim": { 32 | "enable": false, 33 | "speed": 1, 34 | "opacity_min": 0.1, 35 | "sync": false 36 | } 37 | }, 38 | "size": { 39 | "value": 12, 40 | "random": true, 41 | "anim": { 42 | "enable": false, 43 | "speed": 30, 44 | "size_min": 0.1, 45 | "sync": false 46 | } 47 | }, 48 | "line_linked": { 49 | "enable": true, 50 | "distance": 150, 51 | "color": "#ffffff", 52 | "opacity": 0.4, 53 | "width": 1 54 | }, 55 | "move": { 56 | "enable": true, 57 | "speed": 2, 58 | "direction": "none", 59 | "random": false, 60 | "straight": false, 61 | "out_mode": "out", 62 | "bounce": false, 63 | "attract": { 64 | "enable": false, 65 | "rotateX": 600, 66 | "rotateY": 1200 67 | } 68 | } 69 | }, 70 | "interactivity": { 71 | "detect_on": "canvas", 72 | "events": { 73 | "onhover": { 74 | "enable": true, 75 | "mode": "grab" 76 | }, 77 | "onclick": { 78 | "enable": true, 79 | "mode": "push" 80 | }, 81 | "resize": true 82 | }, 83 | "modes": { 84 | "grab": { 85 | "distance": 140, 86 | "line_linked": { 87 | "opacity": 1 88 | } 89 | }, 90 | "bubble": { 91 | "distance": 400, 92 | "size": 40, 93 | "duration": 2, 94 | "opacity": 8, 95 | "speed": 3 96 | }, 97 | "repulse": { 98 | "distance": 200, 99 | "duration": 0.4 100 | }, 101 | "push": { 102 | "particles_nb": 1 103 | }, 104 | "remove": { 105 | "particles_nb": 2 106 | } 107 | } 108 | }, 109 | "retina_detect": true 110 | } -------------------------------------------------------------------------------- /src/scripts/post.ts: -------------------------------------------------------------------------------- 1 | // Lightbox 2 | // -------- 3 | 4 | import 'lightgallery.js'; 5 | import 'lg-zoom.js'; 6 | 7 | // PrismJS 8 | // ------- 9 | 10 | import 'prismjs'; 11 | import 'prismjs/plugins/line-highlight/prism-line-highlight'; 12 | import 'prismjs/components/prism-batch'; 13 | import 'prismjs/components/prism-markup'; 14 | import 'prismjs/components/prism-css'; 15 | import 'prismjs/components/prism-javascript'; 16 | import 'prismjs/components/prism-bash'; 17 | import 'prismjs/components/prism-scss'; 18 | import 'prismjs/components/prism-diff'; 19 | import 'prismjs/components/prism-markup-templating'; 20 | import 'prismjs/components/prism-handlebars'; 21 | import 'prismjs/components/prism-json'; 22 | import 'prismjs/components/prism-typescript'; 23 | 24 | // Feature Image Background 25 | // ------------------------ 26 | 27 | import ColorThief from 'colorthief'; 28 | 29 | // Helper function 30 | // --------------- 31 | 32 | function wrap(el: Element, wrapper: HTMLElement) { 33 | if (!el.parentNode) return; 34 | el.parentNode.insertBefore(wrapper, el); 35 | wrapper.appendChild(el); 36 | } 37 | 38 | // Feature Image Background 39 | // ------------------------ 40 | 41 | const featureImageCt: HTMLElement | null = document.querySelector( 42 | '.post-full-image' 43 | ); 44 | if (featureImageCt) { 45 | const featureImage: HTMLImageElement | null = featureImageCt.querySelector( 46 | 'img' 47 | ); 48 | const postFullImageBg: HTMLElement | null = document.querySelector( 49 | '.post-full-image-background' 50 | ); 51 | const featureImageElm: HTMLImageElement = new Image(); 52 | let paletteReady = false; 53 | 54 | if (featureImage) { 55 | featureImageElm.crossOrigin = 'Anonymous'; 56 | 57 | const featureImageUrl = new URL(featureImage.src); 58 | 59 | if (featureImageUrl.host.includes(window.location.host)) { 60 | featureImageElm.src = featureImageUrl.pathname; 61 | } else { 62 | featureImageElm.src = featureImageUrl.href; 63 | } 64 | 65 | const getPalette = (): void => { 66 | paletteReady = true; 67 | const colorThief = new ColorThief(); 68 | 69 | if (featureImageElm.complete) { 70 | const bgColor: string = colorThief.getColor(featureImageElm); 71 | 72 | featureImageCt.classList.add('loaded'); 73 | 74 | if (postFullImageBg) 75 | postFullImageBg.style.background = `rgba(${bgColor}, 0.9)`; 76 | 77 | setTimeout(() => { 78 | const spinKit: HTMLElement | null = document.getElementById( 79 | 'spinkit' 80 | ); 81 | if (spinKit && spinKit.parentNode) { 82 | spinKit.parentNode.removeChild(spinKit); 83 | } 84 | }, 500); 85 | } 86 | }; 87 | 88 | featureImageElm.addEventListener( 89 | 'load', 90 | () => { 91 | if (!paletteReady) getPalette(); 92 | }, 93 | false 94 | ); 95 | } 96 | } 97 | 98 | // Lightbox 99 | // --------- 100 | 101 | const wrapImages = (elem: string, elemClass: string, exclude: string) => { 102 | const imgs = document.querySelectorAll(elem); 103 | 104 | imgs.forEach((image: Element) => { 105 | let caption: string | null; 106 | const imgLink: string | null = image.getAttribute('src'); 107 | if (image.classList.contains('kg-image')) { 108 | const imageCard: HTMLElement | null = image.closest( 109 | '.kg-image-card' 110 | ); 111 | const figCaption = imageCard?.querySelector('figcaption'); 112 | caption = figCaption?.textContent ?? ''; 113 | } else { 114 | caption = ''; 115 | } 116 | 117 | if (!image.classList.contains(exclude)) { 118 | const imgWrap = document.createElement('div'); 119 | 120 | imgWrap.className = elemClass; 121 | if (imgLink != null) imgWrap.dataset.src = imgLink; 122 | if (caption !== '') imgWrap.dataset.subHtml = caption; 123 | 124 | wrap(image, imgWrap); 125 | } 126 | }); 127 | }; 128 | 129 | wrapImages('.post-content img', 'lightbox', 'no-lightbox'); 130 | const images = document.querySelector('.post-content'); 131 | if (images != null) { 132 | window.lightGallery(images, { 133 | selector: '.lightbox', 134 | escKey: true, 135 | keyPress: true, 136 | controls: true, 137 | getCaptionFromTitleOrAlt: true, 138 | }); 139 | } 140 | 141 | // Responsive Videos 142 | // ----------------- 143 | 144 | const videoSelectors: string[] = [ 145 | 'iframe[src*="player.vimeo.com"]', 146 | 'iframe[src*="youtube.com"]', 147 | 'iframe[src*="youtube-nocookie.com"]', 148 | 'iframe[src*="kickstarter.com"][src*="video.html"]', 149 | 'object:not(object)', 150 | 'embed', 151 | ]; 152 | 153 | const allVideos = document 154 | .querySelector('.post-content')! 155 | .querySelectorAll(videoSelectors.join(',')); 156 | 157 | allVideos.forEach((element) => { 158 | if ( 159 | (element.tagName.toLowerCase() !== 'embed' && 160 | !element.closest('object')) || 161 | !element.closest('.responsive-embed') 162 | ) { 163 | const videoWrap = document.createElement('div'); 164 | videoWrap.className = 'responsive-embed widescreen'; 165 | wrap(element, videoWrap); 166 | } 167 | }); 168 | -------------------------------------------------------------------------------- /src/scripts/search.ts: -------------------------------------------------------------------------------- 1 | // Search 2 | // ------ 3 | // A modification of Ghost-Search 4 | // https://github.com/HauntedThemes/ghost-search 5 | 6 | import 'core-js/es/number/is-integer'; 7 | 8 | // eslint-disable-next-line max-classes-per-file 9 | import GhostContentAPI from '@tryghost/content-api'; 10 | 11 | const fuzzysort = require('fuzzysort'); 12 | 13 | /** 14 | * Element.closest() polyfill 15 | * https://developer.mozilla.org/en-US/docs/Web/API/Element/closest#Polyfill 16 | */ 17 | if (!Element.prototype.matches) { 18 | Element.prototype.matches = 19 | // @ts-ignore 20 | Element.prototype.msMatchesSelector || 21 | Element.prototype.webkitMatchesSelector; 22 | } 23 | 24 | if (!Element.prototype.closest) { 25 | // eslint-disable-next-line func-names 26 | Element.prototype.closest = function (s: string) { 27 | // eslint-disable-next-line @typescript-eslint/no-this-alias 28 | let el: Element | null = this; 29 | 30 | do { 31 | if (el.matches(s)) return el; 32 | el = el.parentElement; 33 | } while (el !== null && el.nodeType === 1); 34 | return null; 35 | }; 36 | } 37 | 38 | // TODO: Create custom type for any types 39 | /* eslint-disable @typescript-eslint/no-explicit-any */ 40 | interface Props { 41 | url: string; 42 | key: string; 43 | version?: string; 44 | input?: string; 45 | results?: string; 46 | button?: string; 47 | defaultValue?: string; 48 | template?: any; 49 | trigger?: string; 50 | options?: any; 51 | api?: any; 52 | on?: any; 53 | } 54 | 55 | interface ObjectOfStrings { 56 | [propName: string]: string; 57 | } 58 | 59 | export default class GhostSearch implements Props { 60 | url: string; 61 | key: string; 62 | version?: string; 63 | input?: string; 64 | results?: string; 65 | button?: string; 66 | defaultValue?: string; 67 | template?: any; 68 | trigger?: string; 69 | options?: any; 70 | api?: any; 71 | on?: any; 72 | private check = false; 73 | 74 | constructor(props?: Props) { 75 | this.url = (props && props.url) || ''; 76 | this.key = (props && props.key) || ''; 77 | this.version = (props && props.version) || 'v3'; 78 | this.input = (props && props.input) || '#ghost-search-field'; 79 | this.results = (props && props.results) || '#ghost-search-results'; 80 | this.button = (props && props.button) || ''; 81 | this.defaultValue = (props && props.defaultValue) || ''; 82 | this.template = 83 | (props && props.template) || 84 | ((result: { slug: string; title: string }): string => { 85 | const url = [ 86 | window.location.protocol, 87 | '//', 88 | window.location.host, 89 | ].join(''); 90 | return `
  • ${result.title}
  • `; 91 | }); 92 | this.trigger = (props && props.trigger) || 'focus'; 93 | this.options = (props && props.options) || { 94 | keys: ['title'], 95 | limit: 10, 96 | threshold: -3500, 97 | allowTypo: false, 98 | }; 99 | this.api = (props && props.api) || { 100 | resource: 'posts', 101 | parameters: { 102 | limit: 'all', 103 | fields: ['title', 'slug', 'created_at'], 104 | filter: '', 105 | include: 'authors', 106 | order: '', 107 | formats: '', 108 | page: '', 109 | }, 110 | }; 111 | this.on = (props && props.on) || { 112 | // eslint-disable-next-line @typescript-eslint/no-empty-function 113 | beforeDisplay: () => {}, 114 | // eslint-disable-next-line @typescript-eslint/no-empty-function 115 | afterDisplay: () => {}, 116 | // eslint-disable-next-line @typescript-eslint/no-empty-function 117 | beforeFetch: () => {}, 118 | // eslint-disable-next-line @typescript-eslint/no-empty-function 119 | afterFetch: () => {}, 120 | }; 121 | this.init(); 122 | } 123 | 124 | fetch = () => { 125 | this.on.beforeFetch(); 126 | 127 | const ghostAPI = new GhostContentAPI({ 128 | url: this.url, 129 | key: this.key, 130 | version: this.version, 131 | }); 132 | 133 | const browse: ObjectOfStrings = {}; 134 | const { parameters } = this.api; 135 | 136 | Object.keys(parameters).forEach((key: string) => { 137 | if (parameters[key] !== '') browse[key] = parameters[key]; 138 | }); 139 | 140 | ghostAPI[this.api.resource] 141 | .browse(browse) 142 | .then((data: any) => { 143 | this.search(data); 144 | }) 145 | .catch((err: string) => { 146 | console.error(err); 147 | }); 148 | }; 149 | 150 | createElementFromHTML = (htmlString: string) => { 151 | const div: HTMLDivElement = document.createElement('div'); 152 | div.innerHTML = htmlString.trim(); 153 | return div.firstChild; 154 | }; 155 | 156 | // TODO: create an interface 157 | displayResults = (data: any) => { 158 | if (!this.results) return; 159 | const inputElm: HTMLInputElement | null = document.querySelector( 160 | this.input! 161 | ); 162 | 163 | const resultsElm: Element | null = document.querySelector(this.results); 164 | 165 | if (resultsElm) { 166 | while (resultsElm.firstChild) { 167 | resultsElm.removeChild(resultsElm.firstChild); 168 | } 169 | } 170 | 171 | let inputValue: string | null; 172 | if (this.defaultValue) { 173 | inputValue = this.defaultValue; 174 | } else if (inputElm) { 175 | inputValue = inputElm.value; 176 | } else { 177 | inputValue = null; 178 | } 179 | 180 | const searchContainer: HTMLDivElement | null = document.querySelector( 181 | '.search-container' 182 | ); 183 | if (searchContainer) searchContainer.classList.add('dirty'); 184 | 185 | const results = fuzzysort.go(inputValue, data, { 186 | keys: this.options.keys, 187 | limit: this.options.limit, 188 | allowTypo: this.options.allowTypo, 189 | threshold: this.options.threshold, 190 | }); 191 | 192 | if (resultsElm) { 193 | Object.keys(results).forEach((key) => { 194 | if (key < results.length) { 195 | resultsElm.appendChild( 196 | this.createElementFromHTML( 197 | this.template(results[key].obj) 198 | )! 199 | ); 200 | } 201 | }); 202 | } 203 | 204 | this.on.afterDisplay(results); 205 | this.defaultValue = ''; 206 | }; 207 | 208 | // TODO: create an interface for data 209 | search = (data: any) => { 210 | this.on.afterFetch(data); 211 | this.check = true; 212 | 213 | const inputElm: HTMLInputElement | null = document.querySelector( 214 | this.input! 215 | ); 216 | 217 | if (this.defaultValue !== '') { 218 | this.on.beforeDisplay(); 219 | this.displayResults(data); 220 | } 221 | 222 | if (this.button) { 223 | const button: HTMLInputElement | null = document.querySelector( 224 | this.button 225 | ); 226 | if ( 227 | button && 228 | button.tagName === 'INPUT' && 229 | button.type === 'submit' 230 | ) { 231 | button.closest('form')!.addEventListener('submit', (e) => { 232 | e.preventDefault(); 233 | }); 234 | 235 | button.addEventListener('click', (e) => { 236 | e.preventDefault(); 237 | this.on.beforeDisplay(); 238 | this.displayResults(data); 239 | }); 240 | } 241 | } else if (inputElm) { 242 | inputElm.addEventListener('keyup', () => { 243 | this.on.beforeDisplay(); 244 | this.displayResults(data); 245 | }); 246 | } 247 | }; 248 | 249 | checkArgs = () => { 250 | const resultsElm: HTMLInputElement | null = document.querySelector( 251 | this.results! 252 | ); 253 | 254 | const inputElm: HTMLInputElement | null = document.querySelector( 255 | this.input! 256 | ); 257 | 258 | if (!document.body.contains(inputElm)) { 259 | console.log('Input not found.'); 260 | return false; 261 | } 262 | if (!document.body.contains(resultsElm)) { 263 | console.log('Results not found.'); 264 | return false; 265 | } 266 | if (this.button && !document.querySelectorAll(this.button).length) { 267 | console.log('Button not found.'); 268 | return false; 269 | } 270 | if (this.url === '') { 271 | console.log( 272 | 'Content API Client Library url missing. Please set the url. Must not end in a trailing slash.' 273 | ); 274 | return false; 275 | } 276 | if (this.key === '') { 277 | console.log( 278 | 'Content API Client Library key missing. Please set the key. Hex string copied from the "Integrations" screen in Ghost Admin.' 279 | ); 280 | return false; 281 | } 282 | return true; 283 | }; 284 | 285 | validate = () => { 286 | return this.checkArgs(); 287 | }; 288 | 289 | // TODO reformat these functions 290 | public openSearch = () => { 291 | const search: HTMLDivElement | null = document.querySelector('#search'); 292 | const bodyElm: HTMLBodyElement | null = document.querySelector('body'); 293 | const inputElm: HTMLInputElement | null = document.querySelector( 294 | this.input! 295 | ); 296 | 297 | if (search) search.style.display = 'block'; 298 | bodyElm!.classList.add('noscroll'); 299 | inputElm!.focus(); 300 | }; 301 | 302 | public closeSearch = () => { 303 | const search: HTMLElement | null = document.querySelector('#search'); 304 | const resultsElm: HTMLElement | null = document.querySelector( 305 | '#ghost-search-results' 306 | ); 307 | 308 | if ( 309 | !search || 310 | search.style.display === 'none' || 311 | search.style.display === '' 312 | ) { 313 | return; 314 | } 315 | 316 | search.style.display = 'none'; 317 | document!.querySelector('body')!.classList.remove('noscroll'); 318 | document!.querySelector('.search-container')!.classList.remove('dirty'); 319 | const inputElm: HTMLInputElement | null = document.querySelector( 320 | this.input! 321 | ); 322 | 323 | inputElm!.value = ''; 324 | 325 | if (resultsElm) { 326 | while (resultsElm.firstChild) { 327 | resultsElm.removeChild(resultsElm.firstChild); 328 | } 329 | } 330 | }; 331 | 332 | init = () => { 333 | const inputElm: HTMLInputElement | null = document.querySelector( 334 | this.input! 335 | ); 336 | if (!this.validate()) { 337 | return; 338 | } 339 | 340 | if (this.defaultValue && inputElm) { 341 | inputElm.value = this.defaultValue; 342 | window.onload = () => { 343 | if (!this.check) this.fetch(); 344 | }; 345 | } 346 | 347 | if (inputElm && this.trigger === 'focus') { 348 | inputElm.addEventListener('focus', () => { 349 | if (!this.check) this.fetch(); 350 | }); 351 | } else if (this.trigger === 'load') { 352 | window.onload = () => { 353 | if (!this.check) this.fetch(); 354 | }; 355 | } 356 | 357 | document.body.addEventListener('keydown', (e) => { 358 | if (e.defaultPrevented) { 359 | return; 360 | } 361 | 362 | const key = e.key || e.keyCode; 363 | if (key === 'Escape' || key === 'Esc' || key === 27) { 364 | this.closeSearch(); 365 | } 366 | }); 367 | }; 368 | } 369 | -------------------------------------------------------------------------------- /src/styles/components/ads.scss: -------------------------------------------------------------------------------- 1 | .ad-container { 2 | display: flex; 3 | align-items: center; 4 | justify-content: center; 5 | } 6 | 7 | .horizontal-ad { 8 | display: inline-block; 9 | width: 300px; 10 | height: 300px; 11 | 12 | @include breakpoint(medium) { 13 | width: 468px; 14 | height: 60px; 15 | } 16 | @include breakpoint(large) { 17 | width: 728px; 18 | height: 90px; 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /src/styles/components/error.scss: -------------------------------------------------------------------------------- 1 | .error-template { 2 | .grid-container { 3 | margin-bottom: 50px; 4 | } 5 | .error-code { 6 | font-size: rem-calc(90); 7 | } 8 | .error-description { 9 | font-size: rem-calc(40); 10 | } 11 | } -------------------------------------------------------------------------------- /src/styles/components/fonts.scss: -------------------------------------------------------------------------------- 1 | /* Fonts */ 2 | 3 | /* Roboto */ 4 | $roboto-font-path: '~roboto-fontface/fonts'; 5 | @import "~roboto-fontface/css/roboto/sass/roboto-fontface-regular"; 6 | @import "~roboto-fontface/css/roboto/sass/roboto-fontface-medium"; 7 | @import "~roboto-fontface/css/roboto/sass/roboto-fontface-regular-italic"; 8 | 9 | /* Font awesome */ 10 | $fa-font-path: '~@fortawesome/fontawesome-free/webfonts'; 11 | @import "~@fortawesome/fontawesome-free/scss/fontawesome"; 12 | @import "~@fortawesome/fontawesome-free/scss/regular"; 13 | @import "~@fortawesome/fontawesome-free/scss/solid"; 14 | @import "~@fortawesome/fontawesome-free/scss/brands"; 15 | 16 | -------------------------------------------------------------------------------- /src/styles/components/footer.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | // --------- 3 | $footer-background: #1a2940; 4 | $footer-font-color: #91a2bd; 5 | 6 | .site-footer { 7 | background: $footer-background; 8 | padding: 3rem 0; 9 | color: $footer-font-color; 10 | 11 | a { 12 | color: $footer-font-color; 13 | 14 | &:focus, 15 | &:hover { 16 | color: $white; 17 | } 18 | } 19 | } 20 | 21 | // Widgets 22 | .widget { 23 | margin-bottom: 2rem; 24 | 25 | .widget-title { 26 | color: #fff; 27 | font-weight: 600; 28 | text-transform: uppercase; 29 | } 30 | } 31 | 32 | // Copyright 33 | // --------- 34 | 35 | .footer-bottom { 36 | padding-top: 3rem; 37 | border-top: 1px solid lighten($footer-background, 10%); 38 | } 39 | 40 | .copyright { 41 | text-align: center; 42 | } 43 | 44 | // Recent Post 45 | // ----------- 46 | 47 | .recent-post-img { 48 | width: 80px; 49 | height: 80px; 50 | background: $footer-font-color; 51 | border-color: $footer-font-color; 52 | transition: all 0.6s ease; 53 | 54 | &:focus, 55 | &:hover { 56 | border-color: $white; 57 | } 58 | } 59 | .recent-post-ct { 60 | border-bottom: 1px solid lighten($footer-background, 10%); 61 | &:last-child { 62 | border-bottom: none; 63 | } 64 | } 65 | .recent-post-title { 66 | font-weight: 500; 67 | } 68 | .recent-post-date { 69 | font-size: rem-calc(13); 70 | .fa-clock { 71 | margin-right: rem-calc(5); 72 | } 73 | } 74 | 75 | .site-footer .media-object-section { 76 | display: flex; 77 | justify-content: center; 78 | flex-direction: column; 79 | flex-flow: wrap; 80 | } 81 | 82 | 83 | // Social networks 84 | // --------------- 85 | 86 | .social-networks { 87 | li { 88 | box-flex: 1; 89 | flex: 1 1 0; 90 | } 91 | } 92 | 93 | // Tags 94 | // ---- 95 | 96 | .site-footer .tags { 97 | li { 98 | margin: 0 7px 10px 0; 99 | a { 100 | font-size: rem-calc(13); 101 | color: $footer-font-color; 102 | border: 1px solid lighten($footer-background, 20%); 103 | 104 | &:hover, 105 | &:focus { 106 | color: $footer-background; 107 | background: $footer-font-color; 108 | } 109 | } 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/styles/components/general.scss: -------------------------------------------------------------------------------- 1 | body .hidden { 2 | display: none; 3 | } 4 | body .no-margin { 5 | margin: 0; 6 | } 7 | 8 | // Links 9 | // ----- 10 | a { 11 | transition: color 0.25s ease-in-out; 12 | 13 | &:focus { 14 | outline: 0; 15 | } 16 | } 17 | .post-card-excerpt, 18 | .post-content { 19 | a { 20 | @include word-wrap; 21 | } 22 | } 23 | 24 | // Buttons 25 | // ------- 26 | button:focus { 27 | outline:0; 28 | } 29 | 30 | 31 | // List 32 | // ---- 33 | .horizontal-list { 34 | display: flex; 35 | padding: 0; 36 | margin: 0; 37 | list-style: none; 38 | position: relative; 39 | flex-wrap: wrap; 40 | flex-direction: row; 41 | box-orient: horizontal; 42 | } 43 | 44 | // Classes 45 | // ------- 46 | .align-center { 47 | text-align: center; 48 | } 49 | .noscroll { 50 | overflow: hidden; 51 | } 52 | -------------------------------------------------------------------------------- /src/styles/components/header.scss: -------------------------------------------------------------------------------- 1 | // Variables 2 | // --------- 3 | $header-background: #1a2940; 4 | $header-font-color: #91a2bd; 5 | 6 | .site-header { 7 | display: flex; 8 | position: relative; 9 | flex-flow: column nowrap; 10 | } 11 | 12 | .site-header-content { 13 | position: relative; 14 | overflow: hidden; 15 | color: $header-font-color; 16 | } 17 | 18 | .toggle-responsive-btn { 19 | display: none; 20 | } 21 | 22 | .cover-image, 23 | .header-overlay, 24 | .site-header-bg { 25 | display: block; 26 | position: absolute; 27 | width: 100%; 28 | height: 100%; 29 | top: 0; 30 | left: 0; 31 | overflow: hidden; 32 | } 33 | 34 | .site-header-bg { 35 | min-height: 400px; 36 | transition: opacity 0.3s ease; 37 | } 38 | 39 | .header-overlay { 40 | background: rgba($header-background, 0.90); 41 | } 42 | 43 | .particles-js-canvas-el { 44 | position: absolute; 45 | top: 0; 46 | left: 0; 47 | } 48 | 49 | .header-title { 50 | position: relative; 51 | width: 100%; 52 | min-height: 100px; 53 | user-select: none; 54 | pointer-events: none; 55 | 56 | .site-logo { 57 | min-height: 50px; 58 | max-height: 100px; 59 | } 60 | } 61 | .header-title-inner { 62 | text-align: center; 63 | justify-content: center; 64 | align-content: center; 65 | padding: rem-calc(90) 0 rem-calc(140) 0; 66 | } 67 | .author-template .header-title-inner { 68 | flex-direction: column; // for social media author page 69 | } 70 | .site-title { 71 | margin: 0; 72 | color: $white; 73 | font-size: 3.5rem; 74 | font-weight: bold; 75 | } 76 | .social-author { 77 | text-align: center; 78 | 79 | .horizontal-list { 80 | display: inline-flex; 81 | 82 | > li { 83 | margin-right: rem-calc(15); 84 | 85 | &:last-child { 86 | margin-right: 0; 87 | } 88 | 89 | 90 | a { 91 | pointer-events: auto; 92 | color: $header-font-color; 93 | 94 | &:focus, 95 | &:hover { 96 | color: $white; 97 | } 98 | } 99 | } 100 | } 101 | } 102 | -------------------------------------------------------------------------------- /src/styles/components/koenig.scss: -------------------------------------------------------------------------------- 1 | 2 | .post-content { 3 | display: flex; 4 | flex-direction: column; 5 | } 6 | 7 | .post-full-content .kg-image { 8 | max-width: 100%; 9 | } 10 | 11 | /* Preventing full-width image overlap with post image. */ 12 | 13 | .post-full-image + .post-full-content .kg-content *:first-child .kg-image { 14 | width: 100%; 15 | } 16 | 17 | .post-full-content { 18 | .kg-width-wide .kg-image { 19 | max-width: 1040px; 20 | } 21 | 22 | .kg-width-full .kg-image { 23 | max-width: 100vw; 24 | } 25 | 26 | figure { 27 | margin: 0.8em 0 2.3em; 28 | } 29 | 30 | h1 + figure, h2 + figure, h3 + figure, h4 + figure { 31 | margin-top: 2em; 32 | } 33 | 34 | figure img { 35 | margin: 0; 36 | } 37 | 38 | figcaption { 39 | margin: 1.0em 0 0; 40 | color: color(var(--midgrey) l(-10%)); 41 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif; 42 | font-size: 75%; 43 | line-height: 1.5em; 44 | text-align: center; 45 | } 46 | } 47 | 48 | .kg-width-full figcaption { 49 | padding: 0 1.5em; 50 | } 51 | 52 | .kg-embed-card { 53 | flex-direction: column; 54 | align-items: center; 55 | width: 100%; 56 | 57 | .fluid-width-video-wrapper { 58 | margin: 0; 59 | } 60 | } 61 | 62 | @media (max-width: 1040px) { 63 | .post-full-content .kg-width-full .kg-image { 64 | width: 100vw; 65 | } 66 | } 67 | 68 | .kg-gallery-container { 69 | display: flex; 70 | flex-direction: column; 71 | max-width: 1040px; 72 | width: 100vw; 73 | } 74 | 75 | .kg-gallery-row { 76 | display: flex; 77 | flex-direction: row; 78 | justify-content: center; 79 | } 80 | 81 | .kg-gallery-image img { 82 | display: block; 83 | margin: 0; 84 | width: 100%; 85 | height: 100%; 86 | } 87 | 88 | .kg-gallery-row:not(:first-of-type) { 89 | margin: 0.75em 0 0 0; 90 | } 91 | 92 | .kg-gallery-image:not(:first-of-type) { 93 | margin: 0 0 0 0.75em; 94 | } 95 | 96 | .kg-gallery-card + { 97 | .kg-image-card.kg-width-wide, .kg-gallery-card { 98 | margin: -2.25em 0 3em; 99 | } 100 | } 101 | 102 | .kg-image-card.kg-width-wide + { 103 | .kg-gallery-card, .kg-image-card.kg-width-wide { 104 | margin: -2.25em 0 3em; 105 | } 106 | } 107 | 108 | /* keep existing
     styles for code cards with captions */
    109 | 
    110 | .kg-code-card {
    111 |   width: 100%;
    112 | 
    113 |   pre {
    114 |     margin: 0;
    115 |   }
    116 | }
    117 | 
    118 | .kg-bookmark-card {
    119 |   width: 100%;
    120 |   background: var(--white);
    121 | }
    122 | 
    123 | .kg-card + .kg-bookmark-card {
    124 |   margin-top: 0;
    125 | }
    126 | 
    127 | .post-full-content .kg-bookmark-container {
    128 |   display: flex;
    129 |   min-height: 148px;
    130 |   color: var(--darkgrey);
    131 |   font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto, Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
    132 |   text-decoration: none;
    133 |   border-radius: 3px;
    134 |   box-shadow: 0 2px 5px -1px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.09);
    135 | 
    136 |   &:hover {
    137 |     color: var(--darkgrey);
    138 |     text-decoration: none;
    139 |     box-shadow: 0 2px 5px -1px rgba(0, 0, 0, 0.15), 0 0 1px rgba(0, 0, 0, 0.09);
    140 |   }
    141 | }
    142 | 
    143 | .kg-bookmark-content {
    144 |   flex-grow: 1;
    145 |   display: flex;
    146 |   flex-direction: column;
    147 |   justify-content: flex-start;
    148 |   align-items: flex-start;
    149 |   padding: 20px;
    150 | }
    151 | 
    152 | .kg-bookmark-title {
    153 |   color: color(var(--midgrey) l(-30%));
    154 |   font-size: 1.6rem;
    155 |   line-height: 1.5em;
    156 |   font-weight: 600;
    157 |   transition: color 0.2s ease-in-out;
    158 | }
    159 | 
    160 | .post-full-content .kg-bookmark-container:hover .kg-bookmark-title {
    161 |   color: var(--blue);
    162 | }
    163 | 
    164 | .kg-bookmark-description {
    165 |   display: -webkit-box;
    166 |   overflow-y: hidden;
    167 |   margin-top: 12px;
    168 |   max-height: 48px;
    169 |   color: color(var(--midgrey) l(-10%));
    170 |   font-size: 1.5rem;
    171 |   line-height: 1.5em;
    172 |   font-weight: 400;
    173 |   -webkit-line-clamp: 2;
    174 |   -webkit-box-orient: vertical;
    175 | }
    176 | 
    177 | .kg-bookmark-thumbnail {
    178 |   position: relative;
    179 |   min-width: 33%;
    180 |   max-height: 100%;
    181 | 
    182 |   img {
    183 |     position: absolute;
    184 |     top: 0;
    185 |     left: 0;
    186 |     width: 100%;
    187 |     height: 100%;
    188 |     border-radius: 0 3px 3px 0;
    189 |     object-fit: cover;
    190 |   }
    191 | }
    192 | 
    193 | .kg-bookmark-metadata {
    194 |   display: flex;
    195 |   flex-wrap: wrap;
    196 |   align-items: center;
    197 |   margin-top: 14px;
    198 |   color: color(var(--midgrey) l(-10%));
    199 |   font-size: 1.5rem;
    200 |   font-weight: 400;
    201 | }
    202 | 
    203 | .post-full-content .kg-bookmark-icon {
    204 |   margin-right: 8px;
    205 |   width: 22px;
    206 |   height: 22px;
    207 | }
    208 | 
    209 | .kg-bookmark-author {
    210 |   line-height: 1.5em;
    211 | 
    212 |   &:after {
    213 |     content: "•";
    214 |     margin: 0 6px;
    215 |   }
    216 | }
    217 | 
    218 | .kg-bookmark-publisher {
    219 |   overflow: hidden;
    220 |   max-width: 240px;
    221 |   line-height: 1.5em;
    222 |   text-overflow: ellipsis;
    223 |   white-space: nowrap;
    224 | }
    225 | 
    226 | @media (max-width: 800px) {
    227 |   .post-full-content {
    228 |     figure {
    229 |       margin: 0.2em 0 1.3em;
    230 |     }
    231 | 
    232 |     h1 + figure, h2 + figure, h3 + figure, h4 + figure {
    233 |       margin-top: 0.9em;
    234 |     }
    235 |   }
    236 | }
    237 | 
    238 | @media (max-width: 500px) {
    239 |   .post-full-content {
    240 |     .kg-width-wide, .kg-width-full {
    241 |       margin-right: -5vw;
    242 |       margin-left: -5vw;
    243 |     }
    244 | 
    245 |     figcaption {
    246 |       margin-bottom: 0.4em;
    247 |     }
    248 | 
    249 |     .kg-bookmark-container {
    250 |       flex-direction: column;
    251 |     }
    252 |   }
    253 | 
    254 |   .kg-bookmark-title, .kg-bookmark-description, .kg-bookmark-metadata {
    255 |     font-size: 1.4rem;
    256 |     line-height: 1.5em;
    257 |   }
    258 | 
    259 |   .post-full-content .kg-bookmark-icon {
    260 |     width: 18px;
    261 |     height: 18px;
    262 |   }
    263 | 
    264 |   .kg-bookmark-thumbnail {
    265 |     order: 1;
    266 |     min-height: 160px;
    267 |     width: 100%;
    268 | 
    269 |     img {
    270 |       border-radius: 3px 3px 0 0;
    271 |     }
    272 |   }
    273 | 
    274 |   .kg-bookmark-content {
    275 |     order: 2;
    276 |   }
    277 | }
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/lightbox.scss:
    --------------------------------------------------------------------------------
     1 | // Fancybox
     2 | // --------
     3 | 
     4 | $lg-path-fonts: '~lightgallery.js/src/fonts';
     5 | $lg-path-images: '~lightgallery.js/src/img';
     6 | 
     7 | @import '~lightgallery.js/src/sass/lightgallery';
     8 | 
     9 | .lightbox {
    10 |   display: inline-block;
    11 |   max-width: 100%;
    12 | 
    13 |   img {
    14 |     flex-shrink: 0;
    15 |     cursor: pointer;
    16 |     cursor: -moz-zoom-in;
    17 |     cursor: zoom-in;
    18 |   }
    19 | }
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/main-content.scss:
    --------------------------------------------------------------------------------
     1 | .main-content {
     2 |   padding: 3rem 0 3rem 0;
     3 |   background: #f0f0f0;
     4 | }
     5 | 
     6 | .post-template .main-content,
     7 | .page-template .main-content {
     8 |   background: #fff;
     9 | }
    10 | 
    11 | .post-template .main-content {
    12 |   padding: 3rem 0 0 0;
    13 | }
    14 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/mixins.scss:
    --------------------------------------------------------------------------------
     1 | %body-color-anchor {
     2 |   color: $body-font-color;
     3 |   &:hover,
     4 |   &:focus {
     5 |     color: $anchor-color-hover;
     6 |   }
     7 | }
     8 | @mixin word-wrap() {
     9 |   overflow-wrap: break-word;
    10 |   word-wrap: break-word;
    11 |   -ms-word-break: break-all;
    12 |   word-break: break-all;
    13 |   word-break: break-word;
    14 |   -ms-hyphens: auto;
    15 |   -moz-hyphens: auto;
    16 |   -webkit-hyphens: auto;
    17 |   hyphens: auto;
    18 | }
    19 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/pagination.scss:
    --------------------------------------------------------------------------------
      1 | // Pagination
      2 | // ---------
      3 | 
      4 | .pagination-ct {
      5 |    align-items: center;
      6 |    justify-content: center;
      7 | }
      8 | 
      9 | %arrow-prev {
     10 |   &:after {
     11 |     content: "";
     12 |     position: absolute;
     13 |     top: 0;
     14 |     left: -22px;
     15 |     width: 0;
     16 |     height: 0;
     17 |     border-top: 22px solid transparent;
     18 |     border-bottom: 22px solid transparent;
     19 |     border-right: 22px solid #fff;
     20 |     transition: all 0.2s linear;
     21 |   }
     22 | }
     23 | 
     24 | %arrow-next {
     25 |   &:after {
     26 |     content: "";
     27 |     position: absolute;
     28 |     top: 0;
     29 |     right: -22px;
     30 |     width: 0;
     31 |     height: 0;
     32 |     border-top: 22px solid transparent;
     33 |     border-bottom: 22px solid transparent;
     34 |     border-left: 22px solid #fff;
     35 |     transition: all 0.2s linear;
     36 |   }
     37 | }
     38 | .pagination {
     39 |   display: inline-flex;
     40 |   margin: 2rem 0 2rem 0;
     41 | 
     42 |   a,
     43 |   button,
     44 |   .current,
     45 |   .disabled {
     46 |       padding: rem-calc(9 15);
     47 |   }
     48 | 
     49 |   li {
     50 |     position: relative;
     51 |     margin-right: - rem-calc(2);
     52 |     font-size: rem-calc(16);
     53 | 
     54 |     a {
     55 |       display: inline-block;
     56 |       position: relative;
     57 |       border: 1px solid #ddd;
     58 |       background: $white;
     59 |       transition: all 0.2s linear;
     60 |     }
     61 | 
     62 |     &:not(:last-child) {
     63 |       border-right: 1px solid $medium-gray;
     64 |     }
     65 |     &:not(:first-child) {
     66 |       a {
     67 |         margin-left: -1px;
     68 |       }
     69 |     }
     70 |     &.pagination-previous {
     71 |       border-top-left-radius: 2px;
     72 |       border-bottom-left-radius: 2px;
     73 |     }
     74 |     &.pagination-next {
     75 |       border-top-right-radius: 2px;
     76 |       border-bottom-right-radius: 2px;
     77 |     }
     78 |     &.current {
     79 |       z-index: 2;
     80 |     }
     81 |     &.ellipsis {
     82 |       padding: rem-calc(9 5);
     83 |       background: $white;
     84 |       border: 1px solid #ddd;
     85 |     }
     86 |   }
     87 | 
     88 |   // Previous arrow
     89 |   .pagination-previous {
     90 |     a,
     91 |     &.disabled {
     92 |       &:before {
     93 |         content: "";
     94 |       }
     95 |       margin-left: 22px;
     96 |       @extend %arrow-prev;
     97 |     }
     98 |     a:hover {
     99 |       &:after {
    100 |         border-right: 22px solid $pagination-item-background-hover;
    101 |       }
    102 |     }
    103 |     &.disabled {
    104 |       background: $white;
    105 |     }
    106 |   }
    107 | 
    108 |   // Next arrow
    109 |   .pagination-next {
    110 |     a,
    111 |     &.disabled {
    112 |       &:before {
    113 |         content: "";
    114 |       }
    115 |       margin-right: 22px;
    116 |       @extend %arrow-next;
    117 |     }
    118 | 
    119 |     a:hover {
    120 |       &:after {
    121 |         border-left: 22px solid $pagination-item-background-hover;
    122 |       }
    123 |     }
    124 |     &.disabled {
    125 |       background: $white;
    126 |     }
    127 |   }
    128 | }
    129 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/placeholder.scss:
    --------------------------------------------------------------------------------
     1 | %animated-background {
     2 |   position: absolute;
     3 |   background: #dcdcdc;
     4 |   background: linear-gradient(to right, #dcdcdc 8%, #d1d1d1 18%, #dcdcdc 33%);
     5 |   background-size: 800px 104px;
     6 |   z-index: 5;
     7 |   animation-duration: 1.25s;
     8 |   animation-fill-mode: forwards;
     9 |   animation-iteration-count: infinite;
    10 |   animation-name: placeHolderShimmer;
    11 |   animation-timing-function: linear;
    12 | }
    13 | 
    14 | .placeholder {
    15 |   @extend %animated-background;
    16 | }
    17 | 
    18 | .placeholder-featured-image {
    19 |   width: 100%;
    20 |   height: 100%;
    21 |   min-height: 220px;
    22 |   top: 0;
    23 |   left: 0;
    24 | }
    25 | 
    26 | .placeholder-content-ct {
    27 |   position: absolute;
    28 |   width: 100%;
    29 |   height: 100%;
    30 |   padding: .75rem;
    31 |   min-height: 180px;
    32 |   top: 0;
    33 |   left: 0;
    34 |   background: #fff;
    35 |   z-index: 5;
    36 | }
    37 | 
    38 | .placeholder-content-inner {
    39 |   position: relative;
    40 |   width: 100%;
    41 |   height: 100%;
    42 | }
    43 | 
    44 | .placeholder-title {
    45 |   @extend %animated-background;
    46 |   width: 80%;
    47 |   height: rem-calc(25);
    48 | }
    49 | 
    50 | .placeholder-text {
    51 |   @extend %animated-background;
    52 |   width: 100%;
    53 |   height: rem-calc(17);
    54 | }
    55 | 
    56 | .placeholder-text1 {
    57 |   top: rem-calc(40);
    58 | }
    59 | 
    60 | .placeholder-text2 {
    61 |   top: rem-calc(70);
    62 | }
    63 | 
    64 | .placeholder-text3 {
    65 |   width: 40%;
    66 |   top: rem-calc(100);
    67 | }
    68 | 
    69 | .placeholder-author {
    70 |   @extend %animated-background;
    71 |   width: 80px;
    72 |   height: rem-calc(15);
    73 |   bottom: 0;
    74 |   left: 0;
    75 | }
    76 | 
    77 | .placeholder-date {
    78 |   @extend %animated-background;
    79 |   width: 80px;
    80 |   height: rem-calc(15);
    81 |   bottom: 0;
    82 |   right: 0;
    83 | }
    84 | 
    85 | // Animation
    86 | @keyframes placeHolderShimmer {
    87 |   0% {
    88 |     background-position: -468px 0
    89 |   }
    90 |   100% {
    91 |     background-position: 468px 0
    92 |   }
    93 | }
    94 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/post-feed.scss:
    --------------------------------------------------------------------------------
      1 | .read-next {
      2 |   .post-card {
      3 |     display: flex;
      4 |     position: relative;
      5 |     margin: 0 0 2rem 0;
      6 |     flex: 1 1 250px;
      7 |     flex-direction: column;
      8 | 
      9 |     @include breakpoint(medium) {
     10 |       &:first-child {
     11 |         margin: 0 2rem 2rem 0;
     12 |       }
     13 |       &:last-child {
     14 |         margin: 0 0 2rem 0;
     15 |       }
     16 |     }
     17 |     @include breakpoint(large) {
     18 |       margin: 0 2rem 2rem 0;
     19 | 
     20 |       &:last-child {
     21 |         margin: 0 0 2rem 0;
     22 |       }
     23 |     }
     24 |   }
     25 |   .post-card-content,
     26 |   .post-card-inner {
     27 |     display: flex;
     28 |     flex-grow: 1;
     29 |     flex-direction: column;
     30 |     justify-content: space-between;
     31 |   }
     32 | 
     33 | 
     34 |   .post-card-featured-image {
     35 |     &:hover,
     36 |     &:focus {
     37 |       .post-card-image {
     38 |         img {
     39 |           transform: matrix(1.2,0,0,1.2,0,0) translateY(-50%);
     40 |         }
     41 |       }
     42 |     }
     43 |     .tags {
     44 |       max-height: calc(100% - 10px);
     45 |     }
     46 |   }
     47 |   .post-card-image {
     48 |     height: 135px;
     49 |     img {
     50 |       position: absolute;
     51 |       top: 50%;
     52 |       transform: translateY(-50%);
     53 |     }
     54 |   }
     55 | }
     56 | 
     57 | .read-next-card {
     58 |   color: $white;
     59 |   border-radius: 5px;
     60 |   overflow: hidden;
     61 | 
     62 |   &:before {
     63 |     content: "";
     64 |     position: absolute;
     65 |     top: 0;
     66 |     right: 0;
     67 |     bottom: 0;
     68 |     left: 0;
     69 |     display: block;
     70 |     background: linear-gradient(135deg, rgba(26,41,64,.95), rgba(26,41,64,.85));
     71 |   }
     72 |   .post-card-inner {
     73 |     background: none;
     74 |   }
     75 |   a {
     76 |     color: $white;
     77 | 
     78 |     &:hover,
     79 |     &:focus {
     80 |       color: $white;
     81 |     }
     82 |   }
     83 | }
     84 | 
     85 | .related-articles {
     86 |   display: flex;
     87 |   flex-flow: row wrap;
     88 | }
     89 | 
     90 | .read-next-card-header-title {
     91 |   text-align: center;
     92 |   text-transform: uppercase;
     93 |   font-weight: 500;
     94 | 
     95 |   i {
     96 |     font-size: 70%;
     97 |   }
     98 | }
     99 | .read-next-card-content {
    100 |   ul {
    101 |     margin: 0;
    102 |     list-style: none;
    103 |      > li {
    104 |        a {
    105 |          display: block;
    106 |          max-width: 86%;
    107 |          margin-left: 7%;
    108 |          padding: rem-calc(15 0);
    109 |          text-align: center;
    110 |          font-weight: 500;
    111 |          border-bottom: 1px solid hsla(0,0%,100%,.3);
    112 |          white-space: nowrap;
    113 |          overflow: hidden;
    114 |          text-overflow: ellipsis;
    115 |        }
    116 |      }
    117 |   }
    118 | }
    119 | 
    120 | .read-next-card-footer {
    121 |   position: relative;
    122 |   margin: rem-calc(15 0 3);
    123 |   text-align: center;
    124 | }
    125 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/posts-list.scss:
    --------------------------------------------------------------------------------
      1 | .post-card {
      2 |   a {
      3 |      @extend %body-color-anchor;
      4 |   }
      5 | }
      6 | .post-card-content {
      7 |   position: relative;
      8 |   padding: 0.75rem;
      9 | }
     10 | .post-card-inner {
     11 |   position: relative;
     12 |   border-radius: 5px;
     13 |   overflow: hidden;
     14 | }
     15 | .post-card-meta {
     16 |   display: flex;
     17 |   flex-flow: row wrap;
     18 |   justify-content: space-between;
     19 |   align-items: flex-end;
     20 |   font-size: rem-calc(13);
     21 | 
     22 |   > * {
     23 |     flex: 0 0 auto;
     24 |   }
     25 | }
     26 | .post-card-inner {
     27 |   background: $white;
     28 | }
     29 | .post-card-featured-image {
     30 |   position: relative;
     31 |   &:hover,
     32 |   &:focus {
     33 |     .post-card-image {
     34 |       img {
     35 |         transform: matrix(1.2,0,0,1.2,0,0)
     36 |       }
     37 |       &:before {
     38 |         opacity: 1;
     39 |       }
     40 |     }
     41 |   }
     42 | }
     43 | .post-card-image {
     44 |   position: relative;
     45 |   overflow: hidden;
     46 |   width: 100%;
     47 | 
     48 |   img {
     49 |     display: block;
     50 |     width: 100%;
     51 |     height: auto;
     52 |     outline: 0;
     53 |     border: none;
     54 |     transition: all 0.3s ease-in-out;
     55 |   }
     56 | 
     57 |   &:before {
     58 |     position: absolute;
     59 |     content: " ";
     60 |     top: 0;
     61 |     left: 0;
     62 |     width: 100%;
     63 |     height: 100%;
     64 |     opacity: 0;
     65 |     z-index: 1;
     66 |     background: rgba(0, 0, 0, 0.6);
     67 |     transition: all 0.3s ease-in-out;
     68 |   }
     69 | }
     70 | .loading-cards .post-card-featured-image {
     71 |   min-height: 220px;
     72 | }
     73 | .loading-cards .post-card-content {
     74 |   min-height: 180px;
     75 | }
     76 | .post-card-ex {
     77 |   position: absolute;
     78 |   opacity: 0;
     79 |   visibility: hidden;
     80 |   max-height: 10px;
     81 |   z-index: -100;
     82 | }
     83 | .author-list {
     84 |   display: inline-flex;
     85 |   margin: 0;
     86 | }
     87 | .author-list-item {
     88 |   display: inline-flex;
     89 |   position: relative;
     90 |   margin-right: rem-calc(5);
     91 | 
     92 |   &:last-child {
     93 |     margin-right: 0;
     94 |   }
     95 | 
     96 |   > a {
     97 |     display: inline-flex;
     98 |     position: relative;
     99 |     align-items: center;
    100 |   }
    101 | }
    102 | .static-avatar {
    103 |   display: inline-block;
    104 |   margin: 0 5px 0 0;
    105 |   width: 16px;
    106 |   height: 16px;
    107 |   border-radius: 50%;
    108 |   overflow: hidden;
    109 |   background: $primary-color;
    110 | }
    111 | 
    112 | // Animation
    113 | // ---------
    114 | 
    115 | .post-feed {
    116 |   position: relative;
    117 |   min-height: 200px;
    118 | 
    119 | }
    120 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/prismjs.scss:
    --------------------------------------------------------------------------------
     1 | // PrismJS
     2 | // -------
     3 | 
     4 | @import "~prismjs/plugins/line-highlight/prism-line-highlight";
     5 | @import "~prismjs/themes/prism-tomorrow";
     6 | 
     7 | // Variables
     8 | // ---------
     9 | 
    10 | $code-color: #e83e8c;
    11 | $code-font-size: 90%;
    12 | 
    13 | 
    14 | // pre code
    15 | // --------
    16 | 
    17 | pre:not([class*=language-]),
    18 | pre[class*=language-] {
    19 |   margin-top: 0;
    20 | }
    21 | 
    22 | pre:not([class*=language-]) {
    23 |   @extend pre[class*="language-"];
    24 |   padding: rem-calc(12 16);
    25 |   font-family: inherit;
    26 | 
    27 |   code {
    28 |     background-color: transparent;
    29 |     color: inherit;
    30 |   }
    31 | }
    32 | 
    33 | pre > code {
    34 |   font-size: $code-font-size;
    35 |   padding: 0;
    36 | }
    37 | 
    38 | 
    39 | // Code
    40 | // ----
    41 | :not(pre) > code {
    42 |   word-break: break-word;
    43 |   font-size: $code-font-size;
    44 | }
    45 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/search.scss:
    --------------------------------------------------------------------------------
      1 | $header-background: #1a2940;
      2 | $header-font-color: #91a2bd;
      3 | 
      4 | .search {
      5 |   display: none;
      6 |   position: fixed;
      7 |   top: 0;
      8 |   left: 0;
      9 |   width: 100%;
     10 |   height: 100%;
     11 |   overflow: hidden;
     12 |   background: rgba($header-background, 0.96);
     13 |   z-index: 500;
     14 | }
     15 | 
     16 | .close-search {
     17 |   position: absolute;
     18 |   padding: 5px;
     19 |   width: 55px;
     20 |   height: 60px;
     21 |   top: 0;
     22 |   right: 0;
     23 |   font-size: 30px;
     24 |   color: $white;
     25 |   text-align: center;
     26 | }
     27 | .close-overlay {
     28 |   position: absolute;
     29 |   width: 100%;
     30 |   height: 100%;
     31 |   top: 0;
     32 |   left: 0;
     33 |   cursor: pointer;
     34 |   background: rgba(255, 255, 255, 0);
     35 | }
     36 | 
     37 | .search-container {
     38 |   position: absolute;
     39 |   width: 100%;
     40 |   max-width: 90%;
     41 |   top: 50%;
     42 |   left: 0;
     43 |   right: 0;
     44 |   margin: 0 auto;
     45 |   transform: translateY(-50%);
     46 |   transition: all 0.8s ease;
     47 | 
     48 |   @include breakpoint(medium) {
     49 |     max-width: 35rem;
     50 |   }
     51 |   @include breakpoint(large) {
     52 |     max-width: 50rem;
     53 |   }
     54 | }
     55 | .search-container.dirty {
     56 |   height: 65%;
     57 | }
     58 | .search-wrapper {
     59 |   display: flex;
     60 |   flex-flow: column nowrap;
     61 |   align-items: center;
     62 |   justify-content: center;
     63 |   max-height: 100%;
     64 | }
     65 | .search-input-ct {
     66 |   position: relative;
     67 |   width: 100%;
     68 | 
     69 |   &:before {
     70 |     position: absolute;
     71 |     top: 0.9rem;
     72 |     left: 0.8rem;
     73 |     font-size: 1.5rem;
     74 |     font-family: "Font Awesome 5 Free";
     75 |     font-weight: 900;
     76 |     content: "\f002";
     77 |     color: $header-font-color;
     78 |   }
     79 | }
     80 | .search-input {
     81 |   height: 4rem;
     82 |   padding: 1rem 1rem 1rem 3rem;
     83 |   color: $white;
     84 |   background: rgba(0, 0, 0, 0.1);
     85 |   border: 1px solid $header-font-color;
     86 | 
     87 |   &:hover,
     88 |   &:focus {
     89 |     background: rgba(0, 0, 0, 0.1);
     90 |     border: 1px solid $header-font-color;
     91 |   }
     92 |   &::placeholder {
     93 |     color: $header-font-color;
     94 |   }
     95 | }
     96 | .search-results {
     97 |   display: flex;
     98 |   width: 100%;
     99 |   overflow-y: auto;
    100 | }
    101 | .results-list {
    102 |   width: 100%;
    103 |   margin: 0;
    104 |   list-style: none;
    105 | 
    106 |   li {
    107 |     &:last-child > a {
    108 |       border-bottom: none;
    109 |     }
    110 |   }
    111 | 
    112 |   a {
    113 |     display: block;
    114 |     padding: rem-calc(15);
    115 |     text-align: center;
    116 |     color: $header-font-color;
    117 |     border-bottom: 1px solid $header-font-color;
    118 |     background-color: rgba(255, 255, 255, 0);
    119 |     transition: background-color 0.5s ease;
    120 | 
    121 |     &:hover,
    122 |     &:focus {
    123 |       color: $white;
    124 |       background-color: rgba(255, 255, 255, 0.14);
    125 |     }
    126 |   }
    127 | }
    128 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/spinkit.scss:
    --------------------------------------------------------------------------------
     1 | .sk-cube-grid {
     2 |   position: absolute;
     3 |   width: 40px;
     4 |   height: 40px;
     5 |   left: 0;
     6 |   right: 0;
     7 |   margin: 0 auto;
     8 |   opacity: 1;
     9 |   transition: opacity 0.6s ease;
    10 | 
    11 |   .sk-cube {
    12 |     width: 33%;
    13 |     height: 33%;
    14 |     background-color: #1a2940;
    15 |     float: left;
    16 |     animation: sk-cubeGridScaleDelay 1.3s infinite ease-in-out;
    17 |   }
    18 |   .sk-cube1 {
    19 |     animation-delay: 0.2s;
    20 |   }
    21 |   .sk-cube2 {
    22 |     animation-delay: 0.3s;
    23 |   }
    24 |   .sk-cube3 {
    25 |     animation-delay: 0.4s;
    26 |   }
    27 |   .sk-cube4 {
    28 |     animation-delay: 0.1s;
    29 |   }
    30 |   .sk-cube5 {
    31 |     animation-delay: 0.2s;
    32 |   }
    33 |   .sk-cube6 {
    34 |     animation-delay: 0.3s;
    35 |   }
    36 |   .sk-cube7 {
    37 |     animation-delay: 0s;
    38 |   }
    39 |   .sk-cube8 {
    40 |     animation-delay: 0.1s;
    41 |   }
    42 |   .sk-cube9 {
    43 |     animation-delay: 0.2s;
    44 |   }
    45 | }
    46 | .post-feed .sk-cube-grid {
    47 |   position: absolute;
    48 |   top: 4rem;
    49 |   left: 0;
    50 |   right: 0;
    51 |   margin: 0 auto;
    52 | }
    53 | .post-full-image .sk-cube-grid {
    54 |   top: 50%;
    55 |   transform: translateY(-50%);
    56 | }
    57 | 
    58 | .loaded .sk-cube-grid {
    59 |   opacity: 0;
    60 | }
    61 | 
    62 | @keyframes sk-cubeGridScaleDelay {
    63 |   0%, 70%, 100% {
    64 |     transform: scale3D(1, 1, 1);
    65 |   }
    66 | 
    67 |   35% {
    68 |     transform: scale3D(0, 0, 1);
    69 |   }
    70 | }
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/tags.scss:
    --------------------------------------------------------------------------------
     1 | .tags {
     2 |   display: block;
     3 |   position: relative;
     4 |   margin: 0 0 10px 0;
     5 |   list-style: none;
     6 |   font-weight: 700;
     7 |   z-index: 2;
     8 | 
     9 |   li {
    10 |     display: inline-block;
    11 |     margin: 0 4px 2px 0;
    12 |     transition: all 0.3s ease-in-out;
    13 | 
    14 |     &:last-child {
    15 |       margin: 0;
    16 |     }
    17 | 
    18 |     a {
    19 |       display: inline-block;
    20 |       padding: 2px 5px;
    21 |       border: 1px solid rgba($body-font-color, .8);
    22 |       border-radius: 2px;
    23 |       font-size: rem-calc(11);
    24 |       text-transform: uppercase;
    25 |       color: rgba($body-font-color, .8);
    26 |       text-decoration: none;
    27 |       transition: all 0.3s ease-in-out;
    28 | 
    29 |       &:hover,
    30 |       &:focus {
    31 |         color: $white;
    32 |         background: rgba($body-font-color, .8);
    33 |       }
    34 |     }
    35 |   }
    36 | }
    37 | 
    38 | .post-card-tags-ct {
    39 |   display: flex;
    40 |   width: 100%;
    41 | }
    42 | 
    43 | .post-card-featured-image .tags {
    44 |   display: inline-block;
    45 |   position: absolute;
    46 |   margin: 0;
    47 |   top: 10px;
    48 |   left: 10px;
    49 |   overflow: hidden;
    50 |   max-width: calc(100% - 50px);
    51 |   max-height: calc(100% - 50px);
    52 | 
    53 |   &:hover {
    54 |     overflow-y: auto;
    55 |   }
    56 | 
    57 |   li {
    58 |     display: list-item;
    59 |     opacity: 0;
    60 |     visibility: hidden;
    61 | 
    62 |     &:first-child {
    63 |       opacity: 1;
    64 |       visibility: visible;
    65 |     }
    66 | 
    67 |     a {
    68 |       border: 1px solid $white;
    69 |       color: $white;
    70 |       text-decoration: none;
    71 |       background: rgba(0,0,0,0.2);
    72 | 
    73 |       &:hover,
    74 |       &:focus {
    75 |         color: $black;
    76 |         background: $white;
    77 |       }
    78 |     }
    79 |   }
    80 | }
    81 | 
    82 | .post-card-featured-image:hover .tags li,
    83 | .post-card-featured-image:focus .tags li {
    84 |   opacity: 1;
    85 |   visibility: visible;
    86 | }
    87 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/components/top-bar.scss:
    --------------------------------------------------------------------------------
      1 | // Variables
      2 | // ---------
      3 | $header-background: #1a2940;
      4 | $header-font-color: #91a2bd;
      5 | 
      6 | .sticky {
      7 |   width: 100%;
      8 |   top: 0 !important;
      9 | 
     10 |   &.is-stuck {
     11 |     z-index: 100;
     12 |   }
     13 |   &.is-anchored {
     14 |     position: fixed;
     15 |   }
     16 | }
     17 | 
     18 | .top-bar {
     19 |   color: $header-font-color;
     20 |   transition: transform 1ms ease-out;
     21 |   z-index: 100;
     22 | 
     23 |   a,
     24 |   .bar-icon,
     25 |   .search-icon {
     26 |     color: $header-font-color;
     27 | 
     28 |     &:focus,
     29 |     &:hover {
     30 |       color: $white;
     31 |     }
     32 |   }
     33 | 
     34 |   .top-bar-title {
     35 |     opacity: 0;
     36 |     visibility: hidden;
     37 |     transition: all 0.3s ease;
     38 |   }
     39 | 
     40 |   .site-logo {
     41 |     height: 35px;
     42 |   }
     43 | 
     44 |   .mobile-buttons {
     45 |     display: block;
     46 | 
     47 |     @include breakpoint(large up) {
     48 |       display: none;
     49 |     }
     50 |   }
     51 | 
     52 |   .bar-icon,
     53 |   .mobile-buttons .search-icon {
     54 |     font-size: rem-calc(25);
     55 |     cursor: pointer;
     56 |   }
     57 | 
     58 |   .search-hot {
     59 |     text-align: center;
     60 |     text-transform: uppercase;
     61 |     font-weight: 700;
     62 |     cursor: pointer;
     63 |     user-select: none;
     64 | 
     65 |     &:hover,
     66 |     &:focus {
     67 |       color: #fff;
     68 |     }
     69 |   }
     70 | 
     71 |   .mobile-buttons .search-hot {
     72 |     margin-right: rem-calc(0);
     73 |   }
     74 | 
     75 |   .search-icon {
     76 |     padding: .7rem 1rem;
     77 |     cursor: pointer;
     78 |   }
     79 | 
     80 |   @include breakpoint(large) {
     81 |     .search-menu-text {
     82 |       display: none;
     83 |     }
     84 |   }
     85 | }
     86 | 
     87 | 
     88 | .bg .top-bar {
     89 |   background: rgba($header-background, 0.95);
     90 | 
     91 |   .top-bar-title {
     92 |     opacity: 1;
     93 |     visibility: visible;
     94 |   }
     95 | }
     96 | 
     97 | .top-bar-left,
     98 | .top-bar-right {
     99 |   padding: rem-calc(10 0);
    100 | }
    101 | 
    102 | .top-bar-left {
    103 |   display: flex;
    104 |   justify-content: space-between;
    105 |   align-items: center;
    106 | }
    107 | 
    108 | .top-bar-right {
    109 |   max-height: 200px;
    110 |   overflow-y: auto;
    111 | 
    112 |   @include breakpoint(medium down) {
    113 |     display: none;
    114 |     padding-top: 0;
    115 |   }
    116 | }
    117 | 
    118 | .top-menu {
    119 |   justify-content: flex-end;
    120 | 
    121 |   .menu-item {
    122 |     a {
    123 |       text-transform: uppercase;
    124 |       font-weight: bold;
    125 |     }
    126 | 
    127 |     @include breakpoint(medium down) {
    128 |       &.nav-search {
    129 |         display: none;
    130 |       }
    131 |       a {
    132 |         text-align: center;
    133 |         border-bottom: 1px solid $header-font-color;
    134 | 
    135 |         &:hover,
    136 |         &:focus {
    137 |           border-color: $white;
    138 |         }
    139 |       }
    140 |       &:first-child a {
    141 |         padding-top: 0;
    142 |       }
    143 |       &:nth-last-child(2) a {
    144 |         border-bottom: none;
    145 |       }
    146 |     }
    147 |   }
    148 | }
    149 | 
    150 | .top-bar .top-bar-title {
    151 |   color: $white;
    152 |   font-size: rem-calc(24);
    153 |   font-weight: bold;
    154 | }
    155 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/main.scss:
    --------------------------------------------------------------------------------
      1 | /* Table of Contents
      2 | /* ------------------------------------------------------------
      3 | 
      4 | This is a development CSS file which is built to a minified
      5 | production stylesheet in assets/built/screen.css
      6 | 
      7 | 1.  Global Styles
      8 | 2.  Layout
      9 | 3.  Special Templates
     10 | 4.  Site Header
     11 | 5.  Site Navigation
     12 | 6.  Post Feed
     13 | 7.  Single Post
     14 |   7.1. Subscribe Form
     15 |   7.2. Post Footer
     16 |      7.2.1 Single Author Byline
     17 |      7.2.2 Multiple Author Byline
     18 |   7.3. Comments
     19 |   7.4. Related Posts
     20 |   7.5. Floating Header
     21 |   7.6. Koenig Styles
     22 | 8.  Author Template
     23 | 9.  Error Template
     24 | 10. Subscribe Overlay
     25 | 11. Site Footer
     26 | 
     27 | */
     28 | 
     29 | @import 'components/fonts';
     30 | @import 'settings';
     31 | @import 'foundation';
     32 | 
     33 | // Global styles
     34 | @include foundation-global-styles;
     35 | @include foundation-forms;
     36 | @include foundation-typography;
     37 | 
     38 | // Grids
     39 | @include foundation-xy-grid-classes;
     40 | 
     41 | // Generic components
     42 | @include foundation-button;
     43 | @include foundation-button-group;
     44 | @include foundation-close-button;
     45 | @include foundation-label;
     46 | //@include foundation-progress-bar;
     47 | //@include foundation-slider;
     48 | //@include foundation-switch;
     49 | @include foundation-table;
     50 | // Basic components
     51 | //@include foundation-badge;
     52 | //@include foundation-breadcrumbs;
     53 | @include foundation-callout;
     54 | //@include foundation-card;
     55 | //@include foundation-dropdown;
     56 | @include foundation-pagination;
     57 | @include foundation-tooltip;
     58 | 
     59 | // Containers
     60 | //@include foundation-accordion;
     61 | @include foundation-media-object;
     62 | //@include foundation-orbit;
     63 | @include foundation-responsive-embed;
     64 | //@include foundation-tabs;
     65 | @include foundation-thumbnail;
     66 | // Menu-based containers
     67 | @include foundation-menu;
     68 | @include foundation-menu-icon;
     69 | //@include foundation-accordion-menu;
     70 | //@include foundation-drilldown-menu;
     71 | //@include foundation-dropdown-menu;
     72 | 
     73 | // Layout components
     74 | //@include foundation-off-canvas;
     75 | //@include foundation-reveal;
     76 | @include foundation-sticky;
     77 | @include foundation-title-bar;
     78 | //@include foundation-top-bar;
     79 | 
     80 | // Helpers
     81 | //@include foundation-float-classes;
     82 | // @include foundation-flex-classes;
     83 | @include foundation-visibility-classes;
     84 | 
     85 | // Custom theme ghost style
     86 | // ------------------------
     87 | @import 'components/mixins';
     88 | @import 'components/general';
     89 | @import 'components/koenig';
     90 | @import 'components/tags';
     91 | @import 'components/main-content';
     92 | @import 'components/footer';
     93 | @import 'components/placeholder';
     94 | @import 'components/posts-list';
     95 | @import 'components/top-bar';
     96 | @import 'components/pagination';
     97 | @import 'components/header';
     98 | @import 'components/search';
     99 | @import 'components/ads';
    100 | @import 'components/error';
    101 | 
    
    
    --------------------------------------------------------------------------------
    /src/styles/post.scss:
    --------------------------------------------------------------------------------
      1 | @import 'settings';
      2 | @import '_global';
      3 | @import 'util/unit';
      4 | @import 'util/breakpoint';
      5 | @import 'xy-grid/_xy-grid';
      6 | @import 'components/spinkit';
      7 | @import 'components/post-feed';
      8 | @import 'components/lightbox';
      9 | @import 'components/prismjs';
     10 | 
     11 | .comments,
     12 | .read-next {
     13 |   background: #f0f0f0;
     14 | }
     15 | .read-next {
     16 |   padding: 2rem;
     17 | }
     18 | .comments {
     19 |   padding-bottom: 3rem;
     20 | }
     21 | 
     22 | %rectangle {
     23 |   position: absolute;
     24 |   content: '';
     25 |   top: 0;
     26 |   z-index: 1;
     27 |   background: rgba(255, 255, 255, 0.05);
     28 |   border: 1px solid rgba(255, 255, 255, 0.1);
     29 | }
     30 | 
     31 | .post-full-image {
     32 |   display: block;
     33 |   position: relative;
     34 |   margin-bottom: 2rem;
     35 |   width: 100%;
     36 |   height: 500px;
     37 |   overflow: hidden;
     38 |   text-align: center;
     39 |   border-top-left-radius: 5px;
     40 |   border-top-right-radius: 5px;
     41 |   background: rgb(241, 241, 241);
     42 | 
     43 |   &:before {
     44 |     @extend %rectangle;
     45 |     width: 250px;
     46 |     height: 250px;
     47 |     left: 6%;
     48 |     transform: rotate(45deg);
     49 |   }
     50 |   &:after {
     51 |     @extend %rectangle;
     52 |     width: 250px;
     53 |     height: 250px;
     54 |     left: 12%;
     55 |     transform: rotate(135deg);
     56 |   }
     57 | 
     58 |   @include breakpoint(medium) {
     59 |     &:before {
     60 |       width: 350px;
     61 |       height: 350px;
     62 |     }
     63 |     &:after {
     64 |       width: 350px;
     65 |       height: 350px;
     66 |     }
     67 |   }
     68 |   @include breakpoint(large) {
     69 |     &:before {
     70 |       width: 500px;
     71 |       height: 500px;
     72 |     }
     73 |     &:after {
     74 |       width: 500px;
     75 |       height: 500px;
     76 |     }
     77 |   }
     78 | 
     79 |   img {
     80 |     position: absolute;
     81 |     max-width: 90%;
     82 |     max-height: 87%;
     83 |     top: 50%;
     84 |     left: 0;
     85 |     right: 0;
     86 |     margin: 0 auto;
     87 |     border-radius: 10px;
     88 |     z-index: 4;
     89 |     transform: translateY(-40%);
     90 |   }
     91 |   &.loaded img {
     92 |     transform: translateY(-53%);
     93 |   }
     94 | 
     95 |   @include breakpoint(medium down) {
     96 |     height: 350px;
     97 |   }
     98 |   @include breakpoint(small down) {
     99 |     height: 250px;
    100 |   }
    101 | 
    102 |   img,
    103 |   .post-full-image-background,
    104 |   .post-full-meta-feature {
    105 |     opacity: 0;
    106 |     transition-property: transform,opacity;
    107 |     transition-duration: 0.6s;
    108 |     transition-timing-function: ease-in;
    109 |   }
    110 | 
    111 |   &.loaded {
    112 |     img,
    113 |     .post-full-image-background,
    114 |     .post-full-meta-feature {
    115 |       opacity: 1;
    116 |     }
    117 |   }
    118 | }
    119 | 
    120 | .post-full-image-background {
    121 |   display: block;
    122 |   position: absolute;
    123 |   width: 100%;
    124 |   height: 100%;
    125 |   top: 0;
    126 |   left: 0;
    127 |   background: rgba(255, 255, 255, 0)
    128 | }
    129 | 
    130 | %meta {
    131 |   display: flex;
    132 |   padding: rem-calc(5 10);
    133 |   width: 100%;
    134 |   font-size: 85%;
    135 |   text-align: left;
    136 |   font-weight: 500;
    137 |   flex-flow: row wrap;
    138 |   justify-content: space-between;
    139 | 
    140 |   .post-date {
    141 |     margin-right: rem-calc(15);
    142 |   }
    143 |   .post-full-meta-date {
    144 |     text-transform: uppercase;
    145 |   }
    146 | }
    147 | 
    148 | .post-full-meta {
    149 |   @extend %meta;
    150 |   position: relative;
    151 |   margin-bottom: rem-calc(25);
    152 |   background: $lightest-gray;
    153 | 
    154 |   .fa,
    155 |   .far,
    156 |   .fas {
    157 |     font-size: 80%;
    158 |   }
    159 | 
    160 |   .meta-tag {
    161 |     text-transform: uppercase;
    162 |     color: $body-font-color;
    163 |   }
    164 | }
    165 | .post-full-meta-feature {
    166 |   @extend %meta;
    167 |   position: absolute;
    168 |   bottom: 0;
    169 |   left: 0;
    170 |   color: $white;
    171 |   background: rgba(0, 0, 0, 0.8);
    172 |   z-index: 20;
    173 | 
    174 |   .fa,
    175 |   .far,
    176 |   .fas {
    177 |     font-size: 80%;
    178 |   }
    179 | 
    180 |   .meta-tag {
    181 |     text-transform: uppercase;
    182 |     color: $white;
    183 | 
    184 |     &:hover,
    185 |     &:focus {
    186 |       color: $white;
    187 |     }
    188 |   }
    189 | }
    190 | 
    191 | .post-full-title {
    192 |   text-align: center;
    193 |   margin-bottom: 2rem;
    194 | }
    195 | 
    196 | .title-wrapper,
    197 | .post-content,
    198 | .comments-container,
    199 | .post-full-meta,
    200 | .post-full-footer {
    201 |   @include breakpoint(medium) {
    202 |     @include xy-cell(9 of 11);
    203 |     @include xy-cell-offset(1, $gutters: $grid-margin-gutters, $gutter-type: margin);
    204 |   }
    205 |   @include breakpoint(large) {
    206 |     @include xy-cell(8);
    207 |     @include xy-cell-offset(2, $gutters: $grid-margin-gutters, $gutter-type: margin);
    208 |   }
    209 | }
    210 | 
    211 | // Images (required by Ghost)
    212 | // --------------------------
    213 | 
    214 | /* Preventing full-width image overlap with post image.  */
    215 | .post-full-image + .post-full-content .kg-content *:first-child .kg-image {
    216 |     width: 100%;
    217 | }
    218 | 
    219 | .post-content {
    220 |   .kg-width-wide .kg-image {
    221 |     max-width: 100%;
    222 |     //TODO
    223 |   }
    224 |   .kg-width-full .kg-image {
    225 |     max-width: 100%;
    226 |     //TODO
    227 |   }
    228 | }
    229 | 
    230 | .kg-gallery-container {
    231 |     display: flex;
    232 |     flex-direction: column;
    233 |     max-width: 100%; // TODO
    234 | }
    235 | 
    236 | .kg-gallery-row {
    237 |     display: flex;
    238 |     flex-direction: row;
    239 |     justify-content: center;
    240 | 
    241 |     &:not(:first-of-type) {
    242 |       margin: 0.75em 0 0 0;
    243 |     }
    244 | }
    245 | 
    246 | .kg-gallery-image {
    247 |   img {
    248 |     display: block;
    249 |     margin: 0;
    250 |     width: 100%;
    251 |     height: 100%;
    252 |   }
    253 |   &:not(:first-of-type) {
    254 |     margin: 0 0 0 0.75em;
    255 |   }
    256 | }
    257 | 
    258 | .kg-card {
    259 |   margin: rem-calc(0 0 16);
    260 | 
    261 |    > * {
    262 |      margin: 0 auto !important;
    263 |    }
    264 | }
    265 | 
    266 | // Author
    267 | // ------
    268 | 
    269 | .post-full-footer {
    270 |   display: flex;
    271 |   align-items: center;
    272 |   justify-content: center;
    273 |   margin-top: 4rem;
    274 | }
    275 | 
    276 | .post-full-container {
    277 |   display: inline-flex;
    278 |   position: relative;
    279 |   padding: rem-calc(6 3 3 3);
    280 |   flex-flow: row wrap;
    281 |   background: #f0f0f0;
    282 |   max-height: 70px;
    283 | 
    284 |   .author-list-item,
    285 |   > section:first-child {
    286 |     margin-right: rem-calc(10);
    287 |   }
    288 | 
    289 |   &:before {
    290 |     display: block;
    291 |     position: absolute;
    292 |     content: " ";
    293 |     width: 0;
    294 |     height: 0;
    295 |     top: 0;
    296 |     left: -70px;
    297 |     border-bottom: 70px solid #f0f0f0;
    298 |     border-left: 70px solid transparent;
    299 |   }
    300 |   &:after {
    301 |     display: block;
    302 |     position: absolute;
    303 |     content: " ";
    304 |     width: 0;
    305 |     height: 0;
    306 |     top: 0;
    307 |     right: -70px;
    308 |     border-bottom: 70px solid #f0f0f0;
    309 |     border-right: 70px solid transparent;
    310 |   }
    311 | }
    312 | 
    313 | .author-list {
    314 |   li:last-child {
    315 |     margin-right: 0;
    316 |   }
    317 | }
    318 | 
    319 | %circles {
    320 |   display: inline-block;
    321 |   position: relative;
    322 |   width: 50px;
    323 |   height: 50px;
    324 |   border-radius: 50%;
    325 |   overflow: hidden;
    326 |   background: $primary-color;
    327 |   text-align: center;
    328 | }
    329 | 
    330 | .author-card {
    331 |   a {
    332 |     border-bottom: none;
    333 |   }
    334 |   .author-profile-image {
    335 |     @extend %circles;
    336 |   }
    337 | }
    338 | .share-icon {
    339 |   @extend %circles;
    340 |   color: $white;
    341 |   font-size: rem-calc(25);
    342 | 
    343 |   > i {
    344 |     padding: rem-calc(12);
    345 |   }
    346 | }
    347 | .open-share {
    348 |   display: block;
    349 |   position: absolute;
    350 |   width: 100%;
    351 |   height: 100%;
    352 |   top: 0;
    353 |   left: 0;
    354 |   cursor: pointer;
    355 |   background: rgba(255, 255, 255, 0);
    356 | }
    357 | .share-post {
    358 |   position: relative;
    359 | 
    360 |   &:hover,
    361 |   &:focus {
    362 |     .share-post-ct {
    363 |       opacity: 1;
    364 |       visibility: visible;
    365 |     }
    366 |   }
    367 | }
    368 | 
    369 | .share-post-ct {
    370 |   position: absolute;
    371 |   flex-flow: row nowrap;
    372 |   bottom: 125%;
    373 |   left: 50%;
    374 |   opacity: 0;
    375 |   visibility: hidden;
    376 |   transform: translateX(-50%);
    377 |   transition: visibility 0.2s linear, opacity 0.2s linear;
    378 |   z-index: 80;
    379 | }
    380 | .share-icons {
    381 |   position: relative;
    382 |   flex-flow: row nowrap;
    383 |   padding: .75rem;
    384 |   border-radius: 0;
    385 |   background-color: #0a0a0a;
    386 | 
    387 |   &::before {
    388 |     display: block;
    389 |     position: absolute;
    390 |     content: " ";
    391 |     width: 0;
    392 |     height: 0;
    393 |     top: 100%;
    394 |     left: 0;
    395 |     right: 0;
    396 |     margin: 0 auto;
    397 |     bottom: auto;
    398 |     border: inset 0.75rem;
    399 |     border-bottom-width: 0;
    400 |     border-top-style: solid;
    401 |     border-color: #0a0a0a transparent transparent;
    402 |   }
    403 | 
    404 |   > li:not(:last-child) {
    405 |     margin-right: rem-calc(7);
    406 |   }
    407 | }
    408 | 
    409 | %social-circle {
    410 |   display: inline-block;
    411 |   position: relative;
    412 |   padding: rem-calc(6);
    413 |   width: 35px;
    414 |   height: 35px;
    415 |   border-radius: 50%;
    416 |   overflow: hidden;
    417 |   text-align: center;
    418 |   color: $white;
    419 |   cursor: pointer;
    420 | 
    421 |   &:hover,
    422 |   &:focus {
    423 |     color: $white;
    424 |   }
    425 | }
    426 | .social-icon {
    427 |   @extend %social-circle;
    428 | }
    429 | .icon-twitter {
    430 |   background-color: #56ADEE;
    431 |   &:hover, &:focus {
    432 |     background-color: darken(#56ADEE, 20%);
    433 |   }
    434 | }
    435 | .icon-facebook {
    436 |   background-color: #4862A2;
    437 | 
    438 |   &:hover, &:focus {
    439 |     background-color: darken(#4862A2, 20%);
    440 |   }
    441 | }
    442 | .icon-google-plus {
    443 |   background-color: #DB4437;
    444 | 
    445 |   &:hover, &:focus {
    446 |     background-color: darken(#DB4437, 20%);
    447 |   }
    448 | }
    449 | .icon-reddit {
    450 |   background-color: #ff4500;
    451 | 
    452 |   &:hover, &:focus {
    453 |     background-color: darken(#ff4500, 20%);
    454 |   }
    455 | }
    456 | .icon-linkedin {
    457 |   background-color: #0071ad;
    458 | 
    459 |   &:hover, &:focus {
    460 |     background-color: darken(#0071ad, 10%);
    461 |   }
    462 | }
    463 | .icon-flipboard {
    464 |   background-color: #ff2a31;
    465 | 
    466 |   &:hover, &:focus {
    467 |     background-color: darken(#ff2a31, 20%);
    468 |   }
    469 | }
    470 | .tooltip {
    471 |   z-index: 80;
    472 | }
    473 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/@tryghost/content-api/index.d.ts:
    --------------------------------------------------------------------------------
    1 | declare module '@tryghost/content-api';
    2 | interface GhostApi {
    3 |     url: string;
    4 |     key: string;
    5 |     version: string;
    6 | }
    7 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
    8 | declare function GhostContentAPI(apiParams: GhostApi): any;
    9 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/@tryghost/index.d.ts:
    --------------------------------------------------------------------------------
    1 | declare module '@tryghost';
    2 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/colorthief/index.d.ts:
    --------------------------------------------------------------------------------
    1 | declare module 'colorthief';
    2 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/custom/index.d.ts:
    --------------------------------------------------------------------------------
     1 | declare module '*.svg';
     2 | declare module '*.png';
     3 | declare module '*.jpg';
     4 | declare module '*.jpeg';
     5 | declare module '*.gif';
     6 | declare module '*.bmp';
     7 | declare module '*.tiff';
     8 | declare module '*.webp';
     9 | declare module '*.json';
    10 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/ghost-search/index.d.ts:
    --------------------------------------------------------------------------------
    1 | // eslint-disable-next-line @typescript-eslint/no-explicit-any
    2 | export default function GhostSearch(args: any): void;
    3 | export as namespace GhostSearch;
    4 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/ghost/index.d.ts:
    --------------------------------------------------------------------------------
    1 | declare namespace ghost {
    2 |     // eslint-disable-next-line @typescript-eslint/no-explicit-any
    3 |     function init(options: any): void;
    4 |     namespace url {
    5 |         // eslint-disable-next-line @typescript-eslint/no-explicit-any
    6 |         function api(resource: string, parameter: Record): any;
    7 |     }
    8 | }
    9 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/lightgallery/index.d.ts:
    --------------------------------------------------------------------------------
    1 | // Lightgallery.js
    2 | 
    3 | interface Window {
    4 |     // eslint-disable-next-line @typescript-eslint/no-explicit-any
    5 |     lightGallery: (el: Element, options: any) => void;
    6 | }
    7 | 
    
    
    --------------------------------------------------------------------------------
    /src/typings/particles.js/index.d.ts:
    --------------------------------------------------------------------------------
    1 | // particlesJS
    2 | 
    3 | interface Window {
    4 |     // eslint-disable-next-line @typescript-eslint/camelcase,@typescript-eslint/no-explicit-any
    5 |     particlesJS: (tag_id: string, params: any) => void;
    6 | }
    7 | 
    
    
    --------------------------------------------------------------------------------
    /tag.hbs:
    --------------------------------------------------------------------------------
     1 | {{!< default}}
     2 | {{!-- The tag above means - insert everything in this file into the {body} of the default.hbs template --}}
     3 | 
     4 | {{#tag}}
     5 |     {{#contentFor "styles"}}
     6 |         
    51 |     {{/contentFor}}
    52 | {{/tag}}
    53 | 
    54 | {{!-- The main content area --}}
    55 | 
    56 |
    57 |
    58 |
    59 | {{#foreach posts}} 60 | {{!-- The tag below includes the markup for each post - partials/post-card.hbs --}} 61 | {{> "post-card"}} 62 | {{/foreach}} 63 |
    64 | {{pagination}} 65 |
    66 |
    67 | 68 | {{#contentFor "scripts"}} 69 | 70 | {{/contentFor}} 71 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "compilerOptions": { 3 | "target": "es5", 4 | "module": "commonjs", 5 | "moduleResolution": "node", 6 | "baseUrl": "./", 7 | "outDir": "assets", 8 | "strict": true, 9 | "sourceMap": true, 10 | "removeComments": true, 11 | "noImplicitAny": true, 12 | "resolveJsonModule": true, 13 | "esModuleInterop": true, 14 | "allowJs": true, 15 | "types": [ 16 | "jquery", 17 | "webpack-env" 18 | ], 19 | "typeRoots": [ 20 | "./node_modules/@types", 21 | "./src/typings" 22 | ], 23 | "lib": [ 24 | "dom", 25 | "es5", 26 | "es2015.core", 27 | "es2015.promise", 28 | "scripthost" 29 | ] 30 | }, 31 | "include": [ 32 | "./src/**/*" 33 | ], 34 | "exclude": [ 35 | "node_modules", 36 | "assets", 37 | "src/build", 38 | "src/img", 39 | "src/styles" 40 | ], 41 | "awesomeTypescriptLoaderOptions": { 42 | "reportFiles": [ 43 | "./src/**/*" 44 | ] 45 | } 46 | } 47 | --------------------------------------------------------------------------------