diff --git a/.babelrc b/.babelrc new file mode 100644 index 0000000..21ae4fd --- /dev/null +++ b/.babelrc @@ -0,0 +1,4 @@ +{ + "presets": ['react', 'es2015', 'stage-1'], + "plugins": ['add-module-exports'] +} \ No newline at end of file diff --git a/browserslist b/.browserslistrc similarity index 61% rename from browserslist rename to .browserslistrc index 10b76d2..ba7dc9e 100644 --- a/browserslist +++ b/.browserslistrc @@ -1,4 +1,5 @@ # Browsers that we support > 1% -Last 2 versions \ No newline at end of file +Last 2 versions +IE 10 \ No newline at end of file diff --git a/.eslintrc b/.eslintrc index 8edd7ed..5210e5c 100644 --- a/.eslintrc +++ b/.eslintrc @@ -1,10 +1,14 @@ { + "parser": "babel-eslint", "extends": "airbnb", "plugins": [ "react", "jsx-a11y", "import" ], + "globals": { + "graphql": true + }, "rules": { "global-require": [0], "react/jsx-filename-extension": [0], @@ -13,7 +17,10 @@ "react/forbid-prop-types": [0], /* to allow importing 'gatsby-helpers' */ "import/no-extraneous-dependencies": [0], + "comma-dangle": ["error", {"functions": "ignore"}], + "arrow-body-style": ["error", "as-needed", { "requireReturnForObjectLiteral": true }], "import/no-unresolved": [0], - "import/extensions": [0] + "import/extensions": [0], + "no-console": "off" } -} +} \ No newline at end of file diff --git a/.gitattributes b/.gitattributes index 1738f75..b8b7606 100644 --- a/.gitattributes +++ b/.gitattributes @@ -1,4 +1,3 @@ $ cat .gitattributes -*.js linguist-language=JavaScript -**/*.js linguist-language=JavaScript -static/css/*.css linguist-vendored \ No newline at end of file +public linguist-vendored +src/assets/fonts linguist-vendored \ No newline at end of file diff --git a/.gitignore b/.gitignore index d5769d3..c39068a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,11 +1,8 @@ node_modules/ +.cache/ +public/ npm-debug.log - .eslintcache - -public - .gatsby-context.js -pages/.manifest .idea gatsby-starter-lumen.iml \ No newline at end of file diff --git a/README.md b/README.md index 4c41823..68999dc 100644 --- a/README.md +++ b/README.md @@ -1,25 +1,86 @@ +[![Gatsby Version](https://img.shields.io/badge/gatsby-1.8.12-744C9E.svg)](https://github.com/gatsbyjs/gatsby) [![GitHub license](https://img.shields.io/badge/license-MIT-blue.svg)](https://raw.githubusercontent.com/alxshelepenok/gatsby-starter-lumen/master/LICENSE) [![Twitter](https://img.shields.io/twitter/url/https/github.com/alxshelepenok/gatsby-starter-lumen.svg?style=social)](https://twitter.com/intent/tweet?text=Wow:&url=https://github.com/alxshelepenok/gatsby-starter-lumen) + # Lumen -[Gatsby](https://github.com/gatsbyjs/gatsby) starter for creating a blog. +Lumen is a minimal, lightweight and mobile-first starter for creating blogs uses [Gatsby](https://github.com/gatsbyjs/gatsby). ## Features -+ Clean and extensible code. + Lost Grid ([peterramsing/lost](https://github.com/peterramsing/lost)). -+ Beautiful Typography ([matejlatin/Gutenberg](https://github.com/matejlatin/Gutenberg)). ++ Beautiful typography inspired by [matejlatin/Gutenberg](https://github.com/matejlatin/Gutenberg). ++ [Mobile-First](https://medium.com/@mrmrs_/mobile-first-css-48bc4cc3f60f) approach in development. ++ Stylesheet built using SASS and [BEM](http://getbem.com/naming/)-Style naming. ++ Syntax highlighting in code blocks. ++ Sidebar menu built using a configuration block. ++ Archive organized by tags and categories. ++ Automatic RSS generation. ++ Automatic Sitemap generation. ++ Offline support. ++ Google Analitics support. -## Installing +## Folder Structure + +``` +└── src + ├── assets + │   ├── fonts + │   │   └── fontello-771c82e0 + │   │   ├── css + │   │   └── font + │   └── scss + │   ├── base + │   ├── mixins + │   └── pages + ├── components + │   ├── CategoryTemplateDetails + │   ├── Links + │   ├── Menu + │   ├── PageTemplateDetails + │   ├── Post + │   ├── PostTemplateDetails + │   ├── Sidebar + │   └── TagTemplateDetails + ├── layouts + ├── pages + │   ├── articles + │   │   ├── 2016-01-09---Perfecting-the-Art-of-Perfection + │   │   ├── 2016-01-12---The-Origins-of-Social-Stationery-Lettering + │   │   ├── 2016-02-02---A-Brief-History-of-Typography + │   │   ├── 2017-18-08---The-Birth-of-Movable-Type + │   │   └── 2017-19-08---Humane-Typography-in-the-Digital-Age + │   └── pages + │   ├── 2015-05-01---about + │   └── 2015-05-01---contact + └── templates +``` + +## Getting Started Install this starter (assuming Gatsby is installed) by running from your CLI: -`gatsby new lumen https://github.com/wpioneer/gatsby-starter-lumen` +`gatsby new lumen https://github.com/alxshelepenok/gatsby-starter-lumen` -## Running in development +#### Running in Development `gatsby develop` +#### Building +`gatsby build` + +## Screenshot + ![](http://i.imgur.com/422y5GV.png) ## Ports - [Statinamic port](https://github.com/thangngoc89/statinamic-theme-lumen) by [Khoa Nguyen](https://github.com/thangngoc89) +## Contributors + +[alxshelepenok](https://github.com/alxshelepenok) |[abisz](https://github.com/abisz) |[ihororlovskyi](https://github.com/ihororlovskyi) |[vinnymac](https://github.com/vinnymac) |[axelclark](https://github.com/axelclark) |[concreted](https://github.com/concreted) | +:---: |:---: |:---: |:---: |:---: |:---: | +[alxshelepenok](https://github.com/alxshelepenok) |[abisz](https://github.com/abisz) |[ihororlovskyi](https://github.com/ihororlovskyi) |[vinnymac](https://github.com/vinnymac) |[axelclark](https://github.com/axelclark) |[concreted](https://github.com/concreted) | + +[charandas](https://github.com/charandas) |[zollillo](https://github.com/zollillo) |[swapnilmishra](https://github.com/swapnilmishra) | +:---: |:---: |:---: | +[charandas](https://github.com/charandas) |[zollillo](https://github.com/zollillo) |[swapnilmishra](https://github.com/swapnilmishra) | + + ## License The MIT License (MIT) diff --git a/components/ReadNext/index.jsx b/components/ReadNext/index.jsx deleted file mode 100644 index 21deaef..0000000 --- a/components/ReadNext/index.jsx +++ /dev/null @@ -1,48 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import { include as includes } from 'underscore.string'; -import find from 'lodash/find'; - -import './style.css'; - -class ReadNext extends React.Component { - render() { - const { post } = this.props; - const { pages } = this.props.route; - const { readNext } = post; - - let nextPost; - if (readNext) { - nextPost = find(pages, page => includes(page.path, readNext)); - } - if (!nextPost) { - return React.createElement('noscript', null); - } - - nextPost = find(pages, page => includes(page.path, readNext.slice(1, -1))); - const description = nextPost.data.description; - - return ( -
-
READ THIS NEXT:
-

- - {nextPost.data.title} - -

-

- {description} -

