├── .browserslistrc ├── .github ├── FUNDING.yml └── ISSUE_TEMPLATE │ ├── bug_report.md │ └── feature_request.md ├── .gitignore ├── .huskyrc ├── .lintstagedrc ├── .prettierrc ├── .stylelintignore ├── .stylelintrc.json ├── .vscode └── settings.json ├── README.md ├── blog ├── 2018-10-01 │ └── index.md ├── 2018-10-02 │ └── index.md ├── 2018-10-03 │ └── index.md ├── 2018-10-04 │ └── index.md └── 2018-10-05 │ └── index.md ├── config └── SiteConfig.ts ├── desktop-dark.png ├── desktop.png ├── gatsby-config.js ├── gatsby-node.js ├── mobile.png ├── netlify.toml ├── package-lock.json ├── package.json ├── src ├── components │ ├── Article.tsx │ ├── Button.tsx │ ├── Content.tsx │ ├── Footer.tsx │ ├── Header.tsx │ ├── Layout.tsx │ ├── Pagination.tsx │ ├── PrevNext.tsx │ ├── SEO.tsx │ ├── SectionTitle.tsx │ ├── Subline.tsx │ ├── Title.tsx │ ├── Wrapper.tsx │ └── index.tsx ├── declarations.d.ts ├── favicon.png ├── models │ ├── AllMarkdownRemark.ts │ ├── Data.ts │ ├── Frontmatter.ts │ ├── PageProps.ts │ ├── PageResources.ts │ ├── PathContext.ts │ └── Post.ts ├── pages │ ├── 404.tsx │ ├── contact.tsx │ └── index.tsx ├── style │ └── all.scss ├── templates │ ├── AllCategory.tsx │ ├── AllTag.tsx │ ├── Blog.tsx │ ├── Category.tsx │ ├── Post.tsx │ └── Tag.tsx ├── theme │ ├── GlobalStyle.ts │ ├── Reset.ts │ ├── common.ts │ ├── darkTheme.ts │ ├── index.ts │ ├── lightTheme.ts │ └── model.ts └── utils │ ├── media.ts │ ├── prismjs-theme.css │ └── typography.ts ├── static ├── CNAME ├── assets │ ├── bg.png │ ├── bg │ │ ├── 1.jpg │ │ ├── 2.jpg │ │ ├── 3.jpg │ │ └── 4.jpg │ ├── logo.png │ └── mask.svg └── robots.txt ├── tsconfig.json └── tslint.json /.browserslistrc: -------------------------------------------------------------------------------- 1 | Last 2 versions 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | github: [mhadaily] 2 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/bug_report.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Bug report 3 | about: Something isn't working as expected? 4 | 5 | --- 6 | 7 | 14 | 15 | ## Description 16 | 17 | Describe the issue that you're seeing. 18 | 19 | ### Steps to reproduce 20 | 21 | Clear steps describing how to reproduce the issue. Please please please link to a demo project if possible, this makes your issue _much_ easier to diagnose (seriously). 22 | 23 | ### Expected result 24 | 25 | What should happen? 26 | 27 | ### Actual result 28 | 29 | What happened. 30 | 31 | ### Environment 32 | 33 | Run `gatsby info --clipboard` in your project directory and paste the output here. Not working? You may need to update your global gatsby-cli - `npm install -g gatsby-cli` 34 | -------------------------------------------------------------------------------- /.github/ISSUE_TEMPLATE/feature_request.md: -------------------------------------------------------------------------------- 1 | --- 2 | name: Feature request 3 | about: Suggest an idea for this project 4 | 5 | --- 6 | 7 | ## Summary 8 | 9 | Brief explanation of the feature. 10 | 11 | ### Basic example 12 | 13 | If the proposal involves a new or changed API, include a basic code example. Omit this section if it's not applicable. 14 | 15 | ### Motivation 16 | 17 | Why are we doing this? What use cases does it support? What is the expected outcome? 18 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | ### Node ### 2 | # Logs 3 | logs 4 | *.log 5 | npm-debug.log* 6 | 7 | # Runtime data 8 | pids 9 | *.pid 10 | *.seed 11 | *.pid.lock 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # nyc test coverage 20 | .nyc_output 21 | 22 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 23 | .grunt 24 | 25 | # node-waf configuration 26 | .lock-wscript 27 | 28 | # Compiled binary addons (http://nodejs.org/api/addons.html) 29 | build/Release 30 | 31 | # Dependency directories 32 | node_modules 33 | jspm_packages 34 | .idea 35 | 36 | # Optional npm cache directory 37 | .npm 38 | 39 | # Optional eslint cache 40 | .eslintcache 41 | 42 | # Optional REPL history 43 | .node_repl_history 44 | 45 | # Output of 'npm pack' 46 | *.tgz 47 | 48 | # Yarn Integrity file 49 | .yarn-integrity 50 | 51 | 52 | # Build Files 53 | public/ 54 | .cache/ 55 | 56 | # Gatsby context 57 | .gatsby-context.js 58 | 59 | # Bundle stats 60 | bundle-stats.json -------------------------------------------------------------------------------- /.huskyrc: -------------------------------------------------------------------------------- 1 | { 2 | "hooks": { 3 | "pre-commit": ["lint-staged"] 4 | } 5 | } -------------------------------------------------------------------------------- /.lintstagedrc: -------------------------------------------------------------------------------- 1 | { 2 | "*.{ts,tsx}": ["npm run lint:ts", "npm run lint:style", "npm run format"], 3 | "*.{scss,json,md}": ["npm run lint:style", "npm run format"] 4 | } -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": true, 3 | "tabWidth": 2, 4 | "printWidth": 100, 5 | "singleQuote": true, 6 | "trailingComma": "all" 7 | } 8 | -------------------------------------------------------------------------------- /.stylelintignore: -------------------------------------------------------------------------------- 1 | **/*.d.ts 2 | **/*.json 3 | **/prismjs-theme.css -------------------------------------------------------------------------------- /.stylelintrc.json: -------------------------------------------------------------------------------- 1 | { 2 | "extends": ["stylelint-config-recommended", "stylelint-config-styled-components"], 3 | "plugins": ["stylelint-scss"], 4 | "rules": { 5 | "scss/dollar-variable-pattern": null, 6 | "scss/selector-no-redundant-nesting-selector": true, 7 | "scss/at-rule-no-unknown": true, 8 | "at-rule-no-unknown": null 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /.vscode/settings.json: -------------------------------------------------------------------------------- 1 | { 2 | "workbench.colorCustomizations": { 3 | "activityBar.activeBackground": "#65c89b", 4 | "activityBar.activeBorder": "#945bc4", 5 | "activityBar.background": "#65c89b", 6 | "activityBar.foreground": "#15202b", 7 | "activityBar.inactiveForeground": "#15202b99", 8 | "activityBarBadge.background": "#945bc4", 9 | "activityBarBadge.foreground": "#e7e7e7", 10 | "editorGroup.border": "#65c89b", 11 | "panel.border": "#65c89b", 12 | "sideBar.border": "#65c89b", 13 | "statusBar.background": "#42b883", 14 | "statusBar.border": "#42b883", 15 | "statusBar.foreground": "#15202b", 16 | "statusBarItem.hoverBackground": "#359268", 17 | "tab.activeBorder": "#65c89b", 18 | "titleBar.activeBackground": "#42b883", 19 | "titleBar.activeForeground": "#15202b", 20 | "titleBar.border": "#42b883", 21 | "titleBar.inactiveBackground": "#42b88399", 22 | "titleBar.inactiveForeground": "#15202b99" 23 | }, 24 | "peacock.color": "#42b883" 25 | } -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Gatsby 2 Power blog starter with Typescript 2 | 3 | I constantly update this theme as this is my main website theme 4 | 5 | ### Description 6 | 7 | This is a standard starter with Typescript, TSLint, StyleLint, Prettier, Lint-Staged(Husky), Sass, StyleComponent, PWA 8 | 9 | ### new project 10 | 11 | ``` 12 | gatsby new my_blog https://github.com/mhadaily/gatsby-starter-typescript-power-blog 13 | ``` 14 | 15 | ## Success Stories 16 | 17 | - I am using this template for my website 18 | 19 | ### Features 20 | 21 | - Mobile-First approach in development. 22 | - Styled Component implementation 23 | - SCSS Ready (if neccessary) 24 | - Themable ready (Light/Dark or even more) 25 | - TSLint & Prettier 26 | - a11y lint rules 27 | - very optimized images by Gatsby Image 28 | - Purge CSS 29 | - Offline support 30 | - Category and Tag for post 31 | - Type Safe by TypeScript 32 | - Format Safe by TSLint, StyleLint and Prettier with Lint-Staged(Husky) (Git Hooks) 33 | - Blog page 34 | - Syntax highlighting in code blocks. 35 | - Pagination Ready 36 | - Ready to deploy to Github pages 37 | - Automatic RSS generation. 38 | - Automatic Sitemap generation. 39 | - Automatic support for Google Tag Manager 40 | - Netlify deploy ready 41 | 42 | #### Desktop 43 | 44 | 45 | 46 | #### Dark Mode 47 | 48 | 49 | 50 | #### Mobile 51 | 52 | 53 | 54 | ### Keywords 55 | 56 | - PWA 57 | - Blog 58 | - Personal website 59 | - TypeScript 60 | - TSLint 61 | - Progressive web app 62 | - StyleLint 63 | - Prettier 64 | - Lint-Staged 65 | - Styling:SCSS 66 | - Prisim.js 67 | - Style Components 68 | - Markdown 69 | - Pagination 70 | -------------------------------------------------------------------------------- /blog/2018-10-01/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2018-01-01" 3 | title: "Test Title For This is a paragraph" 4 | category: "General" 5 | tags: ['gatsby', 'react', 'typescript', 'graphql'] 6 | --- 7 | 8 | [View raw (TEST.md)](https://raw.github.com/adamschwartz/github-markdown-kitchen-sink/master/README.md) 9 | 10 | This is a paragraph. 11 | 12 | This is a paragraph. 13 | 14 | 15 | 16 | Header 1 17 | ======== 18 | 19 | Header 2 20 | -------- 21 | 22 | Header 1 23 | ======== 24 | 25 | Header 2 26 | -------- 27 | 28 | 29 | 30 | # Header 1 31 | ## Header 2 32 | ### Header 3 33 | #### Header 4 34 | ##### Header 5 35 | ###### Header 6 36 | 37 | # Header 1 38 | ## Header 2 39 | ### Header 3 40 | #### Header 4 41 | ##### Header 5 42 | ###### Header 6 43 | 44 | 45 | 46 | # Header 1 # 47 | ## Header 2 ## 48 | ### Header 3 ### 49 | #### Header 4 #### 50 | ##### Header 5 ##### 51 | ###### Header 6 ###### 52 | 53 | # Header 1 # 54 | ## Header 2 ## 55 | ### Header 3 ### 56 | #### Header 4 #### 57 | ##### Header 5 ##### 58 | ###### Header 6 ###### 59 | 60 | 61 | 62 | > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 63 | 64 | > Lorem ipsum dolor sit amet, consectetuer adipiscing elit. Aliquam hendrerit mi posuere lectus. Vestibulum enim wisi, viverra nec, fringilla in, laoreet vitae, risus. 65 | 66 | 67 | 68 | > ## This is a header. 69 | > 1. This is the first list item. 70 | > 2. This is the second list item. 71 | > 72 | > Here's some example code: 73 | > 74 | > Markdown.generate(); 75 | 76 | > ## This is a header. 77 | > 1. This is the first list item. 78 | > 2. This is the second list item. 79 | > 80 | > Here's some example code: 81 | > 82 | > Markdown.generate(); 83 | 84 | 85 | 86 | 87 | - Red 88 | - Green 89 | - Blue 90 | 91 | 92 | + Red 93 | + Green 94 | + Blue 95 | 96 | 97 | * Red 98 | * Green 99 | * Blue 100 | 101 | 102 | ```markdown 103 | - Red 104 | - Green 105 | - Blue 106 | 107 | + Red 108 | + Green 109 | + Blue 110 | 111 | * Red 112 | * Green 113 | * Blue 114 | ``` 115 | 116 | 117 | 118 | 1. Buy flour and salt 119 | 1. Mix together with water 120 | 1. Bake 121 | 122 | ```markdown 123 | 1. Buy flour and salt 124 | 1. Mix together with water 125 | 1. Bake 126 | ``` 127 | 128 | 129 | 130 | Paragraph: 131 | 132 | Code 133 | 134 | 135 | 136 | Paragraph: 137 | 138 | Code 139 | 140 | 141 | 142 | * * * 143 | 144 | *** 145 | 146 | ***** 147 | 148 | - - - 149 | 150 | --------------------------------------- 151 | 152 | * * * 153 | 154 | *** 155 | 156 | ***** 157 | 158 | - - - 159 | 160 | --------------------------------------- 161 | 162 | 163 | 164 | This is [an example](http://example.com "Example") link. 165 | 166 | [This link](http://example.com) has no title attr. 167 | 168 | This is [an example] [id] reference-style link. 169 | 170 | [id]: http://example.com "Optional Title" 171 | 172 | This is [an example](http://example.com "Example") link. 173 | 174 | [This link](http://example.com) has no title attr. 175 | 176 | This is [an example] [id] reference-style link. 177 | 178 | [id]: http://example.com "Optional Title" 179 | 180 | 181 | 182 | *single asterisks* 183 | 184 | _single underscores_ 185 | 186 | **double asterisks** 187 | 188 | __double underscores__ 189 | 190 | *single asterisks* 191 | 192 | _single underscores_ 193 | 194 | **double asterisks** 195 | 196 | __double underscores__ 197 | 198 | 199 | 200 | This paragraph has some `code` in it. 201 | 202 | This paragraph has some `code` in it. 203 | 204 | 205 | 206 | ![Alt Text](https://placehold.it/200x50 "Image Title") 207 | 208 | ![Alt Text](https://placehold.it/200x50 "Image Title") 209 | -------------------------------------------------------------------------------- /blog/2018-10-02/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2018-01-02" 3 | title: "Alper Musig Clare is a create author" 4 | category: "Technology" 5 | tags: ['Author', 'Book'] 6 | banner: "/assets/bg/1.jpg" 7 | --- 8 | 9 | # Heading 1 10 | 11 | Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. 12 | 13 | Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. 14 | 15 | ## Zwei flinke Boxer 16 | 17 | Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. 18 | 19 | > "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. 20 | 21 | ### Heading 3 22 | 23 | Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. 24 | -------------------------------------------------------------------------------- /blog/2018-10-03/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2018-01-03" 3 | title: "A title must be meaningful" 4 | category: "Coding" 5 | tags: ['Technology', 'graphql'] 6 | banner: "/assets/bg/2.jpg" 7 | --- 8 | 9 | Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. 10 | 11 | Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. 12 | 13 | ## Zwei flinke Boxer 14 | 15 | Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. 16 | 17 | > "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. 18 | 19 | Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. 20 | -------------------------------------------------------------------------------- /blog/2018-10-04/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2018-01-04" 3 | title: "Listen to music to enjoy coding" 4 | category: "Music" 5 | tags: ['Music', 'coding'] 6 | banner: "/assets/bg/3.jpg" 7 | --- 8 | 9 | Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. 10 | 11 | Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. 12 | 13 | ## Zwei flinke Boxer 14 | 15 | Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. 16 | 17 | > "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. 18 | 19 | Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. 20 | 21 | Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. 22 | 23 | Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. 24 | -------------------------------------------------------------------------------- /blog/2018-10-05/index.md: -------------------------------------------------------------------------------- 1 | --- 2 | date: "2018-01-05" 3 | title: "Coding is fun, isn't it?" 4 | category: "Coding" 5 | tags: ['Technology', 'Coding'] 6 | banner: "/assets/bg/4.jpg" 7 | --- 8 | 9 | Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. Sylvia wagt quick den Jux bei Pforzheim. Polyfon zwitschernd aßen Mäxchens Vögel Rüben, Joghurt und Quark. "Fix, Schwyz! " quäkt Jürgen blöd vom Paß. Victor jagt zwölf Boxkämpfer quer über den großen Sylter Deich. Falsches Üben von Xylophonmusik quält jeden größeren Zwerg. Heizölrückstoßabdämpfung. Zwei flinke Boxer jagen die quirlige Eva und ihren Mops durch Sylt. Franz jagt im komplett verwahrlosten Taxi quer durch Bayern. Zwölf Boxkämpfer jagen Viktor quer über den großen Sylter Deich. Vogel Quax zwickt Johnys Pferd Bim. 10 | 11 | ```js 12 | (function() { 13 | 14 | var cache = {}; 15 | var form = $('form'); 16 | var minified = true; 17 | 18 | var dependencies = {}; 19 | 20 | var treeURL = 'https://api.github.com/repos/PrismJS/prism/git/trees/gh-pages?recursive=1'; 21 | var treePromise = new Promise(function(resolve) { 22 | $u.xhr({ 23 | url: treeURL, 24 | callback: function(xhr) { 25 | if (xhr.status < 400) { 26 | resolve(JSON.parse(xhr.responseText).tree); 27 | } 28 | } 29 | }); 30 | }); 31 | ``` 32 | 33 | Zwei flinke Boxer jagen die quir 34 | 35 | ```md 36 | # asdfasdfads 37 | - auesufuaus 38 | ``` 39 | 40 | ```css 41 | code[class*="language-"], 42 | pre[class*="language-"] { 43 | color: black; 44 | background: none; 45 | font-family: Consolas, Monaco, 'Andale Mono', 'Ubuntu Mono', monospace; 46 | text-align: left; 47 | white-space: pre; 48 | word-spacing: normal; 49 | word-break: normal; 50 | word-wrap: normal; 51 | line-height: 1.5; 52 | 53 | -moz-tab-size: 4; 54 | -o-tab-size: 4; 55 | tab-size: 4; 56 | 57 | -webkit-hyphens: none; 58 | -moz-hyphens: none; 59 | -ms-hyphens: none; 60 | hyphens: none; 61 | } 62 | ``` -------------------------------------------------------------------------------- /config/SiteConfig.ts: -------------------------------------------------------------------------------- 1 | export default { 2 | pathPrefix: '/', // Prefix for all links. If you deploy your site to example.com/portfolio your pathPrefix should be "portfolio" 3 | 4 | siteTitle: 'Typescript Power Blog', // Navigation and Site Title 5 | siteTitleAlt: 'Typescript Power Blog - Gatsby Starter', // Alternative Site title for SEO 6 | siteUrl: 'https://typescript-power-blog.github.com', // Domain of your site. No trailing slash! 7 | siteLanguage: 'en', // Language Tag on element 8 | siteBanner: '/assets/banner.jpg', // Your image for og:image tag. You can find it in the /static folder 9 | defaultBg: '/assets/bg.png', // default post background header 10 | favicon: 'src/favicon.png', // Your image for favicons. You can find it in the /src folder 11 | siteDescription: 'Typescript Power Blog with big typography', // Your site description 12 | author: 'Majid Hajian', // Author for schemaORGJSONLD 13 | siteLogo: '/assets/logo.png', // Image for schemaORGJSONLD 14 | 15 | // siteFBAppID: '123456789', // Facebook App ID - Optional 16 | userTwitter: '@mhadaily', // Twitter Username - Optional 17 | ogSiteName: 'mhadaily', // Facebook Site Name - Optional 18 | ogLanguage: 'en_US', // Facebook Language 19 | 20 | // Manifest and Progress color 21 | // See: https://developers.google.com/web/fundamentals/web-app-manifest/ 22 | themeColor: '#3498DB', 23 | backgroundColor: '#2b2e3c', 24 | 25 | // Settings for typography.ts 26 | headerFontFamily: 'Bitter', 27 | bodyFontFamily: 'Open Sans', 28 | baseFontSize: '18px', 29 | 30 | // Social media 31 | siteFBAppID: '', 32 | 33 | // 34 | Google_Tag_Manager_ID: 'GTM-XXXXXXX', 35 | POST_PER_PAGE: 4, 36 | }; 37 | -------------------------------------------------------------------------------- /desktop-dark.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhadaily/gatsby-starter-typescript-power-blog/1a7460e2dbc43659bcaf10dd949fbbb70f80e92e/desktop-dark.png -------------------------------------------------------------------------------- /desktop.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhadaily/gatsby-starter-typescript-power-blog/1a7460e2dbc43659bcaf10dd949fbbb70f80e92e/desktop.png -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | require('source-map-support').install(); 2 | require('ts-node').register({ 3 | compilerOptions: { 4 | module: 'commonjs', 5 | target: 'es2017', 6 | }, 7 | }); 8 | 9 | const config = require('./config/SiteConfig').default; 10 | const pathPrefix = config.pathPrefix === '/' ? '' : config.pathPrefix; 11 | 12 | module.exports = { 13 | pathPrefix: config.pathPrefix, 14 | siteMetadata: { 15 | siteUrl: config.siteUrl + pathPrefix, 16 | }, 17 | plugins: [ 18 | 'gatsby-plugin-react-helmet', 19 | 'gatsby-plugin-styled-components', 20 | 'gatsby-plugin-offline', 21 | 'gatsby-plugin-typescript', 22 | 'gatsby-plugin-sass', 23 | 'gatsby-plugin-manifest', 24 | 'gatsby-plugin-catch-links', 25 | 'gatsby-plugin-sitemap', 26 | 'gatsby-plugin-lodash', 27 | { 28 | resolve: 'gatsby-source-filesystem', 29 | options: { 30 | name: 'post', 31 | path: `${__dirname}/blog`, 32 | }, 33 | }, 34 | { 35 | resolve: `gatsby-plugin-google-tagmanager`, 36 | options: { 37 | id: config.Google_Tag_Manager_ID, 38 | // Include GTM in development. 39 | // Defaults to false meaning GTM will only be loaded in production. 40 | includeInDevelopment: false, 41 | }, 42 | }, 43 | { 44 | resolve: 'gatsby-transformer-remark', 45 | options: { 46 | plugins: [ 47 | { 48 | resolve: 'gatsby-remark-external-links', 49 | options: { 50 | target: '_blank', 51 | rel: 'nofollow noopener noreferrer', 52 | }, 53 | }, 54 | 'gatsby-remark-prismjs', 55 | 'gatsby-remark-autolink-headers', 56 | ], 57 | }, 58 | }, 59 | { 60 | resolve: 'gatsby-plugin-typography', 61 | options: { 62 | pathToConfigModule: 'src/utils/typography.ts', 63 | }, 64 | }, 65 | { 66 | resolve: 'gatsby-plugin-manifest', 67 | options: { 68 | name: config.siteTitle, 69 | short_name: config.siteTitleAlt, 70 | description: config.siteDescription, 71 | start_url: config.pathPrefix, 72 | background_color: config.backgroundColor, 73 | theme_color: config.themeColor, 74 | display: 'standalone', 75 | icon: config.favicon, 76 | }, 77 | }, 78 | { 79 | resolve: `gatsby-source-filesystem`, 80 | options: { 81 | name: `images`, 82 | path: `${__dirname}/static/assets`, 83 | }, 84 | }, 85 | 'gatsby-plugin-sharp', 86 | 'gatsby-transformer-sharp', 87 | { 88 | // Removes unused css rules 89 | resolve: 'gatsby-plugin-purgecss', 90 | options: { 91 | // Activates purging in gatsby develop 92 | develop: true, 93 | // Purge only the main css file 94 | purgeOnly: ['all.scss'], 95 | }, 96 | }, 97 | `gatsby-plugin-netlify`, 98 | ], 99 | }; 100 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | const path = require('path'); 2 | const _ = require('lodash'); 3 | const config = require('./config/SiteConfig').default; 4 | 5 | exports.onCreateNode = ({ node, actions }) => { 6 | const { createNodeField } = actions; 7 | if ( 8 | node.internal.type === 'MarkdownRemark' && 9 | _.has(node, 'frontmatter') && 10 | _.has(node.frontmatter, 'title') 11 | ) { 12 | const slug = `${_.kebabCase(node.frontmatter.title)}`; 13 | createNodeField({ node, name: 'slug', value: slug }); 14 | } 15 | }; 16 | 17 | const getPostsByType = (posts, classificationType) => { 18 | const postsByType = {}; 19 | posts.forEach(({ node }) => { 20 | const nodeClassificationType = node.frontmatter[classificationType]; 21 | if (nodeClassificationType) { 22 | if (_.isArray(nodeClassificationType)) { 23 | nodeClassificationType.forEach((name) => { 24 | if (!_.has(postsByType, name)) { 25 | postsByType[name] = []; 26 | } 27 | postsByType[name].push(node); 28 | }); 29 | } else { 30 | const name = nodeClassificationType; 31 | if (!postsByType[name]) { 32 | postsByType[name] = []; 33 | } 34 | postsByType[name].push(node); 35 | } 36 | } 37 | }); 38 | return postsByType; 39 | }; 40 | 41 | const createClassificationPages = ({ createPage, posts, postsPerPage, numPages }) => { 42 | const classifications = [ 43 | { 44 | singularName: 'category', 45 | pluralName: 'categories', 46 | template: { 47 | part: path.resolve(`src/templates/Category.tsx`), 48 | all: path.resolve(`src/templates/AllCategory.tsx`), 49 | }, 50 | postsByClassificationNames: getPostsByType(posts, 'category'), 51 | }, 52 | { 53 | singularName: 'tag', 54 | pluralName: 'tags', 55 | template: { 56 | part: path.resolve(`src/templates/Tag.tsx`), 57 | all: path.resolve(`src/templates/AllTag.tsx`), 58 | }, 59 | postsByClassificationNames: getPostsByType(posts, 'tags'), 60 | }, 61 | ]; 62 | 63 | classifications.forEach((classification) => { 64 | const names = Object.keys(classification.postsByClassificationNames); 65 | 66 | createPage({ 67 | path: _.kebabCase(`/${classification.pluralName}`), 68 | component: classification.template.all, 69 | context: { 70 | [`${classification.pluralName}`]: names.sort(), 71 | }, 72 | }); 73 | 74 | names.forEach((name) => { 75 | const postsByName = classification.postsByClassificationNames[name]; 76 | createPage({ 77 | path: `/${classification.pluralName}/${_.kebabCase(name)}`, 78 | component: classification.template.part, 79 | context: { 80 | posts: postsByName, 81 | [`${classification.singularName}Name`]: name, 82 | }, 83 | }); 84 | }); 85 | }); 86 | }; 87 | 88 | exports.onCreateWebpackConfig = ({ stage, actions }) => { 89 | actions.setWebpackConfig({ 90 | resolve: { 91 | modules: [path.resolve(__dirname, 'src'), 'node_modules'], 92 | }, 93 | }); 94 | }; 95 | 96 | exports.createPages = ({ actions, graphql }) => { 97 | const { createPage } = actions; 98 | 99 | const postTemplate = path.resolve(`src/templates/Post.tsx`); 100 | 101 | return graphql(` 102 | { 103 | allMarkdownRemark(sort: { order: DESC, fields: [frontmatter___date] }, limit: 10000) { 104 | edges { 105 | node { 106 | excerpt(pruneLength: 250) 107 | html 108 | id 109 | fields { 110 | slug 111 | } 112 | frontmatter { 113 | date 114 | title 115 | category 116 | tags 117 | banner 118 | } 119 | timeToRead 120 | } 121 | } 122 | } 123 | } 124 | `).then((result) => { 125 | if (result.errors) { 126 | return Promise.reject(result.errors); 127 | } 128 | const posts = result.data.allMarkdownRemark.edges; 129 | const postsPerPage = config.POST_PER_PAGE; 130 | const numPages = Math.ceil(posts.length / postsPerPage); 131 | 132 | Array.from({ length: numPages }).forEach((_, i) => { 133 | createPage({ 134 | path: i === 0 ? `/blog` : `/blog/${i + 1}`, 135 | component: path.resolve('./src/templates/Blog.tsx'), 136 | context: { 137 | limit: postsPerPage, 138 | skip: i * postsPerPage, 139 | totalPages: numPages, 140 | currentPage: i + 1, 141 | }, 142 | }); 143 | }); 144 | 145 | createClassificationPages({ createPage, posts, postsPerPage, numPages }); 146 | 147 | posts.forEach(({ node }, index) => { 148 | const next = index === 0 ? null : posts[index - 1].node; 149 | const prev = index === posts.length - 1 ? null : posts[index + 1].node; 150 | 151 | createPage({ 152 | path: `/blog/${_.kebabCase(node.frontmatter.title)}`, 153 | component: postTemplate, 154 | context: { 155 | slug: _.kebabCase(node.frontmatter.title), 156 | prev, 157 | next, 158 | }, 159 | }); 160 | }); 161 | }); 162 | }; 163 | -------------------------------------------------------------------------------- /mobile.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mhadaily/gatsby-starter-typescript-power-blog/1a7460e2dbc43659bcaf10dd949fbbb70f80e92e/mobile.png -------------------------------------------------------------------------------- /netlify.toml: -------------------------------------------------------------------------------- 1 | [build] 2 | publish = "public" 3 | command = "npm run build" 4 | [build.environment] 5 | YARN_FLAGS = "--no-ignore-optional" 6 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "gatsby-starter-typescirpt-power-blog", 3 | "description": "gatsyby blog template with typescript and tslint", 4 | "version": "1.1.0", 5 | "author": "Majid Hajian ( mhadaily@gmail.com )", 6 | "keywords": [ 7 | "gatsby, typescript", 8 | "blog" 9 | ], 10 | "license": "MIT", 11 | "main": "n/a", 12 | "scripts": { 13 | "clean": "gatsby clean", 14 | "build": "gatsby clean && gatsby build", 15 | "start": "gatsby clean && gatsby develop", 16 | "deploy:gh": "gatsby build --prefix-paths && gh-pages -d public", 17 | "deploy:netlify": "gatsby build --prefix-paths && netlify deploy --prod --dir=public", 18 | "lint": "tslint --project .", 19 | "lint:fix": "tslint --fix --project .", 20 | "lint:ts": "tslint --fix 'src/**/*.{ts,tsx}' -p tsconfig.json", 21 | "lint:style": "stylelint 'src/**/*.{scss,ts,css,sass,less,tsx}'", 22 | "format": "prettier --write 'src/**/*.{ts,tsx,scss,md}'", 23 | "formatAndFix": "npm run format && npm run lint:ts && npm run style" 24 | }, 25 | "devDependencies": { 26 | "@types/lodash": "^4.14.161", 27 | "@types/react": "^16.9.50", 28 | "@types/react-dom": "^16.9.8", 29 | "@types/react-helmet": "^6.1.0", 30 | "@types/styled-components": "^5.1.3", 31 | "@types/typography": "^0.16.3", 32 | "babel-plugin-styled-components": "^1.11.1", 33 | "gatsby-cli": "^2.12.102", 34 | "gatsby-plugin-catch-links": "^2.3.14", 35 | "gatsby-plugin-lodash": "^3.3.12", 36 | "gatsby-plugin-manifest": "^2.4.33", 37 | "gatsby-plugin-netlify": "^2.3.16", 38 | "gatsby-plugin-offline": "^3.2.30", 39 | "gatsby-plugin-purgecss": "^5.0.0", 40 | "gatsby-plugin-react-helmet": "^3.3.12", 41 | "gatsby-plugin-sass": "^2.3.14", 42 | "gatsby-plugin-sharp": "^2.6.38", 43 | "gatsby-plugin-sitemap": "^2.4.14", 44 | "gatsby-plugin-styled-components": "^3.3.12", 45 | "gatsby-plugin-typescript": "^2.4.21", 46 | "gatsby-plugin-typography": "^2.5.12", 47 | "gatsby-remark-autolink-headers": "^2.3.14", 48 | "gatsby-remark-external-links": "0.0.4", 49 | "gatsby-remark-prismjs": "^3.5.15", 50 | "gatsby-source-filesystem": "^2.3.32", 51 | "gatsby-transformer-remark": "^2.8.37", 52 | "gatsby-transformer-sharp": "^2.5.16", 53 | "gh-pages": "^3.1.0", 54 | "husky": "^4.3.0", 55 | "lint-staged": "^10.4.0", 56 | "node-sass": "^4.14.1", 57 | "prettier": "^2.1.2", 58 | "pretty-quick": "^3.0.2", 59 | "react-typography": "^0.16.19", 60 | "source-map-support": "latest", 61 | "stylelint": "^13.7.2", 62 | "stylelint-config-css-modules": "^2.2.0", 63 | "stylelint-config-prettier": "^8.0.2", 64 | "stylelint-config-recommended": "^3.0.0", 65 | "stylelint-config-recommended-scss": "^4.2.0", 66 | "stylelint-config-styled-components": "^0.1.1", 67 | "stylelint-order": "^4.1.0", 68 | "stylelint-scss": "^3.18.0", 69 | "ts-node": "^9.0.0", 70 | "tslint": "^6.1.3", 71 | "tslint-config-blvd": "^1.2.1", 72 | "tslint-config-prettier": "^1.18.0", 73 | "tslint-plugin-prettier": "^2.3.0", 74 | "tslint-react": "^5.0.0", 75 | "tslint-react-a11y": "^1.1.0", 76 | "typescript": "^4.0.3" 77 | }, 78 | "dependencies": { 79 | "gatsby": "^2.24.67", 80 | "gatsby-image": "^2.4.20", 81 | "gatsby-plugin-google-tagmanager": "^2.3.14", 82 | "lodash": "^4.17.20", 83 | "polished": "^3.6.7", 84 | "prismjs": "^1.21.0", 85 | "react": "^16.13.1", 86 | "react-dom": "^16.13.1", 87 | "react-helmet": "^6.1.0", 88 | "styled-components": "^5.2.0", 89 | "typography": "^0.16.19" 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/components/Article.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { Link } from 'gatsby'; 4 | import { kebabCase } from 'lodash'; 5 | import { Subline } from './Subline'; 6 | 7 | const Post = styled.article` 8 | display: flex; 9 | flex-direction: column; 10 | margin-top: 3.5rem; 11 | margin-bottom: 3.5rem; 12 | `; 13 | 14 | const Title = styled.h2` 15 | position: relative; 16 | text-shadow: 0 1.2rem 3rem rgba(0, 0, 0, 0.15); 17 | margin-bottom: 0.75rem; 18 | `; 19 | 20 | const Initiale = styled.span` 21 | position: absolute; 22 | font-size: 7rem; 23 | transform: translate(-50%, -50%); 24 | opacity: 0.08; 25 | user-select: none; 26 | z-index: -1; 27 | `; 28 | 29 | const Excerpt = styled.p` 30 | grid-column: -1 / 1; 31 | margin-top: 1rem; 32 | margin-bottom: 1rem; 33 | `; 34 | 35 | interface Props { 36 | title: string; 37 | date: string; 38 | excerpt: string; 39 | slug: string; 40 | timeToRead: number; 41 | category: string; 42 | } 43 | 44 | const Article = ({ title, date, excerpt, slug, timeToRead, category }: Props) => { 45 | const firstChar = title.charAt(0); 46 | return ( 47 | 48 | 49 | <Initiale>{firstChar}</Initiale> 50 | <Link to={`/blog/${slug}`}>{title}</Link> 51 | 52 | 53 | {date} — {timeToRead} Min Read — In 54 | {category} 55 | 56 | {excerpt} 57 | 58 | ); 59 | }; 60 | 61 | export { Article }; 62 | -------------------------------------------------------------------------------- /src/components/Button.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { darken } from 'polished'; 3 | 4 | export const Button = styled.button<{ big: boolean }>` 5 | background: ${(props) => props.theme.colors.primary}; 6 | border: none; 7 | display: inline-flex; 8 | align-items: center; 9 | margin: 0 0.5rem; 10 | border-radius: ${(props) => (props.big ? '1.5rem' : '1rem')}; 11 | font-size: ${(props) => (props.big ? '1.2rem' : '1rem')}; 12 | color: white; 13 | padding: ${(props) => (props.big ? '0.35rem 1.6rem' : '0.25rem 1.5rem')}; 14 | transition: all ${(props) => props.theme.transitions.normal}; 15 | box-shadow: 0 4px 6px rgba(50, 50, 93, 0.11), 0 1px 3px rgba(0, 0, 0, 0.08); 16 | &:hover { 17 | background: ${(props) => darken(0.3, props.theme.colors.primary)}; 18 | cursor: pointer; 19 | transform: translateY(-2px); 20 | } 21 | &:focus { 22 | outline: none; 23 | } 24 | svg { 25 | width: 20px; 26 | height: 20px; 27 | margin-right: 0.75rem; 28 | fill: white; 29 | } 30 | `; 31 | -------------------------------------------------------------------------------- /src/components/Content.tsx: -------------------------------------------------------------------------------- 1 | import styled from 'styled-components'; 2 | import { media } from '../utils/media'; 3 | 4 | export const Content = styled.div` 5 | box-shadow: 0 0.4rem 12rem ${(props) => props.theme.colors.grey.ultraLight}; 6 | border-radius: 1rem; 7 | padding: 2rem 4rem; 8 | background-color: ${(props) => props.theme.colors.bg}; 9 | z-index: 9000; 10 | margin-top: -4rem; 11 | form { 12 | p { 13 | label, 14 | input { 15 | display: block; 16 | } 17 | input { 18 | min-width: 275px; 19 | } 20 | textarea { 21 | resize: vertical; 22 | min-height: 150px; 23 | width: 100%; 24 | } 25 | } 26 | } 27 | @media ${media.tablet} { 28 | padding: 3rem 3rem; 29 | } 30 | @media ${media.phone} { 31 | padding: 2rem 1.5rem; 32 | } 33 | `; 34 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { StaticQuery, graphql } from 'gatsby'; 4 | import { split } from 'lodash'; 5 | 6 | const FooterWrapper = styled.footer` 7 | text-align: center; 8 | padding: 3rem 0; 9 | span { 10 | font-size: 0.75rem; 11 | } 12 | `; 13 | 14 | interface DataProps { 15 | site: { 16 | siteMetadata: { 17 | title: string; 18 | }; 19 | buildTime: string; 20 | }; 21 | } 22 | 23 | const Footer = () => { 24 | const query = graphql` 25 | { 26 | site { 27 | buildTime(formatString: "DD.MM.YYYY") 28 | } 29 | } 30 | `; 31 | const render = (data: DataProps) => { 32 | return ( 33 | 34 | © {split(data.site.buildTime, '.')[2]} by Majid Hajian. All rights reserved.
{' '} 35 | 36 | GitHub Repository{' '} 37 | {' '} 38 |
39 | Last build: {data.site.buildTime}{' '} 40 |
41 | ); 42 | }; 43 | 44 | return ; 45 | }; 46 | 47 | export { Footer }; 48 | -------------------------------------------------------------------------------- /src/components/Header.tsx: -------------------------------------------------------------------------------- 1 | import React from 'react'; 2 | import styled from 'styled-components'; 3 | import { darken, lighten, rgba } from 'polished'; 4 | import { media } from '../utils/media'; 5 | import config from '../../config/SiteConfig'; 6 | 7 | const HeaderWrapper = styled.header<{ banner: string }>` 8 | position: relative; 9 | background: linear-gradient( 10 | -185deg, 11 | ${(props) => rgba(darken(0.1, props.theme.colors.primary), 0.6)}, 12 | ${(props) => rgba(lighten(0.1, props.theme.colors.grey.dark), 0.8)} 13 | ), 14 | url(${(props) => props.banner}) no-repeat; 15 | background-size: cover; 16 | padding: 8rem 2rem 10rem; 17 | text-align: center; 18 | @media ${media.tablet} { 19 | padding: 4rem 2rem 6rem; 20 | } 21 | @media ${media.phone} { 22 | padding: 1rem 0.5rem 2rem; 23 | } 24 | `; 25 | 26 | const Content = styled.div` 27 | position: relative; 28 | z-index: 999; 29 | a { 30 | color: ${(props) => props.theme.colors.bg}; 31 | &:hover { 32 | opacity: 0.85; 33 | color: ${(props) => props.theme.colors.bg}; 34 | } 35 | } 36 | `; 37 | 38 | interface Props { 39 | children: any; 40 | banner?: string; 41 | } 42 | 43 | const Header = (props: Props) => { 44 | return ( 45 | 46 | {props.children} 47 | 48 | ); 49 | }; 50 | 51 | export { Header }; 52 | -------------------------------------------------------------------------------- /src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import React, { useState } from 'react'; 2 | import styled, { ThemeProvider } from 'styled-components'; 3 | import { GlobalStyle } from '../theme/GlobalStyle'; 4 | import { Footer } from './Footer'; 5 | 6 | import '../style/all.scss'; 7 | import { darkTheme, lightTheme } from '../theme'; 8 | 9 | const ModeButton = styled.button` 10 | background: none; 11 | border: 0; 12 | padding: 1rem; 13 | right: 0; 14 | position: fixed; 15 | z-index: 999; 16 | cursor: pointer; 17 | :focus { 18 | border: 0; 19 | outline: none; 20 | } 21 | `; 22 | 23 | const Layout = ({ children }: { children: any }) => { 24 | const stored = typeof window !== 'undefined' && localStorage.getItem('isDarkMode'); 25 | const [isDarkMode, setIsDarkMode] = useState(stored === 'true' ? true : false); 26 | 27 | const toggelThemeMode = () => { 28 | setIsDarkMode(!isDarkMode); 29 | if (typeof window !== 'undefined') { 30 | localStorage.setItem('isDarkMode', `${!isDarkMode}`); 31 | } 32 | }; 33 | return ( 34 | 35 | 36 | 37 | 38 | 52 | 53 | {children} 54 |