Compare commits

..

No commits in common. "master" and "v1.0.0" have entirely different histories.

26 changed files with 55 additions and 1303 deletions

View File

@ -83,21 +83,23 @@ npx tsc --init
Теперь после того как все пакеты установлены, определимся со структурой проекта: Теперь после того как все пакеты установлены, определимся со структурой проекта:
```text ```text
typescript-apollo-server .
├── graphql └── typescript-apollo-server
│ ├── resolvers - обработчики запросов ├── graphql
│ │ ├── Books │ ├── resolvers - обработчики запросов
│ │ │ └── Books.ts │ │ ├── Books
│ │ └── Users │ │ │ └── Books.ts
│ │ └── Users.ts │ │ ├── Users
│ ├── typeDefs - типы │ │ │ └── Users.ts
│ │ ├── Book.graphql │ │ └── index.ts
│ │ ├── User.graphql │ ├── typeDefs - типы
│ │ └── schema.graphql │ │ ├── Book.graphql
│ └── schema.ts │ │ ├── User.graphql
├── index.ts - сервер │ │ └── schema.graphql
├── package.json │ └── schema.ts
└── tsconfig.json ├── index.ts - сервер
├── package.json
└── tsconfig.json
``` ```
В качестве простого примера GraphQL сервера, будем создавать несколько resolvers - это **Books** и **Users**. В качестве простого примера GraphQL сервера, будем создавать несколько resolvers - это **Books** и **Users**.
@ -200,7 +202,7 @@ cd ..
Файл **Books.ts**: Файл **Books.ts**:
```ts ```js
// ./graphql/resolvers/Books/Books.ts // ./graphql/resolvers/Books/Books.ts
import { IResolvers } from "graphql-tools" import { IResolvers } from "graphql-tools"
@ -226,7 +228,7 @@ export default booksResolver
Файл **Users.ts**: Файл **Users.ts**:
```ts ```js
// ./graphql/resolvers/Users/Users.ts // ./graphql/resolvers/Users/Users.ts
import { IResolvers } from "graphql-tools" import { IResolvers } from "graphql-tools"
@ -252,7 +254,7 @@ export default usersResolver
Резолверы получились довольно простые и понятные, теперь нужно собрать их в один массив для дальнейшего экспорта. В файле **index.ts** прописываем следующее: Резолверы получились довольно простые и понятные, теперь нужно собрать их в один массив для дальнейшего экспорта. В файле **index.ts** прописываем следующее:
```ts ```js
// ./graphql/resolvers/index.ts // ./graphql/resolvers/index.ts
import { IResolvers } from "graphql-tools" import { IResolvers } from "graphql-tools"
@ -272,7 +274,7 @@ export default resolvers
Раньше для того чтобы работали наши graphql импорты мы применяли пакет **graphql-import**, но теперь его не нужно устанавливать так как он уже входит в состав **graphql-tools**. Подробнее об этом можно прочитать [здесь](https://www.graphql-tools.com/docs/migration-from-import). Раньше для того чтобы работали наши graphql импорты мы применяли пакет **graphql-import**, но теперь его не нужно устанавливать так как он уже входит в состав **graphql-tools**. Подробнее об этом можно прочитать [здесь](https://www.graphql-tools.com/docs/migration-from-import).
С помощью функций **loadSchemaSync**, **loadFilesSync**, и **addResolversToSchema** мы собираем нашу схему. Функция **mergeResolvers** предназначена для объединения наших резолверов. Подробнее о "**Resolvers merging**" [здесь](https://www.graphql-tools.com/docs/merge-resolvers/). Далее всё что нам остается сделать - это экспортировать нашу схему и написать сервер. С помощью функций **loadSchemaSync**, **loadFilesSync**, и **addResolversToSchema** мы собираем нашу схему. Функция **mergeResolvers** предназначена для объединения наших резолверов. Подробнее о "**Resolvers merging**" [здесь](https://www.graphql-tools.com/docs/merge-resolvers/). Далее всё что нам остается сделать - это экспортировать нашу схему и написать сервер.
```ts ```js
// ./graphql/schema.ts // ./graphql/schema.ts
import { import {
@ -307,7 +309,7 @@ touch index.ts
Импортируем все необходимые пакеты и напишем функцию **startServer**, которая будет запускать наш сервер. Сделаем это согласно документации к пакету [apollo-server-express](https://www.npmjs.com/package/apollo-server-express). Импортируем все необходимые пакеты и напишем функцию **startServer**, которая будет запускать наш сервер. Сделаем это согласно документации к пакету [apollo-server-express](https://www.npmjs.com/package/apollo-server-express).
```ts ```js
// ./index.ts // ./index.ts
import express, { Application, Request, Response } from "express" import express, { Application, Request, Response } from "express"
@ -344,7 +346,7 @@ const startServer = (): void => {
startServer() startServer()
``` ```
Как видим, ничего сложного нет, просто применяем функцию [applyMiddleware](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#applymiddleware) для того чтобы соединить Apollo Server с фрэймворком Express.js. Далее можно протестировать наш сервер, запускаем команду **npm run start** и переходим по адресу **/graphql**. Для тестирования можно выполнить вот такой запрос: Как видим, ничего сложного нет, просто применяем функцию [applyMiddleware](https://www.apollographql.com/docs/apollo-server/api/apollo-server/#applymiddleware) для того чтобы соедениеть Apollo Server с фрэймворком Express.js. Далее можно протестировать наш сервер, запускаем команду **npm run start** и переходим по адресу **/graphql**. Для тестирования можно выполнить вот такой запрос:
```text ```text
{ {

View File

@ -1,4 +0,0 @@
---
templateKey: category
title: CMS
---

View File

@ -1,4 +0,0 @@
---
templateKey: tag
title: gatsbyjs
---

View File

@ -1,4 +0,0 @@
---
templateKey: tag
title: jamstack
---

View File

@ -1,4 +0,0 @@
---
templateKey: tag
title: javascript
---

View File

@ -1,4 +0,0 @@
---
templateKey: tag
title: netlify
---

View File

@ -4,7 +4,21 @@ import Layout from "./src/components/Layout/Layout"
import "prismjs/themes/prism-tomorrow.css" import "prismjs/themes/prism-tomorrow.css"
import "prismjs/plugins/line-numbers/prism-line-numbers.css" import "prismjs/plugins/line-numbers/prism-line-numbers.css"
import "./src/styles/global.scss" import "./src/styles/global.scss"
import "./src/components/Header/Header.scss"
import "./src/components/About/About.scss"
import "./src/components/Offers/Offers.scss"
import "./src/components/Articles/Articles.scss"
import "./src/components/Articles/ArticleCard/ArticleCard.scss"
import "./src/components/Newsletter/Newsletter.scss"
import "./src/components/Article/Article.scss"
import "./src/components/Snippet/Snippet.scss"
import "./src/components/Snippets/Snippets.scss"
import "./src/components/Articles/MoreArticles/MoreArticles.scss"
import "./src/components/Books/Books.scss"
import "./src/components/Contacts/Contacts.scss"
import "./src/components/Footer/Footer.scss"
export const shouldUpdateScroll = ({ routerProps: { location } }) => { export const shouldUpdateScroll = ({ routerProps: { location } }) => {
const { pathname } = location const { pathname } = location

View File

@ -56,12 +56,6 @@ module.exports = {
defer: false, defer: false,
}, },
}, },
{
resolve: "gatsby-plugin-mailchimp",
options: {
endpoint: process.env.MAILCHIMP_ENDPOINT,
},
},
"gatsby-plugin-sitemap", "gatsby-plugin-sitemap",
{ {
resolve: "gatsby-plugin-robots-txt", resolve: "gatsby-plugin-robots-txt",
@ -212,7 +206,7 @@ module.exports = {
{ {
resolve: `gatsby-remark-images`, resolve: `gatsby-remark-images`,
options: { options: {
maxWidth: 970, maxWidth: 900,
quality: 100, quality: 100,
withWebp: true, withWebp: true,
loading: "lazy", loading: "lazy",

View File

@ -53,13 +53,13 @@ exports.createPages = async ({ actions, graphql }) => {
}, },
}) })
// createPage({ createPage({
// path: `amp/article/${node.frontmatter.slug}/`, path: `amp/article/${node.frontmatter.slug}/`,
// component: articleTemplateAMP, component: articleTemplateAMP,
// context: { context: {
// slug: node.frontmatter.slug, slug: node.frontmatter.slug,
// }, },
// }) })
}) })
snippets.forEach(({ node }) => { snippets.forEach(({ node }) => {

39
package-lock.json generated
View File

@ -1,6 +1,6 @@
{ {
"name": "devthread.ru", "name": "devthread.ru",
"version": "1.0.0", "version": "0.1.0",
"lockfileVersion": 1, "lockfileVersion": 1,
"requires": true, "requires": true,
"dependencies": { "dependencies": {
@ -7055,11 +7055,6 @@
} }
} }
}, },
"email-validator": {
"version": "2.0.4",
"resolved": "https://registry.npmjs.org/email-validator/-/email-validator-2.0.4.tgz",
"integrity": "sha512-gYCwo7kh5S3IDyZPLZf6hSS0MnZT8QmJFqYvbqlDZSbwdZlY6QZWxJ4i/6UhITOJ4XzyI647Bm2MXKCLqnJ4nQ=="
},
"emoji-regex": { "emoji-regex": {
"version": "8.0.0", "version": "8.0.0",
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz", "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
@ -9153,15 +9148,6 @@
"resolved": "https://registry.npmjs.org/gatsby-plugin-firebase/-/gatsby-plugin-firebase-0.2.0-beta.4.tgz", "resolved": "https://registry.npmjs.org/gatsby-plugin-firebase/-/gatsby-plugin-firebase-0.2.0-beta.4.tgz",
"integrity": "sha512-F1uh9T5dY38aeNvKzqj+3K655dce1QS70wuG4bhV9L3cnTJR2vitTWyIoCvRJJfPs7Xq7LgjUDmHDrEos4S3gQ==" "integrity": "sha512-F1uh9T5dY38aeNvKzqj+3K655dce1QS70wuG4bhV9L3cnTJR2vitTWyIoCvRJJfPs7Xq7LgjUDmHDrEos4S3gQ=="
}, },
"gatsby-plugin-mailchimp": {
"version": "5.2.2",
"resolved": "https://registry.npmjs.org/gatsby-plugin-mailchimp/-/gatsby-plugin-mailchimp-5.2.2.tgz",
"integrity": "sha512-O9JizVPJAe5YT1QAHZNRh1xUVdPnfayfIRhsBULiK2629TQRvEzzQxTDbt/WZU02cVm8415Fx2CneaxYKLt0ag==",
"requires": {
"email-validator": "^2.0.4",
"jsonp": "^0.2.1"
}
},
"gatsby-plugin-manifest": { "gatsby-plugin-manifest": {
"version": "2.4.17", "version": "2.4.17",
"resolved": "https://registry.npmjs.org/gatsby-plugin-manifest/-/gatsby-plugin-manifest-2.4.17.tgz", "resolved": "https://registry.npmjs.org/gatsby-plugin-manifest/-/gatsby-plugin-manifest-2.4.17.tgz",
@ -13268,29 +13254,6 @@
"resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz", "resolved": "https://registry.npmjs.org/jsonify/-/jsonify-0.0.0.tgz",
"integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM=" "integrity": "sha1-LHS27kHZPKUbe1qu6PUDYx0lKnM="
}, },
"jsonp": {
"version": "0.2.1",
"resolved": "https://registry.npmjs.org/jsonp/-/jsonp-0.2.1.tgz",
"integrity": "sha1-pltPoPEL2nGaBUQep7lMVfPhW64=",
"requires": {
"debug": "^2.1.3"
},
"dependencies": {
"debug": {
"version": "2.6.9",
"resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz",
"integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==",
"requires": {
"ms": "2.0.0"
}
},
"ms": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz",
"integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g="
}
}
},
"jsprim": { "jsprim": {
"version": "1.4.1", "version": "1.4.1",
"resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz",

View File

@ -24,7 +24,6 @@
"gatsby-plugin-amp": "^0.2.2", "gatsby-plugin-amp": "^0.2.2",
"gatsby-plugin-feed": "^2.5.11", "gatsby-plugin-feed": "^2.5.11",
"gatsby-plugin-firebase": "^0.2.0-beta.4", "gatsby-plugin-firebase": "^0.2.0-beta.4",
"gatsby-plugin-mailchimp": "^5.2.2",
"gatsby-plugin-manifest": "^2.4.17", "gatsby-plugin-manifest": "^2.4.17",
"gatsby-plugin-netlify-cms": "^4.3.9", "gatsby-plugin-netlify-cms": "^4.3.9",
"gatsby-plugin-netlify-cms-paths": "^1.3.0", "gatsby-plugin-netlify-cms-paths": "^1.3.0",

View File

@ -130,7 +130,7 @@ const Article = ({
owner, owner,
admin: admin.split(","), admin: admin.split(","),
language: "ru", language: "ru",
id: slug.substr(0, 48), id: slug,
title: title, title: title,
labels: ["Статья", "Обсуждение"], labels: ["Статья", "Обсуждение"],
}} }}

View File

@ -1,59 +1,8 @@
import React from "react" import React from "react"
import addToMailchimp from "gatsby-plugin-mailchimp"
const Newsletter = () => { const Newsletter = () => {
const [email, setEmail] = React.useState("") const submitHandler = e => {
const [success, setSuccess] = React.useState(false) e.preventDefault()
const [error, setError] = React.useState({ isError: false, message: "" })
const $subscribeButton = React.useRef()
const submitHandler = async e => {
try {
e.preventDefault()
document.body.style.cursor = "wait"
$subscribeButton.current.style.cursor = "wait"
if (
!email.match(
/^[a-zA-Z0-9.!#$%&'*+/=?^_`{|}~-]+@[a-zA-Z0-9-]+(?:\.[a-zA-Z0-9-]+)*$/
)
) {
setError({ isError: true, message: "Заполните поле в формате E-mail!" })
setSuccess(false)
window.setTimeout(() => setError({ isError: false, message: "" }), 5000)
return
}
setError({ isError: false, message: "" })
const data = await addToMailchimp(email)
if (data.result !== "success") {
setError({
isError: true,
message: `Произошла ошибка, возможно "${email}" уже подписан на рассылку. Попробуйте запрос позже.`,
})
window.setTimeout(() => setError({ isError: false, message: "" }), 5000)
console.log(data.msg)
document.body.style.cursor = "auto"
$subscribeButton.current.style.cursor = "pointer"
return
}
setSuccess(true)
window.setTimeout(() => setSuccess(false), 5000)
document.body.style.cursor = "auto"
$subscribeButton.current.style.cursor = "pointer"
} catch (error) {
console.log(error)
setSuccess(false)
}
}
const handleChangeEmail = e => {
const email = e.target.value.trim().toLowerCase()
setEmail(email)
} }
return ( return (
@ -70,27 +19,10 @@ const Newsletter = () => {
</p> </p>
<form onSubmit={submitHandler} action="#" target="_blank"> <form onSubmit={submitHandler} action="#" target="_blank">
<div className="email-field"> <div className="email-field">
<input <input placeholder="ваш e-mail" type="email" name="email" />
value={email} <button>Подписаться</button>
onChange={handleChangeEmail}
placeholder="ваш e-mail"
type="email"
name="email"
/>
<button ref={$subscribeButton}>Подписаться</button>
</div> </div>
</form> </form>
{success ? (
<p className="newsletter-content__success">
<span role="img" aria-label="checkMark">
✔️
</span>{" "}
Вы успешно подписались на рыссылку!
</p>
) : null}
{error.isError ? (
<p className="newsletter-content__error">{error.message}</p>
) : null}
</div> </div>
</div> </div>
) )

View File

@ -51,14 +51,6 @@
} }
} }
} }
&__error {
color: tomato;
margin-top: 15px;
}
&__success {
color: rgb(101, 190, 101);
margin-top: 15px;
}
} }
} }

View File

@ -38,7 +38,7 @@ const Snippet = ({ data: { slug, description, title, date }, html }) => {
owner, owner,
admin: admin.split(","), admin: admin.split(","),
language: "ru", language: "ru",
id: slug.substr(0, 48), id: slug,
title: title, title: title,
labels: ["Сниппет", "Обсуждение"], labels: ["Сниппет", "Обсуждение"],
}} }}

