gatsby frontend to display all ideas/projects with a page for each tier of app idea/project

pull/135/head
mcacciano 6 years ago
parent a8bf229ea2
commit bd4684f148

69
app/.gitignore vendored

@ -0,0 +1,69 @@
# Logs
logs
*.log
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# Runtime data
pids
*.pid
*.seed
*.pid.lock
# Directory for instrumented libs generated by jscoverage/JSCover
lib-cov
# Coverage directory used by tools like istanbul
coverage
# nyc test coverage
.nyc_output
# Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files)
.grunt
# Bower dependency directory (https://bower.io/)
bower_components
# node-waf configuration
.lock-wscript
# Compiled binary addons (http://nodejs.org/api/addons.html)
build/Release
# Dependency directories
node_modules/
jspm_packages/
# Typescript v1 declaration files
typings/
# Optional npm cache directory
.npm
# Optional eslint cache
.eslintcache
# Optional REPL history
.node_repl_history
# Output of 'npm pack'
*.tgz
# dotenv environment variable files
.env*
# gatsby files
.cache/
public
# Mac files
.DS_Store
# Yarn
yarn-error.log
.pnp/
.pnp.js
# Yarn Integrity file
.yarn-integrity

@ -0,0 +1,4 @@
.cache
package.json
package-lock.json
public

@ -0,0 +1,7 @@
{
"endOfLine": "lf",
"semi": true,
"singleQuote": true,
"tabWidth": 2,
"trailingComma": "es5"
}

@ -0,0 +1,22 @@
The MIT License (MIT)
Copyright (c) 2015 gatsbyjs
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

@ -0,0 +1,40 @@
# TODO
- Filter and Sort for all pages (home page probably most important as it displays all tiers of ideas)
- If this gets accepted and merged update CONTRIBUTING.md to have new md app idea files to include necessary fields for Gatsby markdown plugin
- Style could use some love in general - currently just super simple css grid
- Update SEO for all pages to return accurate title for content
- IdeaTemplate needs a lof styling love. Currently only showing the HTML that is derived from the markdown files
- Look into possibly adding more fields to each markdown file to allow for more custom styling on each page (this can still be done by creating tight styling components
based on the exact structure of the markdown parsed HTML)
- look into some way to trigger rebuild of gatsby site when hosted(probably Netlify) every time a new Idea is merged in from a PR
- I believe github actions can do this?
<br />
# Gatsby
## Plugins
- gatsby-plugin-react-helmet
- gatsby-source-filesystem
- gatsby-transformer-sharp
- gatsby-plugin-sharp
- gatsby-plugin-manifest
- gatsby-source-filesystem
- gatsby-transformer-remark
- gatsby-plugin-styled-components
<br />
# NOTES
- each page is querying only the tier of idea that coincides with the page tier
- Gatsby createPages being used to create a new page for each project that displays the markdown file in HTML format currently

@ -0,0 +1,7 @@
/**
* Implement Gatsby's Browser APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/browser-apis/
*/
// You can delete this file if you're not using it

@ -0,0 +1,48 @@
module.exports = {
siteMetadata: {
title: `AppIdeas`,
description: `Looking for you next project idea? Look to further!`,
author: ``,
},
plugins: [
`gatsby-plugin-react-helmet`,
{
resolve: `gatsby-source-filesystem`,
options: {
name: `images`,
path: `${__dirname}/src/images`,
},
},
`gatsby-transformer-sharp`,
`gatsby-plugin-sharp`,
{
resolve: `gatsby-plugin-manifest`,
options: {
name: `gatsby-starter-default`,
short_name: `starter`,
start_url: `/`,
background_color: `#663399`,
theme_color: `#663399`,
display: `minimal-ui`,
icon: `src/images/gatsby-icon.png`, // This path is relative to the root of the site.
},
},
{
resolve: `gatsby-source-filesystem`,
options: {
name: `markdown-pages`,
path: `../Projects`,
},
},
`gatsby-transformer-remark`,
{
resolve: `gatsby-plugin-styled-components`,
options: {
// Add any options here
},
},
// this (optional) plugin enables Progressive Web App + Offline functionality
// To learn more, visit: https://gatsby.dev/offline
// `gatsby-plugin-offline`,
],
}

