mirror of
https://github.com/sergeyyarkov/devthread.ru.git
synced 2026-10-11 02:09:04 +03:00
refactor
This commit is contained in:
parent
2a969a2642
commit
5b42b3c29d
@ -3,7 +3,7 @@ module.exports = {
|
||||
keywords:
|
||||
"веб разработка, javascript, seo, программирование, reactjs, graphql",
|
||||
siteName: "Cборник статей и руководств - devthread.ru",
|
||||
titleTemplate: "%s · статьи и руководства по веб-разработке",
|
||||
titleTemplate: "%s · devthread.ru",
|
||||
description:
|
||||
"Cборник статей и руководств по тематике веб-разработки и IT для того чтобы помочь вам",
|
||||
url: "https://devthread.netlify.app",
|
||||
|
||||
@ -40,12 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
||||
|
||||
```js
|
||||
const {
|
||||
//L1
|
||||
siteMetadata: {
|
||||
title,
|
||||
menuLinks,
|
||||
social: { twitter, telegram },
|
||||
},
|
||||
} = useSiteMetadataQuery() //L1
|
||||
} = useSiteMetadataQuery()
|
||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||
const [isDark, setIsDark] = React.useState(false)
|
||||
|
||||
@ -40,12 +40,13 @@ Lorem ipsum dolor sit amet, consectetur adipiscing elit. Nunc non fermentum ligu
|
||||
|
||||
```js
|
||||
const {
|
||||
//L1
|
||||
siteMetadata: {
|
||||
title,
|
||||
menuLinks,
|
||||
social: { twitter, telegram },
|
||||
},
|
||||
} = useSiteMetadataQuery() //L1
|
||||
} = useSiteMetadataQuery()
|
||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||
const [isDark, setIsDark] = React.useState(false)
|
||||
|
||||
@ -1,6 +1,5 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import SEO from "../SEO/SEO"
|
||||
import Img from "gatsby-image"
|
||||
import ViewCounter from "../ViewCounter/ViewCounter"
|
||||
import useSiteMetadataQuery from "../../hooks/useSiteMetadataQuery"
|
||||
@ -14,17 +13,7 @@ import TwitterIcon from "../../images/twitter-icon__large.svg"
|
||||
import FacebookIcon from "../../images/facebook-icon__large.svg"
|
||||
|
||||
const Article = ({
|
||||
data: {
|
||||
slug,
|
||||
keywords,
|
||||
title,
|
||||
image,
|
||||
description,
|
||||
category,
|
||||
tags,
|
||||
time,
|
||||
date,
|
||||
},
|
||||
data: { slug, title, image, description, category, tags, time, date },
|
||||
html,
|
||||
}) => {
|
||||
const {
|
||||
@ -34,14 +23,6 @@ const Article = ({
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={title}
|
||||
titleTemplate={false}
|
||||
keywords={keywords.join(", ")}
|
||||
description={description}
|
||||
image={`${siteUrl}${image.childImageSharp.fluid.src}`}
|
||||
type="article"
|
||||
/>
|
||||
<div className="article">
|
||||
<article>
|
||||
<div className="article-info">
|
||||
|
||||
@ -2,13 +2,10 @@ import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import ContactsFrom from "./ContactsForm/ContactsForm"
|
||||
|
||||
import MemoIcon from "../../images/memo-icon.svg"
|
||||
|
||||
const Contacts = ({ email, telegram }) => {
|
||||
return (
|
||||
<div className="contacts">
|
||||
<div className="contacts-heading">
|
||||
<MemoIcon />
|
||||
<h1>Контакты</h1>
|
||||
</div>
|
||||
<div className="contacts-description">
|
||||
|
||||
@ -9,7 +9,7 @@
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
align-items: center;
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 10px;
|
||||
& svg {
|
||||
margin-right: 10px;
|
||||
}
|
||||
|
||||
@ -19,15 +19,20 @@ const Header = () => {
|
||||
} = useSiteMetadataQuery()
|
||||
const [isScrolled, setIsScrolled] = React.useState(false)
|
||||
const [isMobileOpen, setIsMobileOpen] = React.useState(false)
|
||||
const [ready, setReady] = React.useState(false)
|
||||
const [isDark, setIsDark] = React.useState(false)
|
||||
|
||||
const { pathname } = useLocation()
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsDark(window.__isDarkTheme)
|
||||
setReady(true)
|
||||
isMobileOpen
|
||||
? (document.body.style.overflowY = "hidden")
|
||||
: (document.body.style.overflowY = "")
|
||||
document.body.onscroll = () =>
|
||||
window.pageYOffset >= 100 ? setIsScrolled(true) : setIsScrolled(false)
|
||||
}, [isMobileOpen])
|
||||
}, [isMobileOpen, setIsDark, setReady])
|
||||
|
||||
const mobileHandler = () => {
|
||||
setIsMobileOpen(!isMobileOpen)
|
||||
@ -71,7 +76,7 @@ const Header = () => {
|
||||
<div className="header-nav__links">
|
||||
<nav>{renderLinks()}</nav>
|
||||
</div>
|
||||
<ThemeSwitcher />
|
||||
<ThemeSwitcher ready={ready} isDark={isDark} setIsDark={setIsDark} />
|
||||
</div>
|
||||
<div
|
||||
className={
|
||||
@ -84,6 +89,11 @@ const Header = () => {
|
||||
<>
|
||||
<span>{title}</span>
|
||||
<nav>{renderLinks()}</nav>
|
||||
<ThemeSwitcher
|
||||
ready={ready}
|
||||
isDark={isDark}
|
||||
setIsDark={setIsDark}
|
||||
/>
|
||||
<div className="mobile-social">
|
||||
<a href="/" target="_blank">
|
||||
<TelegramIcon />
|
||||
|
||||
@ -84,17 +84,10 @@ header {
|
||||
color: rgba(0,0,0,.8);
|
||||
}
|
||||
}
|
||||
& .header-nav__theme {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
}
|
||||
& .header-nav__theme.ready {
|
||||
opacity: 1;
|
||||
transition: all 0.2s linear 0s;
|
||||
}
|
||||
}
|
||||
&__nav.mobile {
|
||||
background: #0d0d0d;
|
||||
background-color: rgba(250,252,254, .9);
|
||||
backdrop-filter: blur(8px);
|
||||
position: fixed;
|
||||
right: 0;
|
||||
left: 0;
|
||||
@ -102,11 +95,14 @@ header {
|
||||
bottom: 0;
|
||||
height: 0%;
|
||||
transition: padding-top .2s ease-out;
|
||||
overflow: scroll;
|
||||
overflow-x: hidden;
|
||||
z-index: 99;
|
||||
& .theme-switcher {
|
||||
position: absolute;
|
||||
right: 22px;
|
||||
bottom: 45px;
|
||||
}
|
||||
& span {
|
||||
color: $white-clr;
|
||||
color: #0A0C10;
|
||||
display: block;
|
||||
margin-bottom: 20px;
|
||||
font-weight: 700;
|
||||
@ -118,10 +114,13 @@ header {
|
||||
& a {
|
||||
font-size: 28px;
|
||||
text-decoration: none;
|
||||
color: $white-clr;
|
||||
color: #0A0C10;
|
||||
font-weight: 600;
|
||||
}
|
||||
}
|
||||
& li.active {
|
||||
margin-left: 20px;
|
||||
}
|
||||
}
|
||||
& .mobile-social {
|
||||
margin-top: 30px;
|
||||
@ -135,11 +134,11 @@ header {
|
||||
}
|
||||
& svg {
|
||||
& .telegram-svg-social {
|
||||
fill: $white-clr;
|
||||
fill: #0A0C10;
|
||||
width: 50px;
|
||||
}
|
||||
& .twitter-svg-social {
|
||||
fill: $white-clr;
|
||||
fill: #0A0C10;
|
||||
}
|
||||
}
|
||||
& a:nth-child(2) {
|
||||
@ -188,18 +187,18 @@ header {
|
||||
&__button.mobile.active {
|
||||
& span:nth-child(1) {
|
||||
transform: rotate(45deg);
|
||||
background: $white-clr;
|
||||
background: #0A0C10;
|
||||
top: -3px;
|
||||
left: 0px;
|
||||
}
|
||||
& span:nth-child(2) {
|
||||
width: 0%;
|
||||
opacity: 0;
|
||||
background: $white-clr;
|
||||
background: #0A0C10;
|
||||
}
|
||||
& span:nth-child(3) {
|
||||
transform: rotate(-45deg);
|
||||
background: $white-clr;
|
||||
background: #0A0C10;
|
||||
top: 18px;
|
||||
left: 0px;
|
||||
}
|
||||
@ -261,11 +260,43 @@ header {
|
||||
}
|
||||
}
|
||||
}
|
||||
&__nav.mobile {
|
||||
background-color: rgba(7,11,14, .99);
|
||||
& span {
|
||||
color: $white-clr;
|
||||
}
|
||||
& nav {
|
||||
& li {
|
||||
& a {
|
||||
color: $white-clr;
|
||||
}
|
||||
}
|
||||
}
|
||||
& svg {
|
||||
& .telegram-svg-social {
|
||||
fill: $white-clr;
|
||||
}
|
||||
& .twitter-svg-social {
|
||||
fill: $white-clr;
|
||||
}
|
||||
}
|
||||
}
|
||||
&__button.mobile {
|
||||
& span {
|
||||
background: $white-clr;
|
||||
}
|
||||
}
|
||||
&__button.mobile.active {
|
||||
& span:nth-child(1) {
|
||||
background: $white-clr;
|
||||
}
|
||||
& span:nth-child(2) {
|
||||
background: $white-clr;
|
||||
}
|
||||
& span:nth-child(3) {
|
||||
background: $white-clr;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,19 +1,12 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
|
||||
import MoonIcon from "../../../images/moon-icon.svg"
|
||||
import SunIcon from "../../../images/sun-icon.svg"
|
||||
|
||||
const ThemeSwitcher = () => {
|
||||
const [ready, setReady] = React.useState(false)
|
||||
const [isDark, setIsDark] = React.useState(false)
|
||||
|
||||
React.useEffect(() => {
|
||||
setIsDark(window.__isDarkTheme)
|
||||
setReady(true)
|
||||
}, [setIsDark, setReady])
|
||||
|
||||
const ThemeSwitcher = ({ ready, isDark, setIsDark }) => {
|
||||
return (
|
||||
<div className={ready ? "header-nav__theme ready" : "header-nav__theme"}>
|
||||
<div className={ready ? "theme-switcher ready" : "theme-switcher"}>
|
||||
{isDark ? (
|
||||
<SunIcon
|
||||
onClick={() => {
|
||||
@ -34,3 +27,9 @@ const ThemeSwitcher = () => {
|
||||
}
|
||||
|
||||
export default ThemeSwitcher
|
||||
|
||||
ThemeSwitcher.propTypes = {
|
||||
ready: PropTypes.bool,
|
||||
isDark: PropTypes.bool,
|
||||
setIsDark: PropTypes.func,
|
||||
}
|
||||
|
||||
@ -85,6 +85,11 @@
|
||||
& .tag-item {
|
||||
& a {
|
||||
color: #5183F5;
|
||||
background: rgba(0,0,0, .2);
|
||||
&:hover {
|
||||
background: #111;
|
||||
color: #99c9f7;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,17 +1,9 @@
|
||||
import React from "react"
|
||||
import PropTypes from "prop-types"
|
||||
import SEO from "../SEO/SEO"
|
||||
|
||||
const Snippet = ({ data: { keywords, description, title, date }, html }) => {
|
||||
const Snippet = ({ data: { description, title, date }, html }) => {
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={title}
|
||||
titleTemplate={false}
|
||||
description={description}
|
||||
keywords={keywords.join(", ")}
|
||||
type="article"
|
||||
/>
|
||||
<div className="snippet">
|
||||
<article>
|
||||
<div className="snippet-date">{date}</div>
|
||||
|
||||
File diff suppressed because one or more lines are too long
|
Before Width: | Height: | Size: 5.5 KiB |
@ -7,7 +7,7 @@ import SEO from "../components/SEO/SEO"
|
||||
const NotFound = () => {
|
||||
return (
|
||||
<>
|
||||
<SEO />
|
||||
<SEO title="Ошибка 404" />
|
||||
<Main>
|
||||
<Grid fluid>
|
||||
<div className="error">
|
||||
|
||||
@ -23,7 +23,10 @@ const IndexPage = ({ data: { allMarkdownRemark: edges } }) => {
|
||||
|
||||
return (
|
||||
<>
|
||||
<SEO />
|
||||
<SEO
|
||||
title="devthread.ru · Статьи и руководства по веб-разработке"
|
||||
titleTemplate={false}
|
||||
/>
|
||||
<Main>
|
||||
<Grid fluid>
|
||||
<Row>
|
||||
|
||||
@ -13,11 +13,11 @@ const SnippetsPage = ({
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<SEO />
|
||||
<SEO title="Сниппеты" />
|
||||
<Main>
|
||||
<Grid fluid>
|
||||
<Row>
|
||||
<Col lg={12}>
|
||||
<Col xs={12}>
|
||||
<Snippets>
|
||||
<h1>Сниппеты</h1>
|
||||
<p>
|
||||
|
||||
@ -142,6 +142,15 @@
|
||||
background: linear-gradient(135.9deg, #F5F9FF 0%, #F5F9FF 0.01%, #F6F4FB 98.96%);
|
||||
}
|
||||
|
||||
.theme-switcher {
|
||||
cursor: pointer;
|
||||
opacity: 0;
|
||||
&.ready {
|
||||
opacity: 1;
|
||||
transition: all 0.2s linear 0s;
|
||||
}
|
||||
}
|
||||
|
||||
.dark {
|
||||
background: #202020;
|
||||
& .light-default-light {
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React from "react"
|
||||
import { Main } from "../ui/ui"
|
||||
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||
import SEO from "../components/SEO/SEO"
|
||||
import Article from "../components/Article/Article"
|
||||
import Offers from "../components/Offers/Offers"
|
||||
import MoreArticles from "../components/Articles/MoreArticles/MoreArticles"
|
||||
@ -9,11 +10,22 @@ import { graphql } from "gatsby"
|
||||
|
||||
const articleTemplate = ({
|
||||
data: {
|
||||
markdownRemark: { frontmatter, html },
|
||||
article: { frontmatter, html },
|
||||
site: {
|
||||
siteMetadata: { siteUrl },
|
||||
},
|
||||
},
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={frontmatter.title}
|
||||
titleTemplate={false}
|
||||
keywords={frontmatter.keywords.join(", ")}
|
||||
description={frontmatter.description}
|
||||
image={`${siteUrl}${frontmatter.image.childImageSharp.fluid.src}`}
|
||||
type="article"
|
||||
/>
|
||||
<Main>
|
||||
<Grid fluid>
|
||||
<Row>
|
||||
@ -34,7 +46,7 @@ const articleTemplate = ({
|
||||
|
||||
export const pageQuery = graphql`
|
||||
query Article($slug: String!) {
|
||||
markdownRemark(frontmatter: { slug: { eq: $slug } }) {
|
||||
article: markdownRemark(frontmatter: { slug: { eq: $slug } }) {
|
||||
html
|
||||
frontmatter {
|
||||
slug
|
||||
@ -54,6 +66,11 @@ export const pageQuery = graphql`
|
||||
category
|
||||
}
|
||||
}
|
||||
site {
|
||||
siteMetadata {
|
||||
siteUrl: url
|
||||
}
|
||||
}
|
||||
}
|
||||
`
|
||||
|
||||
|
||||
@ -1,6 +1,7 @@
|
||||
import React from "react"
|
||||
import { Main } from "../ui/ui"
|
||||
import { Grid, Row, Col } from "react-flexbox-grid"
|
||||
import SEO from "../components/SEO/SEO"
|
||||
import Snippet from "../components/Snippet/Snippet"
|
||||
import { graphql } from "gatsby"
|
||||
|
||||
@ -11,6 +12,13 @@ const snippetTemplate = ({
|
||||
}) => {
|
||||
return (
|
||||
<>
|
||||
<SEO
|
||||
title={frontmatter.title}
|
||||
titleTemplate={false}
|
||||
description={frontmatter.description}
|
||||
keywords={frontmatter.keywords.join(", ")}
|
||||
type="article"
|
||||
/>
|
||||
<Main>
|
||||
<Grid fluid style={{ maxWidth: 900 }}>
|
||||
<Row>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user