Very basic NextJS and Api
commit
652143db1d
@ -0,0 +1,2 @@
|
|||||||
|
.next/
|
||||||
|
node_modules/
|
@ -0,0 +1,8 @@
|
|||||||
|
const router = require('express-promise-router')()
|
||||||
|
|
||||||
|
router.get('/', (req, res)=>{
|
||||||
|
console.log('api request')
|
||||||
|
res.json({test: true})
|
||||||
|
})
|
||||||
|
|
||||||
|
module.exports = router;
|
@ -0,0 +1,31 @@
|
|||||||
|
import Link from "next/link"
|
||||||
|
import {DateTime} from 'luxon'
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
import styles from './style.module.css'
|
||||||
|
|
||||||
|
const Footer = () => (
|
||||||
|
<footer className={styles.container}>
|
||||||
|
<div>
|
||||||
|
<h1 className={styles.title}>
|
||||||
|
<Link href="/"><a>Society <span>of</span> Socks</a></Link>
|
||||||
|
</h1>
|
||||||
|
<div className={styles.footerInfo}>
|
||||||
|
<p>Website by <a href="https://coleserickson.com/">Cole Erickson</a> - © 2015 - {DateTime.utc().year} Society of Socks</p>
|
||||||
|
</div>
|
||||||
|
<ul className={styles.footerNav}>
|
||||||
|
<li><Link href="#mailingList"><a onClick={(ev)=>{if(ev) ev.preventDefault(); console.log('mailing list')}}>Mailing List</a></Link></li>
|
||||||
|
<li><Link href="/contact"><a>Contact Us</a></Link></li>
|
||||||
|
<li><Link href="/privacy"><a>Privacy</a></Link></li>
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
</footer>
|
||||||
|
)
|
||||||
|
|
||||||
|
Footer.propTypes = {
|
||||||
|
}
|
||||||
|
|
||||||
|
Footer.defaultProps = {
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Footer
|
@ -0,0 +1,94 @@
|
|||||||
|
.container {
|
||||||
|
background: #313131;
|
||||||
|
box-shadow: inset 0 15px 7.5px -7.5px rgba(0,0,0,0.2);
|
||||||
|
padding-top: 15px;
|
||||||
|
color: white;
|
||||||
|
padding-left: 25px;
|
||||||
|
padding-right: 25px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container > div {
|
||||||
|
max-width: 1000px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
position: relative;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
top: -20px;
|
||||||
|
font-size: 24px;
|
||||||
|
border-bottom: solid rgba(255,255,255,0.2) 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title a {
|
||||||
|
font-family: 'Cormorant Infant',serif;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none !important;
|
||||||
|
text-align: center;
|
||||||
|
color: inherit;
|
||||||
|
height: 1.02em;
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title span {
|
||||||
|
font-family: 'Cormorant Upright',serif;
|
||||||
|
font-weight: 300;
|
||||||
|
text-transform: lowercase;
|
||||||
|
font-style: italic;
|
||||||
|
margin-left: -0.2em;
|
||||||
|
margin-right: .2em;
|
||||||
|
position: relative;
|
||||||
|
top: -0.2em;
|
||||||
|
left: .05em;
|
||||||
|
font-size: 73.91304348%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title a {
|
||||||
|
border-bottom: solid 1px transparent;
|
||||||
|
position: relative;
|
||||||
|
padding-bottom: 2px;
|
||||||
|
top: 1px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title a:hover {
|
||||||
|
border-bottom: solid 1px currentColor;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerInfo {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerInfo a {
|
||||||
|
color: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerNav {
|
||||||
|
position: absolute;
|
||||||
|
list-style: none;
|
||||||
|
top: -8px;
|
||||||
|
right: 0px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerNav li {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: 'Cormorant SC', serif;
|
||||||
|
padding-left: 40px;
|
||||||
|
text-transform: uppercase;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerNav li a {
|
||||||
|
display: inline-block;
|
||||||
|
font-family: 'Cormorant SC', serif;
|
||||||
|
color: white;
|
||||||
|
opacity: .7;
|
||||||
|
text-decoration: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.footerNav li a:hover {
|
||||||
|
opacity: .9;
|
||||||
|
border-bottom: solid 1px white;
|
||||||
|
}
|
@ -0,0 +1,45 @@
|
|||||||
|
import Link from "next/link"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import React from "react"
|
||||||
|
|
||||||
|
// import logo from './sos-logo.png'
|
||||||
|
import styles from './style.module.css'
|
||||||
|
|
||||||
|
const Header = ({user}) => (
|
||||||
|
<header className={styles.container}>
|
||||||
|
<div className={styles.logo}>
|
||||||
|
{/* <img alt="" src={logo}/> */}
|
||||||
|
</div>
|
||||||
|
<h1 className={styles.title}>
|
||||||
|
<Link href="/"><a>Society <span>of</span> Socks</a></Link>
|
||||||
|
</h1>
|
||||||
|
<ul className={styles.primaryNav}>
|
||||||
|
<li><Link href="/store/categories"><a>Catalogue</a></Link></li>
|
||||||
|
<li><Link href="/store/popular"><a>Popular</a></Link></li>
|
||||||
|
<li><Link href="/store/new"><a>New</a></Link></li>
|
||||||
|
</ul>
|
||||||
|
<ul className={styles.accountNav}>
|
||||||
|
<li><Link href="/store/cart"><a><span className="fa fa-shopping-cart"></span> Cart</a></Link></li>
|
||||||
|
{
|
||||||
|
(!user)?(
|
||||||
|
<li><Link href="/login"><a>Log in</a></Link></li>
|
||||||
|
):(
|
||||||
|
<>
|
||||||
|
<li><Link href="/account"><a>Account</a></Link></li>
|
||||||
|
<li><Link href="/logout"><a>Log out</a></Link></li>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</header>
|
||||||
|
)
|
||||||
|
|
||||||
|
Header.propTypes = {
|
||||||
|
user: PropTypes.object,
|
||||||
|
}
|
||||||
|
|
||||||
|
Header.defaultProps = {
|
||||||
|
user: null,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Header
|
Binary file not shown.
After Width: | Height: | Size: 45 KiB |
@ -0,0 +1,139 @@
|
|||||||
|
@import url('https://fonts.googleapis.com/css?family=Cormorant+Infant:400,600|Cormorant+SC|Cormorant+Upright:300');
|
||||||
|
@import url('https://cdnjs.cloudflare.com/ajax/libs/font-awesome/4.7.0/css/font-awesome.min.css');
|
||||||
|
|
||||||
|
.container {
|
||||||
|
width: 100%;
|
||||||
|
height: 100px;
|
||||||
|
position: relative;
|
||||||
|
box-sizing: content-box;
|
||||||
|
background: white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container::after {
|
||||||
|
display: block;
|
||||||
|
content: ' ';
|
||||||
|
position: absolute;
|
||||||
|
height: 15px;
|
||||||
|
top: 100%;
|
||||||
|
left: 0;
|
||||||
|
right: 0;
|
||||||
|
background: #9C27B0;
|
||||||
|
box-shadow: inset 0 5px 2.5px -2.5px rgba(0,0,0,0.2);
|
||||||
|
z-index: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container + div {
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo {
|
||||||
|
height: 100px;
|
||||||
|
position: relative;
|
||||||
|
overflow-y: hidden;
|
||||||
|
user-select: none;
|
||||||
|
pointer-events: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.logo img {
|
||||||
|
position: absolute;
|
||||||
|
top: -70px;
|
||||||
|
height: 180%;
|
||||||
|
padding: 20px;
|
||||||
|
opacity: .47;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title {
|
||||||
|
display: block;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
position: absolute;
|
||||||
|
top: -20px;
|
||||||
|
font-size: 46px;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title a {
|
||||||
|
font-family: 'Cormorant Infant',serif;
|
||||||
|
font-weight: 600;
|
||||||
|
text-transform: uppercase;
|
||||||
|
text-decoration: none !important;
|
||||||
|
text-align: center;
|
||||||
|
color: inherit;
|
||||||
|
height: 1.02em;
|
||||||
|
display: inline-block;
|
||||||
|
width: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title span {
|
||||||
|
font-family: 'Cormorant Upright',serif;
|
||||||
|
font-weight: 300;
|
||||||
|
text-transform: lowercase;
|
||||||
|
font-style: italic;
|
||||||
|
margin-left: -0.2em;
|
||||||
|
margin-right: .2em;
|
||||||
|
position: relative;
|
||||||
|
top: -0.2em;
|
||||||
|
left: .05em;
|
||||||
|
font-size: 73.91304348%;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1.title a:hover {
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primaryNav {
|
||||||
|
position: absolute;
|
||||||
|
top: 60px;
|
||||||
|
width: 100%;
|
||||||
|
text-align: center;
|
||||||
|
|
||||||
|
color: black;
|
||||||
|
opacity: .87;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primaryNav li {
|
||||||
|
font-family: 'Cormorant SC',serif;
|
||||||
|
text-transform: uppercase;
|
||||||
|
font-weight: 400;
|
||||||
|
font-size: 14px;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primaryNav li a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.primaryNav li:not(:first-child){
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountNav {
|
||||||
|
position: absolute;
|
||||||
|
top: -5px;
|
||||||
|
right: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountNav li {
|
||||||
|
font-family: 'Cormorant Infant',serif;
|
||||||
|
font-weight: 400;
|
||||||
|
display: inline-block;
|
||||||
|
padding: 0;
|
||||||
|
color: black;
|
||||||
|
opacity: .87;
|
||||||
|
font-weight: 500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountNav li a {
|
||||||
|
text-decoration: none;
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
|
|
||||||
|
.accountNav li:not(:first-child){
|
||||||
|
padding-left: 40px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.container ul li a:hover {
|
||||||
|
border-bottom: solid 1px black;
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 297 KiB |
@ -0,0 +1,21 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
import logo from './societyofsocks-white.png'
|
||||||
|
import background from './hero-background-wood.jpg'
|
||||||
|
import styles from './style.module.css'
|
||||||
|
|
||||||
|
export default function Hero(){
|
||||||
|
return (
|
||||||
|
<div className={styles.hero}>
|
||||||
|
<div style={{backgroundImage: `url(${background})`}}>
|
||||||
|
<img class={styles.icon} src={logo}/>
|
||||||
|
<div class={styles.content}>
|
||||||
|
<h2>Your Socks. Your Style.</h2>
|
||||||
|
<p>Are you tired of plain (boring) white socks? We've got you covered.</p>
|
||||||
|
<p>At Society of Socks we strive to give every design a unique personality that is sure to stand out from the crowd.</p>
|
||||||
|
<p>So find your style, and wear them with pride. They're your socks, shouldn't they fit you?</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
}
|
Binary file not shown.
After Width: | Height: | Size: 54 KiB |
@ -0,0 +1,51 @@
|
|||||||
|
.hero {
|
||||||
|
background: linear-gradient(#0f0f0f, #080808);
|
||||||
|
position: relative;
|
||||||
|
box-shadow: inset 0 -15px 7.5px -7.5px rgba(0,0,0,0.2);
|
||||||
|
margin-top: -15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero > div {
|
||||||
|
margin: 0;
|
||||||
|
margin-right: 0px;
|
||||||
|
margin-left: 0px;
|
||||||
|
max-width: 2000px;
|
||||||
|
margin-left: auto;
|
||||||
|
margin-right: auto;
|
||||||
|
padding: 0;
|
||||||
|
position: relative;
|
||||||
|
top: 0;
|
||||||
|
background-size: cover;
|
||||||
|
background-position: center center;
|
||||||
|
min-height: 400px;
|
||||||
|
box-shadow: inset 0 -15px 7.5px -7.5px rgba(0,0,0,0.2);
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero img.icon {
|
||||||
|
position: absolute;
|
||||||
|
right: 60%;
|
||||||
|
margin-right: 20px;
|
||||||
|
margin-top: -10px;
|
||||||
|
top: 80px;
|
||||||
|
max-width: 300px;
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero div.content {
|
||||||
|
position: absolute;
|
||||||
|
left: 40%;
|
||||||
|
right: 20%;
|
||||||
|
padding-left: 20px;
|
||||||
|
top: 80px;
|
||||||
|
color: white;
|
||||||
|
font-family: 'Cormorant Infant',serif;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero h2 {
|
||||||
|
font-family: 'Cormorant SC',serif;
|
||||||
|
font-size: 36px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hero p {
|
||||||
|
opacity: .7;
|
||||||
|
}
|
@ -0,0 +1,88 @@
|
|||||||
|
/**
|
||||||
|
* SEO component that queries for data with
|
||||||
|
* Gatsby's useStaticQuery React hook
|
||||||
|
*
|
||||||
|
* See: https://www.gatsbyjs.org/docs/use-static-query/
|
||||||
|
*/
|
||||||
|
|
||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
import Helmet from "react-helmet"
|
||||||
|
import { useStaticQuery, graphql } from "gatsby"
|
||||||
|
|
||||||
|
function SEO({ description, lang, meta, title }) {
|
||||||
|
const { site } = useStaticQuery(
|
||||||
|
graphql`
|
||||||
|
query {
|
||||||
|
site {
|
||||||
|
siteMetadata {
|
||||||
|
title
|
||||||
|
description
|
||||||
|
author
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
`
|
||||||
|
)
|
||||||
|
|
||||||
|
const metaDescription = description || site.siteMetadata.description
|
||||||
|
|
||||||
|
return (
|
||||||
|
<Helmet
|
||||||
|
htmlAttributes={{
|
||||||
|
lang,
|
||||||
|
}}
|
||||||
|
title={title}
|
||||||
|
titleTemplate={`%s | ${site.siteMetadata.title}`}
|
||||||
|
meta={[
|
||||||
|
{
|
||||||
|
name: `description`,
|
||||||
|
content: metaDescription,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:title`,
|
||||||
|
content: title,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:description`,
|
||||||
|
content: metaDescription,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
property: `og:type`,
|
||||||
|
content: `website`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:card`,
|
||||||
|
content: `summary`,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:creator`,
|
||||||
|
content: site.siteMetadata.author,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:title`,
|
||||||
|
content: title,
|
||||||
|
},
|
||||||
|
{
|
||||||
|
name: `twitter:description`,
|
||||||
|
content: metaDescription,
|
||||||
|
},
|
||||||
|
].concat(meta)}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
SEO.defaultProps = {
|
||||||
|
lang: `en`,
|
||||||
|
meta: [],
|
||||||
|
description: ``,
|
||||||
|
}
|
||||||
|
|
||||||
|
SEO.propTypes = {
|
||||||
|
description: PropTypes.string,
|
||||||
|
lang: PropTypes.string,
|
||||||
|
meta: PropTypes.arrayOf(PropTypes.object),
|
||||||
|
title: PropTypes.string.isRequired,
|
||||||
|
}
|
||||||
|
|
||||||
|
export default SEO
|
@ -0,0 +1,32 @@
|
|||||||
|
const express = require('express')
|
||||||
|
const nextjs = require('next')
|
||||||
|
const {promisify} = require('util')
|
||||||
|
|
||||||
|
const dev = process.env.NODE_ENV !== 'production'
|
||||||
|
const next = nextjs({dev})
|
||||||
|
const nextRequestHandler = next.getRequestHandler()
|
||||||
|
|
||||||
|
;(async ()=>{
|
||||||
|
|
||||||
|
// Allow Next.js to compile its templates
|
||||||
|
console.log('Preparing Next.js templates . . .')
|
||||||
|
await next.prepare()
|
||||||
|
|
||||||
|
const app = express()
|
||||||
|
|
||||||
|
app.use('/api', require('./api'))
|
||||||
|
app.use(nextRequestHandler)
|
||||||
|
|
||||||
|
// await promisify(app.listen)(3000)
|
||||||
|
|
||||||
|
app.listen(3000, err=>{
|
||||||
|
if(err) throw err
|
||||||
|
|
||||||
|
console.log('App listening on port 3000')
|
||||||
|
})
|
||||||
|
|
||||||
|
|
||||||
|
})().catch((ex) => {
|
||||||
|
console.error(ex.stack)
|
||||||
|
process.exit(1)
|
||||||
|
})
|
@ -0,0 +1,8 @@
|
|||||||
|
const path = require('path')
|
||||||
|
|
||||||
|
module.exports = {
|
||||||
|
webpack(config, options) {
|
||||||
|
config.resolve.alias["components"] = path.join(__dirname, 'components');
|
||||||
|
return config;
|
||||||
|
}
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,22 @@
|
|||||||
|
{
|
||||||
|
"name": "sos-nextjs",
|
||||||
|
"version": "1.0.0",
|
||||||
|
"description": "",
|
||||||
|
"main": "index.js",
|
||||||
|
"scripts": {
|
||||||
|
"start": "next start",
|
||||||
|
"dev": "next dev",
|
||||||
|
"build": "next build"
|
||||||
|
},
|
||||||
|
"author": "",
|
||||||
|
"license": "ISC",
|
||||||
|
"devDependencies": {},
|
||||||
|
"dependencies": {
|
||||||
|
"express": "^4.17.1",
|
||||||
|
"express-promise-router": "^3.0.3",
|
||||||
|
"luxon": "^1.22.0",
|
||||||
|
"next": "^9.2.1",
|
||||||
|
"react": "^16.12.0",
|
||||||
|
"react-dom": "^16.12.0"
|
||||||
|
}
|
||||||
|
}
|
@ -0,0 +1,27 @@
|
|||||||
|
import React from "react"
|
||||||
|
import PropTypes from "prop-types"
|
||||||
|
|
||||||
|
import Header from 'components/header'
|
||||||
|
import Footer from 'components/footer'
|
||||||
|
import "./layout.css"
|
||||||
|
// import useUserSession from "../hooks/useUserSession";
|
||||||
|
|
||||||
|
const Layout = ({ Component, pageProps }) => {
|
||||||
|
// Retrieve user information
|
||||||
|
// const user = useUserSession()
|
||||||
|
|
||||||
|
return (
|
||||||
|
<>
|
||||||
|
<Header />
|
||||||
|
<main><Component {...pageProps} /></main>
|
||||||
|
<Footer/>
|
||||||
|
</>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
Layout.propTypes = {
|
||||||
|
Component: PropTypes.node.isRequired,
|
||||||
|
pageProps: PropTypes.object
|
||||||
|
}
|
||||||
|
|
||||||
|
export default Layout
|
@ -0,0 +1,8 @@
|
|||||||
|
import React from 'react'
|
||||||
|
|
||||||
|
const Index = () => (
|
||||||
|
<div>
|
||||||
|
<p>Hello Next.js, this is your friend Brian from logrocket</p>
|
||||||
|
</div>
|
||||||
|
)
|
||||||
|
export default Index
|
@ -0,0 +1,22 @@
|
|||||||
|
html {
|
||||||
|
font-family: sans-serif;
|
||||||
|
-ms-text-size-adjust: 100%;
|
||||||
|
-webkit-text-size-adjust: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
-webkit-font-smoothing: antialiased;
|
||||||
|
-moz-osx-font-smoothing: grayscale;
|
||||||
|
}
|
||||||
|
|
||||||
|
html,body {
|
||||||
|
margin: 0;
|
||||||
|
padding: 0;
|
||||||
|
background: #313131;
|
||||||
|
}
|
||||||
|
|
||||||
|
main {
|
||||||
|
background: #E4E4E4;
|
||||||
|
color: black;
|
||||||
|
padding: 30px 0;
|
||||||
|
}
|
Loading…
Reference in New Issue