こんな感じで画面サイズを変えたら記事の配置を変えたい
修正前は最新記事が2等分になって表示するようになっている。タブレットサイズ以上はここの右側に新しいおすすめ記事項目を作りたい。
このサイトのテンプレートは gatsby-starter-netlify-cms でcssのフレームワークにBulmaが使われている。
Bulmaの勉強も兼ねてデザインを整えていく
react-responsiveというパッケージを入れる
yarn add react-responsive
const isMobile = useMediaQuery({query: "(min-device-width: 350px)",})
こんな感じで場合分けできるようになる
import React, { useState, useEffect } from "react";
import PropTypes from "prop-types";
import { Link, graphql } from "gatsby";
import { getImage } from "gatsby-plugin-image";
import Layout from "../components/Layout";
import FullWidthImage from "../components/FullWidthImage";
import Seo from "../components/Seo";
import BlogRoll from "../components/BlogRoll";
import useSiteMetadata from "../components/SiteMetadata";
import Products from "../components/products/Products"
// eslint-disable-next-line
export const IndexPageTemplate = ({
image,
title,
heading,
subheading,
mainpitch,
description,
intro,
blogs,
location,
}) => {
const heroImage = getImage(image) || image;
const { siteUrl } = useSiteMetadata();
const [innerWidth, setInnerWidth] = useState('')
useEffect(() => {
setInnerWidth(window.innerWidth)
}, [])
return (
<div>
<Seo
url={`${siteUrl}${location.pathname}`}
title={title}
/>
<FullWidthImage img={heroImage} title={title} subheading={subheading} />
<section className={`section section--gradient`}>
<div className="container">
<div className={innerWidth > 820 ? `section` : ``}>
<div className="columns">
<div className="column is-10 is-offset-1">
<div className="content">
<div className="column is-12">
<h3 className="has-text-weight-semibold is-size-2" style={innerWidth > 820 ? {} : {paddingTop: 32}}>
{heading}
</h3>
<p>{description}</p>
</div>
<div className="column is-12 has-text-centered">
<Products />
<Link className="btn" to="/products">
See all products
</Link>
</div>
<hr style={{margin: 64}}/>
<div className="column is-12">
<h3 className="has-text-weight-semibold is-size-2">
最新記事
</h3>
<p style={{marginBottom: "1.4rem",}}>....................................</p>
<BlogRoll blogs={blogs}/>
<div className="column is-12 has-text-centered">
<Link className="btn" to="/blog">
Read more
</Link>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
};
IndexPageTemplate.propTypes = {
image: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
title: PropTypes.string,
heading: PropTypes.string,
subheading: PropTypes.string,
mainpitch: PropTypes.object,
description: PropTypes.string,
intro: PropTypes.shape({
blurbs: PropTypes.array,
}),
blogs: PropTypes.array,
};
const IndexPage = ({ data, location }) => {
const { frontmatter } = data.markdownRemark;
const blogs = data.blogs.edges;
return (
<Layout>
<IndexPageTemplate
image={frontmatter.image}
title={frontmatter.title}
heading={frontmatter.heading}
subheading={frontmatter.subheading}
mainpitch={frontmatter.mainpitch}
description={frontmatter.description}
intro={frontmatter.intro}
blogs={blogs}
location={location}
/>
</Layout>
);
};
IndexPage.propTypes = {
data: PropTypes.shape({
markdownRemark: PropTypes.shape({
frontmatter: PropTypes.object,
}),
blogs: PropTypes.shape({
edges: PropTypes.array,
}),
}),
};
export default IndexPage;
export const pageQuery = graphql`
query IndexPageTemplate {
markdownRemark(frontmatter: { templateKey: { eq: "index-page" } }) {
frontmatter {
title
image {
childImageSharp {
gatsbyImageData(quality: 100, layout: FULL_WIDTH)
}
}
heading
subheading
mainpitch {
title
description
}
description
intro {
blurbs {
image {
childImageSharp {
gatsbyImageData(width: 240, quality: 64, layout: CONSTRAINED)
}
}
text
}
}
}
}
blogs: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
filter: { frontmatter: { templateKey: { eq: "blog-post" } } }
limit: 4
) {
edges {
node {
excerpt(pruneLength: 200)
id
fields {
slug
}
frontmatter {
title
templateKey
date(formatString: "MMMM DD, YYYY")
featuredpost
featuredimage {
childImageSharp {
gatsbyImageData(
width: 120
quality: 100
layout: CONSTRAINED
)
}
}
}
}
}
}
}
`
useState、useEffectをやめた。
おすすめ記事をgraphqlでrecommendという名前で取得するようにした。
列で分けたいセクションは
<div className="column is-12-mobile is-12-tablet is-9-desktop is-9-widescreen">
のようにclassをつける
BlogRollコンポーネントの引数にroleを持たせて場合分けする
import React from "react";
import PropTypes from "prop-types";
import { Link, graphql } from "gatsby";
import { getImage } from "gatsby-plugin-image";
import Layout from "../components/Layout";
import FullWidthImage from "../components/FullWidthImage";
import Seo from "../components/Seo";
import BlogRoll from "../components/BlogRoll";
import useSiteMetadata from "../components/SiteMetadata";
import Products from "../components/products/Products"
// eslint-disable-next-line
export const IndexPageTemplate = ({
image,
title,
heading,
subheading,
mainpitch,
description,
intro,
blogs,
location,
recommend,
}) => {
const heroImage = getImage(image) || image;
const { siteUrl } = useSiteMetadata();
return (
<div>
<Seo
url={`${siteUrl}${location.pathname}`}
title={title}
/>
<FullWidthImage img={heroImage} title={title} subheading={subheading} />
<section className={`section section--gradient`}>
<div className="container">
<div className="columns is-multiline">
<div className="column is-12-mobile is-12-tablet is-9-desktop is-9-widescreen">
<div className="content">
<div className="column is-12">
<h3 className="has-text-weight-semibold is-size-2">
{heading}
</h3>
<p>{description}</p>
</div>
<div className="column is-12 has-text-centered">
<Products />
<Link className="btn" to="/products">
See all products
</Link>
</div>
<hr style={{margin: 64}}/>
<div className="column is-12">
<h3 className="has-text-weight-semibold is-size-2">
最新記事
</h3>
<p style={{marginBottom: "1.4rem",}}>....................................</p>
<BlogRoll blogs={blogs} role={"main"}/>
<div className="column is-12 has-text-centered">
<Link className="btn" to="/blog">
Read more
</Link>
</div>
</div>
</div>
</div>
<div className="column is-12-mobile is-12-tablet is-3-desktop is-3-widescreen">
<div className="content">
<div className="column is-12">
<h3 className="has-text-weight-semibold is-size-10">
おすすめ記事
</h3>
<p style={{marginBottom: "1.4rem",}}>....................................</p>
<BlogRoll blogs={recommend} role={"sub"}/>
</div>
</div>
</div>
</div>
</div>
</section>
</div>
);
};
IndexPageTemplate.propTypes = {
image: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
title: PropTypes.string,
heading: PropTypes.string,
subheading: PropTypes.string,
mainpitch: PropTypes.object,
description: PropTypes.string,
intro: PropTypes.shape({
blurbs: PropTypes.array,
}),
blogs: PropTypes.array,
recommend: PropTypes.array,
};
const IndexPage = ({ data, location }) => {
const { frontmatter } = data.markdownRemark;
const blogs = data.blogs.edges;
const recommend = data.recommend.edges;
return (
<Layout>
<IndexPageTemplate
image={frontmatter.image}
title={frontmatter.title}
heading={frontmatter.heading}
subheading={frontmatter.subheading}
mainpitch={frontmatter.mainpitch}
description={frontmatter.description}
intro={frontmatter.intro}
blogs={blogs}
location={location}
recommend={recommend}
/>
</Layout>
);
};
IndexPage.propTypes = {
data: PropTypes.shape({
markdownRemark: PropTypes.shape({
frontmatter: PropTypes.object,
}),
blogs: PropTypes.shape({
edges: PropTypes.array,
}),
recommend: PropTypes.shape({
edges: PropTypes.array,
}),
}),
};
export default IndexPage;
export const pageQuery = graphql`
query IndexPageTemplate {
markdownRemark(frontmatter: { templateKey: { eq: "index-page" } }) {
frontmatter {
title
image {
childImageSharp {
gatsbyImageData(quality: 100, layout: FULL_WIDTH)
}
}
heading
subheading
mainpitch {
title
description
}
description
intro {
blurbs {
image {
childImageSharp {
gatsbyImageData(width: 240, quality: 64, layout: CONSTRAINED)
}
}
text
}
}
}
}
blogs: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
filter: { frontmatter: { templateKey: { eq: "blog-post" } } }
limit: 4
) {
edges {
node {
excerpt(pruneLength: 200)
id
fields {
slug
}
frontmatter {
title
templateKey
date(formatString: "MMMM DD, YYYY")
featuredpost
featuredimage {
childImageSharp {
gatsbyImageData(
width: 120
quality: 100
layout: CONSTRAINED
)
}
}
}
}
}
}
recommend: allMarkdownRemark(
sort: { order: DESC, fields: [frontmatter___date] }
filter: { frontmatter: { templateKey: { eq: "blog-post" }, featuredpost: { eq: true } } }
limit: 3
) {
edges {
node {
excerpt(pruneLength: 200)
id
fields {
slug
}
frontmatter {
title
templateKey
date(formatString: "MMMM DD, YYYY")
featuredpost
featuredimage {
childImageSharp {
gatsbyImageData(
width: 120
quality: 100
layout: CONSTRAINED
)
}
}
}
}
}
}
}
`
react-responsiveを新たにインポート
引数のroleとisLaptopで場合分けさせた
import React from 'react'
import { Link } from 'gatsby'
import PreviewCompatibleImage from './PreviewCompatibleImage'
import { useMediaQuery } from 'react-responsive'
const btnStyles = {
border: "none",
backgroundColor: "rgba(0,0,0,0)",
color: "#aaa",
fontSize: "0.9em",
}
export const BlogRoll = ({ blogs, role }) => {
// const isMobile = useMediaQuery({query: "(min-width: 350px)",})
// const isTablet = useMediaQuery({query: "(min-width: 769px)",})
const isLaptop = useMediaQuery({query: "(min-width: 1024px)",})
// const isDesktop = useMediaQuery({query: "(min-width: 1216px)",})
// const isBigScreen = useMediaQuery({query: "(min-width: 1408px )",})
// ラップトップ未満の場合はメイン記事と同じように表示させる
if (role === "sub") role = !isLaptop ? "main" : "sub"
const classRow = role === "sub" ? "is-parent column is-12" : "is-parent column is-6"
const classTitle = role === "sub" ? "title has-text-primary is-size-12" : "title has-text-primary is-size-4"
return (
<div className="columns is-multiline">
{blogs &&
blogs.map(({ node: post }) => (
<div className={classRow} key={post.id}>
<Link to={post.fields.slug}>
{isLaptop && role === "sub" ?
<article className={`blog-list-item tile is-child box notification`}>
<div>{post.frontmatter.title}<div style={btnStyles}>続きを読む →</div></div>
</article>
:
<article
className={`blog-list-item tile is-child box notification ${
post.frontmatter.featuredpost ? 'is-featured' : ''
}`}
>
<header>
{post.frontmatter.featuredimage ? (
<div className="featured-thumbnail">
<PreviewCompatibleImage
imageInfo={{
image: post.frontmatter.featuredimage,
alt: `featured image thumbnail for post ${post.frontmatter.title}`,
width:
post.frontmatter.featuredimage.childImageSharp
.gatsbyImageData.width,
height:
post.frontmatter.featuredimage.childImageSharp
.gatsbyImageData.height,
}}
/>
</div>
) : null}
<div className="post-meta">
<div className={classTitle}>
{post.frontmatter.title}
</div>
{/* <span> • </span> */}
<span className="subtitle is-size-5 is-block">
{post.frontmatter.date}
</span>
</div>
</header>
<div>
{post.excerpt}
<br />
<br />
<div style={btnStyles}>
続きを読む →
</div>
</div>
</article>
}
</Link>
</div>
))}
</div>
)
}
export default BlogRoll
yarn start
でプログラムを立ち上げて見ないと反映されなかった