@ -0,0 +1,35 @@
const path = require(`path`)
exports.createPages = async ({ actions, graphql, reporter }) => {
const { createPage } = actions
const IdeaTemplate = path.resolve(`src/templates/IdeaTemplate.js`)
const result = await graphql(`
query {
allMarkdownRemark {
edges {
node {
frontmatter {
path
title
}
}
}
}
}
`)
// Handle errors
if (result.errors) {
reporter.panicOnBuild(`Error while running GraphQL query.`)
return
}
result.data.allMarkdownRemark.edges.forEach(({ node }) => {
createPage({
path: node.frontmatter.path,
component: IdeaTemplate,
context: {}, // additional data can be passed via context
})
})
}

@ -0,0 +1,7 @@
/**
* Implement Gatsby's SSR (Server Side Rendering) APIs in this file.
*
* See: https://www.gatsbyjs.org/docs/ssr-apis/
*/
// You can delete this file if you're not using it

17819
app/package-lock.json generated

File diff suppressed because it is too large Load Diff

@ -0,0 +1,48 @@
{
"name": "gatsby-starter-default",
"private": true,
"description": "A simple starter to get up and developing quickly with Gatsby",
"version": "0.1.0",
"author": "Kyle Mathews <mathews.kyle@gmail.com>",
"dependencies": {
"babel-plugin-styled-components": "^1.10.7",
"gatsby": "^2.19.7",
"gatsby-image": "^2.2.39",
"gatsby-plugin-manifest": "^2.2.39",
"gatsby-plugin-offline": "^3.0.32",
"gatsby-plugin-react-helmet": "^3.1.21",
"gatsby-plugin-sharp": "^2.4.3",
"gatsby-plugin-styled-components": "^3.1.19",
"gatsby-source-filesystem": "^2.1.48",
"gatsby-transformer-remark": "^2.6.50",
"gatsby-transformer-sharp": "^2.3.13",
"prop-types": "^15.7.2",
"react": "^16.12.0",
"react-dom": "^16.12.0",
"react-helmet": "^5.2.1",
"styled-components": "^5.0.1"
},
"devDependencies": {
"prettier": "^1.19.1"
},
"keywords": [
"gatsby"
],
"license": "MIT",
"scripts": {
"build": "gatsby build",
"develop": "gatsby develop",
"format": "prettier --write \"**/*.{js,jsx,json,md}\"",
"start": "npm run develop",
"serve": "gatsby serve",
"clean": "gatsby clean",
"test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1"
},
"repository": {
"type": "git",
"url": "https://github.com/gatsbyjs/gatsby-starter-default"
},
"bugs": {
"url": "https://github.com/gatsbyjs/gatsby/issues"
}
}

@ -0,0 +1,21 @@
import React from 'react';
import { useStaticQuery, graphql } from 'gatsby';
import Img from 'gatsby-image';
const AppIdeaBanner = () => {
const data = useStaticQuery(graphql`
query {
placeholderImage: file(relativePath: { eq: "app-ideas.png" }) {
childImageSharp {
fluid(maxWidth: 300, maxHeight: 70) {
...GatsbyImageSharpFluid
}
}
}
}
`);
return <Img fluid={data.placeholderImage.childImageSharp.fluid} />;
};
export default AppIdeaBanner;

@ -0,0 +1,33 @@
import PropTypes from 'prop-types';
import React from 'react';
import { StyledHeader, Nav, NavItem, NavLink } from './header.styles';
const Header = ({ siteTitle }) => (
<StyledHeader>
<Nav>
<NavItem>
<NavLink to="/">All</NavLink>
</NavItem>
<NavItem>
<NavLink to="/beginner">Beginner</NavLink>
</NavItem>
<NavItem>
<NavLink to="/intermediate">Intermediate</NavLink>
</NavItem>
<NavItem>
<NavLink to="/advanced">Advanced</NavLink>
</NavItem>
</Nav>
</StyledHeader>
);
Header.propTypes = {
siteTitle: PropTypes.string,
};
Header.defaultProps = {
siteTitle: ``,
};
export default Header;

