mirror of
https://github.com/sergeyyarkov/devthread.ru.git
synced 2026-10-11 18:29:10 +03:00
format
This commit is contained in:
parent
96f29a1a74
commit
42df591c08
@ -1,3 +1,4 @@
|
|||||||
# devthread.ru
|
# devthread.ru
|
||||||
|
|
||||||
[](https://opensource.org/licenses/MIT)
|
[](https://opensource.org/licenses/MIT)
|
||||||
[](https://app.netlify.com/sites/devthread/deploys)
|
[](https://app.netlify.com/sites/devthread/deploys)
|
||||||
46
config.js
46
config.js
@ -1,38 +1,40 @@
|
|||||||
module.exports = {
|
module.exports = {
|
||||||
title: 'devthread.ru',
|
title: "devthread.ru",
|
||||||
keywords: 'веб разработка, javascript, seo, программирование, reactjs, graphql',
|
keywords:
|
||||||
siteName: 'Cборник статей и руководств - devthread.ru',
|
"веб разработка, javascript, seo, программирование, reactjs, graphql",
|
||||||
titleTemplate: '%s · статьи и руководства по веб-разработке',
|
siteName: "Cборник статей и руководств - devthread.ru",
|
||||||
description: 'Cборник статей и руководств по тематике веб-разработки и IT для того чтобы помочь вам',
|
titleTemplate: "%s · статьи и руководства по веб-разработке",
|
||||||
url: 'https://devthread.netlify.app',
|
description:
|
||||||
|
"Cборник статей и руководств по тематике веб-разработки и IT для того чтобы помочь вам",
|
||||||
|
url: "https://devthread.netlify.app",
|
||||||
menuLinks: [
|
menuLinks: [
|
||||||
{
|
{
|
||||||
name: 'Статьи',
|
name: "Статьи",
|
||||||
link: '/articles'
|
link: "/articles",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'О сайте',
|
name: "О сайте",
|
||||||
link: '/about'
|
link: "/about",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Контакты',
|
name: "Контакты",
|
||||||
link: '/contacts'
|
link: "/contacts",
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
name: 'Сниппеты',
|
name: "Сниппеты",
|
||||||
link: '/snippets'
|
link: "/snippets",
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
social: {
|
social: {
|
||||||
email: 'support@devthread.ru',
|
email: "support@devthread.ru",
|
||||||
telegram: 'https://t.me/devthread',
|
telegram: "https://t.me/devthread",
|
||||||
twitter: 'https://twitter.com/devthread',
|
twitter: "https://twitter.com/devthread",
|
||||||
yadzen: 'https://zen.yandex.ru/'
|
yadzen: "https://zen.yandex.ru/",
|
||||||
},
|
},
|
||||||
options: {
|
options: {
|
||||||
articles: {
|
articles: {
|
||||||
onPage: 6,
|
onPage: 6,
|
||||||
onLoadMore: 2
|
onLoadMore: 2,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
@ -20,11 +20,13 @@ tags:
|
|||||||
- graphql
|
- graphql
|
||||||
- reactjs
|
- reactjs
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -38,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -20,17 +20,18 @@ tags:
|
|||||||
- graphql
|
- graphql
|
||||||
- reactjs
|
- reactjs
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
@ -39,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -19,11 +19,13 @@ description: Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do
|
|||||||
tags:
|
tags:
|
||||||
- javascript
|
- javascript
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -37,13 +39,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -22,17 +22,18 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
@ -41,13 +42,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -19,11 +19,13 @@ tags:
|
|||||||
- graphql
|
- graphql
|
||||||
- reactjs
|
- reactjs
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -37,19 +39,25 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
const { siteMetadata: { title, menuLinks, social: { twitter, telegram } } } = useSiteMetadataQuery() //L1
|
const {
|
||||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
siteMetadata: {
|
||||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
title,
|
||||||
const [isDark, setIsDark] = React.useState(false)
|
menuLinks,
|
||||||
|
social: { twitter, telegram },
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery() //L1
|
||||||
|
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||||
|
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||||
|
const [isDark, setIsDark] = React.useState(false)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setIsDark(window.__isDarkTheme)
|
setIsDark(window.__isDarkTheme)
|
||||||
isMobileOpen
|
isMobileOpen
|
||||||
? document.body.style.overflowY = 'hidden'
|
? (document.body.style.overflowY = "hidden")
|
||||||
: document.body.style.overflowY = ''
|
: (document.body.style.overflowY = "")
|
||||||
document.body.onscroll = () =>
|
document.body.onscroll = () =>
|
||||||
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
||||||
}, [setIsDark, isMobileOpen])
|
}, [setIsDark, isMobileOpen])
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -18,11 +18,13 @@ description: |-
|
|||||||
tags:
|
tags:
|
||||||
- reactjs
|
- reactjs
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -36,13 +38,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -19,11 +19,13 @@ tags:
|
|||||||
- reactjs
|
- reactjs
|
||||||
- javascript
|
- javascript
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -37,13 +39,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -19,11 +19,13 @@ tags:
|
|||||||
- reactjs
|
- reactjs
|
||||||
- javascript
|
- javascript
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -37,19 +39,25 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
const { siteMetadata: { title, menuLinks, social: { twitter, telegram } } } = useSiteMetadataQuery() //L1
|
const {
|
||||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
siteMetadata: {
|
||||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
title,
|
||||||
const [isDark, setIsDark] = React.useState(false)
|
menuLinks,
|
||||||
|
social: { twitter, telegram },
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery() //L1
|
||||||
|
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||||
|
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||||
|
const [isDark, setIsDark] = React.useState(false)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setIsDark(window.__isDarkTheme)
|
setIsDark(window.__isDarkTheme)
|
||||||
isMobileOpen
|
isMobileOpen
|
||||||
? document.body.style.overflowY = 'hidden'
|
? (document.body.style.overflowY = "hidden")
|
||||||
: document.body.style.overflowY = ''
|
: (document.body.style.overflowY = "")
|
||||||
document.body.onscroll = () =>
|
document.body.onscroll = () =>
|
||||||
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
||||||
}, [setIsDark, isMobileOpen])
|
}, [setIsDark, isMobileOpen])
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -20,11 +20,13 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -38,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -20,11 +20,13 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -38,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -21,11 +21,13 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -39,13 +41,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -20,11 +20,13 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -38,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -20,11 +20,13 @@ tags:
|
|||||||
- javascript
|
- javascript
|
||||||
- graphql
|
- graphql
|
||||||
---
|
---
|
||||||
|
|
||||||
## this is second article
|
## this is second article
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
- Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
@ -38,13 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -13,17 +13,18 @@ tags:
|
|||||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
||||||
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
@ -32,13 +33,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -13,17 +13,18 @@ tags:
|
|||||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
||||||
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
@ -32,13 +33,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -13,17 +13,18 @@ tags:
|
|||||||
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
description: Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non
|
||||||
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo.
|
||||||
---
|
---
|
||||||
|
|
||||||
## Lorem ipsum dolor
|
## Lorem ipsum dolor
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit.
|
||||||
|
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
* Nunc non fermentum ligula?
|
- Nunc non fermentum ligula?
|
||||||
|
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligula. Aenean et ex nec magna faucibus congue eu ac justo. Cras malesuada diam lectus, vitae feugiat nulla condimentum id. Duis interdum sodales eros ornare mattis. Nunc id viverra ante. Maecenas suscipit est sed rhoncus condimentum. Orci varius natoque penatibus et magnis dis parturient montes, nascetur ridiculus mus. Curabitur vehicula risus nisi, quis hendrerit magna tincidunt eu. Phasellus fringilla accumsan viverra. Mauris a cursus orci.
|
||||||
|
|
||||||
@ -32,13 +33,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
|||||||

|

|
||||||
|
|
||||||
```js
|
```js
|
||||||
module.exports = {
|
module.exports = {
|
||||||
plugins: [
|
plugins: [
|
||||||
{
|
{
|
||||||
resolve: `plugin`
|
resolve: `plugin`,
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
}
|
||||||
```
|
```
|
||||||
|
|
||||||
## List
|
## List
|
||||||
|
|||||||
@ -1,27 +1,25 @@
|
|||||||
import 'firebase/database';
|
import "firebase/database"
|
||||||
|
|
||||||
import 'gatsby-remark-vscode/styles.css'
|
import "gatsby-remark-vscode/styles.css"
|
||||||
|
|
||||||
import './src/styles/global.scss'
|
import "./src/styles/global.scss"
|
||||||
import './src/components/Header/Header.scss'
|
import "./src/components/Header/Header.scss"
|
||||||
import './src/components/About/About.scss'
|
import "./src/components/About/About.scss"
|
||||||
import './src/components/Offers/Offers.scss'
|
import "./src/components/Offers/Offers.scss"
|
||||||
import './src/components/Articles/Articles.scss'
|
import "./src/components/Articles/Articles.scss"
|
||||||
import './src/components/Articles/ArticleCard/ArticleCard.scss'
|
import "./src/components/Articles/ArticleCard/ArticleCard.scss"
|
||||||
import './src/components/Newsletter/Newsletter.scss'
|
import "./src/components/Newsletter/Newsletter.scss"
|
||||||
import './src/components/Article/Article.scss'
|
import "./src/components/Article/Article.scss"
|
||||||
import './src/components/Snippet/Snippet.scss'
|
import "./src/components/Snippet/Snippet.scss"
|
||||||
import './src/components/Snippets/Snippets.scss'
|
import "./src/components/Snippets/Snippets.scss"
|
||||||
import './src/components/Articles/MoreArticles/MoreArticles.scss'
|
import "./src/components/Articles/MoreArticles/MoreArticles.scss"
|
||||||
import './src/components/Books/Books.scss'
|
import "./src/components/Books/Books.scss"
|
||||||
import './src/components/Contacts/Contacts.scss'
|
import "./src/components/Contacts/Contacts.scss"
|
||||||
import './src/components/Footer/Footer.scss'
|
import "./src/components/Footer/Footer.scss"
|
||||||
|
|
||||||
export const shouldUpdateScroll = ({
|
export const shouldUpdateScroll = ({ routerProps: { location } }) => {
|
||||||
routerProps: { location }
|
|
||||||
}) => {
|
|
||||||
const { pathname } = location
|
const { pathname } = location
|
||||||
const stopScrollLinks = ['/articles/']
|
const stopScrollLinks = ["/articles/"]
|
||||||
|
|
||||||
if (stopScrollLinks.includes(pathname)) return false
|
if (stopScrollLinks.includes(pathname)) return false
|
||||||
|
|
||||||
|
|||||||
@ -1,19 +1,19 @@
|
|||||||
require('dotenv').config()
|
require("dotenv").config()
|
||||||
|
|
||||||
const siteConfig = require('./config')
|
const siteConfig = require("./config")
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
siteMetadata: {
|
siteMetadata: {
|
||||||
...siteConfig
|
...siteConfig,
|
||||||
},
|
},
|
||||||
plugins: [
|
plugins: [
|
||||||
'gatsby-plugin-react-helmet',
|
"gatsby-plugin-react-helmet",
|
||||||
'gatsby-plugin-sass',
|
"gatsby-plugin-sass",
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-source-filesystem',
|
resolve: "gatsby-source-filesystem",
|
||||||
options: {
|
options: {
|
||||||
path: `${__dirname}/static/assets`,
|
path: `${__dirname}/static/assets`,
|
||||||
name: 'assets',
|
name: "assets",
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -40,7 +40,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-plugin-firebase',
|
resolve: "gatsby-plugin-firebase",
|
||||||
options: {
|
options: {
|
||||||
credentials: {
|
credentials: {
|
||||||
apiKey: process.env.API_KEY,
|
apiKey: process.env.API_KEY,
|
||||||
@ -61,7 +61,7 @@ module.exports = {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
"gatsby-plugin-sharp",
|
"gatsby-plugin-sharp",
|
||||||
"gatsby-transformer-sharp",
|
"gatsby-transformer-sharp",
|
||||||
{
|
{
|
||||||
resolve: `gatsby-transformer-remark`,
|
resolve: `gatsby-transformer-remark`,
|
||||||
options: {
|
options: {
|
||||||
@ -69,8 +69,8 @@ module.exports = {
|
|||||||
{
|
{
|
||||||
resolve: `gatsby-remark-relative-images`,
|
resolve: `gatsby-remark-relative-images`,
|
||||||
options: {
|
options: {
|
||||||
name: "assets"
|
name: "assets",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: `gatsby-remark-images`,
|
resolve: `gatsby-remark-images`,
|
||||||
@ -89,41 +89,41 @@ module.exports = {
|
|||||||
removeAccents: true,
|
removeAccents: true,
|
||||||
isIconAfterHeader: true,
|
isIconAfterHeader: true,
|
||||||
elements: [`h1`, `h2`, `h3`, `h4`],
|
elements: [`h1`, `h2`, `h3`, `h4`],
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: `gatsby-remark-vscode`,
|
resolve: `gatsby-remark-vscode`,
|
||||||
options: {
|
options: {
|
||||||
extensions: ['material-theme'],
|
extensions: ["material-theme"],
|
||||||
theme: {
|
theme: {
|
||||||
default: 'Light+ (default light)',
|
default: "Light+ (default light)",
|
||||||
parentSelector: {
|
parentSelector: {
|
||||||
'body.dark': 'One Dark Pro'
|
"body.dark": "One Dark Pro",
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
]
|
],
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
],
|
],
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-plugin-react-svg',
|
resolve: "gatsby-plugin-react-svg",
|
||||||
options: {
|
options: {
|
||||||
rule: {
|
rule: {
|
||||||
include: /images/
|
include: /images/,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
resolve: 'gatsby-source-filesystem',
|
resolve: "gatsby-source-filesystem",
|
||||||
options: {
|
options: {
|
||||||
name: 'content',
|
name: "content",
|
||||||
path: `${__dirname}/content`
|
path: `${__dirname}/content`,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
'gatsby-plugin-netlify-cms',
|
"gatsby-plugin-netlify-cms",
|
||||||
],
|
],
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,14 +1,14 @@
|
|||||||
import slugify from './src/helpers/slugify'
|
import slugify from "./src/helpers/slugify"
|
||||||
import { fmImagesToRelative } from 'gatsby-remark-relative-images'
|
import { fmImagesToRelative } from "gatsby-remark-relative-images"
|
||||||
import path from 'path'
|
import path from "path"
|
||||||
|
|
||||||
exports.createPages = async ({ actions, graphql }) => {
|
exports.createPages = async ({ actions, graphql }) => {
|
||||||
const { createPage } = actions
|
const { createPage } = actions
|
||||||
|
|
||||||
const articleTemplate = path.resolve('src/templates/articleTemplate.js')
|
const articleTemplate = path.resolve("src/templates/articleTemplate.js")
|
||||||
const snippetTemplate = path.resolve('src/templates/snippetTemplate.js')
|
const snippetTemplate = path.resolve("src/templates/snippetTemplate.js")
|
||||||
const categoryTemplate = path.resolve('src/templates/categoryTemplate.js')
|
const categoryTemplate = path.resolve("src/templates/categoryTemplate.js")
|
||||||
const tagTemplate = path.resolve('src/templates/tagTemplate.js')
|
const tagTemplate = path.resolve("src/templates/tagTemplate.js")
|
||||||
|
|
||||||
const result = await graphql(
|
const result = await graphql(
|
||||||
`
|
`
|
||||||
@ -33,19 +33,25 @@ exports.createPages = async ({ actions, graphql }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const all = result.data.allMarkdownRemark.edges
|
const all = result.data.allMarkdownRemark.edges
|
||||||
const articles = all.filter(article => article.node.frontmatter.templateKey === 'article')
|
const articles = all.filter(
|
||||||
const snippets = all.filter(snippet => snippet.node.frontmatter.templateKey === 'snippet')
|
article => article.node.frontmatter.templateKey === "article"
|
||||||
const categories = all.filter(category => category.node.frontmatter.templateKey === 'category')
|
)
|
||||||
const tags = all.filter(tag => tag.node.frontmatter.templateKey === 'tag')
|
const snippets = all.filter(
|
||||||
|
snippet => snippet.node.frontmatter.templateKey === "snippet"
|
||||||
|
)
|
||||||
|
const categories = all.filter(
|
||||||
|
category => category.node.frontmatter.templateKey === "category"
|
||||||
|
)
|
||||||
|
const tags = all.filter(tag => tag.node.frontmatter.templateKey === "tag")
|
||||||
|
|
||||||
articles.forEach(({ node }) => {
|
articles.forEach(({ node }) => {
|
||||||
createPage({
|
createPage({
|
||||||
path: `article/${node.frontmatter.slug}`,
|
path: `article/${node.frontmatter.slug}`,
|
||||||
component: articleTemplate,
|
component: articleTemplate,
|
||||||
context: {
|
context: {
|
||||||
slug: node.frontmatter.slug
|
slug: node.frontmatter.slug,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
snippets.forEach(({ node }) => {
|
snippets.forEach(({ node }) => {
|
||||||
@ -53,7 +59,7 @@ exports.createPages = async ({ actions, graphql }) => {
|
|||||||
path: `snippet/${node.frontmatter.slug}`,
|
path: `snippet/${node.frontmatter.slug}`,
|
||||||
component: snippetTemplate,
|
component: snippetTemplate,
|
||||||
context: {
|
context: {
|
||||||
slug: node.frontmatter.slug
|
slug: node.frontmatter.slug,
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
@ -63,9 +69,9 @@ exports.createPages = async ({ actions, graphql }) => {
|
|||||||
path: `category/${slugify(node.frontmatter.title)}`,
|
path: `category/${slugify(node.frontmatter.title)}`,
|
||||||
component: categoryTemplate,
|
component: categoryTemplate,
|
||||||
context: {
|
context: {
|
||||||
title: node.frontmatter.title
|
title: node.frontmatter.title,
|
||||||
},
|
},
|
||||||
});
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
tags.forEach(({ node }) => {
|
tags.forEach(({ node }) => {
|
||||||
@ -73,12 +79,12 @@ exports.createPages = async ({ actions, graphql }) => {
|
|||||||
path: `tag/${slugify(node.frontmatter.title)}`,
|
path: `tag/${slugify(node.frontmatter.title)}`,
|
||||||
component: tagTemplate,
|
component: tagTemplate,
|
||||||
context: {
|
context: {
|
||||||
title: node.frontmatter.title
|
title: node.frontmatter.title,
|
||||||
}
|
},
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
exports.onCreateNode = ({ node }) => {
|
exports.onCreateNode = ({ node }) => {
|
||||||
fmImagesToRelative(node);
|
fmImagesToRelative(node)
|
||||||
};
|
}
|
||||||
|
|||||||
@ -1,2 +1,2 @@
|
|||||||
require = require('esm')(module)
|
require = require("esm")(module)
|
||||||
module.exports = require('./gatsby-node.esm.js')
|
module.exports = require("./gatsby-node.esm.js")
|
||||||
|
|||||||
@ -1,10 +1,11 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import 'firebase/database';
|
import "firebase/database"
|
||||||
|
|
||||||
const OnDark = () => {
|
const OnDark = () => {
|
||||||
return (
|
return (
|
||||||
<script
|
<script
|
||||||
dangerouslySetInnerHTML={{ __html: `
|
dangerouslySetInnerHTML={{
|
||||||
|
__html: `
|
||||||
(() => {
|
(() => {
|
||||||
window.__isDarkTheme = false
|
window.__isDarkTheme = false
|
||||||
|
|
||||||
@ -31,11 +32,12 @@ const OnDark = () => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})()
|
})()
|
||||||
` }}
|
`,
|
||||||
|
}}
|
||||||
/>
|
/>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export const onRenderBody = ({ setPreBodyComponents }) => {
|
export const onRenderBody = ({ setPreBodyComponents }) => {
|
||||||
setPreBodyComponents(<OnDark key='isDarkTheme' />)
|
setPreBodyComponents(<OnDark key="isDarkTheme" />)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
import ContactsIcon from '../../images/contacts-icon.svg'
|
import ContactsIcon from "../../images/contacts-icon.svg"
|
||||||
|
|
||||||
const About = ({ title, pageTitle, social }) => {
|
const About = ({ title, pageTitle, social }) => {
|
||||||
return (
|
return (
|
||||||
@ -15,11 +15,12 @@ const About = ({ title, pageTitle, social }) => {
|
|||||||
<h2>{title}</h2>
|
<h2>{title}</h2>
|
||||||
<h3>публикуем статьи о мире веб-разрабоки и IT</h3>
|
<h3>публикуем статьи о мире веб-разрабоки и IT</h3>
|
||||||
<p>
|
<p>
|
||||||
этот сайт придуман для того, чтобы помочь вам разобраться с вашей проблемой и решить её. Сайт содержит
|
этот сайт придуман для того, чтобы помочь вам разобраться с вашей
|
||||||
в себе статьи и руководства.
|
проблемой и решить её. Сайт содержит в себе статьи и руководства.
|
||||||
</p>
|
</p>
|
||||||
<p>
|
<p>
|
||||||
~ к тому же здесь публикуются различные новости которые произошли за последнее время
|
~ к тому же здесь публикуются различные новости которые произошли за
|
||||||
|
последнее время
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<div className="about-content__contacts">
|
<div className="about-content__contacts">
|
||||||
@ -28,9 +29,15 @@ const About = ({ title, pageTitle, social }) => {
|
|||||||
<span>контакты</span>
|
<span>контакты</span>
|
||||||
</div>
|
</div>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={`mailto:${social.email}`}>{social.email}</a></li>
|
<li>
|
||||||
<li><a href={social.telegram} target='_blank' rel='noreferrer'>telegram</a></li>
|
<a href={`mailto:${social.email}`}>{social.email}</a>
|
||||||
<Link to='/contacts'>форма обратной связи</Link>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={social.telegram} target="_blank" rel="noreferrer">
|
||||||
|
telegram
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<Link to="/contacts">форма обратной связи</Link>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -43,5 +50,5 @@ export default About
|
|||||||
About.propTypes = {
|
About.propTypes = {
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
pageTitle: PropTypes.string,
|
pageTitle: PropTypes.string,
|
||||||
email: PropTypes.string
|
email: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,25 +1,47 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import SEO from '../SEO/SEO'
|
import SEO from "../SEO/SEO"
|
||||||
import Img from "gatsby-image"
|
import Img from "gatsby-image"
|
||||||
import ViewCounter from '../ViewCounter/ViewCounter'
|
import ViewCounter from "../ViewCounter/ViewCounter"
|
||||||
import useSiteMetadataQuery from '../../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||||
import slugify from '../../helpers/slugify'
|
import slugify from "../../helpers/slugify"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
|
|
||||||
import ViewsIcon from '../../images/views-icon.svg'
|
import ViewsIcon from "../../images/views-icon.svg"
|
||||||
import VkIcon from '../../images/vk-icon.svg'
|
import VkIcon from "../../images/vk-icon.svg"
|
||||||
import TwitterIcon from '../../images/twitter-icon__large.svg'
|
import TwitterIcon from "../../images/twitter-icon__large.svg"
|
||||||
import FacebookIcon from '../../images/facebook-icon__large.svg'
|
import FacebookIcon from "../../images/facebook-icon__large.svg"
|
||||||
|
|
||||||
const Article = ({ data: { slug, keywords, title, image, description, category, tags, time, date }, html }) => {
|
const Article = ({
|
||||||
const { siteMetadata: { siteUrl } } = useSiteMetadataQuery()
|
data: {
|
||||||
|
slug,
|
||||||
|
keywords,
|
||||||
|
title,
|
||||||
|
image,
|
||||||
|
description,
|
||||||
|
category,
|
||||||
|
tags,
|
||||||
|
time,
|
||||||
|
date,
|
||||||
|
},
|
||||||
|
html,
|
||||||
|
}) => {
|
||||||
|
const {
|
||||||
|
siteMetadata: { siteUrl },
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO title={title} titleTemplate={false} keywords={keywords.join(', ')} description={description} image={`${siteUrl}${image.childImageSharp.fluid.src}`} type='article' />
|
<SEO
|
||||||
|
title={title}
|
||||||
|
titleTemplate={false}
|
||||||
|
keywords={keywords.join(", ")}
|
||||||
|
description={description}
|
||||||
|
image={`${siteUrl}${image.childImageSharp.fluid.src}`}
|
||||||
|
type="article"
|
||||||
|
/>
|
||||||
<div className="article">
|
<div className="article">
|
||||||
<article>
|
<article>
|
||||||
<div className="article-info">
|
<div className="article-info">
|
||||||
@ -40,13 +62,25 @@ const Article = ({ data: { slug, keywords, title, image, description, category,
|
|||||||
</div>
|
</div>
|
||||||
<div className="article-share">
|
<div className="article-share">
|
||||||
<div className="article-share__social">
|
<div className="article-share__social">
|
||||||
<a href={`https://vk.com/share.php?url=${siteUrl}/article/${slug}&title=${title}&image=${siteUrl}${image.childImageSharp.fluid.src}`} target='_blank' rel='noreferrer'>
|
<a
|
||||||
|
href={`https://vk.com/share.php?url=${siteUrl}/article/${slug}&title=${title}&image=${siteUrl}${image.childImageSharp.fluid.src}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
<VkIcon />
|
<VkIcon />
|
||||||
</a>
|
</a>
|
||||||
<a href={`https://twitter.com/intent/tweet?text=${title}&url=${siteUrl}/article/${slug}&image=${siteUrl}${image.childImageSharp.fluid.src}`} target='_blank' rel='noreferrer'>
|
<a
|
||||||
|
href={`https://twitter.com/intent/tweet?text=${title}&url=${siteUrl}/article/${slug}&image=${siteUrl}${image.childImageSharp.fluid.src}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
<TwitterIcon />
|
<TwitterIcon />
|
||||||
</a>
|
</a>
|
||||||
<a href={`https://www.facebook.com/sharer/sharer.php?u=${siteUrl}/article/${slug}&t=${title}`} target='_blank' rel='noreferrer'>
|
<a
|
||||||
|
href={`https://www.facebook.com/sharer/sharer.php?u=${siteUrl}/article/${slug}&t=${title}`}
|
||||||
|
target="_blank"
|
||||||
|
rel="noreferrer"
|
||||||
|
>
|
||||||
<FacebookIcon />
|
<FacebookIcon />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
@ -58,30 +92,37 @@ const Article = ({ data: { slug, keywords, title, image, description, category,
|
|||||||
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-description">
|
<div className="article-description">
|
||||||
<p>
|
<p>{description}</p>
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="article-tags">
|
<div className="article-tags">
|
||||||
{tags.map((tag, i) => <div key={i} className="tag-item">
|
{tags.map((tag, i) => (
|
||||||
<Link to={`/tag/${slugify(tag)}`}>{tag}</Link>
|
<div key={i} className="tag-item">
|
||||||
</div>)}
|
<Link to={`/tag/${slugify(tag)}`}>{tag}</Link>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
<div className="article-image">
|
<div className="article-image">
|
||||||
<Img loading="eager" fadeIn={false} fluid={image.childImageSharp.fluid} alt={title} />
|
<Img
|
||||||
|
loading="eager"
|
||||||
|
fadeIn={false}
|
||||||
|
fluid={image.childImageSharp.fluid}
|
||||||
|
alt={title}
|
||||||
|
/>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-inner inner">
|
<div className="article-inner inner">
|
||||||
<div dangerouslySetInnerHTML={{__html: html}}></div>
|
<div dangerouslySetInnerHTML={{ __html: html }}></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-more">
|
<div className="article-more">
|
||||||
<span>Смотреть еще в категории <Link to={`/category/${slugify(category)}`}>{category}</Link></span>
|
<span>
|
||||||
|
Смотреть еще в категории{" "}
|
||||||
|
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
||||||
|
</span>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-comments">
|
<div className="article-comments">
|
||||||
<div className="article-comments__heading">
|
<div className="article-comments__heading">
|
||||||
<h2>Комментарии</h2>
|
<h2>Комментарии</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-comments__content">
|
<div className="article-comments__content"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
@ -101,7 +142,7 @@ Article.propTypes = {
|
|||||||
category: PropTypes.string,
|
category: PropTypes.string,
|
||||||
tags: PropTypes.array,
|
tags: PropTypes.array,
|
||||||
time: PropTypes.string,
|
time: PropTypes.string,
|
||||||
date: PropTypes.string
|
date: PropTypes.string,
|
||||||
}),
|
}),
|
||||||
html: PropTypes.string
|
html: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,32 +1,43 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import slugify from '../../../helpers/slugify'
|
import slugify from "../../../helpers/slugify"
|
||||||
import Img from "gatsby-image"
|
import Img from "gatsby-image"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
const ArticleCard = ({ data: { slug, title, image, category, description, tags } }) => {
|
const ArticleCard = ({
|
||||||
|
data: { slug, title, image, category, description, tags },
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<article className="article-card">
|
<article className="article-card">
|
||||||
<div className="article-card__image">
|
<div className="article-card__image">
|
||||||
<Link to={`/article/${slug}`}>
|
<Link to={`/article/${slug}`}>
|
||||||
<Img loading="eager" fadeIn={false} fluid={image.childImageSharp.fluid} alt={title} />
|
<Img
|
||||||
|
loading="eager"
|
||||||
|
fadeIn={false}
|
||||||
|
fluid={image.childImageSharp.fluid}
|
||||||
|
alt={title}
|
||||||
|
/>
|
||||||
</Link>
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-card__heading">
|
<div className="article-card__heading">
|
||||||
<h2><Link to={`/article/${slug}`}>{title}</Link></h2>
|
<h2>
|
||||||
|
<Link to={`/article/${slug}`}>{title}</Link>
|
||||||
|
</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-card__category">
|
<div className="article-card__category">
|
||||||
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-card__tags">
|
<div className="article-card__tags">
|
||||||
<ul>
|
<ul>
|
||||||
{tags.map((tag, i) => <li key={i}><Link to={`/tag/${tag}`}>{tag}</Link></li>)}
|
{tags.map((tag, i) => (
|
||||||
|
<li key={i}>
|
||||||
|
<Link to={`/tag/${tag}`}>{tag}</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-card__description">
|
<div className="article-card__description">
|
||||||
<p>
|
<p>{description}</p>
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
)
|
)
|
||||||
@ -41,6 +52,6 @@ ArticleCard.propTypes = {
|
|||||||
image: PropTypes.object,
|
image: PropTypes.object,
|
||||||
category: PropTypes.string,
|
category: PropTypes.string,
|
||||||
description: PropTypes.string,
|
description: PropTypes.string,
|
||||||
tags: PropTypes.array
|
tags: PropTypes.array,
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
@ -1,10 +1,16 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import useSiteMetadataQuery from '../../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||||
import ArticleCard from './ArticleCard/ArticleCard'
|
import ArticleCard from "./ArticleCard/ArticleCard"
|
||||||
|
|
||||||
const Articles = ({ data: { edges }, limit = 6, setLimit = () => null }) => {
|
const Articles = ({ data: { edges }, limit = 6, setLimit = () => null }) => {
|
||||||
const { siteMetadata: { options: { articles: { onLoadMore } } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
options: {
|
||||||
|
articles: { onLoadMore },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<div className="articles">
|
<div className="articles">
|
||||||
@ -16,14 +22,20 @@ const Articles = ({ data: { edges }, limit = 6, setLimit = () => null }) => {
|
|||||||
return <ArticleCard key={i} data={node.frontmatter} />
|
return <ArticleCard key={i} data={node.frontmatter} />
|
||||||
}
|
}
|
||||||
return null
|
return null
|
||||||
})
|
})}
|
||||||
}
|
|
||||||
</div>
|
</div>
|
||||||
<div className="articles-loadMore">
|
<div className="articles-loadMore">
|
||||||
{edges.length === limit || edges.length <= limit
|
{edges.length === limit || edges.length <= limit ? null : (
|
||||||
? null
|
<button
|
||||||
: <button className='btn-loadMore' onClick={() => setLimit(limit + onLoadMore)}>Загрузить еще <span role='img' aria-label='load more'>👇</span></button>
|
className="btn-loadMore"
|
||||||
}
|
onClick={() => setLimit(limit + onLoadMore)}
|
||||||
|
>
|
||||||
|
Загрузить еще
|
||||||
|
<span role="img" aria-label="load more">
|
||||||
|
👇
|
||||||
|
</span>
|
||||||
|
</button>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</>
|
</>
|
||||||
@ -36,6 +48,6 @@ Articles.propTypes = {
|
|||||||
data: PropTypes.shape({
|
data: PropTypes.shape({
|
||||||
edges: PropTypes.array,
|
edges: PropTypes.array,
|
||||||
limit: PropTypes.number,
|
limit: PropTypes.number,
|
||||||
setLimit: PropTypes.func
|
setLimit: PropTypes.func,
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
@ -1,18 +1,23 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
const Categories = ({ children, setQuery = () => null }) => {
|
const Categories = ({ children, setQuery = () => null }) => {
|
||||||
const { search, pathname } = useLocation()
|
const { search, pathname } = useLocation()
|
||||||
return (
|
return (
|
||||||
<div className="articles-categories">
|
<div className="articles-categories">
|
||||||
<div className={
|
<div
|
||||||
pathname === `/articles` || (pathname === `/articles/` && search === '')
|
className={
|
||||||
? 'tag-item active'
|
pathname === `/articles` ||
|
||||||
: 'tag-item'
|
(pathname === `/articles/` && search === "")
|
||||||
}>
|
? "tag-item active"
|
||||||
<Link onClick={() => setQuery('')} to='/articles'>Все</Link>
|
: "tag-item"
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Link onClick={() => setQuery("")} to="/articles">
|
||||||
|
Все
|
||||||
|
</Link>
|
||||||
</div>
|
</div>
|
||||||
{children}
|
{children}
|
||||||
</div>
|
</div>
|
||||||
@ -22,5 +27,5 @@ const Categories = ({ children, setQuery = () => null }) => {
|
|||||||
export default Categories
|
export default Categories
|
||||||
|
|
||||||
Categories.propTypes = {
|
Categories.propTypes = {
|
||||||
setQuery: PropTypes.func
|
setQuery: PropTypes.func,
|
||||||
}
|
}
|
||||||
@ -1,13 +1,20 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import slugify from '../../../helpers/slugify'
|
import slugify from "../../../helpers/slugify"
|
||||||
|
|
||||||
const CategoryItem = ({ title }) => {
|
const CategoryItem = ({ title }) => {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
return (
|
return (
|
||||||
<div className={pathname === `/category/${slugify(title)}` || pathname === `/category/${slugify(title)}/` ? 'tag-item active' : 'tag-item'}>
|
<div
|
||||||
|
className={
|
||||||
|
pathname === `/category/${slugify(title)}` ||
|
||||||
|
pathname === `/category/${slugify(title)}/`
|
||||||
|
? "tag-item active"
|
||||||
|
: "tag-item"
|
||||||
|
}
|
||||||
|
>
|
||||||
<Link to={`/category/${slugify(title)}`}>{title}</Link>
|
<Link to={`/category/${slugify(title)}`}>{title}</Link>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -16,6 +23,5 @@ const CategoryItem = ({ title }) => {
|
|||||||
export default CategoryItem
|
export default CategoryItem
|
||||||
|
|
||||||
CategoryItem.propTypes = {
|
CategoryItem.propTypes = {
|
||||||
title: PropTypes.string
|
title: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import useMoreArticlesQuery from '../../../hooks/useMoreArticlesQuery'
|
import useMoreArticlesQuery from "../../../hooks/useMoreArticlesQuery"
|
||||||
import ArticleCard from '../ArticleCard/ArticleCard'
|
import ArticleCard from "../ArticleCard/ArticleCard"
|
||||||
|
|
||||||
const MoreArticles = () => {
|
const MoreArticles = () => {
|
||||||
const { edges } = useMoreArticlesQuery()
|
const { edges } = useMoreArticlesQuery()
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const query = pathname.split('/')[pathname.split('/').length - 1]
|
const query = pathname.split("/")[pathname.split("/").length - 1]
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="more-articles">
|
<div className="more-articles">
|
||||||
@ -14,12 +14,15 @@ const MoreArticles = () => {
|
|||||||
<h2>Вам также может понравится...</h2>
|
<h2>Вам также может понравится...</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="more-articles__content">
|
<div className="more-articles__content">
|
||||||
{edges.filter(({ node }) => node.frontmatter.slug !== query).sort(() => Math.random() - 0.5).map(({ node }, i) => {
|
{edges
|
||||||
if (i < 4) {
|
.filter(({ node }) => node.frontmatter.slug !== query)
|
||||||
return <ArticleCard key={i} data={node.frontmatter} />
|
.sort(() => Math.random() - 0.5)
|
||||||
}
|
.map(({ node }, i) => {
|
||||||
return null
|
if (i < 4) {
|
||||||
})}
|
return <ArticleCard key={i} data={node.frontmatter} />
|
||||||
|
}
|
||||||
|
return null
|
||||||
|
})}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,40 +1,55 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import { navigate } from 'gatsby'
|
import { navigate } from "gatsby"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
const Search = ({ allArticles, filterArticles, articlesLength, resultsLength, query, setQuery, setFiltredArticles, setLimit, onPage }) => {
|
const Search = ({
|
||||||
const handleInput = e => {
|
allArticles,
|
||||||
const query = e.target.value
|
filterArticles,
|
||||||
if (query === '') {
|
articlesLength,
|
||||||
navigate('/articles/')
|
resultsLength,
|
||||||
setQuery('')
|
query,
|
||||||
setLimit(onPage)
|
setQuery,
|
||||||
return null
|
setFiltredArticles,
|
||||||
}
|
setLimit,
|
||||||
navigate(`/articles/?search=${query.trim()}`)
|
onPage,
|
||||||
setQuery(query)
|
}) => {
|
||||||
setFiltredArticles(filterArticles(allArticles))
|
const handleInput = e => {
|
||||||
setLimit(onPage)
|
const query = e.target.value
|
||||||
}
|
if (query === "") {
|
||||||
|
navigate("/articles/")
|
||||||
|
setQuery("")
|
||||||
|
setLimit(onPage)
|
||||||
|
return null
|
||||||
|
}
|
||||||
|
navigate(`/articles/?search=${query.trim()}`)
|
||||||
|
setQuery(query)
|
||||||
|
setFiltredArticles(filterArticles(allArticles))
|
||||||
|
setLimit(onPage)
|
||||||
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="articles-search">
|
<div className="articles-search">
|
||||||
<input onChange={e => handleInput(e)} value={query} placeholder="Напишите сюда чтобы отфильтровать статьи" type="text" />
|
<input
|
||||||
<span>{query === '' ? articlesLength : resultsLength}</span>
|
onChange={e => handleInput(e)}
|
||||||
|
value={query}
|
||||||
|
placeholder="Напишите сюда чтобы отфильтровать статьи"
|
||||||
|
type="text"
|
||||||
|
/>
|
||||||
|
<span>{query === "" ? articlesLength : resultsLength}</span>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Search
|
export default Search
|
||||||
|
|
||||||
Search.propTypes = {
|
Search.propTypes = {
|
||||||
allArticles: PropTypes.array,
|
allArticles: PropTypes.array,
|
||||||
filterArticles: PropTypes.func,
|
filterArticles: PropTypes.func,
|
||||||
articlesLength: PropTypes.number,
|
articlesLength: PropTypes.number,
|
||||||
resultsLength: PropTypes.number,
|
resultsLength: PropTypes.number,
|
||||||
query: PropTypes.string,
|
query: PropTypes.string,
|
||||||
setQuery: PropTypes.func,
|
setQuery: PropTypes.func,
|
||||||
setFiltredArticles: PropTypes.func,
|
setFiltredArticles: PropTypes.func,
|
||||||
setLimit: PropTypes.func,
|
setLimit: PropTypes.func,
|
||||||
onPage: PropTypes.number
|
onPage: PropTypes.number,
|
||||||
}
|
}
|
||||||
@ -1,17 +1,36 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import slugify from '../../helpers/slugify'
|
import slugify from "../../helpers/slugify"
|
||||||
import Img from "gatsby-image"
|
import Img from "gatsby-image"
|
||||||
|
|
||||||
const Books = ({ data: { edges } }) => {
|
const Books = ({ data: { edges } }) => {
|
||||||
return (
|
return (
|
||||||
<div className="books">
|
<div className="books">
|
||||||
<div className="books-inner inner">
|
<div className="books-inner inner">
|
||||||
{edges.map(({ node }, i) => <div key={i}>
|
{edges.map(({ node }, i) => (
|
||||||
<h2>{node.frontmatter.title} <a id={slugify(node.frontmatter.title)} href={`/books#${slugify(node.frontmatter.title)}`} className='anchor'>{node.frontmatter.title}</a></h2>
|
<div key={i}>
|
||||||
<Img loading="eager" fadeIn={false} fluid={node.frontmatter.image.childImageSharp.fluid} alt={node.frontmatter.title} />
|
<h2>
|
||||||
<div className='md' dangerouslySetInnerHTML={{__html: node.html}}></div>
|
{node.frontmatter.title}{" "}
|
||||||
</div>)}
|
<a
|
||||||
|
id={slugify(node.frontmatter.title)}
|
||||||
|
href={`/books#${slugify(node.frontmatter.title)}`}
|
||||||
|
className="anchor"
|
||||||
|
>
|
||||||
|
{node.frontmatter.title}
|
||||||
|
</a>
|
||||||
|
</h2>
|
||||||
|
<Img
|
||||||
|
loading="eager"
|
||||||
|
fadeIn={false}
|
||||||
|
fluid={node.frontmatter.image.childImageSharp.fluid}
|
||||||
|
alt={node.frontmatter.title}
|
||||||
|
/>
|
||||||
|
<div
|
||||||
|
className="md"
|
||||||
|
dangerouslySetInnerHTML={{ __html: node.html }}
|
||||||
|
></div>
|
||||||
|
</div>
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
@ -21,6 +40,6 @@ export default Books
|
|||||||
|
|
||||||
Books.propTypes = {
|
Books.propTypes = {
|
||||||
data: PropTypes.shape({
|
data: PropTypes.shape({
|
||||||
edges: PropTypes.array
|
edges: PropTypes.array,
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import ContactsFrom from './ContactsForm/ContactsForm';
|
import ContactsFrom from "./ContactsForm/ContactsForm"
|
||||||
|
|
||||||
import MemoIcon from '../../images/memo-icon.svg'
|
import MemoIcon from "../../images/memo-icon.svg"
|
||||||
|
|
||||||
const Contacts = ({ email, telegram }) => {
|
const Contacts = ({ email, telegram }) => {
|
||||||
return (
|
return (
|
||||||
@ -13,15 +13,21 @@ const Contacts = ({ email, telegram }) => {
|
|||||||
</div>
|
</div>
|
||||||
<div className="contacts-description">
|
<div className="contacts-description">
|
||||||
<p>
|
<p>
|
||||||
Для того чтобы задать вопрос, сообщить об ошибках или просто поздороваться, вы можете воспользоваться формой обратной связи или использовать контактные данные.
|
Для того чтобы задать вопрос, сообщить об ошибках или просто
|
||||||
|
поздороваться, вы можете воспользоваться формой обратной связи или
|
||||||
|
использовать контактные данные.
|
||||||
</p>
|
</p>
|
||||||
</div>
|
</div>
|
||||||
<ContactsFrom />
|
<ContactsFrom />
|
||||||
<div className="contacts-info">
|
<div className="contacts-info">
|
||||||
<h2>контактные данные</h2>
|
<h2>контактные данные</h2>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={`mailto:${email}`}>{email}</a></li>
|
<li>
|
||||||
<li><a href={telegram}>telegram</a></li>
|
<a href={`mailto:${email}`}>{email}</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={telegram}>telegram</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -32,5 +38,5 @@ export default Contacts
|
|||||||
|
|
||||||
Contacts.propTypes = {
|
Contacts.propTypes = {
|
||||||
email: PropTypes.string,
|
email: PropTypes.string,
|
||||||
telegram: PropTypes.string
|
telegram: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,4 +1,4 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
|
|
||||||
const ContactsFrom = () => {
|
const ContactsFrom = () => {
|
||||||
return (
|
return (
|
||||||
|
|||||||
@ -1,54 +1,92 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import useSiteMetadataQuery from '../../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||||
|
|
||||||
import LogoIcon from '../../images/logo-icon.svg'
|
import LogoIcon from "../../images/logo-icon.svg"
|
||||||
import GatsbyIcon from '../../images/gatsby-icon.svg'
|
import GatsbyIcon from "../../images/gatsby-icon.svg"
|
||||||
import NetlifyIcon from '../../images/netlify-icon.svg'
|
import NetlifyIcon from "../../images/netlify-icon.svg"
|
||||||
|
|
||||||
const Footer = () => {
|
const Footer = () => {
|
||||||
const { siteMetadata: { title, menuLinks, social: { email, telegram, twitter, yadzen } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
title,
|
||||||
|
menuLinks,
|
||||||
|
social: { email, telegram, twitter, yadzen },
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
return (
|
return (
|
||||||
<footer>
|
<footer>
|
||||||
<div className="footer-content">
|
<div className="footer-content">
|
||||||
<div className="footer-content__logo">
|
<div className="footer-content__logo">
|
||||||
<LogoIcon />
|
<LogoIcon />
|
||||||
<Link to='/'>{title}</Link>
|
<Link to="/">{title}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="footer-content__nav">
|
<div className="footer-content__nav">
|
||||||
<div className="footer-nav__links">
|
<div className="footer-nav__links">
|
||||||
<div className="links-nav">
|
<div className="links-nav">
|
||||||
<p>Навигация</p>
|
<p>Навигация</p>
|
||||||
<ul>
|
<ul>
|
||||||
{menuLinks.map((page, i) => page.link !== '/contacts' ? <li key={i}><Link to={page.link}>{page.name}</Link></li> : null)}
|
{menuLinks.map((page, i) =>
|
||||||
|
page.link !== "/contacts" ? (
|
||||||
|
<li key={i}>
|
||||||
|
<Link to={page.link}>{page.name}</Link>
|
||||||
|
</li>
|
||||||
|
) : null
|
||||||
|
)}
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="links-contacts">
|
<div className="links-contacts">
|
||||||
<p>Контакты</p>
|
<p>Контакты</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><Link to='/contacts'>Форма обратной связи</Link></li>
|
<li>
|
||||||
<li><a href={telegram}>Телеграмм</a></li>
|
<Link to="/contacts">Форма обратной связи</Link>
|
||||||
<li><a href={`mailto:${email}`}>Почта</a></li>
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={telegram}>Телеграмм</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={`mailto:${email}`}>Почта</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
<div className="links-social">
|
<div className="links-social">
|
||||||
<p>Социальные сети</p>
|
<p>Социальные сети</p>
|
||||||
<ul>
|
<ul>
|
||||||
<li><a href={telegram} rel='noreferrer' target='_blank'>Наш телеграмм канал</a></li>
|
<li>
|
||||||
<li><a href={yadzen} rel='noreferrer' target='_blank'>Яндекс.Дзен</a></li>
|
<a href={telegram} rel="noreferrer" target="_blank">
|
||||||
<li><a href={twitter} rel='noreferrer' target='_blank'>Твиттер</a></li>
|
Наш телеграмм канал
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={yadzen} rel="noreferrer" target="_blank">
|
||||||
|
Яндекс.Дзен
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href={twitter} rel="noreferrer" target="_blank">
|
||||||
|
Твиттер
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className="footer-nav__helpers">
|
<div className="footer-nav__helpers">
|
||||||
<span>Разработка при помощи:</span>
|
<span>Разработка при помощи:</span>
|
||||||
<div className="helpers-icons">
|
<div className="helpers-icons">
|
||||||
<a href="https://www.gatsbyjs.org/" rel='noreferrer' target="_blank">
|
<a
|
||||||
|
href="https://www.gatsbyjs.org/"
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<GatsbyIcon />
|
<GatsbyIcon />
|
||||||
GatsbyJS
|
GatsbyJS
|
||||||
</a>
|
</a>
|
||||||
<a href="https://www.netlify.com/" rel='noreferrer' target="_blank">
|
<a
|
||||||
|
href="https://www.netlify.com/"
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
>
|
||||||
<NetlifyIcon />
|
<NetlifyIcon />
|
||||||
Netlify
|
Netlify
|
||||||
</a>
|
</a>
|
||||||
@ -66,9 +104,9 @@ const Footer = () => {
|
|||||||
export default Footer
|
export default Footer
|
||||||
|
|
||||||
Footer.propTypes = {
|
Footer.propTypes = {
|
||||||
title: PropTypes.string
|
title: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
Footer.defaultProps = {
|
Footer.defaultProps = {
|
||||||
title: null
|
title: null,
|
||||||
}
|
}
|
||||||
@ -1,26 +1,35 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import useSiteMetadataQuery from '../../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||||
|
|
||||||
import LogoIcon from '../../images/logo-icon.svg'
|
import LogoIcon from "../../images/logo-icon.svg"
|
||||||
import TelegramIcon from '../../images/telegram-icon.svg'
|
import TelegramIcon from "../../images/telegram-icon.svg"
|
||||||
import TwitterIcon from '../../images/twitter-icon.svg'
|
import TwitterIcon from "../../images/twitter-icon.svg"
|
||||||
import MoonIcon from '../../images/moon-icon.svg'
|
import MoonIcon from "../../images/moon-icon.svg"
|
||||||
import SunIcon from '../../images/sun-icon.svg'
|
import SunIcon from "../../images/sun-icon.svg"
|
||||||
|
|
||||||
const Header = () => {
|
const Header = () => {
|
||||||
const { siteMetadata: { title, menuLinks, social: { twitter, telegram } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
title,
|
||||||
|
menuLinks,
|
||||||
|
social: { twitter, telegram },
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||||
const [isDark, setIsDark] = React.useState(false)
|
const [isDark, setIsDark] = React.useState(false)
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setIsDark(window.__isDarkTheme)
|
setIsDark(window.__isDarkTheme)
|
||||||
isMobileOpen ? document.body.style.overflowY = 'hidden' : document.body.style.overflowY = ''
|
isMobileOpen
|
||||||
document.body.onscroll = () => window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
? (document.body.style.overflowY = "hidden")
|
||||||
|
: (document.body.style.overflowY = "")
|
||||||
|
document.body.onscroll = () =>
|
||||||
|
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
||||||
}, [setIsDark, isMobileOpen])
|
}, [setIsDark, isMobileOpen])
|
||||||
|
|
||||||
const mobileHandler = () => {
|
const mobileHandler = () => {
|
||||||
@ -30,62 +39,90 @@ const Header = () => {
|
|||||||
const renderLinks = () => {
|
const renderLinks = () => {
|
||||||
return (
|
return (
|
||||||
<ul>
|
<ul>
|
||||||
{menuLinks.map((page, i) => <li key={i} className={page.link === pathname || pathname === `${page.link}/` ? 'active' : null}><Link to={page.link}>{page.name}</Link></li>)}
|
{menuLinks.map((page, i) => (
|
||||||
|
<li
|
||||||
|
key={i}
|
||||||
|
className={
|
||||||
|
page.link === pathname || pathname === `${page.link}/`
|
||||||
|
? "active"
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<Link to={page.link}>{page.name}</Link>
|
||||||
|
</li>
|
||||||
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<header className={isScrolled ? 'headerScrolled' : null}>
|
<header className={isScrolled ? "headerScrolled" : null}>
|
||||||
<div className="header-content">
|
<div className="header-content">
|
||||||
<div className="header-content__logo">
|
<div className="header-content__logo">
|
||||||
<LogoIcon />
|
<LogoIcon />
|
||||||
<Link to='/'>{title}</Link>
|
<Link to="/">{title}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="header-content__nav desktop">
|
<div className="header-content__nav desktop">
|
||||||
<div className="header-nav__social">
|
<div className="header-nav__social">
|
||||||
<a href={telegram} target="_blank" rel='noreferrer'>
|
<a href={telegram} target="_blank" rel="noreferrer">
|
||||||
<TelegramIcon />
|
<TelegramIcon />
|
||||||
</a>
|
</a>
|
||||||
<a href={twitter} target="_blank" rel='noreferrer'>
|
<a href={twitter} target="_blank" rel="noreferrer">
|
||||||
<TwitterIcon />
|
<TwitterIcon />
|
||||||
</a>
|
</a>
|
||||||
</div>
|
</div>
|
||||||
<div className="header-nav__links">
|
<div className="header-nav__links">
|
||||||
<nav>
|
<nav>{renderLinks()}</nav>
|
||||||
{renderLinks()}
|
|
||||||
</nav>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="header-nav__theme">
|
<div className="header-nav__theme">
|
||||||
{isDark ? <SunIcon onClick={() => {
|
{isDark ? (
|
||||||
window.__setTheme('light')
|
<SunIcon
|
||||||
setIsDark(!isDark)
|
onClick={() => {
|
||||||
}} /> : <MoonIcon onClick={() => {
|
window.__setTheme("light")
|
||||||
window.__setTheme('dark')
|
setIsDark(!isDark)
|
||||||
setIsDark(!isDark)
|
}}
|
||||||
}} />}
|
/>
|
||||||
|
) : (
|
||||||
|
<MoonIcon
|
||||||
|
onClick={() => {
|
||||||
|
window.__setTheme("dark")
|
||||||
|
setIsDark(!isDark)
|
||||||
|
}}
|
||||||
|
/>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div className={isMobileOpen ? 'header-content__nav mobile mobileOpen' : 'header-content__nav mobile'}>
|
<div
|
||||||
{isMobileOpen
|
className={
|
||||||
? <>
|
isMobileOpen
|
||||||
<span>{title}</span>
|
? "header-content__nav mobile mobileOpen"
|
||||||
<nav>
|
: "header-content__nav mobile"
|
||||||
{renderLinks()}
|
|
||||||
</nav>
|
|
||||||
<div className="mobile-social">
|
|
||||||
<a href="/" target="_blank">
|
|
||||||
<TelegramIcon />
|
|
||||||
</a>
|
|
||||||
<a href="/" target="_blank">
|
|
||||||
<TwitterIcon />
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</>
|
|
||||||
: null
|
|
||||||
}
|
}
|
||||||
|
>
|
||||||
|
{isMobileOpen ? (
|
||||||
|
<>
|
||||||
|
<span>{title}</span>
|
||||||
|
<nav>{renderLinks()}</nav>
|
||||||
|
<div className="mobile-social">
|
||||||
|
<a href="/" target="_blank">
|
||||||
|
<TelegramIcon />
|
||||||
|
</a>
|
||||||
|
<a href="/" target="_blank">
|
||||||
|
<TwitterIcon />
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
</>
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
<button aria-label='menu' onClick={mobileHandler} className={isMobileOpen ? "header-content__button mobile active" : 'header-content__button mobile'}>
|
<button
|
||||||
|
aria-label="menu"
|
||||||
|
onClick={mobileHandler}
|
||||||
|
className={
|
||||||
|
isMobileOpen
|
||||||
|
? "header-content__button mobile active"
|
||||||
|
: "header-content__button mobile"
|
||||||
|
}
|
||||||
|
>
|
||||||
<span />
|
<span />
|
||||||
<span />
|
<span />
|
||||||
<span />
|
<span />
|
||||||
@ -102,12 +139,12 @@ Header.propTypes = {
|
|||||||
menuLinks: PropTypes.arrayOf(
|
menuLinks: PropTypes.arrayOf(
|
||||||
PropTypes.shape({
|
PropTypes.shape({
|
||||||
link: PropTypes.string,
|
link: PropTypes.string,
|
||||||
name: PropTypes.string
|
name: PropTypes.string,
|
||||||
})
|
})
|
||||||
)
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
Header.defaultProps = {
|
Header.defaultProps = {
|
||||||
title: null,
|
title: null,
|
||||||
menuLinks: null
|
menuLinks: null,
|
||||||
}
|
}
|
||||||
@ -1,12 +1,12 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import Header from '../Header/Header'
|
import Header from "../Header/Header"
|
||||||
import Footer from '../Footer/Footer'
|
import Footer from "../Footer/Footer"
|
||||||
|
|
||||||
const Layout = ({ children }) => {
|
const Layout = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<Header />
|
<Header />
|
||||||
{children}
|
{children}
|
||||||
<Footer />
|
<Footer />
|
||||||
</>
|
</>
|
||||||
)
|
)
|
||||||
|
|||||||
@ -1,17 +1,20 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
|
|
||||||
const Newsletter = () => {
|
const Newsletter = () => {
|
||||||
return (
|
return (
|
||||||
<div className="newsletter">
|
<div className="newsletter">
|
||||||
<div className="newsletter-heading">
|
<div className="newsletter-heading">Новостная рассылка</div>
|
||||||
Новостная рассылка
|
|
||||||
</div>
|
|
||||||
<div className="newsletter-content">
|
<div className="newsletter-content">
|
||||||
<form action="#">
|
<form action="#">
|
||||||
<p>
|
<p>
|
||||||
<span role="img" aria-label="hot" >🔥</span> At vero eos et accusamus et iusto odio dignissimos ducimus qui blanditiis praesentium voluptatum
|
<span role="img" aria-label="hot">
|
||||||
deleniti atque corrupti quos dolores et quas molestias excepturi sint occaecati cupiditate non
|
🔥
|
||||||
provident, similique sunt in culpa qui officia deserunt mollitia animi, id est laborum et dolorum fuga
|
</span>{" "}
|
||||||
|
At vero eos et accusamus et iusto odio dignissimos ducimus qui
|
||||||
|
blanditiis praesentium voluptatum deleniti atque corrupti quos
|
||||||
|
dolores et quas molestias excepturi sint occaecati cupiditate non
|
||||||
|
provident, similique sunt in culpa qui officia deserunt mollitia
|
||||||
|
animi, id est laborum et dolorum fuga
|
||||||
</p>
|
</p>
|
||||||
<div className="email-field">
|
<div className="email-field">
|
||||||
<input placeholder="ваш e-mail" type="text" name="email" />
|
<input placeholder="ваш e-mail" type="text" name="email" />
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import usePopularArticlesQuery from '../../hooks/usePopularArticlesQuery'
|
import usePopularArticlesQuery from "../../hooks/usePopularArticlesQuery"
|
||||||
import useTagsQuery from '../../hooks/useTagsQuery'
|
import useTagsQuery from "../../hooks/useTagsQuery"
|
||||||
import Popular from './Popular/Popular'
|
import Popular from "./Popular/Popular"
|
||||||
import Tags from './Tags/Tags'
|
import Tags from "./Tags/Tags"
|
||||||
import Subscription from './Subscription/Subscription'
|
import Subscription from "./Subscription/Subscription"
|
||||||
|
|
||||||
import PopularItem from './Popular/PopularItem'
|
import PopularItem from "./Popular/PopularItem"
|
||||||
import TagItem from './Tags/TagItem'
|
import TagItem from "./Tags/TagItem"
|
||||||
|
|
||||||
const Offers = () => {
|
const Offers = () => {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
@ -15,12 +15,23 @@ const Offers = () => {
|
|||||||
const { tags } = useTagsQuery()
|
const { tags } = useTagsQuery()
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div style={{ height: pathname === '/' ? '78%' : '78.5%' }} className="offers">
|
<div
|
||||||
|
style={{ height: pathname === "/" ? "78%" : "78.5%" }}
|
||||||
|
className="offers"
|
||||||
|
>
|
||||||
<Popular>
|
<Popular>
|
||||||
{articles.map(({ node }, i) => <PopularItem key={i} slug={node.frontmatter.slug} title={node.frontmatter.title} />)}
|
{articles.map(({ node }, i) => (
|
||||||
|
<PopularItem
|
||||||
|
key={i}
|
||||||
|
slug={node.frontmatter.slug}
|
||||||
|
title={node.frontmatter.title}
|
||||||
|
/>
|
||||||
|
))}
|
||||||
</Popular>
|
</Popular>
|
||||||
<Tags>
|
<Tags>
|
||||||
{tags.map(({ node }, i) => <TagItem key={i} title={node.frontmatter.title} />)}
|
{tags.map(({ node }, i) => (
|
||||||
|
<TagItem key={i} title={node.frontmatter.title} />
|
||||||
|
))}
|
||||||
</Tags>
|
</Tags>
|
||||||
<Subscription />
|
<Subscription />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
|
|
||||||
import PopularIcon from '../../../images/popular-icon.svg'
|
import PopularIcon from "../../../images/popular-icon.svg"
|
||||||
|
|
||||||
const Popular = ({ children }) => {
|
const Popular = ({ children }) => {
|
||||||
return (
|
return (
|
||||||
<div className="offers-popular offer-box">
|
<div className="offers-popular offer-box">
|
||||||
<div className="offers-popular__heading offer-heading">
|
<div className="offers-popular__heading offer-heading">
|
||||||
<PopularIcon />
|
<PopularIcon />
|
||||||
Популярные статьи</div>
|
Популярные статьи
|
||||||
<div className="offers-popular__content">
|
|
||||||
{children}
|
|
||||||
</div>
|
</div>
|
||||||
|
<div className="offers-popular__content">{children}</div>
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
const PopularItem = ({ slug, title }) => {
|
const PopularItem = ({ slug, title }) => {
|
||||||
return (
|
return (
|
||||||
@ -8,8 +8,7 @@ const PopularItem = ({ slug, title }) => {
|
|||||||
<div className="article-item__title">
|
<div className="article-item__title">
|
||||||
<Link to={`/article/${slug}`}>{title}</Link>
|
<Link to={`/article/${slug}`}>{title}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-item__views">
|
<div className="article-item__views"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@ -18,5 +17,5 @@ export default PopularItem
|
|||||||
|
|
||||||
PopularItem.propTypes = {
|
PopularItem.propTypes = {
|
||||||
slug: PropTypes.string,
|
slug: PropTypes.string,
|
||||||
title: PropTypes.string
|
title: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,19 +1,40 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
|
|
||||||
const Subscription = () => {
|
const Subscription = () => {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
return (
|
return (
|
||||||
<div style={pathname !== '/about' && pathname !== '/about/' ? { height: '100%' } : null}>
|
<div
|
||||||
<div style={pathname !== '/about' && pathname !== '/about/' ? { position: 'sticky', top: 75 } : null} className="offers-subscription offer-box">
|
style={
|
||||||
|
pathname !== "/about" && pathname !== "/about/"
|
||||||
|
? { height: "100%" }
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
>
|
||||||
|
<div
|
||||||
|
style={
|
||||||
|
pathname !== "/about" && pathname !== "/about/"
|
||||||
|
? { position: "sticky", top: 75 }
|
||||||
|
: null
|
||||||
|
}
|
||||||
|
className="offers-subscription offer-box"
|
||||||
|
>
|
||||||
<div className="offers-subscription__heading offer-heading">
|
<div className="offers-subscription__heading offer-heading">
|
||||||
Канал в Telegram
|
Канал в Telegram
|
||||||
</div>
|
</div>
|
||||||
<div className="offers-subscription__content">
|
<div className="offers-subscription__content">
|
||||||
<p>
|
<p>
|
||||||
В нашем канале telegram вы не пропустите статьи и новости, присоединяйтесь к другим разработчикам
|
В нашем канале telegram вы не пропустите статьи и новости,
|
||||||
|
присоединяйтесь к другим разработчикам
|
||||||
</p>
|
</p>
|
||||||
<a href="https://t.me/devthread" rel='noreferrer' target="_blank" className="btn-primary">Подписаться</a>
|
<a
|
||||||
|
href="https://t.me/devthread"
|
||||||
|
rel="noreferrer"
|
||||||
|
target="_blank"
|
||||||
|
className="btn-primary"
|
||||||
|
>
|
||||||
|
Подписаться
|
||||||
|
</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import sligify from '../../../helpers/slugify'
|
import sligify from "../../../helpers/slugify"
|
||||||
|
|
||||||
const TagItem = ({ title }) => {
|
const TagItem = ({ title }) => {
|
||||||
return (
|
return (
|
||||||
@ -14,5 +14,5 @@ const TagItem = ({ title }) => {
|
|||||||
export default TagItem
|
export default TagItem
|
||||||
|
|
||||||
TagItem.propTypes = {
|
TagItem.propTypes = {
|
||||||
title: PropTypes.string
|
title: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,18 +1,15 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
|
|
||||||
import TagIcon from '../../../images/tag-icon.svg'
|
import TagIcon from "../../../images/tag-icon.svg"
|
||||||
|
|
||||||
const Tags = ({ children }) => {
|
const Tags = ({ children }) => {
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="offers-tags offer-box">
|
<div className="offers-tags offer-box">
|
||||||
<div className="offers-tags__heading offer-heading">
|
<div className="offers-tags__heading offer-heading">
|
||||||
<TagIcon />
|
<TagIcon />
|
||||||
Тэги
|
Тэги
|
||||||
</div>
|
</div>
|
||||||
<div className="offers-tags__content">
|
<div className="offers-tags__content">{children}</div>
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,10 +1,18 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import useSiteMetadataQuery from '../../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import { Helmet } from 'react-helmet'
|
import { Helmet } from "react-helmet"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
|
|
||||||
const SEO = ({ title, titleTemplate, keywords, description, image, type, canonical }) => {
|
const SEO = ({
|
||||||
|
title,
|
||||||
|
titleTemplate,
|
||||||
|
keywords,
|
||||||
|
description,
|
||||||
|
image,
|
||||||
|
type,
|
||||||
|
canonical,
|
||||||
|
}) => {
|
||||||
const { pathname } = useLocation()
|
const { pathname } = useLocation()
|
||||||
const { siteMetadata } = useSiteMetadataQuery()
|
const { siteMetadata } = useSiteMetadataQuery()
|
||||||
|
|
||||||
@ -12,55 +20,62 @@ const SEO = ({ title, titleTemplate, keywords, description, image, type, canonic
|
|||||||
title: title || siteMetadata.title,
|
title: title || siteMetadata.title,
|
||||||
titleTemplate: true,
|
titleTemplate: true,
|
||||||
siteName: siteMetadata.siteName,
|
siteName: siteMetadata.siteName,
|
||||||
type: type || 'website',
|
type: type || "website",
|
||||||
image: image || 'custom image url...',
|
image: image || "custom image url...",
|
||||||
description: description || siteMetadata.description,
|
description: description || siteMetadata.description,
|
||||||
keywords: keywords || siteMetadata.keywords,
|
keywords: keywords || siteMetadata.keywords,
|
||||||
url: `${siteMetadata.siteUrl}${pathname}`,
|
url: `${siteMetadata.siteUrl}${pathname}`,
|
||||||
canonical: canonical || `${siteMetadata.siteUrl}${pathname}`
|
canonical: canonical || `${siteMetadata.siteUrl}${pathname}`,
|
||||||
}
|
}
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Helmet title={seo.title} titleTemplate={titleTemplate === false ? null : siteMetadata.titleTemplate}>
|
<Helmet
|
||||||
|
title={seo.title}
|
||||||
|
titleTemplate={
|
||||||
|
titleTemplate === false ? null : siteMetadata.titleTemplate
|
||||||
|
}
|
||||||
|
>
|
||||||
<html lang="ru" />
|
<html lang="ru" />
|
||||||
<meta name="description" content={seo.description} />
|
<meta name="description" content={seo.description} />
|
||||||
{seo.keywords && (
|
{seo.keywords && <meta name="keywords" content={seo.keywords} />}
|
||||||
<meta name='keywords' content={seo.keywords} />
|
<meta property="og:locale" content="ru_RU" />
|
||||||
)}
|
|
||||||
<meta property='og:locale' content='ru_RU' />
|
|
||||||
<meta property="og:url" content={seo.url} />
|
<meta property="og:url" content={seo.url} />
|
||||||
<meta property='og:title' content={seo.title}
|
<meta property="og:title" content={seo.title} />
|
||||||
/>
|
<meta property="og:site_name" content={seo.siteName} />
|
||||||
<meta property='og:site_name' content={seo.siteName}
|
{seo.type && <meta property="og:type" content={seo.type} />}
|
||||||
/>
|
{seo.image && <meta property="og:image" content={seo.image} />}
|
||||||
{seo.type && (
|
|
||||||
<meta property='og:type' content={seo.type} />
|
|
||||||
)}
|
|
||||||
{seo.image && (
|
|
||||||
<meta property="og:image" content={seo.image} />
|
|
||||||
)}
|
|
||||||
{seo.description && (
|
{seo.description && (
|
||||||
<meta property="og:description" content={seo.description} />
|
<meta property="og:description" content={seo.description} />
|
||||||
)}
|
)}
|
||||||
<link rel="canonical" href={seo.canonical} />
|
<link rel="canonical" href={seo.canonical} />
|
||||||
<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png" />
|
<link
|
||||||
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png" />
|
rel="apple-touch-icon"
|
||||||
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png" />
|
sizes="180x180"
|
||||||
|
href="/apple-touch-icon.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="32x32"
|
||||||
|
href="/favicon-32x32.png"
|
||||||
|
/>
|
||||||
|
<link
|
||||||
|
rel="icon"
|
||||||
|
type="image/png"
|
||||||
|
sizes="16x16"
|
||||||
|
href="/favicon-16x16.png"
|
||||||
|
/>
|
||||||
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#191919" />
|
<link rel="mask-icon" href="/safari-pinned-tab.svg" color="#191919" />
|
||||||
<meta name="msapplication-TileColor" content="#ffffff" />
|
<meta name="msapplication-TileColor" content="#ffffff" />
|
||||||
<meta name="theme-color" content="#ffffff" />
|
<meta name="theme-color" content="#ffffff" />
|
||||||
<script type="application/ld+json">
|
<script type="application/ld+json">
|
||||||
{
|
{JSON.stringify({
|
||||||
JSON.stringify({
|
"@context": "http://schema.org",
|
||||||
'@context': 'http://schema.org',
|
"@type": "Organization",
|
||||||
'@type': 'Organization',
|
name: "devthread",
|
||||||
name: 'devthread',
|
url: siteMetadata.siteUrl,
|
||||||
url: siteMetadata.siteUrl,
|
sameAs: [siteMetadata.social.twitter],
|
||||||
sameAs : [
|
})}
|
||||||
siteMetadata.social.twitter,
|
|
||||||
]
|
|
||||||
})
|
|
||||||
}
|
|
||||||
</script>
|
</script>
|
||||||
</Helmet>
|
</Helmet>
|
||||||
)
|
)
|
||||||
@ -75,6 +90,5 @@ SEO.propTypes = {
|
|||||||
description: PropTypes.string,
|
description: PropTypes.string,
|
||||||
image: PropTypes.string,
|
image: PropTypes.string,
|
||||||
type: PropTypes.string,
|
type: PropTypes.string,
|
||||||
canonical: PropTypes.string
|
canonical: PropTypes.string,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,33 +1,34 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import SEO from '../SEO/SEO'
|
import SEO from "../SEO/SEO"
|
||||||
|
|
||||||
const Snippet = ({ data: { keywords, description, title, date }, html }) => {
|
const Snippet = ({ data: { keywords, description, title, date }, html }) => {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<SEO title={title} titleTemplate={false} description={description} keywords={keywords.join(', ')} type='article' />
|
<SEO
|
||||||
|
title={title}
|
||||||
|
titleTemplate={false}
|
||||||
|
description={description}
|
||||||
|
keywords={keywords.join(", ")}
|
||||||
|
type="article"
|
||||||
|
/>
|
||||||
<div className="snippet">
|
<div className="snippet">
|
||||||
<article>
|
<article>
|
||||||
<div className="snippet-date">
|
<div className="snippet-date">{date}</div>
|
||||||
{date}
|
|
||||||
</div>
|
|
||||||
<div className="snippet-heading">
|
<div className="snippet-heading">
|
||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="snippet-description">
|
<div className="snippet-description">
|
||||||
<p>
|
<p>{description}</p>
|
||||||
{description}
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
<div className="snippet-inner inner">
|
<div className="snippet-inner inner">
|
||||||
<div dangerouslySetInnerHTML={{__html: html}}></div>
|
<div dangerouslySetInnerHTML={{ __html: html }}></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="snippet-comments">
|
<div className="snippet-comments">
|
||||||
<div className="snippet-comments__heading">
|
<div className="snippet-comments__heading">
|
||||||
<h2>Комментарии</h2>
|
<h2>Комментарии</h2>
|
||||||
</div>
|
</div>
|
||||||
<div className="snippet-comments__content">
|
<div className="snippet-comments__content"></div>
|
||||||
</div>
|
|
||||||
</div>
|
</div>
|
||||||
</article>
|
</article>
|
||||||
</div>
|
</div>
|
||||||
@ -42,7 +43,7 @@ Snippet.propTypes = {
|
|||||||
keywords: PropTypes.array,
|
keywords: PropTypes.array,
|
||||||
title: PropTypes.string,
|
title: PropTypes.string,
|
||||||
description: PropTypes.string,
|
description: PropTypes.string,
|
||||||
date: PropTypes.string
|
date: PropTypes.string,
|
||||||
}),
|
}),
|
||||||
html: PropTypes.string
|
html: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,13 +1,11 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
|
|
||||||
const SnippetItem = ({ slug, title, date, tags }) => {
|
const SnippetItem = ({ slug, title, date, tags }) => {
|
||||||
return (
|
return (
|
||||||
<div className='snippet-item'>
|
<div className="snippet-item">
|
||||||
<div className="left-info">
|
<div className="left-info">
|
||||||
<div className="snippet-item__date">
|
<div className="snippet-item__date">{date}</div>
|
||||||
{date}
|
|
||||||
</div>
|
|
||||||
<div className="snippet-item__heading">
|
<div className="snippet-item__heading">
|
||||||
<Link to={`/snippet/${slug}`}>{title}</Link>
|
<Link to={`/snippet/${slug}`}>{title}</Link>
|
||||||
</div>
|
</div>
|
||||||
@ -15,7 +13,9 @@ const SnippetItem = ({ slug, title, date, tags }) => {
|
|||||||
<div className="right-info">
|
<div className="right-info">
|
||||||
<div className="snippet-item__tags">
|
<div className="snippet-item__tags">
|
||||||
{tags.map((tag, i) => (
|
{tags.map((tag, i) => (
|
||||||
<div key={i} className="tag-item">{tag}</div>
|
<div key={i} className="tag-item">
|
||||||
|
{tag}
|
||||||
|
</div>
|
||||||
))}
|
))}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@ -1,11 +1,7 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
|
|
||||||
const Snippets = ({ children }) => {
|
const Snippets = ({ children }) => {
|
||||||
return (
|
return <div className="snippets">{children}</div>
|
||||||
<div className='snippets'>
|
|
||||||
{children}
|
|
||||||
</div>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default Snippets
|
export default Snippets
|
||||||
@ -1,36 +1,32 @@
|
|||||||
import React, { useEffect, useState } from 'react';
|
import React, { useEffect, useState } from "react"
|
||||||
import PropTypes from 'prop-types'
|
import PropTypes from "prop-types"
|
||||||
import firebase from 'gatsby-plugin-firebase';
|
import firebase from "gatsby-plugin-firebase"
|
||||||
import incrementViews from '../../lib/increment-views';
|
import incrementViews from "../../lib/increment-views"
|
||||||
|
|
||||||
const ViewCounter = ({ id }) => {
|
const ViewCounter = ({ id }) => {
|
||||||
const [viewCount, setViewCount] = useState('');
|
const [viewCount, setViewCount] = useState("")
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
const onViews = (newViews) => {
|
const onViews = newViews => {
|
||||||
setViewCount(newViews.val() === 1 ? 0 : newViews.val());
|
setViewCount(newViews.val() === 1 ? 0 : newViews.val())
|
||||||
};
|
}
|
||||||
|
|
||||||
incrementViews(id);
|
incrementViews(id)
|
||||||
|
|
||||||
firebase.database().ref(`/views`).child(id).on(`value`, onViews);
|
firebase.database().ref(`/views`).child(id).on(`value`, onViews)
|
||||||
|
|
||||||
return () => {
|
return () => {
|
||||||
if (firebase.database()) {
|
if (firebase.database()) {
|
||||||
firebase.database().ref(`/views`).child(id).off(`value`, onViews);
|
firebase.database().ref(`/views`).child(id).off(`value`, onViews)
|
||||||
}
|
}
|
||||||
};
|
}
|
||||||
}, [id]);
|
}, [id])
|
||||||
|
|
||||||
return (
|
return <span>{viewCount ? viewCount : `---`}</span>
|
||||||
<span>
|
}
|
||||||
{viewCount ? viewCount : `---`}
|
|
||||||
</span>
|
|
||||||
);
|
|
||||||
};
|
|
||||||
|
|
||||||
export default ViewCounter;
|
export default ViewCounter
|
||||||
|
|
||||||
ViewCounter.propTypes = {
|
ViewCounter.propTypes = {
|
||||||
id: PropTypes.string
|
id: PropTypes.string,
|
||||||
}
|
}
|
||||||
@ -1,6 +1,6 @@
|
|||||||
const slugify = str => {
|
const slugify = str => {
|
||||||
const patterns = {
|
const patterns = {
|
||||||
rus: /^[0-9а-яё-\s]*$/i
|
rus: /^[0-9а-яё-\s]*$/i,
|
||||||
}
|
}
|
||||||
|
|
||||||
const translit = str => {
|
const translit = str => {
|
||||||
@ -35,33 +35,33 @@ const slugify = str => {
|
|||||||
ы: "y",
|
ы: "y",
|
||||||
э: "e",
|
э: "e",
|
||||||
ю: "u",
|
ю: "u",
|
||||||
я: "ya"
|
я: "ya",
|
||||||
},
|
},
|
||||||
newStr = [];
|
newStr = []
|
||||||
|
|
||||||
for (var i = 0; i < str.length; ++i) {
|
for (var i = 0; i < str.length; ++i) {
|
||||||
const candidate = str[i].toLowerCase()
|
const candidate = str[i].toLowerCase()
|
||||||
|
|
||||||
if (ru[candidate]) {
|
if (ru[candidate]) {
|
||||||
newStr.push(ru[candidate]);
|
newStr.push(ru[candidate])
|
||||||
}
|
}
|
||||||
|
|
||||||
if (candidate === '-' || !isNaN(candidate)) {
|
if (candidate === "-" || !isNaN(candidate)) {
|
||||||
newStr.push(candidate)
|
newStr.push(candidate)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return newStr.join("");
|
return newStr.join("")
|
||||||
}
|
}
|
||||||
|
|
||||||
return 'not rus'
|
return "not rus"
|
||||||
}
|
}
|
||||||
|
|
||||||
if (str.match(patterns.rus)) {
|
if (str.match(patterns.rus)) {
|
||||||
return translit(str).split(' ').join('-').toLowerCase()
|
return translit(str).split(" ").join("-").toLowerCase()
|
||||||
}
|
}
|
||||||
|
|
||||||
return str.split(' ').join('-').toLowerCase()
|
return str.split(" ").join("-").toLowerCase()
|
||||||
};
|
}
|
||||||
|
|
||||||
export default slugify
|
export default slugify
|
||||||
@ -3,10 +3,10 @@ const toFrontmatter = array => {
|
|||||||
edges: array.map(el => {
|
edges: array.map(el => {
|
||||||
return {
|
return {
|
||||||
node: {
|
node: {
|
||||||
frontmatter: el
|
frontmatter: el,
|
||||||
}
|
},
|
||||||
}
|
}
|
||||||
})
|
}),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const useCategoriesQuery = () => {
|
const useCategoriesQuery = () => {
|
||||||
const { allMarkdownRemark: { edges } } = useStaticQuery(graphql`
|
const {
|
||||||
|
allMarkdownRemark: { edges },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "category"}}}) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "category" } } }
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,9 +1,15 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const useMoreArticlesQuery = () => {
|
const useMoreArticlesQuery = () => {
|
||||||
const { allMarkdownRemark: { edges } } = useStaticQuery(graphql`
|
const {
|
||||||
|
allMarkdownRemark: { edges },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}, sort: {order: DESC, fields: frontmatter___date}, limit: 6) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "article" } } }
|
||||||
|
sort: { order: DESC, fields: frontmatter___date }
|
||||||
|
limit: 6
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,9 +1,17 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const usePopularArticlesQuery = () => {
|
const usePopularArticlesQuery = () => {
|
||||||
const { allMarkdownRemark: { edges } } = useStaticQuery(graphql`
|
const {
|
||||||
|
allMarkdownRemark: { edges },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}, popular: {eq: true}}}, sort: {fields: frontmatter___date, order: DESC}, limit: 5) {
|
allMarkdownRemark(
|
||||||
|
filter: {
|
||||||
|
frontmatter: { templateKey: { eq: "article" }, popular: { eq: true } }
|
||||||
|
}
|
||||||
|
sort: { fields: frontmatter___date, order: DESC }
|
||||||
|
limit: 5
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,7 +1,9 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const useSiteMetadata = () => {
|
const useSiteMetadata = () => {
|
||||||
const { site: { siteMetadata } } = useStaticQuery(graphql`
|
const {
|
||||||
|
site: { siteMetadata },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
site {
|
site {
|
||||||
siteMetadata {
|
siteMetadata {
|
||||||
|
|||||||
@ -1,9 +1,14 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const useSnippetsQuery = () => {
|
const useSnippetsQuery = () => {
|
||||||
const { allMarkdownRemark: { edges } } = useStaticQuery(graphql`
|
const {
|
||||||
|
allMarkdownRemark: { edges },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "snippet"}}}, sort: {order: DESC, fields: frontmatter___date}) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "snippet" } } }
|
||||||
|
sort: { order: DESC, fields: frontmatter___date }
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,9 +1,13 @@
|
|||||||
import { useStaticQuery, graphql } from 'gatsby'
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
const useTagsQuery = () => {
|
const useTagsQuery = () => {
|
||||||
const { allMarkdownRemark: { edges } } = useStaticQuery(graphql`
|
const {
|
||||||
|
allMarkdownRemark: { edges },
|
||||||
|
} = useStaticQuery(graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "tag"}}}) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "tag" } } }
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import firebase from 'gatsby-plugin-firebase';
|
import firebase from "gatsby-plugin-firebase"
|
||||||
|
|
||||||
const incrementViews = async id => {
|
const incrementViews = async id => {
|
||||||
const ref = firebase.database().ref(`/views`).child(id);
|
const ref = firebase.database().ref(`/views`).child(id)
|
||||||
|
|
||||||
ref.transaction(currentViews => currentViews + 1)
|
ref.transaction(currentViews => currentViews + 1)
|
||||||
}
|
}
|
||||||
|
|
||||||
export default incrementViews;
|
export default incrementViews
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid } from 'react-flexbox-grid'
|
import { Grid } from "react-flexbox-grid"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from "gatsby"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
|
|
||||||
const NotFound = () => {
|
const NotFound = () => {
|
||||||
return (
|
return (
|
||||||
@ -14,7 +14,7 @@ const NotFound = () => {
|
|||||||
<div className="error">
|
<div className="error">
|
||||||
<span>#404</span>
|
<span>#404</span>
|
||||||
<h1>страница не найдена</h1>
|
<h1>страница не найдена</h1>
|
||||||
<Link to='/'>вернуться на главную</Link>
|
<Link to="/">вернуться на главную</Link>
|
||||||
</div>
|
</div>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Main>
|
</Main>
|
||||||
|
|||||||
@ -1,22 +1,33 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
import About from '../components/About/About'
|
import About from "../components/About/About"
|
||||||
|
|
||||||
const AboutPage = () => {
|
const AboutPage = () => {
|
||||||
const { siteMetadata: { title, menuLinks, social } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: { title, menuLinks, social },
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO title='О сайте' description='Этот сайт придуман для того, чтобы помочь вам разобраться с вашей проблемой и решить её. Сайт содержит в себе статьи и руководства.' />
|
<SEO
|
||||||
|
title="О сайте"
|
||||||
|
description="Этот сайт придуман для того, чтобы помочь вам разобраться с вашей проблемой и решить её. Сайт содержит в себе статьи и руководства."
|
||||||
|
/>
|
||||||
<Main>
|
<Main>
|
||||||
<Grid fluid>
|
<Grid fluid>
|
||||||
<Row>
|
<Row>
|
||||||
<Col lg={9} xs={12}>
|
<Col lg={9} xs={12}>
|
||||||
<About title={title} pageTitle={menuLinks.filter(page => page.link === '/about')[0].name} social={social} />
|
<About
|
||||||
|
title={title}
|
||||||
|
pageTitle={
|
||||||
|
menuLinks.filter(page => page.link === "/about")[0].name
|
||||||
|
}
|
||||||
|
social={social}
|
||||||
|
/>
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={3} xs={12}>
|
<Col lg={3} xs={12}>
|
||||||
<Offers />
|
<Offers />
|
||||||
|
|||||||
@ -1,51 +1,71 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import { graphql } from 'gatsby'
|
import { graphql } from "gatsby"
|
||||||
import { useLocation } from '@reach/router'
|
import { useLocation } from "@reach/router"
|
||||||
import * as queryString from 'query-string'
|
import * as queryString from "query-string"
|
||||||
import useCategoriesQuery from '../hooks/useCategoriesQuery'
|
import useCategoriesQuery from "../hooks/useCategoriesQuery"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
|
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Articles from '../components/Articles/Articles'
|
import Articles from "../components/Articles/Articles"
|
||||||
import Categories from '../components/Articles/Categories/Categories'
|
import Categories from "../components/Articles/Categories/Categories"
|
||||||
import CategoryItem from '../components/Articles/Categories/CategoryItem'
|
import CategoryItem from "../components/Articles/Categories/CategoryItem"
|
||||||
import Search from '../components/Articles/Search/Search'
|
import Search from "../components/Articles/Search/Search"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
|
|
||||||
import SearchIcon from '../images/search-icon.svg'
|
import SearchIcon from "../images/search-icon.svg"
|
||||||
|
|
||||||
const ArticlesPage = ({ data: { allMarkdownRemark: edges }, }) => {
|
const ArticlesPage = ({ data: { allMarkdownRemark: edges } }) => {
|
||||||
const { categories } = useCategoriesQuery()
|
const { categories } = useCategoriesQuery()
|
||||||
const { siteMetadata: { options: { articles: { onPage } } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
options: {
|
||||||
|
articles: { onPage },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
const { search } = useLocation()
|
const { search } = useLocation()
|
||||||
|
|
||||||
let [limit, setLimit] = React.useState(onPage)
|
let [limit, setLimit] = React.useState(onPage)
|
||||||
const [filtredArticles, setFiltredArticles] = React.useState([])
|
const [filtredArticles, setFiltredArticles] = React.useState([])
|
||||||
const [query, setQuery] = React.useState(queryString.parse(search).search || '')
|
const [query, setQuery] = React.useState(
|
||||||
|
queryString.parse(search).search || ""
|
||||||
|
)
|
||||||
|
|
||||||
const allArticles = edges
|
const allArticles = edges
|
||||||
|
|
||||||
const filterArticles = React.useCallback(arr => {
|
const filterArticles = React.useCallback(
|
||||||
return arr.filter(({ node: { frontmatter } }) =>
|
arr => {
|
||||||
frontmatter.title.toLowerCase().includes(query.toLowerCase().trim())
|
return arr.filter(
|
||||||
|| frontmatter.description.toLowerCase().includes(query.toLowerCase().trim())
|
({ node: { frontmatter } }) =>
|
||||||
|| frontmatter.category.toLowerCase().includes(query.toLowerCase().trim())
|
frontmatter.title
|
||||||
|| frontmatter.tags.join('').toLowerCase().includes(query.toLowerCase().trim())
|
.toLowerCase()
|
||||||
)
|
.includes(query.toLowerCase().trim()) ||
|
||||||
}, [query])
|
frontmatter.description
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(query.toLowerCase().trim()) ||
|
||||||
|
frontmatter.category
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(query.toLowerCase().trim()) ||
|
||||||
|
frontmatter.tags
|
||||||
|
.join("")
|
||||||
|
.toLowerCase()
|
||||||
|
.includes(query.toLowerCase().trim())
|
||||||
|
)
|
||||||
|
},
|
||||||
|
[query]
|
||||||
|
)
|
||||||
|
|
||||||
React.useEffect(() => {
|
React.useEffect(() => {
|
||||||
setLimit(onPage)
|
setLimit(onPage)
|
||||||
if (query !== '') setFiltredArticles(filterArticles(allArticles.edges))
|
if (query !== "") setFiltredArticles(filterArticles(allArticles.edges))
|
||||||
}, [setFiltredArticles, filterArticles, allArticles.edges, query, onPage])
|
}, [setFiltredArticles, filterArticles, allArticles.edges, query, onPage])
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO title='Статьи' />
|
<SEO title="Статьи" />
|
||||||
<Main>
|
<Main>
|
||||||
<Grid fluid>
|
<Grid fluid>
|
||||||
<Row>
|
<Row>
|
||||||
@ -55,25 +75,51 @@ const ArticlesPage = ({ data: { allMarkdownRemark: edges }, }) => {
|
|||||||
<h1>Статьи</h1>
|
<h1>Статьи</h1>
|
||||||
</div>
|
</div>
|
||||||
<Categories setQuery={setQuery}>
|
<Categories setQuery={setQuery}>
|
||||||
{categories.map(({ node }, i) => <CategoryItem key={i} title={node.frontmatter.title} />)}
|
{categories.map(({ node }, i) => (
|
||||||
|
<CategoryItem key={i} title={node.frontmatter.title} />
|
||||||
|
))}
|
||||||
</Categories>
|
</Categories>
|
||||||
<Search allArticles={allArticles.edges} filterArticles={filterArticles} articlesLength={edges.edges.length} resultsLength={filtredArticles.length} query={query} setQuery={setQuery} setFiltredArticles={setFiltredArticles} setLimit={setLimit} onPage={onPage} />
|
<Search
|
||||||
|
allArticles={allArticles.edges}
|
||||||
|
filterArticles={filterArticles}
|
||||||
|
articlesLength={edges.edges.length}
|
||||||
|
resultsLength={filtredArticles.length}
|
||||||
|
query={query}
|
||||||
|
setQuery={setQuery}
|
||||||
|
setFiltredArticles={setFiltredArticles}
|
||||||
|
setLimit={setLimit}
|
||||||
|
onPage={onPage}
|
||||||
|
/>
|
||||||
<div className="articles-info">
|
<div className="articles-info">
|
||||||
{query && query !== '' ? filtredArticles.length === 0 ? <p><SearchIcon /> Ничего не найдено</p> : null : null}
|
{query && query !== "" ? (
|
||||||
|
filtredArticles.length === 0 ? (
|
||||||
|
<p>
|
||||||
|
<SearchIcon />
|
||||||
|
Ничего не найдено
|
||||||
|
</p>
|
||||||
|
) : null
|
||||||
|
) : null}
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
<Row>
|
<Row>
|
||||||
<Col lg={9} xs={12}>
|
<Col lg={9} xs={12}>
|
||||||
{query && query !== ''
|
{query && query !== "" ? (
|
||||||
? filtredArticles.length > 0 ? <Articles data={{edges: filtredArticles}} limit={limit} setLimit={setLimit} /> : null
|
filtredArticles.length > 0 ? (
|
||||||
: <Articles data={edges} limit={limit} setLimit={setLimit} />
|
<Articles
|
||||||
}
|
data={{ edges: filtredArticles }}
|
||||||
</Col >
|
limit={limit}
|
||||||
|
setLimit={setLimit}
|
||||||
|
/>
|
||||||
|
) : null
|
||||||
|
) : (
|
||||||
|
<Articles data={edges} limit={limit} setLimit={setLimit} />
|
||||||
|
)}
|
||||||
|
</Col>
|
||||||
<Col lg={3} xs={12}>
|
<Col lg={3} xs={12}>
|
||||||
<Offers />
|
<Offers />
|
||||||
</Col >
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</Grid>
|
</Grid>
|
||||||
</Main>
|
</Main>
|
||||||
@ -83,7 +129,9 @@ const ArticlesPage = ({ data: { allMarkdownRemark: edges }, }) => {
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "article" } } }
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,16 +1,23 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Contacts from '../components/Contacts/Contacts'
|
import Contacts from "../components/Contacts/Contacts"
|
||||||
|
|
||||||
const ContactsPage = () => {
|
const ContactsPage = () => {
|
||||||
const { siteMetadata: { social: { email, telegram } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
social: { email, telegram },
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO title='📝 Контакты' description='Для того чтобы задать вопрос, сообщить об ошибках или просто поздороваться, вы можете воспользоваться формой обратной связи или использовать контактные данные.' />
|
<SEO
|
||||||
|
title="📝 Контакты"
|
||||||
|
description="Для того чтобы задать вопрос, сообщить об ошибках или просто поздороваться, вы можете воспользоваться формой обратной связи или использовать контактные данные."
|
||||||
|
/>
|
||||||
<Main>
|
<Main>
|
||||||
<Grid fluid>
|
<Grid fluid>
|
||||||
<Row>
|
<Row>
|
||||||
|
|||||||
@ -1,18 +1,24 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { Link, graphql } from 'gatsby'
|
import { Link, graphql } from "gatsby"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
import useSnippetsQuery from '../hooks/useSnippetsQuery'
|
import useSnippetsQuery from "../hooks/useSnippetsQuery"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Articles from '../components/Articles/Articles'
|
import Articles from "../components/Articles/Articles"
|
||||||
import Snippets from '../components/Snippets/Snippets'
|
import Snippets from "../components/Snippets/Snippets"
|
||||||
import SnippetItem from '../components/Snippets/SnippetItem/SnippetItem'
|
import SnippetItem from "../components/Snippets/SnippetItem/SnippetItem"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
|
|
||||||
const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
||||||
const { siteMetadata: { options: { articles: { onPage } } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
options: {
|
||||||
|
articles: { onPage },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
const { snippets } = useSnippetsQuery()
|
const { snippets } = useSnippetsQuery()
|
||||||
let [limit, setLimit] = React.useState(onPage)
|
let [limit, setLimit] = React.useState(onPage)
|
||||||
|
|
||||||
@ -26,7 +32,7 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
|||||||
<div className="articles">
|
<div className="articles">
|
||||||
<div className="articles-heading">
|
<div className="articles-heading">
|
||||||
<h1>Последние статьи</h1>
|
<h1>Последние статьи</h1>
|
||||||
<Link to='/articles'>смотреть все</Link>
|
<Link to="/articles">смотреть все</Link>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -36,7 +42,7 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
|||||||
<Articles data={edges} limit={limit} setLimit={setLimit} />
|
<Articles data={edges} limit={limit} setLimit={setLimit} />
|
||||||
<Snippets>
|
<Snippets>
|
||||||
<h2>Сниппеты</h2>
|
<h2>Сниппеты</h2>
|
||||||
{snippets.map(({ node: { frontmatter } }, i) =>
|
{snippets.map(({ node: { frontmatter } }, i) => (
|
||||||
<SnippetItem
|
<SnippetItem
|
||||||
key={i}
|
key={i}
|
||||||
slug={frontmatter.slug}
|
slug={frontmatter.slug}
|
||||||
@ -44,7 +50,7 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
|||||||
date={frontmatter.date}
|
date={frontmatter.date}
|
||||||
tags={frontmatter.tags}
|
tags={frontmatter.tags}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
</Snippets>
|
</Snippets>
|
||||||
</Col>
|
</Col>
|
||||||
<Col lg={3} xs={12}>
|
<Col lg={3} xs={12}>
|
||||||
@ -59,7 +65,10 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}, sort: {order: DESC, fields: frontmatter___date}) {
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { templateKey: { eq: "article" } } }
|
||||||
|
sort: { order: DESC, fields: frontmatter___date }
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,13 +1,17 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { graphql } from "gatsby"
|
import { graphql } from "gatsby"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Snippets from '../components/Snippets/Snippets'
|
import Snippets from "../components/Snippets/Snippets"
|
||||||
import SnippetItem from '../components/Snippets/SnippetItem/SnippetItem'
|
import SnippetItem from "../components/Snippets/SnippetItem/SnippetItem"
|
||||||
|
|
||||||
const SnippetsPage = ({ data: { allMarkdownRemark: { snippets } } }) => {
|
const SnippetsPage = ({
|
||||||
|
data: {
|
||||||
|
allMarkdownRemark: { snippets },
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<SEO />
|
<SEO />
|
||||||
@ -17,8 +21,11 @@ const SnippetsPage = ({ data: { allMarkdownRemark: { snippets } } }) => {
|
|||||||
<Col lg={12}>
|
<Col lg={12}>
|
||||||
<Snippets>
|
<Snippets>
|
||||||
<h1>Сниппеты</h1>
|
<h1>Сниппеты</h1>
|
||||||
<p>Сниппеты это готовые решения некоторых проблем, которые можно скопировать и вставить</p>
|
<p>
|
||||||
{snippets.map(({ node: { frontmatter } }, i) =>
|
Сниппеты это готовые решения некоторых проблем, которые можно
|
||||||
|
скопировать и вставить
|
||||||
|
</p>
|
||||||
|
{snippets.map(({ node: { frontmatter } }, i) => (
|
||||||
<SnippetItem
|
<SnippetItem
|
||||||
key={i}
|
key={i}
|
||||||
slug={frontmatter.slug}
|
slug={frontmatter.slug}
|
||||||
@ -26,7 +33,7 @@ const SnippetsPage = ({ data: { allMarkdownRemark: { snippets } } }) => {
|
|||||||
date={frontmatter.date}
|
date={frontmatter.date}
|
||||||
tags={frontmatter.tags}
|
tags={frontmatter.tags}
|
||||||
/>
|
/>
|
||||||
)}
|
))}
|
||||||
</Snippets>
|
</Snippets>
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
@ -37,21 +44,24 @@ const SnippetsPage = ({ data: { allMarkdownRemark: { snippets } } }) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "snippet"}}}, sort: {order: DESC, fields: frontmatter___date}) {
|
allMarkdownRemark(
|
||||||
snippets: edges {
|
filter: { frontmatter: { templateKey: { eq: "snippet" } } }
|
||||||
node {
|
sort: { order: DESC, fields: frontmatter___date }
|
||||||
frontmatter {
|
) {
|
||||||
slug
|
snippets: edges {
|
||||||
title
|
node {
|
||||||
tags
|
frontmatter {
|
||||||
description
|
slug
|
||||||
date(formatString: "D MMMM YYYY", locale: "ru-RU")
|
title
|
||||||
|
tags
|
||||||
|
description
|
||||||
|
date(formatString: "D MMMM YYYY", locale: "ru-RU")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
`
|
`
|
||||||
|
|
||||||
export default SnippetsPage
|
export default SnippetsPage
|
||||||
|
|||||||
@ -1,14 +1,18 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Article from '../components/Article/Article'
|
import Article from "../components/Article/Article"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
import MoreArticles from '../components/Articles/MoreArticles/MoreArticles'
|
import MoreArticles from "../components/Articles/MoreArticles/MoreArticles"
|
||||||
import Newsletter from '../components/Newsletter/Newsletter'
|
import Newsletter from "../components/Newsletter/Newsletter"
|
||||||
import { graphql } from "gatsby"
|
import { graphql } from "gatsby"
|
||||||
|
|
||||||
const articleTemplate = ({ data: { markdownRemark: { frontmatter, html } } }) => {
|
const articleTemplate = ({
|
||||||
|
data: {
|
||||||
|
markdownRemark: { frontmatter, html },
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Main>
|
<Main>
|
||||||
@ -31,7 +35,7 @@ const articleTemplate = ({ data: { markdownRemark: { frontmatter, html } } }) =>
|
|||||||
|
|
||||||
export const pageQuery = graphql`
|
export const pageQuery = graphql`
|
||||||
query Article($slug: String!) {
|
query Article($slug: String!) {
|
||||||
markdownRemark(frontmatter: {slug: {eq: $slug}}) {
|
markdownRemark(frontmatter: { slug: { eq: $slug } }) {
|
||||||
html
|
html
|
||||||
frontmatter {
|
frontmatter {
|
||||||
slug
|
slug
|
||||||
|
|||||||
@ -1,19 +1,29 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import { graphql } from 'gatsby'
|
import { graphql } from "gatsby"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
import useCategoriesQuery from '../hooks/useCategoriesQuery'
|
import useCategoriesQuery from "../hooks/useCategoriesQuery"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Articles from '../components/Articles/Articles'
|
import Articles from "../components/Articles/Articles"
|
||||||
import Categories from '../components/Articles/Categories/Categories'
|
import Categories from "../components/Articles/Categories/Categories"
|
||||||
import CategoryItem from '../components/Articles/Categories/CategoryItem'
|
import CategoryItem from "../components/Articles/Categories/CategoryItem"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
|
|
||||||
const CategoryPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title } }) => {
|
const CategoryPage = ({
|
||||||
|
data: { allMarkdownRemark: edges },
|
||||||
|
pageContext: { title },
|
||||||
|
}) => {
|
||||||
const { categories } = useCategoriesQuery()
|
const { categories } = useCategoriesQuery()
|
||||||
const { siteMetadata: { siteUrl, options: { articles: { onPage } } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
siteUrl,
|
||||||
|
options: {
|
||||||
|
articles: { onPage },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
|
|
||||||
let [limit, setLimit] = React.useState(onPage)
|
let [limit, setLimit] = React.useState(onPage)
|
||||||
|
|
||||||
@ -26,13 +36,19 @@ const CategoryPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title
|
|||||||
<Col lg={9} xs={12}>
|
<Col lg={9} xs={12}>
|
||||||
<div className="articles">
|
<div className="articles">
|
||||||
<div className="articles-heading">
|
<div className="articles-heading">
|
||||||
<h1>Категория: <u>{title}</u></h1>
|
<h1>
|
||||||
|
Категория: <u>{title}</u>
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<Categories>
|
<Categories>
|
||||||
{categories.map(({ node }, i) => <CategoryItem key={i} title={node.frontmatter.title} />)}
|
{categories.map(({ node }, i) => (
|
||||||
|
<CategoryItem key={i} title={node.frontmatter.title} />
|
||||||
|
))}
|
||||||
</Categories>
|
</Categories>
|
||||||
<div className="articles-info">
|
<div className="articles-info">
|
||||||
<p>Найдено {edges.edges.length} из категории "{title}"</p>
|
<p>
|
||||||
|
Найдено {edges.edges.length} из категории "{title}"
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -53,7 +69,14 @@ const CategoryPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title
|
|||||||
|
|
||||||
export const pageQuery = graphql`
|
export const pageQuery = graphql`
|
||||||
query articlesByCategory($title: String!) {
|
query articlesByCategory($title: String!) {
|
||||||
allMarkdownRemark(filter: {frontmatter: {category: {eq: $title}, templateKey: {eq: "article"}}}) {
|
allMarkdownRemark(
|
||||||
|
filter: {
|
||||||
|
frontmatter: {
|
||||||
|
category: { eq: $title }
|
||||||
|
templateKey: { eq: "article" }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,11 +1,15 @@
|
|||||||
import React from 'react'
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import Snippet from '../components/Snippet/Snippet'
|
import Snippet from "../components/Snippet/Snippet"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import { graphql } from "gatsby"
|
import { graphql } from "gatsby"
|
||||||
|
|
||||||
const snippetTemplate = ({ data: { markdownRemark: { frontmatter, html } } }) => {
|
const snippetTemplate = ({
|
||||||
|
data: {
|
||||||
|
markdownRemark: { frontmatter, html },
|
||||||
|
},
|
||||||
|
}) => {
|
||||||
return (
|
return (
|
||||||
<Layout>
|
<Layout>
|
||||||
<Main>
|
<Main>
|
||||||
@ -23,7 +27,9 @@ const snippetTemplate = ({ data: { markdownRemark: { frontmatter, html } } }) =>
|
|||||||
|
|
||||||
export const pageQuery = graphql`
|
export const pageQuery = graphql`
|
||||||
query Snippet($slug: String!) {
|
query Snippet($slug: String!) {
|
||||||
markdownRemark(frontmatter: {slug: {eq: $slug}, templateKey: {eq: "snippet"}}) {
|
markdownRemark(
|
||||||
|
frontmatter: { slug: { eq: $slug }, templateKey: { eq: "snippet" } }
|
||||||
|
) {
|
||||||
html
|
html
|
||||||
frontmatter {
|
frontmatter {
|
||||||
slug
|
slug
|
||||||
|
|||||||
@ -1,19 +1,29 @@
|
|||||||
import React from "react"
|
import React from "react"
|
||||||
import { Main } from '../ui/ui'
|
import { Main } from "../ui/ui"
|
||||||
import { Grid, Row, Col } from 'react-flexbox-grid'
|
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||||
import { graphql } from 'gatsby'
|
import { graphql } from "gatsby"
|
||||||
import useSiteMetadataQuery from '../hooks/useSiteMetadataQuery'
|
import useSiteMetadataQuery from "../hooks/useSiteMetadataQuery"
|
||||||
import useCategoriesQuery from '../hooks/useCategoriesQuery'
|
import useCategoriesQuery from "../hooks/useCategoriesQuery"
|
||||||
import SEO from '../components/SEO/SEO'
|
import SEO from "../components/SEO/SEO"
|
||||||
import Layout from '../components/Layout/Layout'
|
import Layout from "../components/Layout/Layout"
|
||||||
import Articles from '../components/Articles/Articles'
|
import Articles from "../components/Articles/Articles"
|
||||||
import Categories from '../components/Articles/Categories/Categories'
|
import Categories from "../components/Articles/Categories/Categories"
|
||||||
import CategoryItem from '../components/Articles/Categories/CategoryItem'
|
import CategoryItem from "../components/Articles/Categories/CategoryItem"
|
||||||
import Offers from '../components/Offers/Offers'
|
import Offers from "../components/Offers/Offers"
|
||||||
|
|
||||||
const TagPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title } }) => {
|
const TagPage = ({
|
||||||
|
data: { allMarkdownRemark: edges },
|
||||||
|
pageContext: { title },
|
||||||
|
}) => {
|
||||||
const { categories } = useCategoriesQuery()
|
const { categories } = useCategoriesQuery()
|
||||||
const { siteMetadata: { siteUrl, options: { articles: { onPage } } } } = useSiteMetadataQuery()
|
const {
|
||||||
|
siteMetadata: {
|
||||||
|
siteUrl,
|
||||||
|
options: {
|
||||||
|
articles: { onPage },
|
||||||
|
},
|
||||||
|
},
|
||||||
|
} = useSiteMetadataQuery()
|
||||||
|
|
||||||
let [limit, setLimit] = React.useState(onPage)
|
let [limit, setLimit] = React.useState(onPage)
|
||||||
|
|
||||||
@ -26,13 +36,19 @@ const TagPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title } })
|
|||||||
<Col lg={9} xs={12}>
|
<Col lg={9} xs={12}>
|
||||||
<div className="articles">
|
<div className="articles">
|
||||||
<div className="articles-heading">
|
<div className="articles-heading">
|
||||||
<h1>Тэг: <u>{title}</u></h1>
|
<h1>
|
||||||
|
Тэг: <u>{title}</u>
|
||||||
|
</h1>
|
||||||
</div>
|
</div>
|
||||||
<Categories>
|
<Categories>
|
||||||
{categories.map(({ node }, i) => <CategoryItem key={i} title={node.frontmatter.title} />)}
|
{categories.map(({ node }, i) => (
|
||||||
|
<CategoryItem key={i} title={node.frontmatter.title} />
|
||||||
|
))}
|
||||||
</Categories>
|
</Categories>
|
||||||
<div className="articles-info">
|
<div className="articles-info">
|
||||||
<p>Найдено {edges.edges.length} по тегу "{title}"</p>
|
<p>
|
||||||
|
Найдено {edges.edges.length} по тегу "{title}"
|
||||||
|
</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</Col>
|
</Col>
|
||||||
@ -53,7 +69,11 @@ const TagPage = ({ data: { allMarkdownRemark: edges }, pageContext: { title } })
|
|||||||
|
|
||||||
export const pageQuery = graphql`
|
export const pageQuery = graphql`
|
||||||
query articlesByTag($title: [String!]) {
|
query articlesByTag($title: [String!]) {
|
||||||
allMarkdownRemark(filter: {frontmatter: {tags: {in: $title}, templateKey: {eq: "article"}}}) {
|
allMarkdownRemark(
|
||||||
|
filter: {
|
||||||
|
frontmatter: { tags: { in: $title }, templateKey: { eq: "article" } }
|
||||||
|
}
|
||||||
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
@ -1,12 +1,7 @@
|
|||||||
import React from 'react';
|
import React from "react"
|
||||||
|
|
||||||
const Main = ({ children, ...props }) => {
|
const Main = ({ children, ...props }) => {
|
||||||
return (
|
return <main {...props}>{children}</main>
|
||||||
<main {...props}>
|
|
||||||
{children}
|
|
||||||
</main>
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
export { Main }
|
export { Main }
|
||||||
Loading…
x
Reference in New Issue
Block a user