Website optimization

- Remove AnyLink and ReactCSSTransitionReplace
- Clean up GraphQL queries
- Improve getTextualContent method in website utilities
- Convert ttf fonts to woff2
- Add title attribute to menu items
This commit is contained in:
Angelos Chalaris
2019-08-27 20:14:07 +03:00
parent c643adda83
commit 5e8dd9a9b3
31 changed files with 55 additions and 239 deletions

View File

@ -1,8 +1,6 @@
import React from 'react';
import { graphql, useStaticQuery } from 'gatsby';
import { graphql, useStaticQuery, Link } from 'gatsby';
import { connect } from 'react-redux';
import AniLink from 'gatsby-plugin-transition-link/AniLink';
import ReactCSSTransitionReplace from 'react-css-transition-replace';
import config from '../../../config';
import { toggleDarkMode } from '../state/app';
@ -52,67 +50,50 @@ const Shell = ({
}
}
`);
let viewportWidth = typeof window !== 'undefined' && window.innerWidth;
return (
<div className={isDarkMode ? 'page-container dark' : 'page-container'}>
{/* Menu */}
<header className='menu'>
<AniLink
cover
direction={viewportWidth < 600 ? 'up' : 'right'}
bg={isDarkMode ? '#434E76' : '#FFFFFF'}
<Link
to='/search'
aria-label='Search'
aria-label='Search'title='Search'
className={isSearch ? 'menu-button active' : 'menu-button'}
>
<SearchIcon />
</AniLink>
<AniLink
cover
direction={viewportWidth < 600 ? 'up' : 'right'}
bg={isDarkMode ? '#434E76' : '#FFFFFF'}
</Link>
<Link
to='/list'
aria-label='Snippet list'
aria-label='Snippet list' title='Snippet list'
className={isList ? 'menu-button active' : 'menu-button'}
>
<ListIcon />
</AniLink>
</Link>
{/* eslint-disable-next-line */}
<a target='_blank'
rel='noopener'
href={config.repositoryUrl}
aria-label='View on GitHub'
aria-label='View on GitHub' title='View on GitHub'
className='menu-button'
>
<GithubIcon />
</a>
{/*
The use of React.Fragment here will cause a lot of errors to show up in webber:dev.
Truth is, this is the only decent way I found to deal with this module's odd behavior.
Keep as is, unless you can provide a better solution, in which case please send a PR.
*/}
<ReactCSSTransitionReplace
transitionName='cross-fade'
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
component='button'
<button
aria-label={isDarkMode ? 'Switch to light mode' : 'Switch to dark mode'}
className='menu-button'
childComponent={React.Fragment}
>
title={isDarkMode ? 'Switch to light mode' : 'Switch to dark mode'}
className='menu-button'>
{isDarkMode ? (
<LightModeIcon
key='lmit'
onClick={() => dispatch(toggleDarkMode(!isDarkMode))}
/>
) : (
<DarkModeIcon
key='dmit'
onClick={() => dispatch(toggleDarkMode(!isDarkMode))}
/>
)}
</ReactCSSTransitionReplace>
<DarkModeIcon
key='dmit'
onClick={() => dispatch(toggleDarkMode(!isDarkMode))}
/>
)}
</button>
</header>
{/* Content */}
<div className='content'>

View File

@ -1,14 +1,14 @@
import React from 'react';
import { CopyToClipboard } from 'react-copy-to-clipboard';
import config from '../../../config';
import { Link } from 'gatsby';
import { getTextualContent, getCodeBlocks, optimizeAllNodes } from '../util';
// import ClipboardIcon from './SVGs/ClipboardIcon';
// import ShareIcon from './SVGs/ShareIcon';
import AniLink from 'gatsby-plugin-transition-link/AniLink';
import CollapseOpenIcon from './SVGs/CollapseOpenIcon';
import CollapseClosedIcon from './SVGs/CollapseClosedIcon';
import ReactCSSTransitionReplace from 'react-css-transition-replace';
// import ReactCSSTransitionReplace from 'react-css-transition-replace';
// ===================================================
// Snippet Card HOC - check components below for more
@ -96,18 +96,18 @@ const FullCard = ({ snippetData, difficulty, isDarkMode }) => {
>
{examplesOpen ? <CollapseOpenIcon /> : <CollapseClosedIcon />}Examples
</button>
<ReactCSSTransitionReplace
{/* <ReactCSSTransitionReplace
transitionName='roll-up'
transitionEnterTimeout={300}
transitionLeaveTimeout={300}
>
> */}
{examplesOpen && (
<pre
className='section card-examples language-js'
dangerouslySetInnerHTML={{ __html: cardExamplesHtml }}
/>
)}
</ReactCSSTransitionReplace>
{/* </ReactCSSTransitionReplace> */}
</div>
</div>
);
@ -118,27 +118,18 @@ const FullCard = ({ snippetData, difficulty, isDarkMode }) => {
// ===================================================
const ShortCard = ({
snippetData,
withCode = false,
archived = false,
difficulty,
isDarkMode
}) => {
let cardCodeHtml;
if(withCode)
cardCodeHtml = `${optimizeAllNodes(
getCodeBlocks(snippetData.html).code,
)}`;
return (
<div className='card short'>
<CardCorner difficulty={difficulty} />
<h4 className='card-title'>
<AniLink
paintDrip
<Link
to={archived ? `/archive/${snippetData.id}` : `/snippet/${snippetData.id}`}
hex={isDarkMode ? '#434E76' : '#FFFFFF'}
>
{snippetData.title}
</AniLink>
</Link>
</h4>
<div
className='card-description'
@ -146,32 +137,6 @@ const ShortCard = ({
__html: `${getTextualContent(snippetData.html, true)}`,
}}
/>
{ withCode ? <div className='card-bottom'>
<CopyToClipboard
text={snippetData.code}
onCopy={() => {
let tst = document.createElement('div');
tst.classList = 'toast';
tst.innerHTML = 'Snippet copied to clipboard!';
document.body.appendChild(tst);
setTimeout(function() {
tst.style.opacity = 0;
setTimeout(function() {
document.body.removeChild(tst);
}, 300);
}, 1700);
}}
>
<button
className='button button-a button-copy'
aria-label='Copy to clipboard'
/>
</CopyToClipboard>
<pre
className={`card-code language-${config.language}`}
dangerouslySetInnerHTML={{ __html: cardCodeHtml }}
/>
</div> : ''}
</div>
);
};

View File

@ -1,6 +1,6 @@
import React from 'react';
import { connect } from 'react-redux';
import AniLink from 'gatsby-plugin-transition-link/AniLink';
import { Link } from 'gatsby';
import Shell from '../components/Shell';
import Meta from '../components/Meta';
@ -21,10 +21,8 @@ const NotFoundPage = ({ isDarkMode }) => (
<p className='empty-page-subtext'>
Seems like you have reached a page that does not exist.
</p>
<AniLink
paintDrip
<Link
to='/'
hex={isDarkMode ? '#434E76' : '#FFFFFF'}
className='button button-a button-home'
>
<svg
@ -43,7 +41,7 @@ const NotFoundPage = ({ isDarkMode }) => (
<polyline points='9 22 9 12 15 12 15 22'></polyline>
</svg>
&nbsp;&nbsp;Go home
</AniLink>
</Link>
</div>
</Shell>
</>

View File

@ -5,9 +5,7 @@ import { pushNewPage } from '../state/app';
import Meta from '../components/Meta';
import Shell from '../components/Shell';
import SnippetCard from '../components/SnippetCard';
import { getRawCodeBlocks as getCodeBlocks } from '../util';
import SnippetCard from '../components/SnippetCard'
// ===================================================
// Individual snippet category/tag page
@ -35,7 +33,6 @@ const ArchivePage = props => {
snippetData={{
title: node.frontmatter.title,
html: node.html,
code: getCodeBlocks(node.rawMarkdownBody).code,
tags: node.frontmatter.tags.split(',').map(v => v.trim()),
id: node.fields.slug.slice(1),
}}

View File

@ -8,8 +8,6 @@ import Meta from '../components/Meta';
import Search from '../components/Search';
import SnippetCard from '../components/SnippetCard';
import { getRawCodeBlocks as getCodeBlocks } from '../util';
// ===================================================
// Home page (splash and search)
// ===================================================
@ -20,13 +18,7 @@ const IndexPage = props => {
v => v.node.frontmatter.title === snippet.title,
).node.html,
tags: snippet.attributes.tags,
text: snippet.attributes.text,
id: snippet.id,
code: getCodeBlocks(
props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.rawMarkdownBody,
).code,
id: snippet.id
}));
const [searchQuery, setSearchQuery] = React.useState(props.searchQuery);
@ -129,26 +121,15 @@ export const indexPageQuery = graphql`
title
attributes {
tags
text
}
}
}
allMarkdownRemark(
limit: 1000
sort: { fields: [frontmatter___title], order: ASC }
) {
totalCount
allMarkdownRemark {
edges {
node {
id
html
rawMarkdownBody
fields {
slug
}
frontmatter {
title
tags
}
}
}

View File

@ -1,5 +1,5 @@
import React from 'react';
import { graphql } from 'gatsby';
import { graphql, Link } from 'gatsby';
import { connect } from 'react-redux';
import { pushNewPage } from '../state/app';
import { capitalize } from '../util';
@ -7,10 +7,8 @@ import config from '../../../config';
import Shell from '../components/Shell';
import Meta from '../components/Meta';
import AniLink from 'gatsby-plugin-transition-link/AniLink';
import SnippetCard from '../components/SnippetCard';
import { getRawCodeBlocks as getCodeBlocks } from '../util';
import SimpleCard from '../components/SimpleCard';
// ===================================================
@ -23,16 +21,7 @@ const ListPage = props => {
v => v.node.frontmatter.title === snippet.title,
).node.html,
tags: snippet.attributes.tags,
text: snippet.attributes.text,
id: snippet.id,
archived: props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.fileAbsolutePath.indexOf(config.snippetArchivePath) !== -1,
code: getCodeBlocks(
props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.rawMarkdownBody,
).code,
}));
const archivedSnippets = props.data.snippetsArchiveDataJson.data.map(snippet => ({
title: snippet.title,
@ -40,16 +29,7 @@ const ListPage = props => {
v => v.node.frontmatter.title === snippet.title,
).node.html,
tags: snippet.attributes.tags,
text: snippet.attributes.text,
id: snippet.id,
archived: props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.fileAbsolutePath.indexOf(config.snippetArchivePath) !== -1,
code: getCodeBlocks(
props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.rawMarkdownBody,
).code,
}));
const tags = snippets.reduce((acc, snippet) => {
if (!snippet.tags) return acc;
@ -91,57 +71,47 @@ const ListPage = props => {
{tags.sort((a,b) => a.localeCompare(b)).map(tag => (
<>
<h3 className='tag-title' key={`tag_title_${tag}`}>
<AniLink
<Link
key={`tag_link_${tag}`}
paintDrip
to={`/tag/${tag}`}
hex={props.isDarkMode ? '#434E76' : '#FFFFFF'}
>
{capitalize(tag)}
</AniLink>
</Link>
</h3>
{snippets
.filter(snippet => !snippet.archived)
.filter(snippet => snippet.tags[0] === tag)
.map(snippet => (
<SnippetCard
key={`snippet_${snippet.id}`}
short
snippetData={snippet}
isDarkMode={props.isDarkMode}
/>
))}
</>
))}
<h3 className='tag-title'><AniLink
paintDrip
<h3 className='tag-title'><Link
to={`/archive`}
hex={props.isDarkMode ? '#434E76' : '#FFFFFF'}
>
Archived snippets
</AniLink></h3>
</Link></h3>
{archivedSnippets
.filter(snippet => snippet.archived)
.map(snippet => (
<SnippetCard
key={`a_snippet_${snippet.id}`}
short
archived
snippetData={snippet}
isDarkMode={props.isDarkMode}
/>
))}
<br/>
{staticPages.map(page => (
<SimpleCard
title={(
<AniLink
paintDrip
<Link
to={`/${page.url}`}
hex={props.isDarkMode ? '#434E76' : '#FFFFFF'}
>
{page.title}
</AniLink>
</Link>
)}
>
<p>{page.description}</p>
@ -170,7 +140,6 @@ export const listPageQuery = graphql`
title
attributes {
tags
text
}
}
}
@ -180,28 +149,16 @@ export const listPageQuery = graphql`
title
attributes {
tags
text
}
}
}
allMarkdownRemark(
limit: 1000
sort: { fields: [frontmatter___title], order: ASC }
) {
totalCount
allMarkdownRemark {
edges {
node {
id
html
rawMarkdownBody
fields {
slug
}
frontmatter {
title
tags
}
fileAbsolutePath
}
}
}

View File

@ -8,8 +8,6 @@ import Meta from '../components/Meta';
import Search from '../components/Search';
import SnippetCard from '../components/SnippetCard';
import { getRawCodeBlocks as getCodeBlocks } from '../util';
// ===================================================
// Search page
// ===================================================
@ -20,13 +18,7 @@ const SearchPage = props => {
v => v.node.frontmatter.title === snippet.title,
).node.html,
tags: snippet.attributes.tags,
text: snippet.attributes.text,
id: snippet.id,
code: getCodeBlocks(
props.data.allMarkdownRemark.edges.find(
v => v.node.frontmatter.title === snippet.title,
).node.rawMarkdownBody,
).code,
}));
const [searchQuery, setSearchQuery] = React.useState(props.searchQuery);
@ -116,26 +108,15 @@ export const searchPageQuery = graphql`
title
attributes {
tags
text
}
}
}
allMarkdownRemark(
limit: 1000
sort: { fields: [frontmatter___title], order: ASC }
) {
totalCount
allMarkdownRemark {
edges {
node {
id
node {
html
rawMarkdownBody
fields {
slug
}
frontmatter {
title
tags
}
}
}

View File

@ -126,7 +126,7 @@
}
// Tags
.tag {
:not(.token).tag {
transition: 0.3s ease all;
border: 2px solid var(--tag-border-color);
border-radius: 0.25rem;
@ -143,8 +143,3 @@
margin-top: 0.375rem;
}
}
// Animation for card example
.roll-up-height {
transition: height 0.3s ease-in-out;
}

View File

@ -28,7 +28,7 @@
font-style: normal;
font-weight: 300;
font-display: swap;
src: local('Noto Sans Light'), local('NotoSans-Light'), url(../../../assets/NotoSans-Light.ttf) format('truetype');
src: local('Noto Sans Light'), local('NotoSans-Light'), url(../../../assets/NotoSans-Light.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -36,7 +36,7 @@
font-style: italic;
font-weight: 300;
font-display: swap;
src: local('Noto Sans LightItalic'), local('NotoSans-LightItalic'), url(../../../assets/NotoSans-LightItalic.ttf) format('truetype');
src: local('Noto Sans LightItalic'), local('NotoSans-LightItalic'), url(../../../assets/NotoSans-LightItalic.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -44,7 +44,7 @@
font-style: normal;
font-weight: 400;
font-display: swap;
src: local('Noto Sans'), local('NotoSans-Regular'), url(../../../assets/NotoSans-Regular.ttf) format('truetype');
src: local('Noto Sans'), local('NotoSans-Regular'), url(../../../assets/NotoSans-Regular.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -52,7 +52,7 @@
font-style: italic;
font-weight: 400;
font-display: swap;
src: local('Noto Sans Italic'), local('NotoSans-Italic'), url(../../../assets/NotoSans-Italic.ttf) format('truetype');
src: local('Noto Sans Italic'), local('NotoSans-Italic'), url(../../../assets/NotoSans-Italic.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -60,7 +60,7 @@
font-style: normal;
font-weight: 500;
font-display: swap;
src: local('Noto Sans Medium'), local('NotoSans-Medium'), url(../../../assets/NotoSans-Medium.ttf) format('truetype');
src: local('Noto Sans Medium'), local('NotoSans-Medium'), url(../../../assets/NotoSans-Medium.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -68,7 +68,7 @@
font-style: italic;
font-weight: 500;
font-display: swap;
src: local('Noto Sans Medium Italic'), local('NotoSans-MediumItalic'), url(../../../assets/NotoSans-MediumItalic.ttf) format('truetype');
src: local('Noto Sans Medium Italic'), local('NotoSans-MediumItalic'), url(../../../assets/NotoSans-MediumItalic.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -76,7 +76,7 @@
font-style: normal;
font-weight: 600;
font-display: swap;
src: local('Noto Sans SemiBold'), local('NotoSans-SemiBold'), url(../../../assets/NotoSans-SemiBold.ttf) format('truetype');
src: local('Noto Sans SemiBold'), local('NotoSans-SemiBold'), url(../../../assets/NotoSans-SemiBold.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}
@font-face {
@ -84,6 +84,6 @@
font-style: italic;
font-weight: 600;
font-display: swap;
src: local('Noto Sans SemiBold Italic'), local('NotoSans-SemiBoldItalic'), url(../../../assets/NotoSans-SemiBoldItalic.ttf) format('truetype');
src: local('Noto Sans SemiBold Italic'), local('NotoSans-SemiBoldItalic'), url(../../../assets/NotoSans-SemiBoldItalic.woff2) format('woff2');
unicode-range: U+0000-00FF, U+0131, U+0152-0153, U+02BB-02BC, U+02C6, U+02DA, U+02DC, U+2000-206F, U+2074, U+20AC, U+2122, U+2191, U+2193, U+2212, U+2215, U+FEFF, U+FFFD;
}

View File

@ -63,23 +63,3 @@
}
}
}
// Animate transition between light and dark mode
.cross-fade-leave {
transform: scale(1);
}
.cross-fade-leave.cross-fade-leave-active {
transition: all 0.3s cubic-bezier(0.47, 0, 0.745, 0.715);
transform: scale(0.1);
}
.cross-fade-enter {
transform: scale(0.1);
}
.cross-fade-enter.cross-fade-enter-active {
transition: all 0.3s cubic-bezier(0.215, 0.610, 0.355, 1);
transform: scale(0.95)
}
.cross-fade-height {
height: 61px;
transition: height 0.15s ease-in-out 0.15s;
}

View File

@ -1,12 +1,11 @@
import React from 'react';
import { graphql } from 'gatsby';
import { graphql, Link } from 'gatsby';
import { connect } from 'react-redux';
import Meta from '../components/Meta';
import Shell from '../components/Shell';
import SnippetCard from '../components/SnippetCard';
import BackArrowIcon from '../components/SVGs/BackArrowIcon';
import AniLink from 'gatsby-plugin-transition-link/AniLink';
// ===================================================
// Individual snippet page template
@ -21,16 +20,13 @@ const SnippetPage = props => {
<>
<Meta title={post.frontmatter.title} description={post.excerpt} />
<Shell>
<AniLink
<Link
className='link-back'
to={`${props.lastPageUrl}`}
cover
direction='right'
bg={props.isDarkMode ? '#434E76' : '#FFFFFF'}
>
<BackArrowIcon />
&nbsp;&nbsp;Back to {props.lastPageTitle}
</AniLink>
</Link>
<SnippetCard
snippetData={{
title: postData.title,

View File

@ -34,7 +34,6 @@ const TagRoute = props => {
snippetData={{
title: node.frontmatter.title,
html: node.html,
code: getCodeBlocks(node.rawMarkdownBody).code,
tags: node.frontmatter.tags.split(',').map(v => v.trim()),
id: node.fields.slug.slice(1),
}}
@ -68,7 +67,6 @@ export const tagPageQuery = graphql`
node {
id
html
rawMarkdownBody
fields {
slug
}

View File

@ -7,19 +7,10 @@ const capitalize = (str, lowerRest = false) =>
// Get the textual content in a gatsby page
const getTextualContent = (str, noExplain = false) => {
const regex = /([\s\S]*?)<div class="gatsby-highlight"/g;
const results = [];
let m = null;
while ((m = regex.exec(str)) !== null) {
if (m.index === regex.lastIndex) regex.lastIndex += 1;
m.forEach((match, groupIndex) => {
results.push(match);
});
}
const result = str.slice(0, str.indexOf('<div class="gatsby-highlight"'));
if (noExplain)
return results[1].slice(0, results[1].lastIndexOf('<p>'));
return results[1];
return result.slice(0, result.lastIndexOf('<p>'));
return result;
};
// Gets the code blocks in a gatsby page