mirror of
https://github.com/sergeyyarkov/devthread.ru.git
synced 2026-10-11 18:29:10 +03:00
added category page
This commit is contained in:
parent
8abf87d842
commit
cb48215bc4
60
gatsby-node.esm.js
Normal file
60
gatsby-node.esm.js
Normal file
@ -0,0 +1,60 @@
|
|||||||
|
import slugify from './src/helpers/slugify'
|
||||||
|
import { fmImagesToRelative } from 'gatsby-remark-relative-images'
|
||||||
|
import path from 'path'
|
||||||
|
|
||||||
|
exports.createPages = async ({ actions, graphql }) => {
|
||||||
|
const { createPage } = actions
|
||||||
|
|
||||||
|
const articleTemplate = path.resolve('src/templates/articleTemplate.js')
|
||||||
|
const categoryTemplate = path.resolve('src/templates/categoryTemplate.js')
|
||||||
|
|
||||||
|
const result = await graphql(
|
||||||
|
`
|
||||||
|
{
|
||||||
|
allMarkdownRemark {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
frontmatter {
|
||||||
|
templateKey
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
if (result.errors) {
|
||||||
|
throw result.errors
|
||||||
|
}
|
||||||
|
|
||||||
|
const all = result.data.allMarkdownRemark.edges
|
||||||
|
const articles = all.filter(article => article.node.frontmatter.templateKey === 'article')
|
||||||
|
const categories = all.filter(category => category.node.frontmatter.templateKey === 'category')
|
||||||
|
|
||||||
|
articles.forEach(({ node }) => {
|
||||||
|
createPage({
|
||||||
|
path: `article/${node.frontmatter.slug}`,
|
||||||
|
component: articleTemplate,
|
||||||
|
context: {
|
||||||
|
slug: node.frontmatter.slug
|
||||||
|
},
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
categories.forEach(({ node }) => {
|
||||||
|
createPage({
|
||||||
|
path: `category/${slugify(node.frontmatter.title)}`,
|
||||||
|
component: categoryTemplate,
|
||||||
|
context: {
|
||||||
|
title: node.frontmatter.title
|
||||||
|
},
|
||||||
|
});
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
exports.onCreateNode = ({ node }) => {
|
||||||
|
fmImagesToRelative(node);
|
||||||
|
};
|
||||||
@ -1,39 +1,2 @@
|
|||||||
const { fmImagesToRelative } = require('gatsby-remark-relative-images');
|
require = require('esm')(module)
|
||||||
const path = require('path')
|
module.exports = require('./gatsby-node.esm.js')
|
||||||
|
|
||||||
exports.createPages = ({ actions, graphql }) => {
|
|
||||||
const { createPage } = actions
|
|
||||||
const articleTemplate = path.resolve('src/templates/articleTemplate.js')
|
|
||||||
|
|
||||||
return graphql(`
|
|
||||||
{
|
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}) {
|
|
||||||
edges {
|
|
||||||
node {
|
|
||||||
frontmatter {
|
|
||||||
slug
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
`).then(result => {
|
|
||||||
if (result.errors) {
|
|
||||||
return Promise.reject(result.errors);
|
|
||||||
}
|
|
||||||
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
|
|
||||||
createPage({
|
|
||||||
path: `article/${node.frontmatter.slug}`,
|
|
||||||
component: articleTemplate,
|
|
||||||
context: {
|
|
||||||
slug: node.frontmatter.slug
|
|
||||||
},
|
|
||||||
});
|
|
||||||
});
|
|
||||||
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
exports.onCreateNode = ({ node }) => {
|
|
||||||
fmImagesToRelative(node);
|
|
||||||
};
|
|
||||||
5
package-lock.json
generated
5
package-lock.json
generated
@ -7314,6 +7314,11 @@
|
|||||||
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/eslint-visitor-keys/-/eslint-visitor-keys-1.3.0.tgz",
|
||||||
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
|
"integrity": "sha512-6J72N8UNa462wa/KFODt/PJ3IU60SDpC3QXC1Hjc1BXXpfL2C9R5+AU7jhe0F6GREqVMh4Juu+NY7xn+6dipUQ=="
|
||||||
},
|
},
|
||||||
|
"esm": {
|
||||||
|
"version": "3.2.25",
|
||||||
|
"resolved": "https://registry.npmjs.org/esm/-/esm-3.2.25.tgz",
|
||||||
|
"integrity": "sha512-U1suiZ2oDVWv4zPO56S0NcR5QriEahGtdN2OR6FiOG4WJvcjBVFB0qI4+eKoWFH483PKGuLuu6V8Z4T5g63UVA=="
|
||||||
|
},
|
||||||
"espree": {
|
"espree": {
|
||||||
"version": "6.2.1",
|
"version": "6.2.1",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-6.2.1.tgz",
|
||||||
|
|||||||
@ -16,6 +16,7 @@
|
|||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@reach/router": "^1.3.4",
|
"@reach/router": "^1.3.4",
|
||||||
|
"esm": "^3.2.25",
|
||||||
"gatsby": "^2.23.12",
|
"gatsby": "^2.23.12",
|
||||||
"gatsby-image": "^2.4.12",
|
"gatsby-image": "^2.4.12",
|
||||||
"gatsby-plugin-netlify-cms": "^4.3.9",
|
"gatsby-plugin-netlify-cms": "^4.3.9",
|
||||||
|
|||||||
@ -1,6 +1,7 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import SEO from '../SEO/SEO'
|
import SEO from '../SEO/SEO'
|
||||||
import Img from "gatsby-image"
|
import Img from "gatsby-image"
|
||||||
|
import slugify from '../../helpers/slugify'
|
||||||
import { Link } from 'gatsby'
|
import { Link } from 'gatsby'
|
||||||
import './Article.scss'
|
import './Article.scss'
|
||||||
|
|
||||||
@ -35,7 +36,7 @@ const Article = ({ data: { title, image, description, category, tags, time, date
|
|||||||
<h1>{title}</h1>
|
<h1>{title}</h1>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-category">
|
<div className="article-category">
|
||||||
<Link to={`/category/${category}`}>{category}</Link>
|
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-share">
|
<div className="article-share">
|
||||||
<span>Поделиться:</span>
|
<span>Поделиться:</span>
|
||||||
@ -68,7 +69,7 @@ const Article = ({ data: { title, image, description, category, tags, time, date
|
|||||||
<div dangerouslySetInnerHTML={{__html: html}}></div>
|
<div dangerouslySetInnerHTML={{__html: html}}></div>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-more">
|
<div className="article-more">
|
||||||
<span>Смотреть еще в категории <Link to={`/category/${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">
|
||||||
|
|||||||
@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import slugify from '../../../helpers/slugify'
|
||||||
import Img from "gatsby-image"
|
import Img from "gatsby-image"
|
||||||
import { Link } from 'gatsby'
|
import { Link } from 'gatsby'
|
||||||
import './ArticleCard.scss'
|
import './ArticleCard.scss'
|
||||||
@ -15,7 +16,7 @@ const ArticleCard = ({ data: { slug, title, image, category, description, tags }
|
|||||||
<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/${category}`}>{category}</Link>
|
<Link to={`/category/${slugify(category)}`}>{category}</Link>
|
||||||
</div>
|
</div>
|
||||||
<div className="article-card__tags">
|
<div className="article-card__tags">
|
||||||
<ul>
|
<ul>
|
||||||
|
|||||||
67
src/helpers/slugify.js
Normal file
67
src/helpers/slugify.js
Normal file
@ -0,0 +1,67 @@
|
|||||||
|
const slugify = str => {
|
||||||
|
const patterns = {
|
||||||
|
rus: /^[0-9а-яё-\s]*$/i
|
||||||
|
}
|
||||||
|
|
||||||
|
const translit = str => {
|
||||||
|
if (str.match(patterns.rus)) {
|
||||||
|
const ru = {
|
||||||
|
а: "a",
|
||||||
|
б: "b",
|
||||||
|
в: "v",
|
||||||
|
г: "g",
|
||||||
|
д: "d",
|
||||||
|
е: "e",
|
||||||
|
ё: "e",
|
||||||
|
ж: "j",
|
||||||
|
з: "z",
|
||||||
|
и: "i",
|
||||||
|
к: "k",
|
||||||
|
л: "l",
|
||||||
|
м: "m",
|
||||||
|
н: "n",
|
||||||
|
о: "o",
|
||||||
|
п: "p",
|
||||||
|
р: "r",
|
||||||
|
с: "s",
|
||||||
|
т: "t",
|
||||||
|
у: "u",
|
||||||
|
ф: "f",
|
||||||
|
х: "h",
|
||||||
|
ц: "c",
|
||||||
|
ч: "ch",
|
||||||
|
ш: "sh",
|
||||||
|
щ: "shch",
|
||||||
|
ы: "y",
|
||||||
|
э: "e",
|
||||||
|
ю: "u",
|
||||||
|
я: "ya"
|
||||||
|
},
|
||||||
|
newStr = [];
|
||||||
|
|
||||||
|
for (var i = 0; i < str.length; ++i) {
|
||||||
|
const candidate = str[i].toLowerCase()
|
||||||
|
|
||||||
|
if (ru[candidate]) {
|
||||||
|
newStr.push(ru[candidate]);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (candidate === '-' || !isNaN(candidate)) {
|
||||||
|
newStr.push(candidate)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return newStr.join("");
|
||||||
|
}
|
||||||
|
|
||||||
|
return 'not rus'
|
||||||
|
}
|
||||||
|
|
||||||
|
if (str.match(patterns.rus)) {
|
||||||
|
return translit(str).split(' ').join('-').toLowerCase()
|
||||||
|
}
|
||||||
|
|
||||||
|
return str.split(' ').join('-').toLowerCase()
|
||||||
|
};
|
||||||
|
|
||||||
|
export default slugify
|
||||||
@ -43,7 +43,7 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
|||||||
|
|
||||||
export const query = graphql`
|
export const query = graphql`
|
||||||
{
|
{
|
||||||
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}) {
|
allMarkdownRemark(filter: {frontmatter: {templateKey: {eq: "article"}}}, sort: {order: DESC, fields: frontmatter___date}) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
frontmatter {
|
frontmatter {
|
||||||
|
|||||||
100
src/templates/categoryTemplate.js
Normal file
100
src/templates/categoryTemplate.js
Normal file
@ -0,0 +1,100 @@
|
|||||||
|
import React from "react"
|
||||||
|
import { Link, graphql } from 'gatsby'
|
||||||
|
import SEO from '../components/SEO/SEO'
|
||||||
|
import Layout from '../components/Layout/Layout'
|
||||||
|
import Articles from '../components/Articles/Articles'
|
||||||
|
import Offers from '../components/Offers/Offers'
|
||||||
|
import Newsletter from '../components/Newsletter/Newsletter'
|
||||||
|
|
||||||
|
const CategoryPage = ({ data: { allMarkdownRemark: edges } }) => {
|
||||||
|
return (
|
||||||
|
<Layout>
|
||||||
|
<SEO title='Категория' />
|
||||||
|
<main>
|
||||||
|
<div className="container-fluid">
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-9 col-xs-12">
|
||||||
|
<div className="articles">
|
||||||
|
<div className="articles-heading">
|
||||||
|
<h1>Статьи</h1>
|
||||||
|
</div>
|
||||||
|
<div className="articles-categories">
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Все</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Javascript</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>GraphQL</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Reactjs</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>SEO оптимизация</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Web разработка</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>pet-проекты</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Nodejs</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>ООП</Link>
|
||||||
|
</div>
|
||||||
|
<div className="tag-item">
|
||||||
|
<Link to='/'>Новости</Link>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="articles-search">
|
||||||
|
<input placeholder="Напишите сюда чтобы отфильтровать статьи" type="text" />
|
||||||
|
<span>278</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div className="row">
|
||||||
|
<div className="col-md-9 col-xs-12">
|
||||||
|
<Articles data={edges} />
|
||||||
|
<Newsletter />
|
||||||
|
</div>
|
||||||
|
<div className="col-md-3 col-xs-12">
|
||||||
|
<Offers />
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</main>
|
||||||
|
</Layout>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const pageQuery = graphql`
|
||||||
|
query articleByCategory($title: String!) {
|
||||||
|
allMarkdownRemark(filter: {frontmatter: {category: {eq: $title}}}) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
frontmatter {
|
||||||
|
slug
|
||||||
|
title
|
||||||
|
image {
|
||||||
|
childImageSharp {
|
||||||
|
fluid {
|
||||||
|
...GatsbyImageSharpFluid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
category
|
||||||
|
tags
|
||||||
|
description
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
|
||||||
|
export default CategoryPage
|
||||||
@ -14,8 +14,8 @@ collections:
|
|||||||
- {label: "Slug", name: "slug", widget: "string"}
|
- {label: "Slug", name: "slug", widget: "string"}
|
||||||
- {label: "Время чтения", name: "time", widget: "string"}
|
- {label: "Время чтения", name: "time", widget: "string"}
|
||||||
- {label: "Заголовок", name: "title", widget: "string"}
|
- {label: "Заголовок", name: "title", widget: "string"}
|
||||||
- {labe: "Обложка", name: "image", widget: "image"}
|
- {label: "Обложка", name: "image", widget: "image"}
|
||||||
- {label: "Категория", name: "category", widget: "relation", collection: "categories", valueField: "title", searchFields: ["title"]}
|
- {label: "Категория", name: "category", widget: "relation", collection: "categories", valueField: "title", searchFields: ["title", "slug"]}
|
||||||
- {label: "Дата публикации", name: "date", widget: "datetime"}
|
- {label: "Дата публикации", name: "date", widget: "datetime"}
|
||||||
- {label: "Описание", name: "description", widget: "text"}
|
- {label: "Описание", name: "description", widget: "text"}
|
||||||
- {label: "Содержание", name: "body", widget: "markdown"}
|
- {label: "Содержание", name: "body", widget: "markdown"}
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user