文章目錄
- Gatsby初試啼聲
- 利用react-bootstrap打造React風格頁面
- 了解Gatsby中GraphQL如何運作
- Gatsby GraphQL讀取JSON
- 在Gatsby GraphQL中組合出完美資料
- Gatsby程序化產生頁面
- 上線個人頁面到Netlify+啟動Netlify CMS
在上一篇文章裡面我們已經利用模板將一個簡單的網站架起來了,現在我們來進行首頁的修改。
src/pages/index.js
import React from "react"
import { Link } from "gatsby"
import Layout from "../components/layout"
import SEO from "../components/seo"
import Button from "../components/button"
class IndexPage extends React.Component {
render() {
const siteTitle = "Gatsby Starter Personal Website"
return (
<Layout location={this.props.location} title={siteTitle}>
<SEO
title="Home"
keywords={[`blog`, `gatsby`, `javascript`, `react`]}
/>
...
</Layout>
)
}
}
export default IndexPage
在模板提供的首頁裡,已經有一個Layout
的Component,我們可以利用這個已經完成的Component來省下一些工作,對他進行修改就可以重複使用。
導入bootstrap
因為是使用React,所以我在這裡選擇使用react-bootstrap
這個套件庫,來更符合React Component的特色,但是要直接使用Bootstrap
也是沒有問題的。
首先安裝react-bootstrap
。
npm install --save react-bootstrap bootstrap
在src/pages/index.js
中匯入bootstrap css。
import 'bootstrap/dist/css/bootstrap.min.css';
接著在src/components/layout
匯入會之後使用到的Component。
import Container from 'react-bootstrap/Container';
import Navbar from 'react-bootstrap/Navbar';
import Nav from 'react-bootstrap/Nav';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
class layout extends React.Component {
render() {
...
}
}
先把Bootstrap的container
做出來,並在裡面加入Navbar
。
class layout extends React.Component {
render() {
const { children, title } = this.props;
return (
<Container>
<Navbar>
<Navbar.Brand as={Link} to="/">Herbert Lin</Navbar.Brand>
<Nav className="ml-auto">
<Nav.Item>
<Nav.Link as={Link} to="/work">Work</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={Link} to="/blog">Blog</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={Link} to="/about">About</Nav.Link>
</Nav.Item>
</Nav>
</Navbar>
{children}
</Container>
);
}
}
除此之外,我也沿用了原本Layout裡面有的屬性title
以及children
,children
是為什麼Layout可以被重複利用的原因,只要是在Layout底下傳入的JSX就可以以children
的形式插入。
在上一篇文章提到過,網站內部連結可以利用Gatsby Link
套件,所以這裡把Link
傳到Navbar.Brand
與Nav.Link
中,讓他們做使用。
接下來製作footer。因應後續footer想要全版的樣式,所以我把他做到另外一個container
裡面。
class layout extends React.Component {
render() {
const { children, title } = this.props;
return (
<Container>
...
</Container>
<Container>
<Row>
<Col md={8}>
<h3>Herbert Lin</h3>
<a href="mailto:herbert.lin.7@gmail.com">herbert.lin.7@gmail.com</a>
</Col>
<Col md={4}>
// 這裡做 social media
</Col>
</Row>
</Container>
);
}
}
這裡會發現React報錯,因為render
只能return一個根元素,所以這裡使用React.Fragment
把他包裝成一個單一元素。
class layout extends React.Component {
render() {
const { children, title } = this.props;
return (
<React.Fragment>
<Container>
...
</Container>
<Container>
...
</Container>
</React.Fragment>
);
}
}
製作social media
在繼續之前,為了製作social media部份,要先裝react-fontawesome
,這樣才能夠使用各種social media的圖示。
$ npm i --save @fortawesome/fontawesome-svg-core @fortawesome/free-brands-svg-icons @fortawesome/react-fontawesome
並且在檔案中匯入font-awesome。
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { library } from '@fortawesome/fontawesome-svg-core';
import { fab } from '@fortawesome/free-brands-svg-icons';
class layout extends React.Component {
render() {
library.add(fab);
...
}
}
接下來加入一些個人的social media。
class layout extends React.Component {
render() {
return (
<React.Fragment>
<Container>
...
</Container>
<Container className="pt-6">
<Row>
...
<Col md={4} className="d-flex align-items-center justify-content-end">
<div className="social-media">
<ul>
<li>
<a href="https://github.com/XcrossD">
<FontAwesomeIcon icon={['fab', 'github']} />
</a>
</li>
<li>
<a href="https://www.facebook.com/herbert.lin">
<FontAwesomeIcon icon={['fab', 'facebook']} />
</a>
</li>
<li>
<a href="https://www.instagram.com/gummypearin/">
<FontAwesomeIcon icon={['fab', 'instagram']} />
</a>
</li>
<li>
<a href="https://www.linkedin.com/in/herbert-lin-28240446/">
<FontAwesomeIcon icon={['fab', 'linkedin']} />
</a>
</li>
</ul>
</div>
</Col>
</Row>
</Container>
</React.Fragment>
);
}
}
做到目前為止的成果如下:
調整樣式
做到這個階段Layout基本的架構有了,但是還需要調整樣式。
在第一篇文章中我說我不喜歡自帶的typographyjs
,所以我會把他卸除。有興趣的朋友可以自行前往typographyjs官網研究這個套件是否符合需求。
在這個專案裡面如果可以透過加上className
的方式利用bootstrap
調整,我會優先採用這種方式,因為只要在加上className
屬性即可。其他的部份我會使用styled components
來調整樣式,但是一樣如果有偏好的styling可以自行使用。可以參考Gatsby styling文檔設定其他系統。
卸除typographyjs與其週邊套件
npm uninstall --save gatsby-plugin-typography react-typography typeface-merriweather typeface-montserrat typography typography-theme-wordpress-2016
gatsby-config.js
// 刪除以下內容
{
resolve: `gatsby-plugin-typography`,
options: {
pathToConfigModule: `src/utils/typography`,
},
},
gatsby-browser.js
// 刪除以下內容
import "typeface-montserrat"
import "typeface-merriweather"
刪除 src/utils
資料夾(裡面包含typography.js)
// 修改有匯入src/utils/typography的檔案
// 有以下檔案
// 現在先隨便修改,後面會再把這些檔案修改完成
src/components/layout.js
src/components/bio.js
src/pages/blog.js
src/templates/blog-post.js
src/components/bio.js
...
style={{
marginRight: `20px`,
marginBottom: 0,
minWidth: 50,
borderRadius: `100%`,
}}
...
src/pages/blog.js
...
<h3
style={{
marginBottom: `10px`,
}}
>
...
src/templates/blog-post.js
...
<h1>{post.frontmatter.title}</h1>
<p
style={{
display: `block`,
marginBottom: `40px`,
marginTop: `-40px`,
}}
>
{post.frontmatter.date}
</p>
<MDXRenderer>{post.body}</MDXRenderer>
<hr
style={{
marginBottom: `40px`,
}}
/>
...
重新執行gatsby develop
,更新設定。
加上樣式
使用
styled components
之前需要匯入
import styled from "styled-components";
但是原本在模板裡已經匯入過所以這只是提醒
src/components/layout.js
先調整Navbar
的部份。
class layout extends React.Component {
render() {
return (
<React.Fragment>
<Container>
<Navbar className="mb-3 pl-0">
<Navbar.Brand as={Link} to="/">Herbert Lin</Navbar.Brand>
<Nav className="ml-auto">
<Nav.Item>
<Nav.Link as={Link} to="/work">Work</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={Link} to="/blog">Blog</Nav.Link>
</Nav.Item>
<Nav.Item>
<Nav.Link as={Link} to="/about">About</Nav.Link>
</Nav.Item>
</Nav>
</Navbar>
{children}
</Container>
<Container>
...
</Container>
</React.Fragment>
);
}
}
只有加上了一些bootstrap className
。bootstrap文檔
再來調整footer的部份。
const FooterWrapper = styled.footer`
background-color: #171717;
color: #f1f1f1;
margin-top: 100px;
padding: 50px 0;
`;
const EmailLink = styled.a`
text-decoration: none;
background-color: transparent;
color: #f1f1f1;
&:hover, &:visited, &:active {
color: #f1f1f1;
}
`;
const SocialMedia = styled.div`
display: flex;
flex-direction: row;
flex-wrap: nowrap;
align-items: flex-end;
align-content: stretch;
text-align: right;
`;
const SocialMediaUl = styled.ul`
list-style: none;
display: inline-block;
margin: 0;
padding: 0;
`;
const SocialMediaLi = styled.li`
display: inline-block;
margin: 0 18px 0 18px;
padding: 0;
`;
const SocialMediaLink = styled.a`
text-decoration: none;
background-color: transparent;
color: #f1f1f1;
&:hover, &:visited, &:active {
color: #f1f1f1;
}
`;
class layout extends React.Component {
render() {
return (
<React.Fragment>
<Container>
...
</Container>
<FooterWrapper>
<Container className="pt-6">
<Row>
<Col md={8} className="d-flex flex-column justify-content-center">
<h3>Herbert Lin</h3>
<EmailLink href="mailto:herbert.lin.7@gmail.com">herbert.lin.7@gmail.com</EmailLink>
</Col>
<Col md={4} className="d-flex align-items-center justify-content-end">
<SocialMedia className="social-media">
<SocialMediaUl>
<SocialMediaLi>
<SocialMediaLink href="https://github.com/XcrossD">
<FontAwesomeIcon icon={['fab', 'github']} size="lg" />
</SocialMediaLink>
</SocialMediaLi>
<SocialMediaLi>
<SocialMediaLink href="https://www.facebook.com/herbert.lin">
<FontAwesomeIcon icon={['fab', 'facebook']} size="lg" />
</SocialMediaLink>
</SocialMediaLi>
<SocialMediaLi>
<SocialMediaLink href="https://www.instagram.com/gummypearin/">
<FontAwesomeIcon icon={['fab', 'instagram']} size="lg" />
</SocialMediaLink>
</SocialMediaLi>
<SocialMediaLi>
<SocialMediaLink href="https://www.linkedin.com/in/herbert-lin-28240446/">
<FontAwesomeIcon icon={['fab', 'linkedin']} size="lg" />
</SocialMediaLink>
</SocialMediaLi>
</SocialMediaUl>
</SocialMedia>
</Col>
</Row>
</Container>
</FooterWrapper>
</React.Fragment>
);
}
}
- 將背景顏色調為黑色。如果直接對
Container
進行調整會發現因為bootstrap container有設定padding的關係,所以多加了一個FooterWrapper
來達到全版的效果。 - 雖然已經使用
color: white
把文字變為白色了,超連結的顏色還是需要調整,所以製作了EmailLink
,讓超連結的顏色永遠保持白色的狀態。 - 利用
css flexbox
調整social media區塊:橫向排列、去除li預設樣式、li之間加上間隔。 - 加大social media圖示,傳入
size="lg"
屬性。 - 利用
bootstrap className
為Container
加上padding、兩個Col
內容置中。
首頁再編輯非Navbar
與footer
區域,我們就有一個首頁了。
src/pages/index.js
import React from "react";
import { Link } from "gatsby";
import styled from "styled-components";
import Jumbotron from 'react-bootstrap/Jumbotron';
import Button from 'react-bootstrap/Button';
import Row from 'react-bootstrap/Row';
import Col from 'react-bootstrap/Col';
import 'bootstrap/dist/css/bootstrap.min.css';
import Layout from "../components/layout";
import SEO from"../components/seo";
const Hero = styled(Jumbotron)`
&&& {
background-color: white;
}
`;
class IndexPage extends React.Component {
render() {
return (
<Layout>
<SEO
title="Home"
keywords={[`blog`, `herbert lin`, `javascript`, `react`, `python`, `data science`]}
/>
<Hero className="px-0">
<h1>Hi! I'm Herbert.</h1>
<p>
Previous front end developer.
<br />
Currently located in Taiwan, trying to transition into data-related stuff.
</p>
<Link to="/about/">
<Button variant="primary">Learn more about me</Button>
</Link>
</Hero>
<Row>
<Col>
<h2 className="mb-4">Recent work</h2>
</Col>
</Row>
<Row>
// 這裡之後會製作一個Component跟work一起共用
</Row>
<Row className="mt-4">
<Col>
<Link to="/work/">
<Button variant="primary">View more</Button>
</Link>
</Col>
</Row>
</Layout>
)
}
}
export default IndexPage
在這裡我沿用了原本模板裡面做好的SEO
。如果去觀察src/components/seo.js
就會發現那是使用react-helmet
製作幫助優化SEO的Component,所以我們就直接沿用了。
實際效果如下:
本篇文章的程式碼的實作可以在github repo中
2-react-bootstrap-page
找到