Compare commits

..

1 Commits

877 changed files with 19850 additions and 142971 deletions

View File

@@ -1,8 +0,0 @@
# Changesets
Hello and welcome! This folder has been automatically generated by `@changesets/cli`, a build tool that works
with multi-package repos, or single-package repos to help you version and publish your code. You can
find the full documentation for it [in our repository](https://github.com/changesets/changesets)
We have a quick list of common questions to get you started engaging with this project in
[our documentation](https://github.com/changesets/changesets/blob/main/docs/common-questions.md)

View File

@@ -1,14 +0,0 @@
{
"$schema": "https://unpkg.com/@changesets/config@2.3.0/schema.json",
"changelog": [
"@changesets/changelog-github",
{ "repo": "datopian/portaljs" }
],
"commit": false,
"fixed": [],
"linked": [],
"access": "restricted",
"baseBranch": "main",
"updateInternalDependencies": "patch",
"ignore": []
}

View File

@@ -1,39 +0,0 @@
name: Release
on:
push:
branches:
- main
concurrency: release-${{ github.ref }}
jobs:
release:
name: Release
runs-on: ubuntu-latest
steps:
- name: Checkout Repo
uses: actions/checkout@v3
- name: Setup Node.js 16.x
uses: actions/setup-node@v3
with:
node-version: 16.x
- name: Install Dependencies
run: npm ci
- name: Create Release Pull Request or Publish to npm
id: changesets
uses: changesets/action@v1
with:
publish: npm run release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
# - name: Send a Discord notification if a publish happens
# if: steps.changesets.outputs.published == 'true'
# uses: Ilshidur/action-discord@0.3.2
# with:
# args: 'The project {{ EVENT_PAYLOAD.repository.full_name }} has been deployed.'

1
.gitignore vendored
View File

@@ -16,7 +16,6 @@ node_modules
*.launch
.settings/
*.sublime-workspace
.obsidian
# IDE - VSCode
.vscode/*

View File

@@ -13,7 +13,7 @@ Structure:
- **dataset-frictionless**: Example utilizing a frictionless dataset as an example
- **site**: the website for the project, with a landing page and the docs
- **packages**:
- **portaljs-components**: the library of components for creating a data portal
- **portaljs-components**: the library of components for creating a data portal
## How to contribute
@@ -26,11 +26,10 @@ If you'd like to work on one of the issues you can:
3. Clone the forked repository to your machine.
4. Create a feature branch (e.g. `50-update-readme`, where `50` is the number of the related issue).
5. Commit your changes to the feature branch.
6. Add changeset file describing the changes. (See section below)
7. Push the feature branch to your forked repository.
8. Create a Pull Request against the original repository.
6. Push the feature branch to your forked repository.
7. Create a Pull Request against the original repository.
- add a short description of the changes included in the PR
9. Address review comments if requested by our demanding reviewers 😜.
8. Address review comments if requested by our demanding reviewers 😜.
If you have an idea for improvement, and it doesn't have a corresponding issue yet, simply submit a new one.
@@ -63,7 +62,6 @@ or you can use just:
nx <target> <project>
# e.g. npx nx serve ckan
```
if you have the `nx` binary installed globally in your machine
#### Running multiple tasks
@@ -111,7 +109,7 @@ To check code formatting in selected projects:
```sh
npx nx format:check --projects=<array of projects>
# npx nx format:check --projects=ckan,dataset-frictionless
# npx nx format:check --projects=ckan,dataset-frictionless
```
To check code formatting in all projects:
@@ -126,7 +124,7 @@ To fix code formatting in selected projects:
```sh
npx nx format:write --projects=<array projects>
# npx nx format:write --projects=ckan,dataset-frictionless
# npx nx format:write --projects=ckan,dataset-frictionless
```
To fix formatting in all projects:
@@ -176,23 +174,3 @@ To learn more see this [offical docs page](https://nx.dev/reference/nx-json).
Each project also has it's own configuration file - `project.json`, where you can define and configure it's targets (and more).
To learn more see this [offical docs page](https://nx.dev/reference/project-configuration).
## Changesets and publishing packages
> This monorepo is set up with changesets versioning tool. See their [github repository](https://github.com/changesets/changesets) to learn more.
### What are Changesets?
Changesets are files that describe the intention of a contributor to bump a version of the package according to their changes. Changeset file holds two key bits of information: a version type (following semver), and change information to be added to a changelog.
### Adding changesets
In the root directory of the repo, run:
```
npx changeset
```
Select the package that has been changed, the semver version that should be bumped with it and a description of your changes. Please make sure to add the most accurate but also concise information.
To learn about semantic versioning standards see [this semver doc page](https://semver.org/).

View File

@@ -10,24 +10,12 @@ This is also a Next.JS project so you can use the following steps to run the web
## Getting started
To get started first clone this repo in your local machine like so:
```bash
npx create-next-app turing --example https://github.com/datopian/portaljs/tree/main/examples/turing
cd turing
```
Then install the npm dependencies:
To get started first install the npm dependencies:
```bash
npm install
```
Next, run this command, its related to [markdowndb](https://github.com/datopian/markdowndb):
```bash
npm run mddb
```
Next, run the development server:
```bash

View File

@@ -140,7 +140,7 @@ function MobileNavigation(props) {
</div>
<nav className="mt-6">
<ul className="-my-2 divide-y divide-zinc-100 text-base text-zinc-800 dark:divide-zinc-100/5 dark:text-zinc-300">
<MobileNavItem href="https://github.com/datopian/portaljs/tree/main/examples/turing">
<MobileNavItem href="https://github.com/leondz/hatespeechdata">
View on Github <GithubIcon />
</MobileNavItem>
</ul>
@@ -179,7 +179,7 @@ function DesktopNavigation(props) {
return (
<nav {...props}>
<ul className="flex rounded-full bg-white/90 px-3 text-sm font-medium text-zinc-800 shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur dark:bg-zinc-800/90 dark:text-zinc-200 dark:ring-white/10">
<NavItem href="https://github.com/datopian/portaljs/tree/main/examples/turing">
<NavItem href="https://github.com/leondz/hatespeechdata">
View on Github <GithubIcon />
</NavItem>
</ul>

View File

@@ -36,7 +36,7 @@ In the following page type `content/datasets/<name-of-the-file>.md`. if you want
### Fill in content
Copy the contents of `templates/dataset.md` or `templates/keywords.md` respectively to the camp below, filling out the fields with the correct data format. Everything below the second `---` will automatically get rendered into the page, so you may add any standard markdown fields e.g tables, headings, lists...
Copy the contents of `templates/dataset.md` or `templates/keywords.md` respectively to the camp below, filling out the fields with the correct data format
![](https://i.imgur.com/x6JIjhz.png)

Binary file not shown.

View File

@@ -6,6 +6,7 @@ import { Card } from '../components/Card'
import Head from 'next/head'
import parse from '../lib/markdown'
import { Mermaid } from '@flowershow/core';
import { Header } from '../components/Header';
export const getStaticProps = async ({ params }) => {
const urlPath = params.slug ? params.slug.join('/') : ''
@@ -81,13 +82,15 @@ export default function DRDPage({ mdxSource }) {
)
return (
<>
<Header />
<Head>
<title>{meta.title}</title>
</Head>
<Container className="mt-9 relative">
<Container className="mt-16 lg:mt-32 relative">
<Header />
<article>
<header className="flex flex-col">
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
<h1 className="mt-6 text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
{meta.title}
</h1>
<Card as="article">

View File

Before

Width:  |  Height:  |  Size: 566 B

After

Width:  |  Height:  |  Size: 566 B

View File

@@ -0,0 +1 @@
DMS=https://demo.dev.datopian.com

View File

@@ -10,7 +10,6 @@
},
"dependencies": {
"@heroicons/react": "^2.0.17",
"@portaljs/ckan": "^0.0.2",
"next": "13.3.1",
"next-seo": "^6.0.0",
"octokit": "^2.0.14",
@@ -21,14 +20,14 @@
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"@types/node": "18.16.0",
"@types/react": "18.0.38",
"@types/react-dom": "18.0.11",
"autoprefixer": "^10.4.14",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.1",
"typescript": "5.0.4"
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"typescript": "5.0.4",
"@types/node": "18.16.0",
"@types/react": "18.0.38",
"@types/react-dom": "18.0.11"
}
}

View File

@@ -11,9 +11,8 @@ import {
ServerIcon,
UserIcon,
} from '@heroicons/react/20/solid';
import { CKAN } from '@portaljs/ckan';
const backend_url = getConfig().publicRuntimeConfig.DMS;
const dms = getConfig().publicRuntimeConfig.DMS;
const formatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
@@ -26,12 +25,14 @@ const formatter = new Intl.DateTimeFormat('en-US', {
});
export const getServerSideProps: GetServerSideProps = async (context) => {
const ckan = new CKAN(backend_url)
const { dataset } = context.query;
const _dataset = await ckan.getDatasetDetails(dataset as string)
const response = await fetch(
`${dms}/api/3/action/package_show?id=${dataset}`
);
const _dataset = await response.json();
return {
props: {
dataset: _dataset,
dataset: _dataset.result,
},
};
};

View File

@@ -1,8 +1,7 @@
import getConfig from 'next/config';
import styles from './index.module.css';
import { CKAN } from '@portaljs/ckan';
const backend_url = getConfig().publicRuntimeConfig.DMS
const dms = getConfig().publicRuntimeConfig.DMS
const formatter = new Intl.DateTimeFormat('en-US', {
year: 'numeric',
@@ -16,11 +15,12 @@ const formatter = new Intl.DateTimeFormat('en-US', {
export async function getServerSideProps() {
const ckan = new CKAN(backend_url)
const { datasets } = await ckan.packageSearch({ limit: 1000, offset: 0, groups:[], orgs: [], tags: []})
const datasetsWithDetails = await Promise.all(datasets.map(async (dataset) => {
const _dataset = await ckan.getDatasetDetails(dataset.name)
return _dataset
const response = await fetch(`${dms}/api/3/action/package_search`)
const datasets = await response.json()
const datasetsWithDetails = await Promise.all(datasets.result.results.map(async (dataset) => {
const response = await fetch(`${dms}/api/3/action/package_show?id=` + dataset.name)
const json = await response.json()
return json.result
}))
return {
@@ -79,7 +79,7 @@ export function Index({ datasets }) {
</thead>
<tbody className="divide-y divide-gray-200">
{datasets.map((dataset) => (
<tr key={dataset.name}>
<tr>
<td className="px-3 py-4 text-sm text-gray-500">
{dataset.title}
</td>

View File

@@ -1,21 +0,0 @@
import { MDXRemote } from 'next-mdx-remote';
import dynamic from 'next/dynamic';
import { Mermaid } from '@flowershow/core';
// Custom components/renderers to pass to MDX.
// Since the MDX files aren't loaded by webpack, they have no knowledge of how
// to handle import statements. Instead, you must include components in scope
// here.
const components = {
Table: dynamic(() => import('@portaljs/components').then(mod => mod.Table)),
Catalog: dynamic(() => import('@portaljs/components').then(mod => mod.Catalog)),
FlatUiTable: dynamic(() => import('@portaljs/components').then(mod => mod.FlatUiTable)),
mermaid: Mermaid,
Vega: dynamic(() => import('@portaljs/components').then(mod => mod.Vega)),
VegaLite: dynamic(() => import('@portaljs/components').then(mod => mod.VegaLite)),
LineChart: dynamic(() => import('@portaljs/components').then(mod => mod.LineChart)),
} as any;
export default function DRD({ source }: { source: any }) {
return <MDXRemote {...source} components={components} />;
}

View File

@@ -1,3 +0,0 @@
# Test
Test Data Rich Stories

View File

@@ -1,11 +0,0 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
publicRuntimeConfig: {
DMS: process.env.DMS
? process.env.DMS.replace(/\/?$/, '')
: 'https://demo.dev.datopian.com/',
},
};
module.exports = nextConfig;

File diff suppressed because it is too large Load Diff

View File

@@ -1,47 +0,0 @@
{
"name": "ckan",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"prebuild": "npm run mddb",
"build": "next build",
"start": "next start",
"lint": "next lint",
"mddb": "mddb ./content"
},
"dependencies": {
"@flowershow/core": "^0.4.13",
"@flowershow/markdowndb": "^0.1.5",
"@flowershow/remark-callouts": "^1.0.0",
"@flowershow/remark-embed": "^1.0.0",
"@githubocto/flat-ui": "^0.14.1",
"@heroicons/react": "^2.0.18",
"@portaljs/ckan": "^0.0.2",
"@portaljs/components": "0.1.6",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "20.2.3",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"autoprefixer": "10.4.14",
"eslint": "8.41.0",
"eslint-config-next": "13.4.3",
"isomorphic-unfetch": "^4.0.2",
"next": "13.4.3",
"next-mdx-remote": "^4.4.1",
"papaparse": "^5.4.1",
"postcss": "8.4.23",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-query": "^3.39.3",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex": "^6.0.3",
"rehype-prism-plus": "^1.5.1",
"rehype-slug": "^5.1.0",
"remark-math": "^5.1.1",
"remark-smartypants": "^2.0.0",
"remark-toc": "^8.0.1",
"tailwindcss": "3.3.2",
"typescript": "5.0.4"
}
}

View File

@@ -1,179 +0,0 @@
import Head from "next/head";
import { CKAN, Dataset } from "@portaljs/ckan";
import {
ChevronRightIcon,
HomeIcon,
PaperClipIcon,
} from "@heroicons/react/20/solid";
import Link from "next/link";
import getConfig from "next/config";
const backend_url = getConfig().publicRuntimeConfig.DMS
export const getServerSideProps = async (context: any) => {
try {
const datasetName = context.params?.dataset;
if (!datasetName) {
return {
notFound: true,
};
}
const ckan = new CKAN(backend_url);
const dataset = await ckan.getDatasetDetails(datasetName as string);
if (!dataset) {
return {
notFound: true,
};
}
return {
props: { dataset },
};
} catch {
return {
notFound: true,
};
}
};
export default function DatasetPage({
dataset,
}: {
dataset: Dataset;
}): JSX.Element {
return (
<>
<Head>
<title>{`${dataset.title || dataset.name} - Dataset`}</title>
<meta name="description" content="Generated by create next app" />
<link rel="icon" href="/favicon.ico" />
</Head>
<main className="flex min-h-screen flex-col items-center justify-between p-24 bg-zinc-900">
<div className="bg-white p-8 my-4 rounded-lg">
<nav className="flex px-4 py-8" aria-label="Breadcrumb">
<ol role="list" className="flex items-center space-x-4">
<li>
<div>
<Link href="/" className="text-gray-400 hover:text-gray-500">
<HomeIcon
className="h-5 w-5 flex-shrink-0"
aria-hidden="true"
/>
<span className="sr-only">Home</span>
</Link>
</div>
</li>
<li>
<div className="flex items-center">
<ChevronRightIcon
className="h-5 w-5 flex-shrink-0 text-gray-400"
aria-hidden="true"
/>
<span
className="ml-4 text-sm font-medium text-gray-500 hover:text-gray-700"
aria-current={"page"}
>
{dataset.name}
</span>
</div>
</li>
</ol>
</nav>
{dataset && (
<div>
<div className="px-4 sm:px-0">
<h3 className="text-base font-semibold leading-7 text-gray-900">
{dataset.title || dataset.name}
</h3>
<p className="mt-1 max-w-2xl text-sm leading-6 text-gray-500">
Dataset details
</p>
</div>
<div className="mt-6 border-t border-gray-100">
<dl className="divide-y divide-gray-100">
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Title
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.title}
</dd>
</div>
{dataset.tags && dataset.tags.length > 0 && (
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Tags
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.tags.map((tag) => tag.display_name).join(", ")}
</dd>
</div>
)}
{dataset.tags && dataset.tags.length > 0 && (
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
URL
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.url}
</dd>
</div>
)}
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
{dataset.notes && (
<>
<dt className="text-sm font-medium leading-6 text-gray-900">
Description
</dt>
<dd className="mt-1 text-sm leading-6 text-gray-700 sm:col-span-2 sm:mt-0">
{dataset.notes}
</dd>
</>
)}
</div>
<div className="px-4 py-6 sm:grid sm:grid-cols-3 sm:gap-4 sm:px-0">
<dt className="text-sm font-medium leading-6 text-gray-900">
Files
</dt>
<dd className="mt-2 text-sm text-gray-900 sm:col-span-2 sm:mt-0">
<ul
role="list"
className="divide-y divide-gray-100 rounded-md border border-gray-200"
>
{dataset.resources.map((resource) => (
<li key={resource.id} className="flex items-center justify-between py-4 pl-4 pr-5 text-sm leading-6">
<div className="flex w-0 flex-1 items-center">
<PaperClipIcon
className="h-5 w-5 flex-shrink-0 text-gray-400"
aria-hidden="true"
/>
<div className="ml-4 flex min-w-0 flex-1 gap-2">
<span className="truncate font-medium">
{resource.name || resource.id}
</span>
<span className="flex-shrink-0 text-gray-400">
{resource.size}
</span>
</div>
</div>
<div className="ml-4 flex-shrink-0">
<a
href={resource.url}
className="font-medium hover:text-indigo-500 mr-4"
>
Download
</a>
</div>
</li>
))}
</ul>
</dd>
</div>
</dl>
</div>
</div>
)}
</div>
</main>
</>
);
}

View File

@@ -1,18 +0,0 @@
import fetch from 'isomorphic-unfetch';
const Cors = async (req: any, res: any) => {
const { url } = req.query;
try {
const resProxy = await fetch(url, {
headers: {
Range: 'bytes=0-5132288',
},
});
const data = await resProxy.text();
return res.status(200).send(data);
} catch (error: any) {
res.status(400).send(error.toString());
}
};
export default Cors;

View File

@@ -1,55 +0,0 @@
import {
CKAN,
DatasetSearchForm,
ListOfDatasets,
PackageSearchOptions,
Organization,
Group,
} from '@portaljs/ckan';
import getConfig from 'next/config';
import { useState } from 'react';
const backend_url = getConfig().publicRuntimeConfig.DMS;
export async function getServerSideProps() {
const ckan = new CKAN(backend_url);
const groups = await ckan.getGroupsWithDetails();
const orgs = await ckan.getOrgsWithDetails();
return {
props: {
groups,
orgs,
},
};
}
export default function Home({
orgs,
groups,
}: {
orgs: Organization[];
groups: Group[];
}) {
const ckan = new CKAN(backend_url);
const [options, setOptions] = useState<PackageSearchOptions>({
offset: 0,
limit: 5,
tags: [],
groups: [],
orgs: [],
});
return (
<main className="flex min-h-screen flex-col items-center p-24 bg-zinc-900">
<DatasetSearchForm
options={options}
setOptions={setOptions}
groups={groups}
orgs={orgs}
/>
<div className="bg-white p-8 my-4 rounded-lg">
<ListOfDatasets options={options} setOptions={setOptions} ckan={ckan} />{' '}
</div>
</main>
);
}

View File

@@ -1,129 +0,0 @@
import { existsSync, promises as fs } from 'fs';
import path from 'path';
import parse from '../../lib/markdown';
import DataRichDocument from '../../components/DataRichDocument';
import clientPromise from '../../lib/mddb';
import getConfig from 'next/config';
import { CKAN } from '@portaljs/ckan';
export const getStaticPaths = async () => {
const contentDir = path.join(process.cwd(), '/content/');
const contentFolders = await fs.readdir(contentDir, 'utf8');
const paths = contentFolders.map((folder: string) => ({
params: { path: [folder.split('.')[0]] },
}));
return {
paths,
fallback: false,
};
};
const backend_url = getConfig().publicRuntimeConfig.DMS;
export const getStaticProps = async (context) => {
const mddb = await clientPromise;
const storyFile = await mddb.getFileByUrl(context.params.path);
const md = await fs.readFile(
`${process.cwd()}/${storyFile.file_path}`,
'utf8'
);
const ckan = new CKAN(backend_url);
const datasets = storyFile.metadata.datasets ? await Promise.all(
storyFile.metadata.datasets.map(
async (datasetName: string) => await ckan.getDatasetDetails(datasetName)
)
) : [];
const orgs = storyFile.metadata.orgs ? await Promise.all(
storyFile.metadata.orgs.map(
async (orgName: string) => await ckan.getOrgDetails(orgName)
)
) : [];
let { mdxSource, frontMatter } = await parse(md, '.mdx', { datasets, orgs });
return {
props: {
mdxSource,
frontMatter: JSON.stringify(frontMatter),
},
};
};
export default function DatasetPage({ mdxSource, frontMatter }) {
frontMatter = JSON.parse(frontMatter);
return (
<main className="flex min-h-screen flex-col justify-between p-16 bg-zinc-900">
<div className="bg-white p-8 my-4 rounded-lg">
<div className="prose mx-auto py-8">
<header>
<div className="mb-6">
<>
<h1 className="mb-2">{frontMatter.title}</h1>
{frontMatter.author && (
<p className="my-0">
<span className="font-semibold">Author: </span>
<span className="my-0">{frontMatter.author}</span>
</p>
)}
{frontMatter.description && (
<p className="my-0">
<span className="font-semibold">Description: </span>
<span className="description my-0">
{frontMatter.description}
</span>
</p>
)}
{frontMatter.modified && (
<p className="my-0">
<span className="font-semibold">Modified: </span>
<span className="description my-0">
{new Date(frontMatter.modified).toLocaleDateString()}
</span>
</p>
)}
{frontMatter.files && (
<section className="py-6">
<h2 className="mt-0">Data files</h2>
<table className="table-auto">
<thead>
<tr>
<th>File</th>
<th>Format</th>
</tr>
</thead>
<tbody>
{frontMatter.files.map((f) => {
const fileName = f.split('/').slice(-1);
return (
<tr key={`resources-list-${f}`}>
<td>
<a target="_blank" href={f}>
{fileName}
</a>
</td>
<td>
{fileName[0]
.split('.')
.slice(-1)[0]
.toUpperCase()}
</td>
</tr>
);
})}
</tbody>
</table>
</section>
)}
</>
</div>
</header>
<main>
<DataRichDocument source={mdxSource} />
</main>
</div>
</div>
</main>
);
}

View File

@@ -1,71 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "@flowershow/remark-callouts/styles.css";
/* mathjax */
.math-inline > mjx-container > svg {
display: inline;
align-items: center;
}
/* smooth scrolling in modern browsers */
html {
scroll-behavior: smooth !important;
}
/* tooltip fade-out clip */
.tooltip-body::after {
content: "";
position: absolute;
right: 0;
top: 3.6rem; /* multiple of $line-height used on the tooltip body (defined in tooltipBodyStyle) */
height: 1.2rem; /* ($top + $height)/$line-height is the number of lines we want to clip tooltip text at*/
width: 10rem;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1) 100%
);
}
:is(h2, h3, h4, h5, h6):not(.blogitem-title) {
margin-left: -2rem !important;
padding-left: 2rem !important;
scroll-margin-top: 4.5rem;
position: relative;
}
.heading-link {
padding: 1px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
margin: auto 0;
border-radius: 5px;
background: #1e293b;
opacity: 0;
transition: opacity 0.2s;
}
.light .heading-link {
/* border: 1px solid #ab2b65; */
/* background: none; */
background: #e2e8f0;
}
:is(h2, h3, h4, h5, h6):not(.blogitem-title):hover .heading-link {
opacity: 100;
}
.heading-link svg {
transform: scale(0.75);
}
@media screen and (max-width: 640px) {
.heading-link {
visibility: hidden;
}
}

