mirror of
https://github.com/kremalicious/blog.git
synced 2025-01-05 19:25:40 +01:00
changes
This commit is contained in:
parent
96f43a4fb0
commit
71feac2ea8
@ -19,7 +19,7 @@ module.exports = {
|
|||||||
rss: '/feed.xml',
|
rss: '/feed.xml',
|
||||||
jsonfeed: '/feed.json',
|
jsonfeed: '/feed.json',
|
||||||
typekitID: 'msu4qap',
|
typekitID: 'msu4qap',
|
||||||
itemsPerPage: 18,
|
itemsPerPage: 25,
|
||||||
repoContentPath: 'https://github.com/kremalicious/blog/tree/main/content',
|
repoContentPath: 'https://github.com/kremalicious/blog/tree/main/content',
|
||||||
menu: [
|
menu: [
|
||||||
{
|
{
|
||||||
|
@ -4,9 +4,8 @@
|
|||||||
.title {
|
.title {
|
||||||
padding-left: 0.2rem;
|
padding-left: 0.2rem;
|
||||||
padding-right: 0.2rem;
|
padding-right: 0.2rem;
|
||||||
color: $brand-grey-light;
|
|
||||||
margin-top: $spacer / 2;
|
margin-top: $spacer / 2;
|
||||||
margin-bottom: 0;
|
margin-bottom: $spacer / 6;
|
||||||
font-size: $font-size-base;
|
font-size: $font-size-base;
|
||||||
transition: color 0.2s ease-out;
|
transition: color 0.2s ease-out;
|
||||||
}
|
}
|
||||||
@ -19,18 +18,20 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.time {
|
||||||
|
font-style: italic;
|
||||||
|
font-size: $font-size-small;
|
||||||
|
color: $text-color-light;
|
||||||
|
}
|
||||||
|
|
||||||
.empty {
|
.empty {
|
||||||
@include media-frame;
|
@include media-frame;
|
||||||
|
|
||||||
height: 100%;
|
display: block;
|
||||||
min-height: 80px;
|
min-height: 95px;
|
||||||
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACaADAAQAAAABAAAACQAAAAAvQpmhAAAAHElEQVQYGWNgoBL4T8gcggoIGcBA0ASCCmhsBQBhFwX7u70C8QAAAABJRU5ErkJggg==);
|
background: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAkAAAAJCAYAAADgkQYQAAAAAXNSR0IArs4c6QAAAERlWElmTU0AKgAAAAgAAYdpAAQAAAABAAAAGgAAAAAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAACaADAAQAAAABAAAACQAAAAAvQpmhAAAAHElEQVQYGWNgoBL4T8gcggoIGcBA0ASCCmhsBQBhFwX7u70C8QAAAABJRU5ErkJggg==);
|
||||||
|
|
||||||
a:hover & {
|
a:hover & {
|
||||||
border-color: $link-color;
|
border-color: $link-color;
|
||||||
}
|
}
|
||||||
|
|
||||||
@media (min-width: $screen-md) {
|
|
||||||
min-height: 110px;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
@ -4,6 +4,7 @@ import { Image } from '../atoms/Image'
|
|||||||
import { Post } from '../../@types/Post'
|
import { Post } from '../../@types/Post'
|
||||||
import PostTitle from '../templates/Post/Title'
|
import PostTitle from '../templates/Post/Title'
|
||||||
import styles from './PostTeaser.module.scss'
|
import styles from './PostTeaser.module.scss'
|
||||||
|
import Time from '../atoms/Time'
|
||||||
|
|
||||||
export const postTeaserQuery = graphql`
|
export const postTeaserQuery = graphql`
|
||||||
fragment PostTeaser on MarkdownRemark {
|
fragment PostTeaser on MarkdownRemark {
|
||||||
@ -13,6 +14,7 @@ export const postTeaserQuery = graphql`
|
|||||||
type
|
type
|
||||||
title
|
title
|
||||||
linkurl
|
linkurl
|
||||||
|
updated
|
||||||
image {
|
image {
|
||||||
childImageSharp {
|
childImageSharp {
|
||||||
...ImageFluidThumb
|
...ImageFluidThumb
|
||||||
@ -22,6 +24,7 @@ export const postTeaserQuery = graphql`
|
|||||||
}
|
}
|
||||||
fields {
|
fields {
|
||||||
slug
|
slug
|
||||||
|
date
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
`
|
`
|
||||||
@ -33,8 +36,8 @@ export default function PostTeaser({
|
|||||||
post: Partial<Post>
|
post: Partial<Post>
|
||||||
toggleSearch?: () => void
|
toggleSearch?: () => void
|
||||||
}): ReactElement {
|
}): ReactElement {
|
||||||
const { image, title, type } = post.frontmatter
|
const { image, title, type, updated } = post.frontmatter
|
||||||
const { slug } = post.fields
|
const { slug, date } = post.fields
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<Link
|
<Link
|
||||||
@ -42,16 +45,23 @@ export default function PostTeaser({
|
|||||||
to={slug}
|
to={slug}
|
||||||
onClick={toggleSearch && toggleSearch}
|
onClick={toggleSearch && toggleSearch}
|
||||||
>
|
>
|
||||||
{image && (
|
{image ? (
|
||||||
<Image
|
<Image
|
||||||
title={type === 'photo' ? title : null}
|
title={type === 'photo' ? title : null}
|
||||||
fluid={image.childImageSharp.fluid}
|
fluid={image.childImageSharp.fluid}
|
||||||
alt={title}
|
alt={title}
|
||||||
original={image.childImageSharp.original}
|
original={image.childImageSharp.original}
|
||||||
/>
|
/>
|
||||||
|
) : (
|
||||||
|
<span className={styles.empty} />
|
||||||
)}
|
)}
|
||||||
|
|
||||||
<PostTitle slug={slug} title={title} className={styles.title} />
|
<PostTitle slug={slug} title={title} className={styles.title} />
|
||||||
|
{date && (
|
||||||
|
<div className={styles.time}>
|
||||||
|
<Time date={date} />
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</Link>
|
</Link>
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
@ -11,3 +11,7 @@
|
|||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.posts h1 {
|
||||||
|
font-size: $font-size-h3;
|
||||||
|
}
|
||||||
|
39
src/components/templates/Posts.module.scss
Normal file
39
src/components/templates/Posts.module.scss
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
@import 'variables';
|
||||||
|
@import 'mixins';
|
||||||
|
|
||||||
|
.hentry {
|
||||||
|
@include divider;
|
||||||
|
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-top: $spacer * 2;
|
||||||
|
padding-bottom: $spacer * 2;
|
||||||
|
|
||||||
|
:global(.gatsby-image-wrapper) {
|
||||||
|
max-height: 100vh;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (min-width: $screen-md) {
|
||||||
|
padding-top: $spacer * 4;
|
||||||
|
padding-bottom: $spacer * 4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.archivetitle {
|
||||||
|
@include divider;
|
||||||
|
|
||||||
|
font-size: $font-size-h3;
|
||||||
|
margin-top: 0;
|
||||||
|
margin-bottom: 0;
|
||||||
|
padding-bottom: $spacer * $line-height;
|
||||||
|
|
||||||
|
span {
|
||||||
|
color: $brand-grey-light;
|
||||||
|
padding-right: $spacer / 12;
|
||||||
|
font-size: $font-size-base;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
.paginationTitle {
|
||||||
|
composes: archivetitle;
|
||||||
|
}
|
28
src/components/templates/Posts.test.tsx
Normal file
28
src/components/templates/Posts.test.tsx
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import React from 'react'
|
||||||
|
import { render } from '@testing-library/react'
|
||||||
|
import { createHistory, createMemorySource } from '@reach/router'
|
||||||
|
|
||||||
|
import Posts from './Posts'
|
||||||
|
import data from '../../../jest/__fixtures__/posts.json'
|
||||||
|
|
||||||
|
describe('Post', () => {
|
||||||
|
const history = createHistory(createMemorySource('/photos'))
|
||||||
|
|
||||||
|
const pageContext = {
|
||||||
|
tag: 'hello',
|
||||||
|
slug: '/hello',
|
||||||
|
currentPageNumber: 2,
|
||||||
|
numPages: 20
|
||||||
|
}
|
||||||
|
|
||||||
|
it('renders without crashing', () => {
|
||||||
|
const { container } = render(
|
||||||
|
<Posts
|
||||||
|
data={data}
|
||||||
|
pageContext={pageContext}
|
||||||
|
location={history.location}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
expect(container.firstChild).toBeInTheDocument()
|
||||||
|
})
|
||||||
|
})
|
123
src/components/templates/Posts.tsx
Normal file
123
src/components/templates/Posts.tsx
Normal file
@ -0,0 +1,123 @@
|
|||||||
|
import React, { ReactElement } from 'react'
|
||||||
|
import { Link, graphql } from 'gatsby'
|
||||||
|
import { Post } from '../../@types/Post'
|
||||||
|
import Pagination from '../molecules/Pagination'
|
||||||
|
import Featured from '../molecules/Featured'
|
||||||
|
import PostTitle from './Post/Title'
|
||||||
|
import PostLead from './Post/Lead'
|
||||||
|
import PostContent from './Post/Content'
|
||||||
|
import PostMore from './Post/More'
|
||||||
|
import PostLinkActions from './Post/LinkActions'
|
||||||
|
import SEO from '../atoms/SEO'
|
||||||
|
import styles from './Posts.module.scss'
|
||||||
|
import { Image } from '../atoms/Image'
|
||||||
|
|
||||||
|
export default function Posts({
|
||||||
|
data,
|
||||||
|
location,
|
||||||
|
pageContext
|
||||||
|
}: {
|
||||||
|
data: any
|
||||||
|
location: Location
|
||||||
|
pageContext: {
|
||||||
|
tag: string
|
||||||
|
slug: string
|
||||||
|
currentPageNumber: number
|
||||||
|
numPages: number
|
||||||
|
}
|
||||||
|
}): ReactElement {
|
||||||
|
const edges = data.allMarkdownRemark.edges
|
||||||
|
const { tag, currentPageNumber, numPages } = pageContext
|
||||||
|
|
||||||
|
const PostsList = edges.map(({ node }: { node: Post }) => {
|
||||||
|
const { type, linkurl, title, image } = node.frontmatter
|
||||||
|
const { slug } = node.fields
|
||||||
|
|
||||||
|
return (
|
||||||
|
<article className={styles.hentry} key={node.id}>
|
||||||
|
{type !== 'photo' && (
|
||||||
|
<PostTitle type={type} slug={slug} linkurl={linkurl} title={title} />
|
||||||
|
)}
|
||||||
|
|
||||||
|
{image && (
|
||||||
|
<Link to={slug} title={title}>
|
||||||
|
<Image
|
||||||
|
title={type === 'photo' ? title : null}
|
||||||
|
fluid={image.childImageSharp.fluid}
|
||||||
|
alt={title}
|
||||||
|
original={image.childImageSharp.original}
|
||||||
|
/>
|
||||||
|
</Link>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{type === 'post' && (
|
||||||
|
<>
|
||||||
|
<PostLead post={node} index />
|
||||||
|
<PostMore to={slug}>Continue Reading</PostMore>
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
|
||||||
|
{type === 'link' && (
|
||||||
|
<>
|
||||||
|
<PostContent post={node} />
|
||||||
|
<PostLinkActions slug={slug} linkurl={linkurl} />
|
||||||
|
</>
|
||||||
|
)}
|
||||||
|
</article>
|
||||||
|
)
|
||||||
|
})
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<SEO />
|
||||||
|
{location.pathname === '/' && <Featured />}
|
||||||
|
{tag && (
|
||||||
|
<h1 className={styles.archivetitle}>
|
||||||
|
<span>#</span>
|
||||||
|
{tag}
|
||||||
|
</h1>
|
||||||
|
)}
|
||||||
|
{numPages > 1 && currentPageNumber > 1 && (
|
||||||
|
<h2
|
||||||
|
className={styles.paginationTitle}
|
||||||
|
>{`Page ${currentPageNumber} / ${numPages}`}</h2>
|
||||||
|
)}
|
||||||
|
{PostsList}
|
||||||
|
{numPages > 1 && <Pagination pageContext={pageContext} />}
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export const postsQuery = graphql`
|
||||||
|
query($tag: String, $skip: Int, $limit: Int) {
|
||||||
|
allMarkdownRemark(
|
||||||
|
filter: { frontmatter: { tags: { eq: $tag } } }
|
||||||
|
sort: { order: DESC, fields: [fields___date] }
|
||||||
|
skip: $skip
|
||||||
|
limit: $limit
|
||||||
|
) {
|
||||||
|
edges {
|
||||||
|
node {
|
||||||
|
id
|
||||||
|
html
|
||||||
|
excerpt(pruneLength: 250)
|
||||||
|
frontmatter {
|
||||||
|
title
|
||||||
|
type
|
||||||
|
linkurl
|
||||||
|
image {
|
||||||
|
childImageSharp {
|
||||||
|
...ImageFluid
|
||||||
|
}
|
||||||
|
}
|
||||||
|
tags
|
||||||
|
}
|
||||||
|
fields {
|
||||||
|
slug
|
||||||
|
date(formatString: "MMMM DD, YYYY")
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
@ -24,11 +24,25 @@
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.articles:first-of-type h1 {
|
||||||
|
font-size: $font-size-h3;
|
||||||
|
}
|
||||||
|
|
||||||
|
.articlesLast {
|
||||||
|
margin-top: $spacer * 1.5;
|
||||||
|
|
||||||
|
@media (min-width: $screen-sm) {
|
||||||
|
gap: $spacer * 1.5;
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
.photos {
|
.photos {
|
||||||
grid-template-columns: repeat(2, 1fr);
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
|
||||||
@media (min-width: $screen-sm) {
|
@media (min-width: $screen-sm) {
|
||||||
grid-template-columns: repeat(auto-fill, minmax(140px, 1fr));
|
gap: $spacer * 1.5;
|
||||||
|
grid-template-columns: repeat(auto-fill, minmax(160px, 1fr));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,26 +1,34 @@
|
|||||||
import React, { ReactElement } from 'react'
|
|
||||||
import { graphql, PageProps } from 'gatsby'
|
import { graphql, PageProps } from 'gatsby'
|
||||||
|
import React, { ReactElement } from 'react'
|
||||||
import { Post } from '../@types/Post'
|
import { Post } from '../@types/Post'
|
||||||
import styles from './index.module.scss'
|
import SEO from '../components/atoms/SEO'
|
||||||
import Featured from '../components/molecules/Featured'
|
|
||||||
import { PhotoThumb } from '../components/templates/Photos'
|
|
||||||
import PostTeaser from '../components/molecules/PostTeaser'
|
import PostTeaser from '../components/molecules/PostTeaser'
|
||||||
|
import { PhotoThumb } from '../components/templates/Photos'
|
||||||
import PostMore from '../components/templates/Post/More'
|
import PostMore from '../components/templates/Post/More'
|
||||||
|
import styles from './index.module.scss'
|
||||||
|
|
||||||
export default function Home(props: PageProps): ReactElement {
|
export default function Home(props: PageProps): ReactElement {
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
|
<SEO />
|
||||||
<section className={styles.section}>
|
<section className={styles.section}>
|
||||||
<h2 className={styles.title}>
|
<h2 className={styles.title}>
|
||||||
Latest Articles <PostMore to="/archive">All Articles</PostMore>
|
Latest Articles <PostMore to="/archive">All Articles</PostMore>
|
||||||
</h2>
|
</h2>
|
||||||
|
|
||||||
<div className={styles.articles}>
|
<div className={styles.articles}>
|
||||||
{(props.data as any).latestArticles.edges.map(
|
{(props.data as any).latestArticles.edges
|
||||||
({ node }: { node: Post }) => (
|
.slice(0, 2)
|
||||||
|
.map(({ node }: { node: Post }) => (
|
||||||
<PostTeaser key={node.id} post={node} />
|
<PostTeaser key={node.id} post={node} />
|
||||||
)
|
))}
|
||||||
)}
|
</div>
|
||||||
|
<div className={`${styles.articles} ${styles.articlesLast}`}>
|
||||||
|
{(props.data as any).latestArticles.edges
|
||||||
|
.slice(2, 8)
|
||||||
|
.map(({ node }: { node: Post }) => (
|
||||||
|
<PostTeaser key={node.id} post={node} />
|
||||||
|
))}
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
|
|
||||||
@ -46,7 +54,7 @@ export const homeQuery = graphql`
|
|||||||
latestArticles: allMarkdownRemark(
|
latestArticles: allMarkdownRemark(
|
||||||
filter: { frontmatter: { type: { ne: "photo" } } }
|
filter: { frontmatter: { type: { ne: "photo" } } }
|
||||||
sort: { order: DESC, fields: [fields___date] }
|
sort: { order: DESC, fields: [fields___date] }
|
||||||
limit: 6
|
limit: 8
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
@ -58,7 +66,7 @@ export const homeQuery = graphql`
|
|||||||
latestPhotos: allMarkdownRemark(
|
latestPhotos: allMarkdownRemark(
|
||||||
filter: { frontmatter: { type: { eq: "photo" } } }
|
filter: { frontmatter: { type: { eq: "photo" } } }
|
||||||
sort: { order: DESC, fields: [fields___date] }
|
sort: { order: DESC, fields: [fields___date] }
|
||||||
limit: 15
|
limit: 12
|
||||||
) {
|
) {
|
||||||
edges {
|
edges {
|
||||||
node {
|
node {
|
||||||
|
Loading…
Reference in New Issue
Block a user