@ -0,0 +1,28 @@
import styled from 'styled-components';
import { Link } from 'gatsby';
export const StyledHeader = styled.header`
color: #fff;
background: #211e1e;
height: 5rem;
`;
export const Nav = styled.ul`
display: flex;
justify-content: space-between;
align-items: center;
height: 100%;
margin: 0 2rem;
list-style: none;
`;
export const NavItem = styled.li``;
export const NavLink = styled(Link)`
text-decoration: none;
padding: 0.5rem 1rem;
color: #fff;
text-transform: uppercase;
font-weight: 500;
`;

@ -0,0 +1,40 @@
import React from 'react';
import {
IdeaItem,
IdeaItemLink,
IdeaTitle,
Tier,
HR,
} from './idea-list-item.styles';
const tierColor = tier => {
switch (tier) {
case 'beginner':
return '#67cc3f';
case 'intermediate':
return '#1670e5';
case 'advanced':
return '#ce1010';
default:
break;
}
};
const IdeaListItem = ({
idea: {
excerpt,
frontmatter: { path, title, tier },
},
}) => (
<IdeaItem borderColor={tierColor(tier)}>
<IdeaItemLink to={path}>
<IdeaTitle>{title}</IdeaTitle>
<Tier backgroundColor={tierColor(tier)}>{tier}</Tier>
<HR color={tierColor(tier)} />
<p>{excerpt}</p>
</IdeaItemLink>
</IdeaItem>
);
export default IdeaListItem;

@ -0,0 +1,33 @@
import styled from 'styled-components';
import { Link } from 'gatsby';
export const IdeaItem = styled.li`
border: 1px solid #211e1e;
border-color: ${props => props.borderColor || '#211e1e'};
border-radius: 5px;
`;
export const IdeaItemLink = styled(Link)`
text-decoration: none;
color: #211e1e;
display: block;
height: 100%;
padding: 1rem;
`;
export const IdeaTitle = styled.h2`
letter-spacing: 1px;
color: ${props => props.color || '#211e1e'};
`;
export const HR = styled.hr`
margin: 5px 0;
`;
export const Tier = styled.small`
background-color: ${props => props.backgroundColor || '#211e1e'};
border-radius: 5px;
color: #fff;
font-weight: 500;
padding: 2px 5px;
`;

@ -0,0 +1,14 @@
import React from 'react';
import IdeaListItem from '../idea-list-item/idea-list-item.component';
import { IdeasList } from './idea-list.styles';
const IdeaList = ({ ideas }) => (
<IdeasList>
{ideas.map(({ node }) => (
<IdeaListItem key={node.id} idea={node} />
))}
</IdeasList>
);
export default IdeaList;

@ -0,0 +1,10 @@
import styled from 'styled-components';
export const IdeasList = styled.ul`
display: grid;
grid-template-columns: repeat(auto-fit, minmax(250px, 1fr));
grid-gap: 1rem;
margin: 2rem;
list-style: none;
`;

@ -0,0 +1,60 @@
/**
* Layout component that queries for data
* with Gatsby's useStaticQuery component
*
* See: https://www.gatsbyjs.org/docs/use-static-query/
*/
import React from 'react';
import PropTypes from 'prop-types';
import { useStaticQuery, graphql } from 'gatsby';
import Header from '../header/header.component';
import { MainLayout } from './layout.styles';
import AppIdeaBanner from '../app-idea-banner/app-idea-banner.component';
import './main.css';
const Layout = ({ children }) => {
const data = useStaticQuery(graphql`
query SiteTitleQuery {
site {
siteMetadata {
title
}
}
}
`);
return (
<MainLayout>
<Header siteTitle={data.site.siteMetadata.title} />
<div style={{ position: 'relative' }}>
<AppIdeaBanner />
<span
style={{
display: 'block',
position: 'absolute',
height: '100%',
width: '100%',
top: '0',
left: '0',
background: 'rgba(0, 0, 0, 0.2)',
}}
></span>
</div>
<main>{children}</main>
<footer>
© {new Date().getFullYear()}, Built with
{` `}
<a href="https://www.gatsbyjs.org">Gatsby</a>
</footer>
</MainLayout>
);
};
Layout.propTypes = {
children: PropTypes.node.isRequired,
};
export default Layout;

@ -0,0 +1,7 @@
import styled from "styled-components"
export const MainLayout = styled.div`
margin: 0;
padding: 0;
box-sizing: border-box;
`

