-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Setup Wikipedia Pageviews homepage (#1)
* pull articles into homepage * add article pinning * add Jest and simple test * handle invalid date entry, add aria-labels * update README
- Loading branch information
1 parent
5ec8010
commit e4feaf9
Showing
19 changed files
with
1,722 additions
and
250 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,3 +2,4 @@ node_modules/ | |
.cache/ | ||
public | ||
src/gatsby-types.d.ts | ||
.vscode/ |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,54 +1,70 @@ | ||
<p align="center"> | ||
<a href="https://www.gatsbyjs.com/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts"> | ||
<img alt="Gatsby" src="https://www.gatsbyjs.com/Gatsby-Monogram.svg" width="60" /> | ||
</a> | ||
</p> | ||
<h1 align="center"> | ||
Gatsby minimal TypeScript starter | ||
<div align="center"> | ||
<h1> | ||
Wikipedia Pageviews 👀 | ||
</h1> | ||
<p>Wikipedia Pageviews is a single-page application that allows users to pick and date and see which Wikipedia pages were viewed the most that day. They can also save articles they want to come back to as pins.</p> | ||
<p>Created by <a href="https://github.com/AlyssaKirstine">@AlyssaKirstine</a></p> | ||
</div> | ||
|
||
## 🚀 Quick start | ||
## 🕵️ Technical Details | ||
|
||
1. **Create a Gatsby site.** | ||
Wikipedia Pageviews was built using the [Gatsby](https://www.gatsbyjs.com/) framework and deployed using [Netlify](https://www.netlify.com/). | ||
|
||
Use the Gatsby CLI to create a new site, specifying the minimal TypeScript starter. | ||
See it live 😍 https://wikipedia-pageviews.netlify.app/ | ||
|
||
```shell | ||
# create a new Gatsby site using the minimal TypeScript starter | ||
npm init gatsby | ||
``` | ||
- The homepage is setup in [`src/pages/index.tsx`](https://github.com/AlyssaKirstine/wikipedia-pageviews/blob/main/src/pages/index.tsx). | ||
- Testing | ||
- This repo is setup to support [Jest tests](https://jestjs.io/). Check out an example test in [`src/utils/article/`](https://github.com/AlyssaKirstine/wikipedia-pageviews/tree/main/src/utils/article/test.ts). | ||
- Code formatting | ||
- This repo uses ESLint and Prettier to format the code automatically before any commits are made. | ||
|
||
## 🚀 Build Instructions | ||
|
||
1. **Setup your local copy of this repo.** | ||
|
||
2. **Start developing.** | ||
Use `git clone` to clone this repo to your local computer. | ||
|
||
Navigate into your new site’s directory and start it up. | ||
Using HTTPS: | ||
|
||
```shell | ||
cd my-gatsby-site/ | ||
npm run develop | ||
git clone https://github.com/AlyssaKirstine/wikipedia-pageviews.git | ||
``` | ||
|
||
3. **Open the code and start customizing!** | ||
Using SSH: | ||
|
||
Your site is now running at http://localhost:8000! | ||
```shell | ||
git clone [email protected]:AlyssaKirstine/wikipedia-pageviews.git | ||
``` | ||
|
||
Edit `src/pages/index.tsx` to see your site update in real-time! | ||
2. **Install node modules.** | ||
|
||
4. **Learn more** | ||
Navigate to the project directory and install node modules. | ||
|
||
- [Documentation](https://www.gatsbyjs.com/docs/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
```shell | ||
cd wikipedia-pageviews/ | ||
yarn install | ||
``` | ||
|
||
3. **Build site** | ||
|
||
- [Tutorials](https://www.gatsbyjs.com/tutorial/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
To start a development build, run `yarn start`. | ||
|
||
- [Guides](https://www.gatsbyjs.com/tutorial/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
```shell | ||
yarn start | ||
``` | ||
|
||
- [API Reference](https://www.gatsbyjs.com/docs/api-reference/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
To start a production build, run `yarn build`. This will generate bundle files via webpack in your `public` root folder. | ||
Then run `yarn serve` to serve. | ||
|
||
- [Plugin Library](https://www.gatsbyjs.com/plugins?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
```shell | ||
yarn build | ||
yarn serve | ||
``` | ||
|
||
- [Cheat Sheet](https://www.gatsbyjs.com/docs/cheat-sheet/?utm_source=starter&utm_medium=readme&utm_campaign=minimal-starter-ts) | ||
4. **Check it out!** | ||
|
||
## 🚀 Quick start (Gatsby Cloud) | ||
Visit the applicable URL in your browser of choice. | ||
|
||
Deploy this starter with one click on [Gatsby Cloud](https://www.gatsbyjs.com/cloud/): | ||
Development build: [`http://localhost:8000`](http://localhost:8000) | ||
|
||
[<img src="https://www.gatsbyjs.com/deploynow.svg" alt="Deploy to Gatsby Cloud">](https://www.gatsbyjs.com/dashboard/deploynow?url=https://github.com/gatsbyjs/gatsby-starter-minimal-ts) | ||
Production build: [`http://localhost:9000`](http://localhost:9000) |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,15 +1,11 @@ | ||
import type { GatsbyConfig } from "gatsby"; | ||
import type { GatsbyConfig } from 'gatsby'; | ||
|
||
const config: GatsbyConfig = { | ||
siteMetadata: { | ||
title: `Wikipedia Pageviews`, | ||
siteUrl: `https://www.yourdomain.tld` | ||
siteUrl: `https://wikipedia-pageviews.netlify.app/`, | ||
}, | ||
// More easily incorporate content into your pages through automatic TypeScript type generation and better GraphQL IntelliSense. | ||
// If you use VSCode you can also use the GraphQL plugin | ||
// Learn more at: https://gatsby.dev/graphql-typegen | ||
graphqlTypegen: true, | ||
plugins: ["gatsby-plugin-emotion"] | ||
plugins: ['gatsby-plugin-emotion'], | ||
}; | ||
|
||
export default config; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
const babelOptions = { | ||
presets: ['babel-preset-gatsby', '@emotion/babel-preset-css-prop'], | ||
env: { | ||
test: { | ||
presets: ['@babel/preset-typescript', '@emotion/babel-preset-css-prop'], | ||
}, | ||
}, | ||
}; | ||
|
||
module.exports = require('babel-jest').default.createTransformer(babelOptions); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,18 @@ | ||
module.exports = { | ||
transform: { | ||
'^.+\\.(t|j)sx?$': '<rootDir>/jest-preprocess.js', | ||
}, | ||
moduleNameMapper: { | ||
'.+\\.(css|styl|less|sass|scss)$': `identity-obj-proxy`, | ||
'.+\\.(jpg|jpeg|png|gif|eot|otf|webp|svg|ttf|woff|woff2|mp4|webm|wav|mp3|m4a|aac|oga)$': `<rootDir>/__mocks__/file-mock.js`, | ||
}, | ||
testPathIgnorePatterns: [`node_modules`, `\\.cache`, `<rootDir>.*/public`], | ||
transformIgnorePatterns: [`node_modules/(?!(gatsby|gatsby-script)/)`], | ||
globals: { | ||
__PATH_PREFIX__: ``, | ||
}, | ||
testEnvironmentOptions: { | ||
url: `http://localhost`, | ||
}, | ||
setupFiles: [`<rootDir>/loadershim.js`], | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,3 @@ | ||
global.___loader = { | ||
enqueue: jest.fn(), | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,26 +2,36 @@ | |
"name": "wikipedia-pageviews", | ||
"version": "1.0.0", | ||
"private": true, | ||
"description": "wikipedia-pageviews", | ||
"author": "Alyssa Melendez", | ||
"description": "A Wikipedia pageviews application", | ||
"repository": "[email protected]:AlyssaKirstine/wikipedia-pageviews.git", | ||
"author": "Alyssa Melendez <[email protected]>", | ||
"keywords": [ | ||
"gatsby" | ||
], | ||
"dependencies": { | ||
"@emotion/react": "^11.9.0", | ||
"@emotion/styled": "^11.8.1", | ||
"axios": "^0.27.2", | ||
"gatsby": "^4.15.2", | ||
"gatsby-plugin-emotion": "^7.16.0", | ||
"react": "^18.1.0", | ||
"react-datepicker": "^4.8.0", | ||
"react-dom": "^18.1.0" | ||
}, | ||
"devDependencies": { | ||
"@babel/preset-typescript": "^7.17.12", | ||
"@emotion/babel-preset-css-prop": "^11.2.0", | ||
"@emotion/eslint-plugin": "^11.7.0", | ||
"@types/jest": "^28.1.1", | ||
"@types/node": "^17.0.35", | ||
"@types/react": "^18.0.9", | ||
"@types/react-datepicker": "^4.4.2", | ||
"@types/react-dom": "^18.0.5", | ||
"@types/react-test-renderer": "^18.0.0", | ||
"@typescript-eslint/eslint-plugin": "^5.27.1", | ||
"@typescript-eslint/parser": "^5.27.1", | ||
"babel-jest": "^28.1.1", | ||
"babel-preset-gatsby": "^2.16.0", | ||
"eslint": "^8.17.0", | ||
"eslint-config-prettier": "^8.5.0", | ||
"eslint-import-resolver-webpack": "^0.13.2", | ||
|
@@ -30,8 +40,11 @@ | |
"eslint-plugin-react": "^7.30.0", | ||
"eslint-webpack-plugin": "^3.1.1", | ||
"husky": "^8.0.1", | ||
"identity-obj-proxy": "^3.0.0", | ||
"jest": "^28.1.1", | ||
"lint-staged": "^13.0.0", | ||
"prettier": "2.6.2", | ||
"react-test-renderer": "^18.1.0", | ||
"typescript": "^4.7.2" | ||
}, | ||
"scripts": { | ||
|
@@ -40,6 +53,7 @@ | |
"build": "gatsby build", | ||
"serve": "gatsby serve", | ||
"clean": "gatsby clean", | ||
"test": "jest", | ||
"typecheck": "tsc --noEmit", | ||
"webpack-dev": "gatsby develop -H gatsby.wikipedia-pageviews.localhost -o", | ||
"prepare": "husky install", | ||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
import axios from 'axios'; | ||
import React, { useEffect, useState } from 'react'; | ||
|
||
import 'react-datepicker/dist/react-datepicker.css'; | ||
import { formatArticleName, getArticleUrl } from '../../utils/article'; | ||
import { | ||
cardContainerStyles, | ||
cardStyles, | ||
nameStyles, | ||
pinIconStyles, | ||
pinnedArticlesStyles, | ||
rankStyles, | ||
} from './style'; | ||
|
||
interface ArticleType { | ||
article: string; | ||
views: number; | ||
rank: number; | ||
} | ||
|
||
const ArticleList = ({ | ||
date, | ||
numberOfResults, | ||
}: { | ||
date: Date; | ||
numberOfResults: number; | ||
}) => { | ||
const [articles, setArticles] = useState<Array<ArticleType>>(); | ||
const [pinnedArticles, setPinnedArticles] = useState<Array<string>>(); | ||
|
||
useEffect(() => { | ||
const fetchData = async () => { | ||
const formattedDate = date | ||
.toISOString() | ||
.slice(0, 10) | ||
.replaceAll('-', '/'); | ||
|
||
const response = await axios.get( | ||
`https://wikimedia.org/api/rest_v1/metrics/pageviews/top/en.wikipedia/all-access/${formattedDate}`, | ||
); | ||
|
||
setArticles(response.data.items[0].articles.slice(0, numberOfResults)); | ||
}; | ||
|
||
fetchData().catch(() => { | ||
setArticles([]); | ||
return console.error; | ||
}); | ||
}, [date, numberOfResults]); | ||
|
||
useEffect(() => { | ||
const storedArticles = localStorage.getItem('articles'); | ||
if (storedArticles) setPinnedArticles(JSON.parse(storedArticles)); | ||
}, []); | ||
|
||
const handlePinClick = (name: string) => { | ||
addArticlePin(name); | ||
}; | ||
|
||
const addArticlePin = (name: string) => { | ||
let newArticlesArray: Array<string> = []; | ||
const storedArticles = localStorage.getItem('articles'); | ||
|
||
if (storedArticles) { | ||
newArticlesArray = JSON.parse(storedArticles); | ||
if (newArticlesArray.find((element) => element === name)) | ||
alert( | ||
`You've already pinned this article. Why don't you explore something new?`, | ||
); | ||
else newArticlesArray.push(name); | ||
} | ||
setPinnedArticles(newArticlesArray); | ||
localStorage.setItem('articles', JSON.stringify(newArticlesArray)); | ||
}; | ||
|
||
const removeArticlePin = (name: string) => { | ||
let newArticlesArray: Array<string> = []; | ||
const storedArticles = localStorage.getItem('articles'); | ||
|
||
if (storedArticles) { | ||
newArticlesArray = JSON.parse(storedArticles); | ||
newArticlesArray = newArticlesArray.filter((value) => value !== name); | ||
setPinnedArticles(newArticlesArray); | ||
localStorage.setItem('articles', JSON.stringify(newArticlesArray)); | ||
} | ||
}; | ||
|
||
return ( | ||
<div> | ||
<div css={pinnedArticlesStyles}> | ||
<p> | ||
<strong>Pins:</strong> | ||
</p> | ||
<p>Click the 📌 icon to save an article here.</p> | ||
<ul> | ||
{pinnedArticles?.map((article) => ( | ||
<li key={article}> | ||
<a href={getArticleUrl(article)}>{formatArticleName(article)}</a>{' '} | ||
<button | ||
onClick={() => removeArticlePin(article)} | ||
aria-label={`delete ${formatArticleName(article)} from pins`} | ||
> | ||
delete | ||
</button> | ||
</li> | ||
))} | ||
</ul> | ||
</div> | ||
<div css={cardContainerStyles}> | ||
{!articles?.length ? ( | ||
<p>Bummer! 😞 There are no results for that date.</p> | ||
) : ( | ||
articles.map(({ article: name, rank, views }) => { | ||
return ( | ||
<div key={name} css={cardStyles}> | ||
<button | ||
onClick={() => handlePinClick(name)} | ||
css={pinIconStyles} | ||
aria-label={`Pin ${formatArticleName(name)} article`} | ||
> | ||
📌 | ||
</button> | ||
<p css={rankStyles}> | ||
<strong>#{rank}</strong> | ||
</p> | ||
<h2 css={nameStyles}> | ||
<a href={getArticleUrl(name)}>{formatArticleName(name)}</a> | ||
</h2> | ||
<p>{views} views</p> | ||
</div> | ||
); | ||
}) | ||
)} | ||
</div> | ||
</div> | ||
); | ||
}; | ||
|
||
export default ArticleList; |
Oops, something went wrong.