-
- ); - } -} - -ReadNext.propTypes = { - post: React.PropTypes.object.isRequired, - pages: React.PropTypes.array, - route: React.PropTypes.object, -}; - -export default ReadNext; - diff --git a/components/ReadNext/style.css b/components/ReadNext/style.css deleted file mode 100644 index a3e7ead..0000000 --- a/components/ReadNext/style.css +++ /dev/null @@ -1,4 +0,0 @@ -.description { - font-size: responsive 12px 14px; - line-height: 1.6; -} \ No newline at end of file diff --git a/components/SiteLinks/index.jsx b/components/SiteLinks/index.jsx deleted file mode 100644 index cd56af1..0000000 --- a/components/SiteLinks/index.jsx +++ /dev/null @@ -1,59 +0,0 @@ -import React from 'react'; -import { config } from 'config'; -import './style.css'; -import '../../static/fonts/fontawesome/style.css'; - -class SiteLinks extends React.Component { - render() { - return ( -
- -
    - {config.siteEmailUrl && ( -
  • - - - -
  • - )} - {config.siteTelegramUrl && ( -
  • - - - -
  • - )} -
-
    - {config.siteRssUrl && ( -
  • - -
  • - )} -
-
- ); - } -} - -export default SiteLinks; diff --git a/components/SiteLinks/style.css b/components/SiteLinks/style.css deleted file mode 100644 index 99de057..0000000 --- a/components/SiteLinks/style.css +++ /dev/null @@ -1,32 +0,0 @@ -.blog-links { - margin-top: 30px; -} -.blog-links ul { - list-style: none; - padding: 0; - margin: 10px 0; - clear: fix-legacy; -} -.blog-links ul > li { - float: left; - margin-right: 5px; - text-align: center; - height: 24px; - width: 24px; - border-radius: 3px; - background: #f4f4f4; -} -.blog-links ul > li:hover { - background: #f4f4f4; -} -.blog-links ul > li > a { - border-bottom: 0; -} -.blog-links ul > li > a > i { - color: #606060; - font-size: 14px; - line-height: 24px; -} -.blog-links ul > li:hover a > i { - color: #444; -} \ No newline at end of file diff --git a/components/SiteNav/index.jsx b/components/SiteNav/index.jsx deleted file mode 100644 index be7ffd8..0000000 --- a/components/SiteNav/index.jsx +++ /dev/null @@ -1,29 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import { prefixLink } from 'gatsby-helpers'; -import './style.css'; - -class SiteNav extends React.Component { - render() { - return ( - - ); - } -} - -export default SiteNav; diff --git a/components/SiteNav/style.css b/components/SiteNav/style.css deleted file mode 100644 index 62e173e..0000000 --- a/components/SiteNav/style.css +++ /dev/null @@ -1,24 +0,0 @@ -.blog-nav { - margin: 20px 0px 10px; -} -.blog-nav ul { - list-style: none; - padding-left: 0; -} -.blog-nav ul li { - margin: 10px 0 10px; -} -.blog-nav ul li a { - font-size: 16px; - line-height: 26px; - margin-bottom: 26px; - border-bottom: 0; - font-weight: 400; - color: #222; -} -.blog-nav ul li a.current { - border-bottom: 1px solid; -} -.blog-nav ul li a:hover { - border-bottom: 1px solid; -} diff --git a/components/SitePage/index.jsx b/components/SitePage/index.jsx deleted file mode 100644 index b58e1ad..0000000 --- a/components/SitePage/index.jsx +++ /dev/null @@ -1,34 +0,0 @@ -import React from 'react'; -import SiteSidebar from '../SiteSidebar'; -import './style.css'; - -class SitePage extends React.Component { - render() { - const { route } = this.props; - const post = route.page.data; - - return ( -
- -
-
-
-
-
-

{post.title}

-
-
-
-
-
-
-
- ); - } -} - -SitePage.propTypes = { - route: React.PropTypes.object.isRequired, -}; - -export default SitePage; diff --git a/components/SitePage/style.css b/components/SitePage/style.css deleted file mode 100644 index 7107e8c..0000000 --- a/components/SitePage/style.css +++ /dev/null @@ -1,17 +0,0 @@ -.blog-page { - margin-bottom: 40px; -} -.blog-page h1 { - font-size: responsive 20px 36px; - margin-top: 0; -} -.blog-page p { - font-size: 16px; - line-height: 26px; - margin-bottom: 26px; -} -@media (max-width:900px) { - .blog-single .text, .blog-single .footer { - padding: 0 15px; - } -} \ No newline at end of file diff --git a/components/SitePost/index.jsx b/components/SitePost/index.jsx deleted file mode 100644 index c92aec7..0000000 --- a/components/SitePost/index.jsx +++ /dev/null @@ -1,51 +0,0 @@ -import React from 'react'; -import moment from 'moment'; -import { Link } from 'react-router'; -import { prefixLink } from 'gatsby-helpers'; -import { config } from 'config'; -import ReadNext from '../ReadNext'; -import './style.css'; -import '../../static/css/highlight.css'; - -class SitePost extends React.Component { - render() { - const { route } = this.props; - const post = route.page.data; - const home = ( -
- All Articles -
- ); - - return ( -
- {home} -
-
-

{post.title}

-
-
- Published {moment(post.date).format('D MMM YYYY')} -
-
-
- -
-

- {config.siteDescr} - -
{config.siteAuthor} on Twitter -
-

-
-
-
- ); - } -} - -SitePost.propTypes = { - route: React.PropTypes.object.isRequired, -}; - -export default SitePost; diff --git a/components/SitePost/style.css b/components/SitePost/style.css deleted file mode 100644 index 5e54d55..0000000 --- a/components/SitePost/style.css +++ /dev/null @@ -1,109 +0,0 @@ -.blog-post { - margin-bottom: 30px; -} -.blog-post:last-child { - margin-bottom: 10px; -} -.blog-post h2 { - margin-top: 10px; - line-height: 30px; - margin-bottom: 20px; -} -.blog-post h2 a { - color: #222; -} -.blog-post h2 a:hover, -.blog-post h2 a:focus { - border-bottom: 1px solid; -} -.blog-post p { - font-size: 16px; - line-height: 26px; - margin-bottom: 26px; -} -.blog-post time { - font-size: 14px; - color: #222; - font-weight: 500; - text-transform: uppercase; -} -.blog-post .blog-category { - font-size: 14px; - color: #f7a046; - font-weight: 500; - text-transform: uppercase; -} -.blog-post .readmore { - font-size: 16px; - color: #5d93ff; -} -.blog-post .readmore:hover { - border-bottom: 1px solid; -} -.blog-single { - max-width: 945px; - margin-left: auto; - margin-right: auto; -} -.blog-single h1 { - text-align: center; - margin-top: 30px; -} -.blog-single .text { - line-height: 31px; - margin-bottom: 31px; -} -.blog-single h1, .blog-single .date-published, .blog-single .text *:not(div) { - max-width: 630px; - margin-left: auto; - margin-right: auto; -} -.blog-single .text img { - max-width: 100%; - height: auto; -} -.blog-single .footer { - max-width: 630px; - margin-left: auto; - margin-right: auto; - line-height: 31px; - margin-bottom: 31px; -} -.gohome { - position: fixed; - left: 20px; - font-size: 16px; - text-align: center; - padding: 8px 16px; - color: #999; - background: #f4f4f4; - font-weight: 400; - border-radius: 3px; -} -.gohome:focus { - color: #444; - background: #f4f4f4; - border: 0; -} -.gohome:hover { - color: #444; - background: #f4f4f4; - border: 0; -} -@media (max-width:900px) { - .blog-single h1 { - margin-top: 15px; - } - .blog-single .text, .blog-single .footer { - padding: 0 15px; - line-height: 26px; - margin-bottom: 26px; - } - .gohome { - position: static; - margin: 20px auto 0; - text-align: center; - width: 85px; - display: block; - } -} \ No newline at end of file diff --git a/components/SiteSidebar/index.jsx b/components/SiteSidebar/index.jsx deleted file mode 100644 index 5726111..0000000 --- a/components/SiteSidebar/index.jsx +++ /dev/null @@ -1,64 +0,0 @@ -import React from 'react'; -import { Link } from 'react-router'; -import { prefixLink } from 'gatsby-helpers'; -import { config } from 'config'; -import SiteNav from '../SiteNav'; -import SiteLinks from '../SiteLinks'; -import './style.css'; -import profilePic from '../../pages/photo.jpg'; - -class SiteSidebar extends React.Component { - render() { - const { location } = this.props; - const isHome = location.pathname === prefixLink('/'); - - /* eslint-disable jsx-a11y/img-redundant-alt*/ - const header = ( -
- - Profile picture of the author - - { isHome ? ( -

{config.siteAuthor}

- ) : -

{config.siteAuthor}

} -

- {config.siteDescr} -

-
- ); - /* eslint-enable jsx-a11y/img-redundant-alt*/ - - return ( -
-
-
-
- {header} -
-
-
- -
- -

- © All rights reserved. -

-
-
-
-
- ); - } -} - -SiteSidebar.propTypes = { - location: React.PropTypes.object, -}; - -export default SiteSidebar; - diff --git a/components/SiteSidebar/style.css b/components/SiteSidebar/style.css deleted file mode 100644 index ada9676..0000000 --- a/components/SiteSidebar/style.css +++ /dev/null @@ -1,67 +0,0 @@ -.sidebar { - lost-column: 1/3; -} -.sidebar .sidebar-inner { - position: relative; - padding: 40px; -} -.sidebar .sidebar-inner:after { - background: #eee; - background: linear-gradient(to bottom, #eee 0%, #eee 48%, #fff 100%); - position: absolute; - content: ''; - width: 1px; - height: 540px; - top: 30px; - right: -10px; - bottom: 0; -} -.sidebar .sidebar-inner img { - display: inline-block; - margin-bottom: 0; - border-radius: 50%; - background-clip: padding-box; -} -.sidebar .sidebar-inner h1, .sidebar .sidebar-inner h2 { - font-size: 18px; - font-weight: 500; - line-height: 18px; - margin: 20px 0 10px; -} -.sidebar .sidebar-inner p { - color: #888; - font-size: 16px; - line-height: 26px; - margin-bottom: 26px; -} -.sidebar .sidebar-inner p.copyright { - color: #b6b6b6; - font-size: 14px; -} -@media (max-width:1100px) { - .sidebar .sidebar-inner { - padding: 35px 20px 0; - } - .sidebar { - lost-column: 1/2; - } -} -@media (max-width:900px) { - .sidebar { - lost-column: 5/12; - } - .sidebar .sidebar-inner { - padding: 30px 20px 0; - } -} -@media (max-width:500px) { - .sidebar { - lost-column: 1; - } - .sidebar .sidebar-inner { - padding: 25px 20px 0; - } - .sidebar .sidebar-inner:after { - display: none; - } -} \ No newline at end of file diff --git a/config.toml b/config.toml deleted file mode 100644 index c4aaeeb..0000000 --- a/config.toml +++ /dev/null @@ -1,14 +0,0 @@ -siteTitle = "Blog by John Doe" -siteDescr = "Lorem Ipsum is simply dummy text of the printing and typesetting industry." -siteAuthor = "John Doe" - -siteTelegramUrl = "#" -siteTwitterUrl = "#" -siteGithubUrl = "#" -siteEmailUrl = "#" -siteRssUrl = "#" -siteVkUrl = "#" - -googleAnalyticsId = "" - -linkPrefix = "/gatsby-starter-lumen" \ No newline at end of file diff --git a/gatsby-browser.js b/gatsby-browser.js deleted file mode 100644 index e5fdf07..0000000 --- a/gatsby-browser.js +++ /dev/null @@ -1,8 +0,0 @@ -import ReactGA from 'react-ga'; -import { config } from 'config'; - -ReactGA.initialize(config.googleAnalyticsId); - -exports.onRouteUpdate = (state) => { - ReactGA.pageview(state.pathname); -}; diff --git a/gatsby-config.js b/gatsby-config.js new file mode 100644 index 0000000..2923f5d --- /dev/null +++ b/gatsby-config.js @@ -0,0 +1,165 @@ +module.exports = { + siteMetadata: { + url: 'https://alxshelepenok.github.com/gatsby-starter-lumen', + title: 'Blog by John Doe', + subtitle: 'Pellentesque odio nisi, euismod in, pharetra a, ultricies in, diam. Sed arcu.', + copyright: '© All rights reserved.', + menu: [ + { + label: 'Articles', + path: '/' + }, + { + label: 'About me', + path: '/about/' + }, + { + label: 'Contact me', + path: '/contact/' + } + ], + author: { + name: 'John Doe', + email: '#', + telegram: '#', + twitter: '#', + github: '#', + rss: '#', + vk: '#' + } + }, + plugins: [ + { + resolve: 'gatsby-source-filesystem', + options: { + path: `${__dirname}/src/pages`, + name: 'pages' + } + }, + { + resolve: 'gatsby-plugin-feed', + options: { + query: ` + { + site { + siteMetadata { + url + title + subtitle + } + } + } + `, + feeds: [ + { + serialize: ({ query: { site, allMarkdownRemark } }) => ( + allMarkdownRemark.edges.map(edge => + Object.assign({}, edge.node.frontmatter, { + description: edge.node.frontmatter.description, + date: edge.node.frontmatter.date, + url: site.siteMetadata.url + edge.node.fields.slug, + guid: site.siteMetadata.url + edge.node.fields.slug, + custom_elements: [{ 'content:encoded': edge.node.html }] + }) + ) + ), + query: ` + { + allMarkdownRemark( + limit: 1000, + sort: { order: DESC, fields: [frontmatter___date] }, + filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } } + ) { + edges { + node { + html + fields { + slug + } + frontmatter { + title + date + layout + draft + description + } + } + } + } + } + `, + output: '/rss.xml' + } + ] + } + }, + { + resolve: 'gatsby-transformer-remark', + options: { + plugins: [ + { + resolve: 'gatsby-remark-images', + options: { + maxWidth: 960, + linkImagesToOriginal: false + } + }, + { + resolve: 'gatsby-remark-responsive-iframe', + options: { + wrapperStyle: 'margin-bottom: 1.0725rem' + } + }, + 'gatsby-remark-prismjs', + 'gatsby-remark-copy-linked-files', + 'gatsby-remark-smartypants' + ] + } + }, + 'gatsby-transformer-sharp', + 'gatsby-plugin-sharp', + { + resolve: 'gatsby-plugin-google-analytics', + options: { + trackingId: '' + } + }, + { + resolve: 'gatsby-plugin-sitemap', + options: { + query: ` + { + site { + siteMetadata { + url + } + } + allSitePage( + filter: { + path: { regex: "/^(?!/404/|/404.html|/dev-404-page/)/" } + } + ) { + edges { + node { + path + } + } + } + }`, + output: '/sitemap.xml', + serialize: ({ site, allSitePage }) => + allSitePage.edges.map((edge) => { + return { + url: site.siteMetadata.url + edge.node.path, + changefreq: 'daily', + priority: 0.7 + }; + }) + } + }, + 'gatsby-plugin-offline', + 'gatsby-plugin-catch-links', + 'gatsby-plugin-react-helmet', + 'gatsby-plugin-postcss-sass' + ] +}; diff --git a/gatsby-node.js b/gatsby-node.js index 0e71008..ff4b130 100644 --- a/gatsby-node.js +++ b/gatsby-node.js @@ -1,22 +1,203 @@ -const rucksack = require('rucksack-css'); +const _ = require('lodash'); +const Promise = require('bluebird'); +const path = require('path'); const lost = require('lost'); -const cssnext = require('postcss-cssnext'); +const pxtorem = require('postcss-pxtorem'); +const slash = require('slash'); -exports.modifyWebpackConfig = function (config) { +exports.createPages = ({ graphql, boundActionCreators }) => { + const { createPage } = boundActionCreators; + + return new Promise((resolve, reject) => { + const postTemplate = path.resolve('./src/templates/post-template.js'); + const pageTemplate = path.resolve('./src/templates/page-template.js'); + const tagTemplate = path.resolve('./src/templates/tag-template.js'); + const categoryTemplate = path.resolve('./src/templates/category-template.js'); + + graphql( + ` + { + allMarkdownRemark( + limit: 1000, + filter: { frontmatter: { layout: { eq: "post" }, draft: { ne: true } } }, + ) { + edges { + node { + fields { + slug + } + frontmatter { + tags + category + } + } + } + } + } + ` + ).then((result) => { + if (result.errors) { + console.log(result.errors); + reject(result.errors); + } + + _.each(result.data.allMarkdownRemark.edges, (edge) => { + createPage({ + path: edge.node.fields.slug, + component: slash(postTemplate), + context: { + slug: edge.node.fields.slug + } + }); + }); + + let tags = []; + _.each(result.data.allMarkdownRemark.edges, (edge) => { + if (_.get(edge, 'node.frontmatter.tags')) { + tags = tags.concat(edge.node.frontmatter.tags); + } + }); + tags = _.uniq(tags); + _.each(tags, (tag) => { + const tagPath = `/tags/${_.kebabCase(tag)}/`; + createPage({ + path: tagPath, + component: tagTemplate, + context: { + tag + } + }); + }); + + let categories = []; + _.each(result.data.allMarkdownRemark.edges, (edge) => { + if (_.get(edge, 'node.frontmatter.category')) { + categories = categories.concat(edge.node.frontmatter.category); + } + }); + categories = _.uniq(categories); + _.each(categories, (category) => { + const categoryPath = `/categories/${_.kebabCase(category)}/`; + createPage({ + path: categoryPath, + component: categoryTemplate, + context: { + category + } + }); + }); + + resolve(); + }); + + graphql( + ` + { + allMarkdownRemark( + limit: 1000, + filter: { frontmatter: { layout: { eq: "page" }, draft: { ne: true } } }, + ) { + edges { + node { + fields { + slug + } + frontmatter { + path + } + } + } + } + } + ` + ).then((result) => { + if (result.errors) { + console.log(result.errors); + reject(result.errors); + } + + _.each(result.data.allMarkdownRemark.edges, (edge) => { + createPage({ + path: edge.node.fields.slug, + component: slash(pageTemplate), + context: { + slug: edge.node.fields.slug + } + }); + }); + + resolve(); + }); + }); +}; + +exports.onCreateNode = ({ node, boundActionCreators, getNode }) => { + const { createNodeField } = boundActionCreators; + + if (node.internal.type === 'File') { + const parsedFilePath = path.parse(node.absolutePath); + const slug = `/${parsedFilePath.dir.split('---')[1]}/`; + createNodeField({ node, name: 'slug', value: slug }); + } else if ( + node.internal.type === 'MarkdownRemark' && + typeof node.slug === 'undefined' + ) { + const fileNode = getNode(node.parent); + let slug = fileNode.fields.slug; + if (typeof node.frontmatter.path !== 'undefined') { + slug = node.frontmatter.path; + } + createNodeField({ + node, + name: 'slug', + value: slug + }); + + if (typeof node.frontmatter.tags !== 'undefined') { + const tagSlugs = node.frontmatter.tags.map( + tag => `/tags/${_.kebabCase(tag)}/` + ); + createNodeField({ node, name: 'tagSlugs', value: tagSlugs }); + } + + if (typeof node.frontmatter.category !== 'undefined') { + const categorySlug = `/categories/${_.kebabCase(node.frontmatter.category)}/`; + createNodeField({ node, name: 'categorySlug', value: categorySlug }); + } + } +}; + +exports.modifyWebpackConfig = ({ config }) => { config.merge({ postcss: [ lost(), - rucksack(), - cssnext({ - browsers: ['>1%', 'last 2 versions'], - }), - ], + pxtorem({ + rootValue: 16, + unitPrecision: 5, + propList: [ + 'font', + 'font-size', + 'line-height', + 'letter-spacing', + 'margin', + 'margin-top', + 'margin-left', + 'margin-bottom', + 'margin-right', + 'padding', + 'padding-top', + 'padding-left', + 'padding-bottom', + 'padding-right', + 'border-radius', + 'width', + 'max-width' + ], + selectorBlackList: [], + replace: true, + mediaQuery: false, + minPixelValue: 0 + }) + ] }); - - config.loader('svg', { - test: /\.(svg)(\?v=[0-9]\.[0-9]\.[0-9])?$/, - loader: 'file-loader', - }); - - return config; }; diff --git a/html.js b/html.js deleted file mode 100644 index e9bec80..0000000 --- a/html.js +++ /dev/null @@ -1,39 +0,0 @@ -import React from 'react'; -import Helmet from 'react-helmet'; -import { prefixLink } from 'gatsby-helpers'; - -const BUILD_TIME = new Date().getTime(); - -module.exports = React.createClass({ - displayName: 'HTML', - propTypes: { - body: React.PropTypes.string, - }, - render() { - const { body } = this.props; - const { title } = Helmet.rewind(); - const font = ; - let css; - if (process.env.NODE_ENV === 'production') { - // eslint-disable-next-line import/no-webpack-loader-syntax - css = + + + + +
+

+ fontello + font demo +

+ +
+
+
+
icon-mail0xe800
+
icon-twitter0xf099
+
icon-facebook0xf09a
+
icon-rss0xf09e
+
+
+
icon-linkedin0xf0e1
+
icon-github0xf113
+
icon-stackoverflow0xf16c
+
icon-instagram0xf16d
+
+
+
icon-tumblr0xf173
+
icon-dribbble0xf17d
+
icon-skype0xf17e
+
icon-vkontakte0xf189
+
+
+
icon-slack0xf198
+
icon-paper-plane0xf1d8
+
icon-whatsapp0xf232
+
icon-odnoklassniki0xf263
+
+
+ + + \ No newline at end of file diff --git a/src/assets/fonts/fontello-771c82e0/font/fontello.eot b/src/assets/fonts/fontello-771c82e0/font/fontello.eot new file mode 100644 index 0000000..ce63906 Binary files /dev/null and b/src/assets/fonts/fontello-771c82e0/font/fontello.eot differ diff --git a/src/assets/fonts/fontello-771c82e0/font/fontello.svg b/src/assets/fonts/fontello-771c82e0/font/fontello.svg new file mode 100644 index 0000000..05e20b9 --- /dev/null +++ b/src/assets/fonts/fontello-771c82e0/font/fontello.svg @@ -0,0 +1,42 @@ + + + +Copyright (C) 2017 by original authors @ fontello.com + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/assets/fonts/fontello-771c82e0/font/fontello.ttf b/src/assets/fonts/fontello-771c82e0/font/fontello.ttf new file mode 100644 index 0000000..cdebc64 Binary files /dev/null and b/src/assets/fonts/fontello-771c82e0/font/fontello.ttf differ diff --git a/src/assets/fonts/fontello-771c82e0/font/fontello.woff b/src/assets/fonts/fontello-771c82e0/font/fontello.woff new file mode 100644 index 0000000..fabd68f Binary files /dev/null and b/src/assets/fonts/fontello-771c82e0/font/fontello.woff differ diff --git a/src/assets/fonts/fontello-771c82e0/font/fontello.woff2 b/src/assets/fonts/fontello-771c82e0/font/fontello.woff2 new file mode 100644 index 0000000..7e411fc Binary files /dev/null and b/src/assets/fonts/fontello-771c82e0/font/fontello.woff2 differ diff --git a/src/assets/scss/_base.scss b/src/assets/scss/_base.scss new file mode 100644 index 0000000..578feca --- /dev/null +++ b/src/assets/scss/_base.scss @@ -0,0 +1,5 @@ +@charset "UTF-8"; + +@import "base/normalize"; +@import "base/generic"; +@import "base/highlight"; \ No newline at end of file diff --git a/src/assets/scss/_mixins.scss b/src/assets/scss/_mixins.scss new file mode 100644 index 0000000..783c4f1 --- /dev/null +++ b/src/assets/scss/_mixins.scss @@ -0,0 +1,6 @@ +@charset "UTF-8"; + +@import "mixins/breakpoints"; +@import "mixins/margin"; +@import "mixins/padding"; +@import "mixins/line-height"; \ No newline at end of file diff --git a/src/assets/scss/_pages.scss b/src/assets/scss/_pages.scss new file mode 100644 index 0000000..a6ba449 --- /dev/null +++ b/src/assets/scss/_pages.scss @@ -0,0 +1,4 @@ +@charset "UTF-8"; + +@import "pages/tags"; +@import "pages/categories"; \ No newline at end of file diff --git a/src/assets/scss/_variables.scss b/src/assets/scss/_variables.scss new file mode 100644 index 0000000..f87df2e --- /dev/null +++ b/src/assets/scss/_variables.scss @@ -0,0 +1,37 @@ +/** + * Variables + */ + +// Colors +$color-base: #222; +$color-primary: #5d93ff; +$color-secondary: #f7a046; + +$color-white: lighten($color-base, 100%); +$color-gray: lighten($color-base, 40%); +$color-gray-border: lighten($color-base, 77%); +$color-gray-bg: lighten($color-base, 79%); + +// Typographic +$typographic-font-family: "Roboto", "Helvetica Neue", "Helvetica", "Arial", sans-serif; + +$typographic-root-font-size: 100; +$typographic-base-font-size: 16px; +$typographic-small-font-size: 14px; + +$typographic-base-line-height: 1.625; + +$typographic-base-font-color: $color-base; +$typographic-link-p-font-color: $color-primary; +$typographic-link-s-font-color: $color-secondary; + +$typographic-leading: round(16 * ($typographic-root-font-size / 100) * $typographic-base-line-height); + +// Layout +$layout-post-single-max-width: 945px; +$layout-post-single-width: $layout-post-single-max-width - 305px; + +$layout-width: 1070px; +$layout-breakpoint-sm: 685px; +$layout-breakpoint-md: 960px; +$layout-breakpoint-lg: 1100px; diff --git a/src/assets/scss/base/_generic.scss b/src/assets/scss/base/_generic.scss new file mode 100644 index 0000000..a00ad1c --- /dev/null +++ b/src/assets/scss/base/_generic.scss @@ -0,0 +1,182 @@ +/** + * Generic + */ + +html { + font-size: $typographic-root-font-size; +} + +body { + font-family: $typographic-font-family; + color: $typographic-base-font-color; + line-height: $typographic-base-line-height; + font-size: $typographic-base-font-size; + -ms-text-size-adjust: 100%; + -webkit-text-size-adjust: 100%; + text-rendering: optimizeLegibility; + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; +} + +h1, +h2, +h3, +h4, +h5, +h6 { + font-family: $typographic-font-family; + font-weight: 500; +} + +h1 { + font-size: $typographic-base-font-size * 2.5; + @include line-height(2); + @include margin-top(4); + @include margin-bottom(1); +} + +h2 { + font-size: $typographic-base-font-size * 1.6875; + @include line-height(1.5); + @include margin-top(2); + @include margin-bottom(.5); +} + +h3 { + font-size: $typographic-base-font-size * 1.375; + @include line-height(1); + @include margin-top(2); + @include margin-bottom(.5); +} + +h4 { + font-size: $typographic-base-font-size * 1.2; + @include line-height(1); + @include margin-top(1.5); + @include margin-bottom(.5); +} + +h5 { + font-size: $typographic-base-font-size; + @include line-height(1); + @include margin-top(2.5); + @include margin-bottom(.5); +} + +h6 { + font-size: $typographic-base-font-size; + @include line-height(1); + @include margin-top(2.5); + @include margin-bottom(.5); +} + +img { + border: 0; + max-width: 100%; + display: block; + margin: inherit auto; +} + +hr { + margin-top: 52px; + margin-bottom: 52px; + border: 0; + color: $color-base; + display: block; + height: 26px; + margin-right: auto; + margin-left: auto; + background-size: 100% 26px; + background-image: linear-gradient(to bottom, transparent 1px, transparent 11px, $color-base 11px, $color-base 15px, transparent 15px, transparent 26px); + width: 100px; +} + +a { + color: $typographic-link-p-font-color; + text-decoration: none; + &:hover, + &:focus, + &:active { + color: $typographic-link-s-font-color; + } +} + +b, +strong { + font-weight: 500; +} + +ul { + list-style: square; + @include margin-bottom(1); + & li { + padding: 0 5px; + margin-bottom: 10px; + } +} + +p { + @include line-height(1); + @include margin-bottom(1); +} + +blockquote { + padding: 0; + font-style: italic; + text-align: center; +} + +figure { + display: block; + width: 100%; + height: auto; +} + +figcaption { + @include line-height(.75); + @include margin-top(.25); + color: $color-base; + font-size: $typographic-small-font-size; + font-style: italic; + margin-bottom: 0; + text-align: center; +} + +.layout { + lost-center: $layout-width; +} + +.content { + &__inner { + padding: 25px 20px; + } +} + +@include breakpoint-sm { + figure.float-left, + figure.float-right { + max-width: 310px; + @include padding(0, 1, 0, 1); + } + .float-right { + float: right; + } + .float-left { + float: left; + } + .content { + lost-column: 7/12; + &__inner { + padding: 30px 20px; + } + } +} + +@include breakpoint-md { + .content { + lost-column: 2/3; + &__inner { + padding: 40px 35px; + } + } +} diff --git a/src/assets/scss/base/_highlight.scss b/src/assets/scss/base/_highlight.scss new file mode 100644 index 0000000..fe19882 --- /dev/null +++ b/src/assets/scss/base/_highlight.scss @@ -0,0 +1,137 @@ +/** + * prism.js default theme for JavaScript, CSS and HTML + * Based on dabblet (http://dabblet.com) + * @author Lea Verou + */ + +code[class*="language-"], +pre[class*="language-"] { + color: black; + background: none; + text-shadow: 0 1px white; + font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; + 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; + -moz-hyphens: none; + -ms-hyphens: none; + hyphens: none; +} + +pre[class*="language-"]::-moz-selection, pre[class*="language-"] ::-moz-selection, +code[class*="language-"]::-moz-selection, code[class*="language-"] ::-moz-selection { + text-shadow: none; + background: #b3d4fc; +} + +pre[class*="language-"]::selection, pre[class*="language-"] ::selection, +code[class*="language-"]::selection, code[class*="language-"] ::selection { + text-shadow: none; + background: #b3d4fc; +} + +@media print { + code[class*="language-"], + pre[class*="language-"] { + text-shadow: none; + } +} + +/* Code blocks */ +pre[class*="language-"] { + padding: 1em; + margin: .5em 0; + overflow: auto; +} + +:not(pre) > code[class*="language-"], +pre[class*="language-"] { + background: #f5f2f0; +} + +/* Inline code */ +:not(pre) > code[class*="language-"] { + padding: .1em; + border-radius: .3em; + white-space: normal; +} + +.token.comment, +.token.prolog, +.token.doctype, +.token.cdata { + color: slategray; +} + +.token.punctuation { + color: #999; +} + +.namespace { + opacity: .7; +} + +.token.property, +.token.tag, +.token.boolean, +.token.number, +.token.constant, +.token.symbol, +.token.deleted { + color: #905; +} + +.token.selector, +.token.attr-name, +.token.string, +.token.char, +.token.builtin, +.token.inserted { + color: #690; +} + +.token.operator, +.token.entity, +.token.url, +.language-css .token.string, +.style .token.string { + color: #a67f59; + background: hsla(0, 0%, 100%, .5); +} + +.token.atrule, +.token.attr-value, +.token.keyword { + color: #07a; +} + +.token.function { + color: #DD4A68; +} + +.token.regex, +.token.important, +.token.variable { + color: #e90; +} + +.token.important, +.token.bold { + font-weight: bold; +} +.token.italic { + font-style: italic; +} + +.token.entity { + cursor: help; +} diff --git a/src/assets/scss/base/_normalize.scss b/src/assets/scss/base/_normalize.scss new file mode 100644 index 0000000..21cd194 --- /dev/null +++ b/src/assets/scss/base/_normalize.scss @@ -0,0 +1,461 @@ +/*! normalize.css v5.0.0 | MIT License | github.com/necolas/normalize.css */ + +/** + * 1. Change the default font family in all browsers (opinionated). + * 2. Correct the line height in all browsers. + * 3. Prevent adjustments of font size after orientation changes in + * IE on Windows Phone and in iOS. + */ + +/* Document + ========================================================================== */ + +html { + font-family: sans-serif; /* 1 */ + line-height: 1.15; /* 2 */ + -ms-text-size-adjust: 100%; /* 3 */ + -webkit-text-size-adjust: 100%; /* 3 */ +} + +/* Sections + ========================================================================== */ + +/** + * Remove the margin in all browsers (opinionated). + */ + +body { + margin: 0; +} + +/** + * Add the correct display in IE 9-. + */ + +article, +aside, +footer, +header, +nav, +section { + display: block; +} + +/** + * Correct the font size and margin on `h1` elements within `section` and + * `article` contexts in Chrome, Firefox, and Safari. + */ + +h1 { + font-size: 2em; + margin: 0.67em 0; +} + +/* Grouping content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + * 1. Add the correct display in IE. + */ + +figcaption, +figure, +main { /* 1 */ + display: block; +} + +/** + * Add the correct margin in IE 8. + */ + +figure { + margin: 1em 40px; +} + +/** + * 1. Add the correct box sizing in Firefox. + * 2. Show the overflow in Edge and IE. + */ + +hr { + box-sizing: content-box; /* 1 */ + height: 0; /* 1 */ + overflow: visible; /* 2 */ +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +pre { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/* Text-level semantics + ========================================================================== */ + +/** + * 1. Remove the gray background on active links in IE 10. + * 2. Remove gaps in links underline in iOS 8+ and Safari 8+. + */ + +a { + background-color: transparent; /* 1 */ + -webkit-text-decoration-skip: objects; /* 2 */ +} + +/** + * Remove the outline on focused links when they are also active or hovered + * in all browsers (opinionated). + */ + +a:active, +a:hover { + outline-width: 0; +} + +/** + * 1. Remove the bottom border in Firefox 39-. + * 2. Add the correct text decoration in Chrome, Edge, IE, Opera, and Safari. + */ + +abbr[title] { + border-bottom: none; /* 1 */ + text-decoration: underline; /* 2 */ + text-decoration: underline dotted; /* 2 */ +} + +/** + * Prevent the duplicate application of `bolder` by the next rule in Safari 6. + */ + +b, +strong { + font-weight: inherit; +} + +/** + * Add the correct font weight in Chrome, Edge, and Safari. + */ + +b, +strong { + font-weight: bolder; +} + +/** + * 1. Correct the inheritance and scaling of font size in all browsers. + * 2. Correct the odd `em` font sizing in all browsers. + */ + +code, +kbd, +samp { + font-family: monospace, monospace; /* 1 */ + font-size: 1em; /* 2 */ +} + +/** + * Add the correct font style in Android 4.3-. + */ + +dfn { + font-style: italic; +} + +/** + * Add the correct background and color in IE 9-. + */ + +mark { + background-color: #ff0; + color: #000; +} + +/** + * Add the correct font size in all browsers. + */ + +small { + font-size: 80%; +} + +/** + * Prevent `sub` and `sup` elements from affecting the line height in + * all browsers. + */ + +sub, +sup { + font-size: 75%; + line-height: 0; + position: relative; + vertical-align: baseline; +} + +sub { + bottom: -0.25em; +} + +sup { + top: -0.5em; +} + +/* Embedded content + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +audio, +video { + display: inline-block; +} + +/** + * Add the correct display in iOS 4-7. + */ + +audio:not([controls]) { + display: none; + height: 0; +} + +/** + * Remove the border on images inside links in IE 10-. + */ + +img { + border-style: none; +} + +/** + * Hide the overflow in IE. + */ + +svg:not(:root) { + overflow: hidden; +} + +/* Forms + ========================================================================== */ + +/** + * 1. Change the font styles in all browsers (opinionated). + * 2. Remove the margin in Firefox and Safari. + */ + +button, +input, +optgroup, +select, +textarea { + font-family: sans-serif; /* 1 */ + font-size: 100%; /* 1 */ + line-height: 1.15; /* 1 */ + margin: 0; /* 2 */ +} + +/** + * Show the overflow in IE. + * 1. Show the overflow in Edge. + */ + +button, +input { /* 1 */ + overflow: visible; +} + +/** + * Remove the inheritance of text transform in Edge, Firefox, and IE. + * 1. Remove the inheritance of text transform in Firefox. + */ + +button, +select { /* 1 */ + text-transform: none; +} + +/** + * 1. Prevent a WebKit bug where (2) destroys native `audio` and `video` + * controls in Android 4. + * 2. Correct the inability to style clickable types in iOS and Safari. + */ + +button, +html [type="button"], /* 1 */ +[type="reset"], +[type="submit"] { + -webkit-appearance: button; /* 2 */ +} + +/** + * Remove the inner border and padding in Firefox. + */ + +button::-moz-focus-inner, +[type="button"]::-moz-focus-inner, +[type="reset"]::-moz-focus-inner, +[type="submit"]::-moz-focus-inner { + border-style: none; + padding: 0; +} + +/** + * Restore the focus styles unset by the previous rule. + */ + +button:-moz-focusring, +[type="button"]:-moz-focusring, +[type="reset"]:-moz-focusring, +[type="submit"]:-moz-focusring { + outline: 1px dotted ButtonText; +} + +/** + * Change the border, margin, and padding in all browsers (opinionated). + */ + +fieldset { + border: 1px solid #c0c0c0; + margin: 0 2px; + padding: 0.35em 0.625em 0.75em; +} + +/** + * 1. Correct the text wrapping in Edge and IE. + * 2. Correct the color inheritance from `fieldset` elements in IE. + * 3. Remove the padding so developers are not caught out when they zero out + * `fieldset` elements in all browsers. + */ + +legend { + box-sizing: border-box; /* 1 */ + color: inherit; /* 2 */ + display: table; /* 1 */ + max-width: 100%; /* 1 */ + padding: 0; /* 3 */ + white-space: normal; /* 1 */ +} + +/** + * 1. Add the correct display in IE 9-. + * 2. Add the correct vertical alignment in Chrome, Firefox, and Opera. + */ + +progress { + display: inline-block; /* 1 */ + vertical-align: baseline; /* 2 */ +} + +/** + * Remove the default vertical scrollbar in IE. + */ + +textarea { + overflow: auto; +} + +/** + * 1. Add the correct box sizing in IE 10-. + * 2. Remove the padding in IE 10-. + */ + +[type="checkbox"], +[type="radio"] { + box-sizing: border-box; /* 1 */ + padding: 0; /* 2 */ +} + +/** + * Correct the cursor style of increment and decrement buttons in Chrome. + */ + +[type="number"]::-webkit-inner-spin-button, +[type="number"]::-webkit-outer-spin-button { + height: auto; +} + +/** + * 1. Correct the odd appearance in Chrome and Safari. + * 2. Correct the outline style in Safari. + */ + +[type="search"] { + -webkit-appearance: textfield; /* 1 */ + outline-offset: -2px; /* 2 */ +} + +/** + * Remove the inner padding and cancel buttons in Chrome and Safari on macOS. + */ + +[type="search"]::-webkit-search-cancel-button, +[type="search"]::-webkit-search-decoration { + -webkit-appearance: none; +} + +/** + * 1. Correct the inability to style clickable types in iOS and Safari. + * 2. Change font properties to `inherit` in Safari. + */ + +::-webkit-file-upload-button { + -webkit-appearance: button; /* 1 */ + font: inherit; /* 2 */ +} + +/* Interactive + ========================================================================== */ + +/* + * Add the correct display in IE 9-. + * 1. Add the correct display in Edge, IE, and Firefox. + */ + +details, /* 1 */ +menu { + display: block; +} + +/* + * Add the correct display in all browsers. + */ + +summary { + display: list-item; +} + +/* Scripting + ========================================================================== */ + +/** + * Add the correct display in IE 9-. + */ + +canvas { + display: inline-block; +} + +/** + * Add the correct display in IE. + */ + +template { + display: none; +} + +/* Hidden + ========================================================================== */ + +/** + * Add the correct display in IE 10-. + */ + +[hidden] { + display: none; +} \ No newline at end of file diff --git a/src/assets/scss/init.scss b/src/assets/scss/init.scss new file mode 100644 index 0000000..23d512c --- /dev/null +++ b/src/assets/scss/init.scss @@ -0,0 +1,6 @@ +@charset "UTF-8"; + +@import "variables"; +@import "mixins"; +@import "base"; +@import "pages"; \ No newline at end of file diff --git a/src/assets/scss/mixins/_breakpoints.scss b/src/assets/scss/mixins/_breakpoints.scss new file mode 100644 index 0000000..f7909ed --- /dev/null +++ b/src/assets/scss/mixins/_breakpoints.scss @@ -0,0 +1,25 @@ +/** + * Breakpoints + */ + +@mixin breakpoint-xs { + @content; +} + +@mixin breakpoint-sm { + @media screen and (min-width: $layout-breakpoint-sm) { + @content; + } +} + +@mixin breakpoint-md { + @media screen and (min-width: $layout-breakpoint-md) { + @content; + } +} + +@mixin breakpoint-lg { + @media screen and (min-width: $layout-breakpoint-lg) { + @content + } +} diff --git a/src/assets/scss/mixins/_line-height.scss b/src/assets/scss/mixins/_line-height.scss new file mode 100644 index 0000000..24b3fe4 --- /dev/null +++ b/src/assets/scss/mixins/_line-height.scss @@ -0,0 +1,7 @@ +/** + * Line-Height + */ + +@mixin line-height($number) { + line-height: #{ $number * $typographic-leading + "px"}; +} diff --git a/src/assets/scss/mixins/_margin.scss b/src/assets/scss/mixins/_margin.scss new file mode 100644 index 0000000..fdc93f8 --- /dev/null +++ b/src/assets/scss/mixins/_margin.scss @@ -0,0 +1,23 @@ +/** + * Margin + */ + +@mixin margin-top($number) { + margin-top: #{ $number * $typographic-leading + "px"}; +} + +@mixin margin-bottom($number) { + margin-bottom: #{ $number * $typographic-leading + "px"}; +} + +@mixin margin($top, $right, $bottom:null, $left:null) { + @if $left==null and $bottom==null { + margin: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"}; + } + @else if $left==null or $left==$right { + margin: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"} #{ $bottom * $typographic-leading + "px"}; + } + @else { + margin: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"} #{ $bottom * $typographic-leading + "px"} #{ $left * $typographic-leading + "px"}; + } +} diff --git a/src/assets/scss/mixins/_padding.scss b/src/assets/scss/mixins/_padding.scss new file mode 100644 index 0000000..77858e4 --- /dev/null +++ b/src/assets/scss/mixins/_padding.scss @@ -0,0 +1,19 @@ +/** + * Padding + */ + +@mixin padding($top, $right, $bottom:null, $left:null) { + @if $left==null and $bottom==null { + padding: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"}; + } + @else if $left==null or $left==$right { + padding: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"} #{ $bottom * $typographic-leading + "px"}; + } + @else { + padding: #{ $top * $typographic-leading + "px"} #{ $right * $typographic-leading + "px"} #{ $bottom * $typographic-leading + "px"} #{ $left * $typographic-leading + "px"}; + } +} + +@mixin padding-equal($number) { + padding: #{ $number * $typographic-leading + "px"}; +} diff --git a/src/assets/scss/pages/_categories.scss b/src/assets/scss/pages/_categories.scss new file mode 100644 index 0000000..f919ae4 --- /dev/null +++ b/src/assets/scss/pages/_categories.scss @@ -0,0 +1,18 @@ +/** + * Categories + */ + +.categories { + &__list { + &-item { + &-link { + color: $color-base; + &:hover, + &:focus { + color: $color-primary; + border-bottom: 1px solid $color-primary; + } + } + } + } +} diff --git a/src/assets/scss/pages/_tags.scss b/src/assets/scss/pages/_tags.scss new file mode 100644 index 0000000..e1ceb21 --- /dev/null +++ b/src/assets/scss/pages/_tags.scss @@ -0,0 +1,18 @@ +/** + * Tags + */ + +.tags { + &__list { + &-item { + &-link { + color: $color-base; + &:hover, + &:focus { + color: $color-primary; + border-bottom: 1px solid $color-primary; + } + } + } + } +} diff --git a/src/components/CategoryTemplateDetails/index.jsx b/src/components/CategoryTemplateDetails/index.jsx new file mode 100644 index 0000000..8fc7d98 --- /dev/null +++ b/src/components/CategoryTemplateDetails/index.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Post from '../Post'; + +class CategoryTemplateDetails extends React.Component { + render() { + const items = []; + const category = this.props.pathContext.category; + const posts = this.props.data.allMarkdownRemark.edges; + posts.forEach((post) => { + items.push( + + ); + }); + + return ( +
+
+
+

+ {category} +

+
+ {items} +
+
+
+
+ ); + } +} + +CategoryTemplateDetails.propTypes = { + data: PropTypes.shape({ + allMarkdownRemark: PropTypes.shape({ + edges: PropTypes.array.isRequired + }) + }), + pathContext: PropTypes.shape({ + category: PropTypes.string.isRequired + }) +}; + +export default CategoryTemplateDetails; diff --git a/src/components/Links/index.jsx b/src/components/Links/index.jsx new file mode 100644 index 0000000..135a203 --- /dev/null +++ b/src/components/Links/index.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import './style.scss'; +import '../../assets/fonts/fontello-771c82e0/css/fontello.css'; + +class Links extends React.Component { + render() { + const author = this.props.data; + const links = { + telegram: author.telegram, + twitter: author.twitter, + github: author.github, + vk: author.vk, + rss: author.rss, + email: author.email + }; + + return ( +
+ + + +
+ ); + } +} + +Links.propTypes = { + data: PropTypes.object.isRequired +}; + +export default Links; diff --git a/src/components/Links/style.scss b/src/components/Links/style.scss new file mode 100644 index 0000000..6f2af32 --- /dev/null +++ b/src/components/Links/style.scss @@ -0,0 +1,35 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.links { + @include margin-bottom(1); + &__list { + display: flex; + list-style: none; + padding: 0; + margin: 10px -3px; + &-item { + padding: 0; + margin: 0 3px; + height: 24px; + width: 24px; + line-height: 24px; + border-radius: 3px; + text-align: center; + background: $color-gray-bg; + & a { + border: 0; + & i { + font-size: 14px; + color: lighten($color-base, 20%); + } + &:hover, + &:focus { + & i { + color: $color-base; + } + } + } + } + } +} diff --git a/src/components/Menu/index.jsx b/src/components/Menu/index.jsx new file mode 100644 index 0000000..b2c4821 --- /dev/null +++ b/src/components/Menu/index.jsx @@ -0,0 +1,38 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Link from 'gatsby-link'; +import './style.scss'; + +class Menu extends React.Component { + render() { + const menu = this.props.data; + + const menuBlock = ( +
    + {menu.map(item => +
  • + + {item.label} + +
  • + )} +
+ ); + + return ( + + ); + } +} + +Menu.propTypes = { + data: PropTypes.array.isRequired +}; + +export default Menu; diff --git a/src/components/Menu/style.scss b/src/components/Menu/style.scss new file mode 100644 index 0000000..8c2efc8 --- /dev/null +++ b/src/components/Menu/style.scss @@ -0,0 +1,30 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.menu { + @include margin-bottom(1); + &__list { + list-style: none; + padding: 0; + margin: 0; + &-item { + padding: 0; + margin: 10px 0; + &-link { + font-size: $typographic-base-font-size; + color: $typographic-base-font-color; + font-weight: 400; + border: 0; + &:hover, + &:focus { + color: $color-primary; + border-bottom: 1px solid $color-primary; + } + &--active { + color: $color-base; + border-bottom: 1px solid $color-base; + } + } + } + } +} diff --git a/src/components/PageTemplateDetails/index.jsx b/src/components/PageTemplateDetails/index.jsx new file mode 100644 index 0000000..0462720 --- /dev/null +++ b/src/components/PageTemplateDetails/index.jsx @@ -0,0 +1,32 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Sidebar from '../Sidebar'; +import './style.scss'; + +class PageTemplateDetails extends React.Component { + render() { + const page = this.props.data.markdownRemark; + + return ( +
+ +
+
+
+

{page.frontmatter.title}

+
+
+
+
+
+ ); + } +} + +PageTemplateDetails.propTypes = { + data: PropTypes.shape({ + markdownRemark: PropTypes.object.isRequired + }) +}; + +export default PageTemplateDetails; diff --git a/src/components/PageTemplateDetails/style.scss b/src/components/PageTemplateDetails/style.scss new file mode 100644 index 0000000..5b060f1 --- /dev/null +++ b/src/components/PageTemplateDetails/style.scss @@ -0,0 +1,18 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.page { + @include margin-bottom(2); + &__title { + font-size: $typographic-base-font-size * 2.5; + font-weight: 500; + @include line-height(2); + @include margin-top(0); + @include margin-bottom(1.45); + } + &__body { + font-size: $typographic-base-font-size; + @include line-height(1); + @include margin(0, 0, 1); + } +} diff --git a/src/components/Post/index.jsx b/src/components/Post/index.jsx new file mode 100644 index 0000000..38ba166 --- /dev/null +++ b/src/components/Post/index.jsx @@ -0,0 +1,46 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Link from 'gatsby-link'; +import moment from 'moment'; +import './style.scss'; + +class Post extends React.Component { + render() { + const data = this.props.data; + const post = { + title: data.node.frontmatter.title, + slug: data.node.fields.slug, + description: data.node.frontmatter.description, + date: data.node.frontmatter.date, + category: data.node.frontmatter.category, + categorySlug: data.node.fields.categorySlug + }; + + return ( +
+
+ + + + + {post.category} + + +
+

+ {post.title} +

+

{post.description}

+ Read +
+ ); + } +} + +Post.propTypes = { + data: PropTypes.object.isRequired +}; + +export default Post; diff --git a/src/components/Post/style.scss b/src/components/Post/style.scss new file mode 100644 index 0000000..1819223 --- /dev/null +++ b/src/components/Post/style.scss @@ -0,0 +1,60 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.post { + @include margin-bottom(1.25); + &:last-child { + @include margin-bottom(.5); + } + &__title { + font-size: $typographic-base-font-size * 1.6875; + @include line-height(1.5); + @include margin-top(0); + @include margin-bottom(.5); + &-link { + color: $color-base; + &:hover, + &:focus { + color: $color-base; + border-bottom: 1px solid $color-base; + } + } + } + &__description { + font-size: $typographic-base-font-size; + @include line-height(1); + @include margin-bottom(.75); + } + &__meta { + &-time { + font-size: $typographic-small-font-size; + color: $color-base; + font-weight: 500; + text-transform: uppercase; + } + &-divider { + margin: 0 5px; + } + &-category { + &-link { + font-size: $typographic-small-font-size; + color: $color-secondary; + font-weight: 500; + text-transform: uppercase; + &:hover, + &:focus { + color: $color-primary; + } + } + } + } + &__readmore { + font-size: $typographic-base-font-size; + color: $color-primary; + &:hover, + &:focus { + color: $color-primary; + border-bottom: 1px solid $color-primary; + } + } +} \ No newline at end of file diff --git a/src/components/PostTemplateDetails/index.jsx b/src/components/PostTemplateDetails/index.jsx new file mode 100644 index 0000000..6620951 --- /dev/null +++ b/src/components/PostTemplateDetails/index.jsx @@ -0,0 +1,72 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Link from 'gatsby-link'; +import moment from 'moment'; +import './style.scss'; + +class PostTemplateDetails extends React.Component { + render() { + const { subtitle, author } = this.props.data.site.siteMetadata; + const post = this.props.data.markdownRemark; + const tags = post.fields.tagSlugs; + + const homeBlock = ( +
+ All Articles +
+ ); + + const tagsBlock = ( +
+
    + {tags.map((tag, i) => +
  • + + {post.frontmatter.tags[i]} + +
  • + )} +
+
+ ); + + return ( +
+ {homeBlock} +
+
+

{post.frontmatter.title}

+
+
+ Published {moment(post.frontmatter.date).format('D MMM YYYY')} +
+
+
+ {tagsBlock} +
+

+ {subtitle} + +
{author.name} on Twitter +
+

+
+
+
+ ); + } +} + +PostTemplateDetails.propTypes = { + data: PropTypes.shape({ + site: PropTypes.shape({ + siteMetadata: PropTypes.shape({ + subtitle: PropTypes.string.isRequired, + author: PropTypes.object.isRequired + }) + }), + markdownRemark: PropTypes.object.isRequired + }) +}; + +export default PostTemplateDetails; diff --git a/src/components/PostTemplateDetails/style.scss b/src/components/PostTemplateDetails/style.scss new file mode 100644 index 0000000..b4ff5c9 --- /dev/null +++ b/src/components/PostTemplateDetails/style.scss @@ -0,0 +1,166 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.post-single { + &__inner { + max-width: $layout-post-single-max-width; + padding: 0 15px; + margin: 0 auto; + } + &__title { + font-size: $typographic-base-font-size * 2; + max-width: $layout-post-single-width; + margin-left: auto; + margin-right: auto; + font-weight: 600; + text-align: center; + @include line-height(1.65); + @include margin-top(1); + @include margin-bottom(0); + } + &__body { + & figure { + @include margin-bottom(1); + & blockquote { + font-style: italic; + text-align: center; + margin-top: 0; + @include padding(1, 0); + & p { + max-width: $layout-post-single-width; + font-size: $typographic-base-font-size * 1.6817; + margin-top: 0; + @include margin-bottom(1); + @include line-height(1.5); + } + } + } + & a { + text-decoration: underline; + } + & .gatsby-highlight { + max-width: $layout-post-single-width; + margin-left: 15px; + margin-right: 15px; + @include margin-bottom(1); + } + & :not(div) { + max-width: $layout-post-single-width; + margin-left: auto; + margin-right: auto; + } + } + &__footer { + max-width: $layout-post-single-width; + margin-left: 15px; + margin-right: 15px; + @include line-height(1); + @include margin-top(1); + @include margin-bottom(2); + &-text { + & a { + text-decoration: underline; + } + } + } + &__date { + max-width: $layout-post-single-width; + margin-left: auto; + margin-right: auto; + } + &__tags { + @include margin-bottom(.5); + &-list { + list-style: none; + margin: 0 -5px; + padding: 0; + &-item { + display: inline-block; + margin: 10px 5px; + &-link { + background: $color-gray-bg; + text-decoration: none; + border: 0; + border-radius: 3px; + color: lighten($color-base, 20%); + line-height: $typographic-base-line-height; + padding: 8px 16px; + &:hover, + &:focus { + color: $color-base; + background: darken($color-gray-bg, 5%); + border: 0; + } + } + } + } + } + &__home-button { + display: block; + margin-left: auto; + margin-right: auto; + max-width: 90px; + font-size: $typographic-base-font-size; + padding: 0 16px; + height: 35px; + line-height: 35px; + text-align: center; + color: lighten($color-base, 20%); + background: $color-gray-bg; + font-weight: 400; + border-radius: 3px; + @include margin-top(1); + &:hover, + &:focus { + color: $color-base; + background: darken($color-gray-bg, 5%); + border: 0; + } + } +} + +@include breakpoint-sm { + .post-single { + &__footer { + margin-left: auto; + margin-right: auto; + } + &__body { + & .gatsby-highlight { + margin-left: auto; + margin-right: auto; + } + } + } +} + +@include breakpoint-md { + .post-single { + &__inner { + padding: 0; + } + &__title { + font-size: $typographic-base-font-size * 3; + @include line-height(2.25); + @include margin-top(2.25); + @include margin-bottom(1.5); + } + &__body { + font-size: $typographic-base-font-size * 1.125; + @include line-height(1.125); + @include margin-bottom(1.125); + & p { + font-size: $typographic-base-font-size * 1.125; + @include line-height(1.125); + @include margin-bottom(1.125); + } + } + &__home-button { + position: fixed; + max-width: auto; + margin: 0; + top: 30px; + left: 30px; + } + } +} diff --git a/src/components/Sidebar/index.jsx b/src/components/Sidebar/index.jsx new file mode 100644 index 0000000..d1fbe14 --- /dev/null +++ b/src/components/Sidebar/index.jsx @@ -0,0 +1,74 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import get from 'lodash/get'; +import Link from 'gatsby-link'; +import Menu from '../Menu'; +import Links from '../Links'; +import profilePic from '../../pages/photo.jpg'; +import './style.scss'; + +class Sidebar extends React.Component { + render() { + const { location } = this.props; + const { author, subtitle, copyright, menu } = this.props.data.site.siteMetadata; + const isHomePage = get(location, 'pathname', '/') === '/'; + + /* eslint-disable jsx-a11y/img-redundant-alt*/ + const authorBlock = ( +
+ + {author.name} + + { isHomePage ? ( +

+ {author.name} +

+ ) : +

+ {author.name} +

+ } +

{subtitle}

+
+ ); + /* eslint-enable jsx-a11y/img-redundant-alt*/ + + return ( +
+
+
+ {authorBlock} +
+
+ + +

+ {copyright} +

+
+
+
+ ); + } +} + +Sidebar.propTypes = { + data: PropTypes.shape({ + site: PropTypes.shape({ + siteMetadata: PropTypes.shape({ + subtitle: PropTypes.string.isRequired, + author: PropTypes.object.isRequired, + copyright: PropTypes.string.isRequired, + menu: PropTypes.array.isRequired + }) + }) + }), + location: PropTypes.object +}; + +export default Sidebar; diff --git a/src/components/Sidebar/style.scss b/src/components/Sidebar/style.scss new file mode 100644 index 0000000..2fccd3a --- /dev/null +++ b/src/components/Sidebar/style.scss @@ -0,0 +1,69 @@ +@import "../../assets/scss/variables"; +@import "../../assets/scss/mixins"; + +.sidebar { + width: 100%; + &__inner { + position: relative; + padding: 25px 20px 0; + } + &__author { + &-photo { + display: inline-block; + margin-bottom: 0; + border-radius: 50%; + background-clip: padding-box; + } + &-title { + font-size: $typographic-base-font-size * 1.125; + font-weight: 500; + @include line-height(1.125); + @include margin(.5, 0, .5, 0); + &-link { + color: $color-base; + &:hover, + &:focus { + color: $color-base; + } + } + } + &-subtitle { + color: $color-gray; + @include line-height(1); + @include margin-bottom(1); + } + } + &__copyright { + color: lighten($color-gray, 18%); + font-size: $typographic-small-font-size; + } +} + +@include breakpoint-sm { + .sidebar { + lost-column: 5/12; + &__inner { + padding: 30px 20px 0; + &:after { + background: $color-gray-border; + background: linear-gradient(to bottom, $color-gray-border 0%, $color-gray-border 48%, $color-white 100%); + position: absolute; + content: ""; + width: 1px; + height: 540px; + top: 30px; + right: -10px; + bottom: 0; + } + } + } +} + +@include breakpoint-md { + .sidebar { + lost-column: 1/3; + &__inner { + padding: 40px; + } + } +} diff --git a/src/components/TagTemplateDetails/index.jsx b/src/components/TagTemplateDetails/index.jsx new file mode 100644 index 0000000..ddeaaff --- /dev/null +++ b/src/components/TagTemplateDetails/index.jsx @@ -0,0 +1,44 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import Post from '../Post'; + +class TagTemplateDetails extends React.Component { + render() { + const items = []; + const tagTitle = this.props.pathContext.tag; + const posts = this.props.data.allMarkdownRemark.edges; + posts.forEach((post) => { + items.push( + + ); + }); + + return ( +
+
+
+

+ All Posts tagget as "{tagTitle}" +

+
+ {items} +
+
+
+
+ ); + } +} + +TagTemplateDetails.propTypes = { + data: PropTypes.shape({ + allMarkdownRemark: PropTypes.shape({ + edges: PropTypes.array.isRequired + }) + }), + pathContext: PropTypes.shape({ + tag: PropTypes.string.isRequired + }) +}; + +export default TagTemplateDetails; diff --git a/src/html.js b/src/html.js new file mode 100644 index 0000000..a046d05 --- /dev/null +++ b/src/html.js @@ -0,0 +1,57 @@ +import React from 'react'; +import PropTypes from 'prop-types'; + +class HTML extends React.Component { + render() { + const { postBodyComponents, headComponents, body } = this.props; + let styles; + if (process.env.NODE_ENV === 'production') { + try { + // eslint-disable-next-line import/no-webpack-loader-syntax + styles = require('!raw-loader!../public/styles.css'); + } catch (e) { + console.log(e); + } + } + + let css; + if (process.env.NODE_ENV === 'production') { + css = ( +