View File

@ -1,22 +1,6 @@
@import './variables.scss'; @import './variables.scss';
@import './fonts.scss'; @import './fonts.scss';
/* Components */
@import '../components/Header/Header.scss';
@import '../components/About/About.scss';
@import '../components/Offers/Offers.scss';
@import '../components/Articles/Articles.scss';
@import '../components/Articles/ArticleCard/ArticleCard.scss';
@import '../components/Newsletter/Newsletter.scss';
@import '../components/Article/Article.scss';
@import '../components/Snippet/Snippet.scss';
@import '../components/Snippets/Snippets.scss';
@import '../components/Articles/MoreArticles/MoreArticles.scss';
@import '../components/Books/Books.scss';
@import '../components/Contacts/Contacts.scss';
@import '../components/Footer/Footer.scss';
.container-fluid { .container-fluid {
max-width: 1200px; max-width: 1200px;
margin: 0 auto; margin: 0 auto;
@ -107,21 +91,15 @@ article .gt-container {
& p img { & p img {
text-align: center; text-align: center;
border-radius: 7px; border-radius: 7px;
border: 1px solid #f0f0f0;
} }
& ul { & ul {
margin-left: 34px; margin-left: 34px;
margin-bottom: 5px; margin-bottom: 15px;
& li { & li {
padding: 7px 0; padding: 7px 0;
& p {
display: inline-block;
font-size: 16px;
position: relative;
right: 4px;
}
&::before { &::before {
content: "\2022"; content: "\2022";
color: #6394F7; color: #6394F7;
@ -201,67 +179,11 @@ article .gt-container {
} }
} }
.gatsby-highlight pre[class*="language-scss"]:before {
content: "scss";
background: #e73eaf;
color: $white-clr;
}
.gatsby-highlight pre[class*="language-scss"] {
& code {
& span.token.property {
color: #dea53d;
}
}
}
.gatsby-highlight pre[class*="language-ts"] {
& code {
& span.token.class-name {
color: #f08787;
}
& span.token.constant {
color: #9a6c07;
}
}
}
.gatsby-highlight pre[class*="language-js"] {
& code {
& span.token.class-name {
color: #f08787;
}
& span.token.constant {
color: #9a6c07;
}
}
}
.gatsby-highlight pre[class*="language-jsx"] {
& code {
& span.token.class-name {
color: #f08787;
}
}
}
.gatsby-highlight pre[class*="language-js"]:before { .gatsby-highlight pre[class*="language-js"]:before {
content: "js"; content: "js";
background: rgb(247, 223, 30); background: rgb(247, 223, 30);
} }
.gatsby-highlight pre[class*="language-jsx"]:before {
content: "jsx";
background: #0a91eb;
color: $white-clr;
}
.gatsby-highlight pre[class*="language-ts"]:before {
content: "ts";
background: #007acc;
color: $white-clr;
}
.gatsby-highlight pre[class*="language-text"]:before { .gatsby-highlight pre[class*="language-text"]:before {
content: "text"; content: "text";
background: #efefef; background: #efefef;
@ -371,26 +293,6 @@ article .gt-container {
} }
& .inner { & .inner {
border-bottom: 1px solid rgba(153, 153, 153, 0.2); border-bottom: 1px solid rgba(153, 153, 153, 0.2);
& p img {
border: 1px solid #505050;
}
.gatsby-highlight pre[class*="language-ts"] {
& code {
& span.token.constant {
color: #f8c555;
}
}
}
.gatsby-highlight pre[class*="language-js"] {
& code {
& span.token.constant {
color: #f8c555;
}
}
}
.gatsby-highlight pre[class*="language-"] { .gatsby-highlight pre[class*="language-"] {
background: #282c34; background: #282c34;
& code { & code {

View File

@ -11,7 +11,7 @@ collections:
create: true create: true
slug: "{{year}}-{{month}}-{{day}}_{{slug}}" slug: "{{year}}-{{month}}-{{day}}_{{slug}}"
fields: fields:
- {label: "Template Key", name: "templateKey", widget: "hidden", default: "article"} - {label: "Template Key", name: "templateKey", wisdget: "hidden", default: "article"}
- {label: "Slug", name: "slug", widget: "string"} - {label: "Slug", name: "slug", widget: "string"}
- {label: "Keywords", name: "keywords", widget: "list"} - {label: "Keywords", name: "keywords", widget: "list"}
- {label: "Время чтения", name: "time", widget: "string"} - {label: "Время чтения", name: "time", widget: "string"}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 280 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 119 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 95 KiB