View File

@@ -1,23 +0,0 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": false,
"forceConsistentCasingInFileNames": true,
"noEmit": true,
"esModuleInterop": true,
"module": "esnext",
"moduleResolution": "node",
"resolveJsonModule": true,
"isolatedModules": true,
"jsx": "preserve",
"incremental": true,
"paths": {
"@/*": ["./*"]
}
},
"include": ["next-env.d.ts", "**/*.ts", "**/*.tsx"],
"exclude": ["node_modules"]
}

View File

@@ -1,27 +1,11 @@
[
{
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-generic-ballot",
"name": "congress-generic-ballot",
"displayName": "congress-generic-<span class=\"lastword\">ballot</span>",
"articles": [
{
"date": "2023-05-11T14:35:40.000Z",
"title": "Do Voters Want Democrats Or Republicans In Congress?",
"url": "https://projects.fivethirtyeight.com/congress-generic-ballot-polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/generic-ballot-data/generic_polllist.csv",
"https://projects.fivethirtyeight.com/polls/data/generic_ballot_averages.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-forecasts",
"name": "nba-forecasts",
"displayName": "nba-<span class=\"lastword\">forecasts</span>",
"articles": [
{
"date": "2023-05-11T11:15:46.000Z",
"date": "2023-05-08T22:33:43.000Z",
"title": "2022-23 NBA Predictions",
"url": "https://projects.fivethirtyeight.com/2023-nba-predictions/"
}
@@ -31,13 +15,61 @@
"https://projects.fivethirtyeight.com/nba-model/nba_elo_latest.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/soccer-spi",
"name": "soccer-spi",
"displayName": "soccer-<span class=\"lastword\">spi</span>",
"articles": [
{
"date": "2023-05-08T22:17:18.000Z",
"title": "Club Soccer Predictions",
"url": "https://projects.fivethirtyeight.com/soccer-predictions/"
}
],
"files": [
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches.csv",
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches_latest.csv",
"https://projects.fivethirtyeight.com/soccer-api/club/spi_global_rankings.csv",
"https://projects.fivethirtyeight.com/soccer-api/international/spi_matches_intl.csv",
"https://projects.fivethirtyeight.com/soccer-api/international/spi_global_rankings_intl.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/polls",
"name": "polls",
"displayName": "<span class=\"lastword\">polls</span>",
"articles": [
{
"date": "2023-05-08T20:36:59.000Z",
"title": "Latest Polls",
"url": "https://projects.fivethirtyeight.com/polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_approval_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls_historical.csv",
"https://projects.fivethirtyeight.com/2020-primary-data/pres_primary_avgs_2020.csv",
"https://projects.fivethirtyeight.com/2020-general-data/presidential_poll_averages_2020.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-raptor",
"name": "nba-raptor",
"displayName": "nba-<span class=\"lastword\">raptor</span>",
"articles": [
{
"date": "2023-05-11T11:13:20.000Z",
"date": "2023-05-08T11:15:48.000Z",
"title": "The Best NBA Players, According To RAPTOR",
"rowspan": 3,
"url": "https://projects.fivethirtyeight.com/nba-player-ratings/"
@@ -60,32 +92,13 @@
"https://projects.fivethirtyeight.com/nba-model/2023/latest_RAPTOR_by_player.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/soccer-spi",
"name": "soccer-spi",
"displayName": "soccer-<span class=\"lastword\">spi</span>",
"articles": [
{
"date": "2023-05-11T05:25:51.000Z",
"title": "Club Soccer Predictions",
"url": "https://projects.fivethirtyeight.com/soccer-predictions/"
}
],
"files": [
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches.csv",
"https://projects.fivethirtyeight.com/soccer-api/club/spi_matches_latest.csv",
"https://projects.fivethirtyeight.com/soccer-api/club/spi_global_rankings.csv",
"https://projects.fivethirtyeight.com/soccer-api/international/spi_matches_intl.csv",
"https://projects.fivethirtyeight.com/soccer-api/international/spi_global_rankings_intl.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nhl-forecasts",
"name": "nhl-forecasts",
"displayName": "nhl-<span class=\"lastword\">forecasts</span>",
"articles": [
{
"date": "2023-05-11T04:53:22.000Z",
"date": "2023-05-08T04:18:20.000Z",
"title": "2022-23 NHL Predictions",
"url": "https://projects.fivethirtyeight.com/2023-nhl-predictions/"
}
@@ -101,7 +114,7 @@
"displayName": "mlb-<span class=\"lastword\">elo</span>",
"articles": [
{
"date": "2023-05-11T02:35:49.000Z",
"date": "2023-05-08T02:25:55.000Z",
"title": "2023 MLB Predictions",
"url": "https://projects.fivethirtyeight.com/2023-mlb-predictions/"
}
@@ -111,6 +124,22 @@
"https://projects.fivethirtyeight.com/mlb-api/mlb_elo_latest.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-generic-ballot",
"name": "congress-generic-ballot",
"displayName": "congress-generic-<span class=\"lastword\">ballot</span>",
"articles": [
{
"date": "2023-05-02T13:48:41.000Z",
"title": "Do Voters Want Democrats Or Republicans In Congress?",
"url": "https://projects.fivethirtyeight.com/congress-generic-ballot-polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/generic-ballot-data/generic_polllist.csv",
"https://projects.fivethirtyeight.com/polls/data/generic_ballot_averages.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-demographics",
"name": "congress-demographics",
@@ -166,35 +195,6 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/polls",
"name": "polls",
"displayName": "<span class=\"lastword\">polls</span>",
"articles": [
{
"date": "2023-05-11T14:35:40.000Z",
"title": "Latest Polls",
"url": "https://projects.fivethirtyeight.com/polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_approval_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls_historical.csv",
"https://projects.fivethirtyeight.com/2020-primary-data/pres_primary_avgs_2020.csv",
"https://projects.fivethirtyeight.com/2020-general-data/presidential_poll_averages_2020.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nfl-elo",
"name": "nfl-elo",
@@ -211,6 +211,18 @@
"https://projects.fivethirtyeight.com/nfl-api/nfl_elo_latest.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/checking-our-work-data",
"name": "checking-our-work-data",
"displayName": "checking-our-work-<span class=\"lastword\">data</span>",
"articles": [
{
"date": "2023-02-02T16:30:00.000Z",
"title": "How Good Are FiveThirtyEight Forecasts?",
"url": "https://projects.fivethirtyeight.com/checking-our-work/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/world-cup-2022",
"name": "world-cup-2022",
@@ -227,6 +239,18 @@
"https://projects.fivethirtyeight.com/soccer-api/international/2022/wc_forecasts.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/covid-19-polls",
"name": "covid-19-polls",
"displayName": "covid-19-<span class=\"lastword\">polls</span>",
"articles": [
{
"date": "2022-11-29T20:20:08.000Z",
"title": "How Americans View Bidens Response To The Coronavirus Crisis",
"url": "https://projects.fivethirtyeight.com/coronavirus-polls/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/election-deniers",
"name": "election-deniers",
@@ -347,6 +371,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/nfl-elo-game",
"name": "nfl-elo-game",
"displayName": "nfl-elo-<span class=\"lastword\">game</span>",
"articles": [
{
"date": "2022-02-14T03:03:26.000Z",
"title": "Can You Beat FiveThirtyEights NFL Forecasts?",
"url": "https://projects.fivethirtyeight.com/2021-nfl-forecasting-game/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/redlining",
"name": "redlining",
@@ -371,6 +407,42 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/negro-leagues-player-ratings",
"name": "negro-leagues-player-ratings",
"displayName": "negro-leagues-player-<span class=\"lastword\">ratings</span>",
"articles": [
{
"date": "2021-02-25T11:00:00.000Z",
"title": "The Negro League Stars That MLB Kept Out — And Is Finally Recognizing",
"url": "https://projects.fivethirtyeight.com/negro-leagues-mlb/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/police-settlements",
"name": "police-settlements",
"displayName": "police-<span class=\"lastword\">settlements</span>",
"articles": [
{
"date": "2021-02-22T11:00:49.000Z",
"title": "Cities Spend Millions On Police Misconduct Every Year. Heres Why Its So Difficult to Hold Departments Accountable.",
"url": "https://fivethirtyeight.com/features/police-misconduct-costs-cities-millions-every-year-but-thats-where-the-accountability-ends/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/superbowl-ads",
"name": "superbowl-ads",
"displayName": "superbowl-<span class=\"lastword\">ads</span>",
"articles": [
{
"date": "2021-02-04T16:11:00.000Z",
"title": "According To Super Bowl Ads, Americans Love America, Animals And Sex",
"url": "https://projects.fivethirtyeight.com/super-bowl-ads/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/trump-approval-ratings",
"name": "trump-approval-ratings",
@@ -403,6 +475,18 @@
"https://projects.fivethirtyeight.com/congress-tracker-data/csv/vote_predictions.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/election-results",
"name": "election-results",
"displayName": "election-<span class=\"lastword\">results</span>",
"articles": [
{
"date": "2020-11-03T05:33:43.000Z",
"title": "2020 Election Forecast",
"url": "https://projects.fivethirtyeight.com/2020-election-forecast/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/election-forecasts-2020",
"name": "election-forecasts-2020",
@@ -473,6 +557,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/WNBA-stats",
"name": "WNBA-stats",
"displayName": "WNBA-<span class=\"lastword\">stats</span>",
"articles": [
{
"date": "2020-05-27T19:06:43.000Z",
"title": "Its Time To Give Basketballs Other GOAT Her Due",
"url": "https://fivethirtyeight.com/features/its-time-to-give-basketballs-other-goat-her-due/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/covid-geography",
"name": "covid-geography",
@@ -512,6 +608,18 @@
"https://projects.fivethirtyeight.com/endorsements-2020-data/endorsements-2020.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/nba-player-advanced-metrics",
"name": "nba-player-advanced-metrics",
"displayName": "nba-player-advanced-<span class=\"lastword\">metrics</span>",
"articles": [
{
"date": "2020-03-09T15:27:37.000Z",
"title": "Luka Dončić And The Mavs Are Pushing The Limits Of Offensive Efficiency",
"url": "https://fivethirtyeight.com/features/luka-doncic-and-the-mavs-are-pushing-the-limits-of-offensive-efficiency/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/impeachment-polls",
"name": "impeachment-polls",
@@ -603,6 +711,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/candidate-emails",
"name": "candidate-emails",
"displayName": "candidate-<span class=\"lastword\">emails</span>",
"articles": [
{
"date": "2019-07-11T15:33:15.000Z",
"title": "What Our Inbox Tells Us About How Democrats Are Tackling Trump",
"url": "https://fivethirtyeight.com/features/which-democrats-are-campaigning-on-trump/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nba-draymond",
"name": "nba-draymond",
@@ -643,6 +763,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/twitter-overlap",
"name": "twitter-overlap",
"displayName": "twitter-<span class=\"lastword\">overlap</span>",
"articles": [
{
"date": "2019-06-12T15:24:07.000Z",
"title": "Which 2020 Candidates Have The Most In Common … On Twitter?",
"url": "https://fivethirtyeight.com/features/which-2020-candidates-have-the-most-in-common-on-twitter/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/trump-lawsuits",
"name": "trump-lawsuits",
@@ -825,6 +957,18 @@
"https://projects.fivethirtyeight.com/congress-model-2018/governor_state_forecast.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/actblue-analysis",
"name": "actblue-analysis",
"displayName": "actblue-<span class=\"lastword\">analysis</span>",
"articles": [
{
"date": "2018-10-25T17:31:42.000Z",
"title": "How ActBlue Is Trying To Turn Small Donations Into A Blue Wave",
"url": "https://fivethirtyeight.com/features/how-actblue-is-trying-to-turn-small-donations-into-a-blue-wave"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/primary-candidates-2018",
"name": "primary-candidates-2018",
@@ -1035,6 +1179,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/redistricting-atlas-data",
"name": "redistricting-atlas-data",
"displayName": "redistricting-atlas-<span class=\"lastword\">data</span>",
"articles": [
{
"date": "2018-01-25T11:00:00.000Z",
"title": "The Atlas Of Redistricting",
"url": "https://projects.fivethirtyeight.com/redistricting-maps/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/next-bechdel",
"name": "next-bechdel",
@@ -1169,6 +1325,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/undefeated-boxers",
"name": "undefeated-boxers",
"displayName": "undefeated-<span class=\"lastword\">boxers</span>",
"articles": [
{
"date": "2017-08-18T18:47:32.000Z",
"title": "Mayweather Is Defined By The Zero Next To His Name",
"url": "https://fivethirtyeight.com/features/mayweather-is-defined-by-the-zero-next-to-his-name/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/chess-transfers",
"name": "chess-transfers",
@@ -1452,6 +1620,37 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/uber-tlc-foil-response",
"name": "uber-tlc-foil-response",
"displayName": "uber-tlc-foil-<span class=\"lastword\">response</span>",
"articles": [
{
"date": "2015-12-09T16:19:40.000Z",
"title": "Is Uber Making NYC Rush-Hour Traffic Worse?",
"rowspan": 4,
"url": "https://fivethirtyeight.com/features/is-uber-making-nyc-rush-hour-traffic-worse/"
},
{
"date": "2015-10-13T20:44:12.000Z",
"title": "Uber Is Taking Millions Of Manhattan Rides Away From Taxis",
"rowspan": 0,
"url": "https://fivethirtyeight.com/features/uber-is-taking-millions-of-manhattan-rides-away-from-taxis/"
},
{
"date": "2015-08-28T10:30:36.000Z",
"title": "Public Transit Should Be Ubers New Best Friend",
"rowspan": 0,
"url": "https://fivethirtyeight.com/features/public-transit-should-be-ubers-new-best-friend/"
},
{
"date": "2015-08-10T18:06:17.000Z",
"title": "Uber Is Serving New Yorks Outer Boroughs More Than Taxis Are",
"rowspan": 0,
"url": "https://fivethirtyeight.com/features/uber-is-serving-new-yorks-outer-boroughs-more-than-taxis-are/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/tarantino",
"name": "tarantino",
@@ -1970,6 +2169,18 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/comma-survey-data",
"name": "comma-survey-data",
"displayName": "comma-survey-<span class=\"lastword\">data</span>",
"articles": [
{
"date": "2014-06-17T16:28:55.000Z",
"title": "Elitist, Superfluous, Or Popular? We Polled Americans on the Oxford Comma",
"url": "http://fivethirtyeight.com/features/elitist-superfluous-or-popular-we-polled-americans-on-the-oxford-comma/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/world-cup-predictions",
"name": "world-cup-predictions",
@@ -2127,18 +2338,6 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/undefeated-boxers",
"name": "undefeated-boxers",
"displayName": "undefeated-<span class=\"lastword\">boxers</span>",
"articles": [
{
"date": "2017-08-18T18:47:32.000Z",
"title": "Mayweather Is Defined By The Zero Next To His Name",
"url": "https://fivethirtyeight.com/features/mayweather-is-defined-by-the-zero-next-to-his-name/"
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/march-madness-predictions",
"name": "march-madness-predictions",

View File

@@ -1,9 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
serverRuntimeConfig: {
github_pat: process.env.GITHUB_PAT ? process.env.GITHUB_PAT : null,
},
}
module.exports = nextConfig

File diff suppressed because it is too large Load Diff

View File

@@ -9,35 +9,18 @@
"lint": "next lint"
},
"dependencies": {
"@flowershow/core": "^0.4.13",
"@headlessui/react": "^1.7.14",
"@heroicons/react": "^2.0.18",
"@portaljs/components": "^0.1.8",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "20.1.1",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"autoprefixer": "10.4.14",
"eslint": "8.40.0",
"eslint-config-next": "13.4.1",
"flexsearch": "^0.7.31",
"next": "13.4.1",
"next-mdx-remote": "^4.4.1",
"next-seo": "^6.0.0",
"octokit": "^2.0.14",
"postcss": "8.4.23",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"remark": "^14.0.3",
"remark-code-frontmatter": "^1.0.0",
"remark-excerpt": "^1.0.0-beta.1",
"remark-extract-frontmatter": "^3.2.0",
"remark-frontmatter": "^4.0.1",
"remark-gfm": "^3.0.1",
"tailwindcss": "3.3.2",
"timeago.js": "^4.0.2",
"to-vfile": "^7.2.4",
"typescript": "5.0.4"
}
}

View File

@@ -1,5 +1,4 @@
import '@/styles/globals.css'
import '@portaljs/ckan/styles.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {

View File

@@ -0,0 +1,13 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
type Data = {
name: string
}
export default function handler(
req: NextApiRequest,
res: NextApiResponse<Data>
) {
res.status(200).json({ name: 'John Doe' })
}

View File

@@ -0,0 +1,195 @@
import Image from 'next/image';
import { Inter } from 'next/font/google';
import { format } from 'timeago.js'
import { promises as fs } from 'fs';
import path from 'path';
const inter = Inter({ subsets: ['latin'] });
interface Article {
date: string;
title: string;
url: string;
}
interface Dataset {
url: string;
name: string;
displayName: string;
articles: Article[];
}
export function MobileItem({dataset} : { dataset: Dataset}) {
return (
<div className="flex gap-x-2 pb-2 py-4 items-center justify-between border-b border-zinc-600">
<div className="flex flex-col">
<span className="font-light">{dataset.name}</span>
{dataset.articles.map((article) => (
<div className='py-1 flex flex-col'>
<span className="font-bold hover:underline">{article.title}</span>
<span className="font-light text-base">{format(article.date)}</span>{' '}
</div>
))}
</div>
<div className="flex flex-col justify-start">
<a
className="border border-zinc-900 font-light px-4 py-1 text-sm transition hover:bg-zinc-900 hover:text-white"
href={dataset.url}
target="_blank"
>
info
</a>
{/*
<button>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-12 h-12 text-blue-400 hover:text-blue-300 transition mt-1"
>
<path
fillRule="evenodd"
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-.53 14.03a.75.75 0 001.06 0l3-3a.75.75 0 10-1.06-1.06l-1.72 1.72V8.25a.75.75 0 00-1.5 0v5.69l-1.72-1.72a.75.75 0 00-1.06 1.06l3 3z"
clipRule="evenodd"
/>
</svg>
</button> */}
</div>
</div>
);
}
export function DesktopItem({dataset} : { dataset: Dataset}) {
return (
<>
{dataset.articles.map((article, index) => (
<tr className={`${index === (dataset.articles.length - 1) ? 'border-b' : ''} border-zinc-400`}>
<td className="py-8 font-light">{index === 0 ? dataset.name : ''}</td>
<td>
<a className="py-8 font-bold hover:underline" href={article.url}>
{article.title}
</a>
</td>
<td className="py-8 font-light text-base min-w-[120px]">{format(article.date)}</td>
<td className="py-8">
{index === 0 && (
<a
className="border border-zinc-900 font-light px-[25px] py-2.5 text-sm transition hover:bg-zinc-900 hover:text-white"
href={dataset.url}
target="_blank"
>
info
</a>
)}
</td>
{/*
<td>
<button>
<svg
xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 24 24"
fill="currentColor"
className="w-12 h-12 text-blue-400 hover:text-blue-300 transition mt-1"
>
<path
fillRule="evenodd"
d="M12 2.25c-5.385 0-9.75 4.365-9.75 9.75s4.365 9.75 9.75 9.75 9.75-4.365 9.75-9.75S17.385 2.25 12 2.25zm-.53 14.03a.75.75 0 001.06 0l3-3a.75.75 0 10-1.06-1.06l-1.72 1.72V8.25a.75.75 0 00-1.5 0v5.69l-1.72-1.72a.75.75 0 00-1.06 1.06l3 3z"
clipRule="evenodd"
/>
</svg>
</button>
</td>*/}
</tr>
))}
</>
);
}
export async function getStaticProps() {
const jsonDirectory = path.join(
process.cwd(),
'/datasets.json'
);
const datasetString = await fs.readFile(jsonDirectory, 'utf8');
const datasets = JSON.parse(datasetString)
return {
props: { datasets },
};
}
export default function Home( { datasets }: { datasets: Dataset[] }) {
return (
<>
<header className="max-w-5xl mx-auto mt-8 w-full">
<div className="border-b-2 pb-2.5 mx-2 border-zinc-800">
<h1>
<span className="sr-only">FiveThirtyEight</span>
<a className='flex gap-x-2 items-center' href="http://fivethirtyeight.com">
<img
width="197"
height="25"
alt="FiveThirtyEight"
src="data:image/svg+xml;base64,PHN2ZyBpZD0iTGF5ZXJfMSIgZGF0YS1uYW1lPSJMYXllciAxIiB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCA0MjEgNTMuNzYiPjxkZWZzPjxzdHlsZT4uY2xzLTF7ZmlsbDojMDEwMTAxO308L3N0eWxlPjwvZGVmcz48dGl0bGU+QXJ0Ym9hcmQgOTU8L3RpdGxlPjxwYXRoIGNsYXNzPSJjbHMtMSIgZD0iTTAgMGgyNXY4SDl2MTBoMTV2OEg5djE3SDBWMHpNMzEgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdIMzF6bTUtMzZoOHY4aC04ek0xNzkgMzZoNVYxOGgtNXYtOGgxM3YyNmg0djdoLTE3em01LTM2aDh2OGgtOHpNMzE2IDM2aDVWMThoLTV2LThoMTN2MjZoNHY3aC0xN3ptNS0zNmg4djhoLTh6TTU0IDI3VjEwaDh2MTVsNCA5Ljk4aDFMNzEgMjVWMTBoOHYxN2wtNyAxNkg2MWwtNy0xNnpNMTExIDQzSDk3LjQyQzg5LjIzIDQzIDg1IDM5LjE5IDg1IDMxLjE3VjIyYzAtNy41NyA0LjMtMTMgMTMtMTMgOS4zMyAwIDEzIDUuMDcgMTMgMTR2N0g5NHYxLjc0YzAgMi42MiAxIDQuMjYgMy40MiA0LjI2SDExMXpNOTQgMjNoOHYtMS41NWMwLTIuNjItMS4wNi01LjQ1LTQuMTMtNS40NS0yLjc5IDAtMy44NyAyLjItMy44NyA1LjQ1ek0xMjUgOGgtMTBWMGgyOXY4aC0xMHYzNWgtOVY4ek0yMDIgNDNWMTBoOHY0YzEuMTQtMi40NSAzLjc1LTQgNy4yMi00SDIyMHY4aC02Yy0yLjg0IDAtNCAuOTQtNCAzLjlWNDN6TTI0NSA0M2gtNC44NEMyMzMuMDUgNDMgMjMwIDM5LjMxIDIzMCAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0gyNDV6TTQyMSA0M2gtNC44NEM0MDkuMDUgNDMgNDA2IDM5LjMxIDQwNiAzMS44NVYxOGgtNnYtOGg2VjNoOHY3aDd2OGgtN2wtLjA3IDEzLjkzYzAgMi4yMi45MyA0LjA3IDMuNjYgNC4wN0g0MjF6TTI1NC4yNiA1My43Nmw0LjYxLTkuNUwyNTEgMjdWMTBoOHYxNWw0IDEwaDFsNC0xMFYxMGg4djE3bC0xMi4zIDI2Ljc2aC05LjQ0ek0yODQgMGgyNXY4aC0xNnY5aDE1djhoLTE1djEwaDE2djhoLTI1VjB6TTMzNyA0OHYtMmgxNi4xYzIgMCAyLjktLjE4IDIuOS0xLjI3di0uMzRjMC0xLjA4LS45MS0xLjM5LTIuOS0xLjM5SDM0MHYtNWw1LTVjLTUuMjktMS40OC04LTUuNDMtOC0xMXYtMWMwLTcuNTYgNC40NC0xMiAxNC0xMmEyMS45MyAyMS45MyAwIDAgMSA1Ljk1IDFMMzYxIDRsNSAzLTQgNmMxLjM3IDEuOTMgMyA0LjkzIDMgOHYxYzAgNy0zLjMgMTAuNjYtMTIgMTFsLTMgNGg2YzUuOTIgMCA5IDIuNjIgOSA3LjY4di4xMWMwIDUuMDYtMi43MSA4LjIxLTguNjIgOC4yMWgtMTNjLTQuMjkgMC02LjM4LTEuODQtNi4zOC01em0xOS0yNXYtM2MwLTMuMy0xLjMzLTQtNS00cy01IC43LTUgNHYzYzAgMy4zIDEuMzkgNCA1IDRzNS0uNyA1LTR6TTM4MCA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuNC00IDctNCA2LjI2IDAgOSAzLjA4IDkgMTAuNzZWNDNoLThWMjJjMC0zLjEzLTEuMDctNS00LTVzLTQgMS44Ny00IDV6TTE1NyA0M2gtOFYwaDh2MTRjMS4xNC0yLjY3IDMuOTEtNCA3LjQ5LTQgNi4yNiAwIDguNTEgMy4xMyA4LjUxIDEwLjgxVjQzaC04VjIxYzAtMy4xMy0xLjA3LTQuNDQtNC00LjQ0cy00IDIuMjYtNCA1LjM5eiIvPjwvc3ZnPg=="
/> by PortalJS
</a>
</h1>
</div>
</header>
<main
className={`flex min-h-screen flex-col items-center max-w-5xl mx-auto pt-20 px-2.5 ${inter.className}`}
>
<div>
<h1 className="text-[40px] font-bold text-zinc-800 text-center">
Our Data
</h1>
<p className="max-w-2xl text-lg text-center text-zinc-700">
Were sharing the data and code behind some of our articles and
graphics. We hope youll use it to check our work and to create
stories and visualizations of&nbsp;your&nbsp;own.
</p>
</div>
<article className="w-full px-2 md:hidden py-4">{datasets.map(dataset => <MobileItem dataset={dataset} />)}</article>
<table className="w-full mt-10 mb-4 hidden md:table">
<thead className="border-b-4 pb-2 border-zinc-900">
<tr>
<th className="uppercase text-left font-light text-xs pb-3">
data set
</th>
<th className="uppercase text-left font-light text-xs pb-3">
related content
</th>
<th className="uppercase text-left font-light text-xs pb-3">
last updated
</th>
</tr>
</thead>
<tbody>{datasets.map(dataset => <DesktopItem dataset={dataset} />)}</tbody>
</table>
<p className="text-[13px] py-8">
Unless otherwise noted, our data sets are available under the{' '}
<a
className="text-blue-400 hover:underline"
href="http://creativecommons.org/licenses/by/4.0/"
>
Creative Commons Attribution 4.0 International license
</a>
, and the code is available under the{' '}
<a
className="text-blue-400 hover:underline"
href="http://opensource.org/licenses/MIT"
>
MIT license
</a>
. If you find this information useful, please{' '}
<a
className="text-blue-400 hover:underline"
href="mailto:data@fivethirtyeight.com"
>
let us know
</a>
.
</p>
</main>
</>
);
}

View File

Before

Width:  |  Height:  |  Size: 25 KiB

After

Width:  |  Height:  |  Size: 25 KiB

View File

Before

Width:  |  Height:  |  Size: 1.3 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

Before

Width:  |  Height:  |  Size: 629 B

After

Width:  |  Height:  |  Size: 629 B

View File

@@ -1,3 +1,3 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind utilities;

View File

@@ -14,5 +14,5 @@ module.exports = {
},
},
},
plugins: [require('@tailwindcss/typography')],
plugins: [],
}

View File

@@ -1,35 +0,0 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
# dependencies
/node_modules
/.pnp
.pnp.js
# testing
/coverage
# next.js
/.next/
/out/
# production
/build
# misc
.DS_Store
*.pem
# debug
npm-debug.log*
yarn-debug.log*
yarn-error.log*
# local env files
.env*.local
# vercel
.vercel
# typescript
*.tsbuildinfo
next-env.d.ts

View File

@@ -1,44 +0,0 @@
This is a replica of the awesome data.fivethirtyeight.com using PortalJS.
You might be asking why we did that, there are three main reasons:
- The website has a great UI, with multiple datasets being displayed elegantly and with simplicity.
- PortalJS allows us to add more functionality to it e.g dataset previews and search functionality.
- The project follows our same principles of open sourcing and free data, with every dataset being publicly available on Github.
## Getting Started
First, run the development server:
```bash
npm run dev
# or
yarn dev
# or
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
You can start editing the page by modifying `pages/index.tsx`. The page auto-updates as you edit the file.
[API routes](https://nextjs.org/docs/api-routes/introduction) can be accessed on [http://localhost:3000/api/hello](http://localhost:3000/api/hello). This endpoint can be edited in `pages/api/hello.ts`.
The `pages/api` directory is mapped to `/api/*`. Files in this directory are treated as [API routes](https://nextjs.org/docs/api-routes/introduction) instead of React pages.
This project uses [`next/font`](https://nextjs.org/docs/basic-features/font-optimization) to automatically optimize and load Inter, a custom Google Font.
## Learn More
To learn more about Next.js, take a look at the following resources:
- [Next.js Documentation](https://nextjs.org/docs) - learn about Next.js features and API.
- [Learn Next.js](https://nextjs.org/learn) - an interactive Next.js tutorial.
You can check out [the Next.js GitHub repository](https://github.com/vercel/next.js/) - your feedback and contributions are welcome!
## Deploy on Vercel
The easiest way to deploy your Next.js app is to use the [Vercel Platform](https://vercel.com/new?utm_medium=default-template&filter=next.js&utm_source=create-next-app&utm_campaign=create-next-app-readme) from the creators of Next.js.
Check out our [Next.js deployment documentation](https://nextjs.org/docs/deployment) for more details.

View File

@@ -1,23 +0,0 @@
import Link from "next/link";
function HomeIcon({ className = "" }) {
return <div className={`inline-block w-4 ${className}`}><svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24"> <path d="M 12 2 A 1 1 0 0 0 11.289062 2.296875 L 1.203125 11.097656 A 0.5 0.5 0 0 0 1 11.5 A 0.5 0.5 0 0 0 1.5 12 L 4 12 L 4 20 C 4 20.552 4.448 21 5 21 L 9 21 C 9.552 21 10 20.552 10 20 L 10 14 L 14 14 L 14 20 C 14 20.552 14.448 21 15 21 L 19 21 C 19.552 21 20 20.552 20 20 L 20 12 L 22.5 12 A 0.5 0.5 0 0 0 23 11.5 A 0.5 0.5 0 0 0 22.796875 11.097656 L 12.716797 2.3027344 A 1 1 0 0 0 12.710938 2.296875 A 1 1 0 0 0 12 2 z"/></svg></div>
}
export default function Breadcrumbs({ links }: { links: { title: string, href?: string, target?: string }[] }) {
const current = links.at(-1);
return <div className="flex items-center uppercase font-black text-xs">
<Link className="flex items-center" href='/'><HomeIcon /></Link>
{/* {links.length > 1 && links.slice(0, -1).map((link) => {
return <>
<span className="mx-4">/</span>
<Link href={link.href}>{link.title}</Link>
</>
})} */}
<span className="mx-4">/</span>
<span>{current?.title}</span>
</div >
}

Some files were not shown because too many files have changed in this diff Show More