@ -0,0 +1,11 @@
*,
*:before,
*:after {
margin: 0;
padding: 0;
box-sizing: border-box;
}
body {
line-height: 1.6;
}

@ -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

Binary file not shown.

After

Width:  |  Height:  |  Size: 149 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 163 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

@ -0,0 +1,14 @@
import React from "react"
import Layout from "../components/main-layout/layout.component"
import SEO from "../components/seo/seo.component"
const NotFoundPage = () => (
<Layout>
<SEO title="404: Not found" />
<h1>NOT FOUND</h1>
<p>You just hit a route that doesn&#39;t exist... the sadness.</p>
</Layout>
)
export default NotFoundPage

@ -0,0 +1,38 @@
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/main-layout/layout.component';
import SEO from '../components/seo/seo.component';
import IdeaList from '../components/idea-list/idea-list.component';
const AdvancedPage = ({ data }) => {
return (
<Layout>
<SEO title="Beginner Ideas" />
<IdeaList ideas={data.advancedIdeas.edges} />
</Layout>
);
};
export const pageQuery = graphql`
query {
advancedIdeas: allMarkdownRemark(
sort: { fields: [frontmatter___title], order: ASC }
filter: { frontmatter: { tier: { eq: "advanced" } } }
) {
edges {
node {
excerpt
frontmatter {
path
title
tier
}
}
}
}
}
`;
export default AdvancedPage;

@ -0,0 +1,38 @@
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/main-layout/layout.component';
import SEO from '../components/seo/seo.component';
import IdeaList from '../components/idea-list/idea-list.component';
const BeginnerPage = ({ data }) => {
return (
<Layout>
<SEO title="Beginner Ideas" />
<IdeaList ideas={data.beginnerIdeas.edges} />
</Layout>
);
};
export const pageQuery = graphql`
query {
beginnerIdeas: allMarkdownRemark(
sort: { fields: [frontmatter___title], order: ASC }
filter: { frontmatter: { tier: { eq: "beginner" } } }
) {
edges {
node {
excerpt
frontmatter {
path
title
tier
}
}
}
}
}
`;
export default BeginnerPage;

@ -0,0 +1,35 @@
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/main-layout/layout.component';
import SEO from '../components/seo/seo.component';
import IdeasList from '../components/idea-list/idea-list.component';
const IndexPage = ({ data }) => {
return (
<Layout>
<SEO title="Home" />
<IdeasList ideas={data.ideas.edges} />
</Layout>
);
};
export const pageQuery = graphql`
query {
ideas: allMarkdownRemark {
edges {
node {
excerpt
frontmatter {
path
title
tier
}
}
}
}
}
`;
export default IndexPage;

@ -0,0 +1,38 @@
import React from 'react';
import { graphql } from 'gatsby';
import Layout from '../components/main-layout/layout.component';
import SEO from '../components/seo/seo.component';
import IdeaList from '../components/idea-list/idea-list.component';
const IntermediatePage = ({ data }) => {
return (
<Layout>
<SEO title="Beginner Ideas" />
<IdeaList ideas={data.intermediateIdeas.edges} />
</Layout>
);
};
export const pageQuery = graphql`
query {
intermediateIdeas: allMarkdownRemark(
sort: { fields: [frontmatter___title], order: ASC }
filter: { frontmatter: { tier: { eq: "intermediate" } } }
) {
edges {
node {
excerpt
frontmatter {
path
title
tier
}
}
}
}
}
`;
export default IntermediatePage;

@ -0,0 +1,36 @@
import React from "react"
import { graphql } from "gatsby"
import Layout from "../components/main-layout/layout.component"
export default function IdeaTemplate({
data, // this prop will be injected by the GraphQL query below.
}) {
const { markdownRemark } = data // data.markdownRemark holds your post data
const { frontmatter, html } = markdownRemark
return (
<Layout>
<div className="blog-post-container" style={{ margin: "1rem" }}>
<div className="blog-post">
{/* <h1>{frontmatter.title}</h1> */}
<div
className="blog-post-content"
dangerouslySetInnerHTML={{ __html: html }}
/>
</div>
</div>
</Layout>
)
}
export const pageQuery = graphql`
query($path: String!) {
markdownRemark(frontmatter: { path: { eq: $path } }) {
html
frontmatter {
path
title
}
}
}
`
Loading…
Cancel
Save