Compare commits

..

64 Commits

Author SHA1 Message Date
Luccas Mateus de Medeiros Gomes
c85934d17a [examples/fivethirtyeight][lg] - first commmit of 538 Example 2023-05-08 20:44:13 -03:00
João Demenech
6705bc1e2d merge: implement tutorial improvements based on feedback
**Issue:** https://github.com/datopian/portaljs/issues/839

## Changes

- Update info about required Node version
- Remove mention to automatic reload from docs
2023-05-08 17:20:36 -03:00
deme
7dfde0935e [#839, docs][xs]: remove mention to automtic reload 2023-05-08 17:17:45 -03:00
deme
3f76bea895 [#839,docs][xs]: change Node version to either 16 or 18, fix small typo 2023-05-08 16:30:04 -03:00
João Demenech
f17efce02e Merge pull request #857 from datopian/alan-turing-fixes
[alan-turing][sm] - fixes requested
2023-05-08 15:40:23 -03:00
Luccas Mateus de Medeiros Gomes
61b96c20ed [alan-turing][xs] - fix links 2023-05-08 14:36:59 -03:00
Luccas Mateus de Medeiros Gomes
4cadc50e46 [alan-turing][m] - additional fixes 2023-05-08 13:25:34 -03:00
Rufus Pollock
684f473e62 Update Gallery.tsx 2023-05-08 17:59:13 +02:00
Rufus Pollock
b963cf2cbb [ex/turing/README][xs]: quick proofing. 2023-05-08 16:08:03 +02:00
Luccas Mateus de Medeiros Gomes
43ac5cfb47 [alan-turing][sm] - fix typo 2023-05-08 08:56:17 -03:00
Luccas Mateus de Medeiros Gomes
f6b8ef2190 [alan-turing][sm] - fixes requested 2023-05-08 08:44:22 -03:00
Anuar Ustayev (aka Anu)
e5c89308d1 Merge pull request #852 from datopian/components-tutorial
[docs][m] - components api section
2023-05-07 11:45:56 +06:00
Anuar Ustayev (aka Anu)
8b51123290 [docs][s]: update and rename components-api.md to components.md 2023-05-07 11:10:26 +06:00
Anuar Ustayev (aka Anu)
53b64b81c9 [docs][xs]: bring back prev link to prev tutorial as was removed by mistake. 2023-05-07 11:06:53 +06:00
Anuar Ustayev (aka Anu)
9fe08fcd1b [docs][xs]: no need to link to the next tutorial as it's irrelevant to getting started series. 2023-05-07 11:05:21 +06:00
Anuar Ustayev (aka Anu)
7150150db0 [sidebar][xs]: moved the components page to higher level. 2023-05-07 11:04:34 +06:00
Luccas Mateus de Medeiros Gomes
5cc312b55b [docs][m] - components api section 2023-05-06 14:31:48 -03:00
João Demenech
5c8431bf39 Fix code blocks not being displayed properly on light mode (#851)
* [#803,blogs][m]: fix code blocks not being displayed properly on light mode

* [docs][m] - fix problems with merge

---------

Co-authored-by: Luccas Mateus <Luccasmmg@gmail.com>
2023-05-06 13:36:49 -03:00
Anuar Ustayev (aka Anu)
45c07f829a Merge pull request #850 from datopian/feature/lhs-navigation
LHS Navigation
2023-05-06 10:35:00 +06:00
deme
53ea7957c0 [blogs][xs]: fix issue with date field 2023-05-05 16:30:44 -03:00
deme
0c65a145c8 [#809,docs][l]: fix Vercel build, add examples do sidebar, fix blogs list 2023-05-05 16:17:28 -03:00
deme
91caeff6c3 [#809,docs][xl]: add LHS sidebar to docs 2023-05-05 15:33:17 -03:00
deme
0f65e253da Merge branch 'main' of github.com:datopian/portal.js into feature/lhs-navigation 2023-05-05 10:32:55 -03:00
Luccas Mateus de Medeiros Gomes
c390a21611 [docs][sm] - fix typo 2023-05-05 09:54:16 -03:00
Luccas Mateus de Medeiros Gomes
dac7d03d05 [learn-example][sm] - remove console.log and fix typo 2023-05-05 09:12:31 -03:00
Luccas Mateus de Medeiros Gomes
89ba260b70 [docs][m] - tutorial part 4 2023-05-05 08:56:09 -03:00
Luccas Mateus de Medeiros Gomes
ce847746d2 [docs][sm] - use "groups" instead of title for facets 2023-05-05 08:54:19 -03:00
deme
5328492575 [#809,docs,navigation][xl]: initial commit 2023-05-04 22:34:17 -03:00
João Demenech
e52e789314 Merge pull request #849 from datopian/tutorial-part-4
[learn-example][m] - add extra metadata fields
2023-05-04 22:31:52 -03:00
Luccas Mateus de Medeiros Gomes
0e8cac7d50 [learn-example][m] - add extra metadata fields 2023-05-04 20:54:17 -03:00
João Demenech
2e30c76a3d [#842,package.json][xs]: move eslint and @types deps to dependencies (#848) 2023-05-04 19:59:12 -03:00
João Demenech
edb2354945 merge: change version to 0.1.0, publish new version which adds (#847)
## Changes:

- @portaljs/components version bumped from 0.0.3 to 0.1.0
- New version adds the Catalog component
2023-05-04 13:56:17 -03:00
João Demenech
5834a4a470 Website Misc Improvements (#836)
* [#803,website][s]: remove gallery button from hero, add gallery link to navbar, make docs listed on /blog be displayed as blog posts

* [#803,analytics,website][xs]: implement GA
2023-05-04 13:43:13 -03:00
João Demenech
90b93e6819 [#819,xlsx][m]: remove data-literate, excel and everything related to the xlsx dependency (#845) 2023-05-04 13:42:13 -03:00
Luccas Mateus de Medeiros Gomes
ad52721a38 [components][m] - move catalog to @portaljs/components 2023-05-04 11:14:39 -03:00
Luccas Mateus de Medeiros Gomes
cf2a93abfd [docs][sm] - change layout of docs 2023-05-04 09:47:02 -03:00
Luccas Mateus de Medeiros Gomes
8afb30c96b [docs][sm] - add filters section to docs 2023-05-04 08:22:01 -03:00
Luccas Mateus
94a3c2a5f0 [learn-example][m] - add facets to catalog component (#841) 2023-05-04 07:39:59 -03:00
João Demenech
a0620f9255 merge: components package preparation, replace components on learn-example (#835)
* [#812,package][xl]: package preparation, replace components on learn-example

* [#812,package][xs]: upgrade portaljs/components version on learn-example

* [package][xs]: add deboundebinput back to lean-example
2023-05-03 19:27:51 -03:00
Luccas Mateus de Medeiros Gomes
e5513f59a6 [learn-example][sm] - fix build 2023-05-03 11:45:57 -03:00
Luccas Mateus
1782f23b84 Part 3 tutorial - Creating an index page (#834)
* [learn-example][m] - code section for the tutorial part 3

* [learn-example][sm] - dont panic when no markdown.db file found

* [docs][m] - creating an inedx page
2023-05-03 11:30:39 -03:00
João Demenech
72405162a1 merge: fix storybook build
* [package][xs]: remove parameter that was not being used

* [package][xs]: remove import that's breaking the build

* [package][xs]: trying to fix build error on Vercel
2023-05-02 17:31:48 -03:00
João Demenech
982733737d merge: Components package initial setup + Components extraction
**Issue:** https://github.com/datopian/portaljs/issues/812

## Changes

- Renamed old package to "components-old"
- Created a Vite project based on https://dev.to/nicolaserny/create-a-react-component-library-with-vite-and-typescript-1ih9 and  https://zach.codes/build-your-own-flexible-component-library-using-tsdx-typescript-tailwind-css-headless-ui/
- Implemented tailwind on it
- Extracted components
  - LineChart
  - Table
  - Vega
  - VegaLite
- Created stories for the extracted components
2023-05-02 16:41:28 -03:00
deme
ea5802a908 [#812,package][xl]: changed project to Vite, created stories for LineChart, Table, Vega and VegaLite 2023-05-02 16:37:22 -03:00
Luccas Mateus
229a7b5324 [alan-turing][m] - fix markdown (#831) 2023-05-02 15:31:45 -03:00
Luccas Mateus
014c4c043d [alan-turing][m] - small tweaks (#830) 2023-05-02 12:53:10 -03:00
Luccas Mateus de Medeiros Gomes
ed3a26cd6d [alan-turing][sm] - fix build 2023-05-01 21:40:46 -03:00
Luccas Mateus
026059184a [alan-turing][m] - individual pages (#828) 2023-05-01 21:06:52 -03:00
João Demenech
a041d69282 merge: tutorial VI
**Issue:** https://github.com/datopian/portaljs/issues/821

## Changes

- Added `npm run export` command to `learn-example`
- Added "Deploying your PortalJS app" section to `/docs`
  - Deploy to Vercel
  - One-Click Deploy (to Vercel)
  - Deploy to  Cloudflare
2023-05-01 19:09:18 -03:00
deme
016f3e20e9 [#812,package][xl]: add Table component and story for it 2023-05-01 18:56:22 -03:00
deme
169a92d313 [#812,package][xl]: initial versioning of the package 2023-05-01 15:53:42 -03:00
deme
14abd5b768 [tutorial][xs]: fix typo 2023-05-01 15:02:59 -03:00
deme
4aaabba229 [#821,tutorial][m]: add export npm command to example-learn, add tutorial VI to /docs 2023-05-01 14:51:02 -03:00
Luccas Mateus de Medeiros Gomes
cc43597130 [learn-example][sm] - fix dark mode styling 2023-05-01 11:16:52 -03:00
João Demenech
d9a6ea4ef1 [docs][xs]: fix install command after rename 2023-05-01 08:30:17 -03:00
Luccas Mateus
f6b94ee254 Alan turing portal (#815)
* [alan-turing-portal][m] - initial commit

* [alan-turing][m] - first page with search

* [alan-turing][m] - cleanup
2023-04-29 23:37:30 -03:00
Luccas Mateus de Medeiros Gomes
04b05c0896 [learn-example][sm] - use getstaticprops 2023-04-29 13:54:51 -03:00
deme
5b4d2d1990 [#814,tutorial,docs][xl]: add initial version of the second tutorial, rename basic-example to learn-example, clean up learn-example 2023-04-28 21:57:49 -03:00
Luccas Mateus de Medeiros Gomes
b7e2e8e6b8 [basic-example][sm] - fix mistake 2023-04-28 09:51:38 -03:00
João Demenech
b6100546e3 merge: new docs inspired by Next.js
## Changes:

- Move the first version of the tutorial aside
- Rewrite the tutorial so that it's more similar to the Next.js one
- Minor fixes on the basic-example
2023-04-28 07:31:41 -03:00
Luccas Mateus de Medeiros Gomes
58ca032d3f [basic-example][m] - update data to breaking bad
- Fix LineChart and allow the use of URLs
- Add applyFullWidthDirective back
- Fix favicon
- Remove data_1.csv and data_2.csv in favour of data.csv
- Remove vestiges of Vercel
2023-04-27 21:38:48 -03:00
Luccas Mateus de Medeiros Gomes
4b5329a93e Merge branch 'feature/nextjs-inspired-docs' of github.com:datopian/portaljs into feature/nextjs-inspired-docs 2023-04-27 20:58:36 -03:00
deme
298b59d291 [#801,docs,tutorial][m]: move initial tutorial aside, rewrite the tutorial in a fashion more similar to the Next.js tutorial 2023-04-27 19:36:46 -03:00
Luccas Mateus
41e7f8ad8d Basic example part 2 (#806)
* [basic-example][m] - initial commit

* [basic-example][m] - fix fetching of actual data

* [basic-example][m] - remove everything related to multiple pages

* [basic-example][sm] fix rendering issue

* [basic-example][m] - remove middleware

* [basic-example][m] - multiple datasets

* [basic-example][m] - multiple datasetst
2023-04-27 15:42:10 -03:00
200 changed files with 61766 additions and 5282 deletions

4
.gitignore vendored
View File

@@ -44,3 +44,7 @@ Thumbs.db
# Env
.env
**/.env
# MarkdownDB
*.db
**/*.db

35
examples/alan-turing-portal/.gitignore vendored Normal file
View File

@@ -0,0 +1,35 @@
# 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*
.pnpm-debug.log*
# local env files
.env*.local
# vercel
.vercel
# generated files
/public/rss/

View File

@@ -0,0 +1,129 @@
# Tailwind UI License
## Personal License
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
The license grants permission to **one individual** (the Licensee) to access and use the Components and Templates.
You **can**:
- Use the Components and Templates to create unlimited End Products.
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
You **cannot**:
- Use the Components and Templates to create End Products that are designed to allow an End User to build their own End Products using the Components and Templates or derivatives of the Components and Templates.
- Re-distribute the Components and Templates or derivatives of the Components and Templates separately from an End Product, neither in code or as design assets.
- Share your access to the Components and Templates with any other individuals.
- Use the Components and Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
### Example usage
Examples of usage **allowed** by the license:
- Creating a personal website by yourself.
- Creating a website or web application for a client that will be owned by that client.
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components (like a conference organization app that uses the components for its UI for example) that is free and open source, where the source code is publicly available.
Examples of usage **not allowed** by the license:
- Creating a repository of your favorite Tailwind UI components or templates (or derivatives based on Tailwind UI components or templates) and publishing it publicly.
- Creating a React or Vue version of Tailwind UI and making it available either for sale or for free.
- Create a Figma or Sketch UI kit based on the Tailwind UI component designs.
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind UI.
- Creating a theme, template, or project starter kit using the components or templates and making it available either for sale or for free.
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
In simple terms, use Tailwind UI for anything you like as long as it doesn't compete with Tailwind UI.
### Personal License Definitions
Licensee is the individual who has purchased a Personal License.
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind UI license.
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
End User is a user of an End Product.
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
## Team License
Tailwind Labs Inc. grants you an on-going, non-exclusive license to use the Components and Templates.
The license grants permission for **up to 25 Employees and Contractors of the Licensee** to access and use the Components and Templates.
You **can**:
- Use the Components and Templates to create unlimited End Products.
- Modify the Components and Templates to create derivative components and templates. Those components and templates are subject to this license.
- Use the Components and Templates to create unlimited End Products for unlimited Clients.
- Use the Components and Templates to create End Products where the End Product is sold to End Users.
- Use the Components and Templates to create End Products that are open source and freely available to End Users.
You **cannot**:
- Use the Components or Templates to create End Products that are designed to allow an End User to build their own End Products using the Components or Templates or derivatives of the Components or Templates.
- Re-distribute the Components or Templates or derivatives of the Components or Templates separately from an End Product.
- Use the Components or Templates to create End Products that are the property of any individual or entity other than the Licensee or Clients of the Licensee.
- Use the Components or Templates to produce anything that may be deemed by Tailwind Labs Inc, in their sole and absolute discretion, to be competitive or in conflict with the business of Tailwind Labs Inc.
### Example usage
Examples of usage **allowed** by the license:
- Creating a website for your company.
- Creating a website or web application for a client that will be owned by that client.
- Creating a commercial SaaS application (like an invoicing app for example) where end users have to pay a fee to use the application.
- Creating a commercial self-hosted web application that is sold to end users for a one-time fee.
- Creating a web application where the primary purpose is clearly not to simply re-distribute the components or templates (like a conference organization app that uses the components or a template for its UI for example) that is free and open source, where the source code is publicly available.
Examples of use **not allowed** by the license:
- Creating a repository of your favorite Tailwind UI components or template (or derivatives based on Tailwind UI components or templates) and publishing it publicly.
- Creating a React or Vue version of Tailwind UI and making it available either for sale or for free.
- Creating a "website builder" project where end users can build their own websites using components or templates included with or derived from Tailwind UI.
- Creating a theme or template using the components or templates and making it available either for sale or for free.
- Creating an admin panel tool (like [Laravel Nova](https://nova.laravel.com/) or [ActiveAdmin](https://activeadmin.info/)) that is made available either for sale or for free.
- Creating any End Product that is not the sole property of either your company or a client of your company. For example your employees/contractors can't use your company Tailwind UI license to build their own websites or side projects.
### Team License Definitions
Licensee is the business entity who has purchased a Team License.
Components and Templates are the source code and design assets made available to the Licensee after purchasing a Tailwind UI license.
End Product is any artifact produced that incorporates the Components or Templates or derivatives of the Components or Templates.
End User is a user of an End Product.
Employee is a full-time or part-time employee of the Licensee.
Contractor is an individual or business entity contracted to perform services for the Licensee.
Client is an individual or entity receiving custom professional services directly from the Licensee, produced specifically for that individual or entity. Customers of software-as-a-service products are not considered clients for the purpose of this document.
## Enforcement
If you are found to be in violation of the license, access to your Tailwind UI account will be terminated, and a refund may be issued at our discretion. When license violation is blatant and malicious (such as intentionally redistributing the Components or Templates through private warez channels), no refund will be issued.
The copyright of the Components and Templates is owned by Tailwind Labs Inc. You are granted only the permissions described in this license; all other rights are reserved. Tailwind Labs Inc. reserves the right to pursue legal remedies for any unauthorized use of the Components or Templates outside the scope of this license.
## Liability
Tailwind Labs Inc.s liability to you for costs, damages, or other losses arising from your use of the Components or Templates — including third-party claims against you — is limited to a refund of your license fee. Tailwind Labs Inc. may not be held liable for any consequential damages related to your use of the Components or Templates.
This Agreement is governed by the laws of the Province of Ontario and the applicable laws of Canada. Legal proceedings related to this Agreement may only be brought in the courts of Ontario. You agree to service of process at the e-mail address on your original order.
## Questions?
Unsure which license you need, or unsure if your use case is covered by our licenses?
Email us at [support@tailwindui.com](mailto:support@tailwindui.com) with your questions.

View File

@@ -0,0 +1,25 @@
This demo data portal is designed for https://hatespeechdata.com. It catalogs datasets annotated for hate speech, online abuse, and offensive language which are useful for training a natural language processing system to detect this online abuse.
The site is built on top of [PortalJS](https://portaljs.org/). It catalogs datasets and lists of offensive keywords. It also includes static pages. All of these are stored as markdown files inside the `content` folder.
- .md files inside `content/datasets/` will appear on the dataset list section of the homepage and be searchable as well as having a individual page in `datasets/<file name>`
- .md files inside `content/keywords/` will appear on the list of offensive keywords section of the homepage as well as having a individual page in `keywords/<file name>`
- .md files inside `content/` will be converted to static pages in the url `/<file name>` eg: `content/about.md` becomes `/about`
This is also a Next.JS project so you can use the following steps to run the website locally.
## Getting started
To get started first install the npm dependencies:
```bash
npm install
```
Next, run the development server:
```bash
npm run dev
```
Finally, open [http://localhost:3000](http://localhost:3000) in your browser to view the website.

View File

@@ -0,0 +1,94 @@
import Link from 'next/link'
import clsx from 'clsx'
function ChevronRightIcon(props) {
return (
<svg viewBox="0 0 16 16" fill="none" aria-hidden="true" {...props}>
<path
d="M6.75 5.75 9.25 8l-2.5 2.25"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
export function Card({ as: Component = 'div', className, children }) {
return (
<Component
className={clsx(className, 'group relative flex flex-col items-start')}
>
{children}
</Component>
)
}
Card.Link = function CardLink({ children, ...props }) {
return (
<>
<div className="absolute -inset-x-4 -inset-y-6 z-0 scale-95 bg-zinc-50 opacity-0 transition group-hover:scale-100 group-hover:opacity-100 dark:bg-zinc-800/50 sm:-inset-x-6 sm:rounded-2xl" />
<Link {...props}>
<span className="absolute -inset-x-4 -inset-y-6 z-20 sm:-inset-x-6 sm:rounded-2xl" />
<span className="relative z-10">{children}</span>
</Link>
</>
)
}
Card.Title = function CardTitle({ as: Component = 'h2', href, children }) {
return (
<Component className="text-base font-semibold tracking-tight text-zinc-800 dark:text-zinc-100">
{href ? <Card.Link href={href}>{children}</Card.Link> : children}
</Component>
)
}
Card.Description = function CardDescription({ children }) {
return (
<p className="z-10 mt-2 text-sm text-zinc-600 dark:text-zinc-400">
{children}
</p>
)
}
Card.Cta = function CardCta({ children }) {
return (
<div
aria-hidden="true"
className="relative z-10 mt-4 flex items-center text-sm font-medium text-teal-500"
>
{children}
<ChevronRightIcon className="ml-1 h-4 w-4 stroke-current" />
</div>
)
}
Card.Eyebrow = function CardEyebrow({
as: Component = 'p',
decorate = false,
className,
children,
...props
}) {
return (
<Component
className={clsx(
className,
'relative z-10 order-first mb-3 flex items-center text-sm text-zinc-400 dark:text-zinc-500',
decorate && 'pl-3.5'
)}
{...props}
>
{decorate && (
<span
className="absolute inset-y-0 left-0 flex items-center"
aria-hidden="true"
>
<span className="h-4 w-0.5 rounded-full bg-zinc-200 dark:bg-zinc-500" />
</span>
)}
{children}
</Component>
)
}

View File

@@ -0,0 +1,42 @@
import { forwardRef } from 'react'
import clsx from 'clsx'
const OuterContainer = forwardRef(function OuterContainer(
{ className, children, ...props },
ref
) {
return (
<div ref={ref} className={clsx('sm:px-8', className)} {...props}>
<div className="mx-auto max-w-7xl lg:px-8">{children}</div>
</div>
)
})
const InnerContainer = forwardRef(function InnerContainer(
{ className, children, ...props },
ref
) {
return (
<div
ref={ref}
className={clsx('relative px-4 sm:px-8 lg:px-12', className)}
{...props}
>
<div className="mx-auto max-w-2xl lg:max-w-5xl">{children}</div>
</div>
)
})
export const Container = forwardRef(function Container(
{ children, ...props },
ref
) {
return (
<OuterContainer ref={ref} {...props}>
<InnerContainer>{children}</InnerContainer>
</OuterContainer>
)
})
Container.Outer = OuterContainer
Container.Inner = InnerContainer

View File

@@ -0,0 +1,36 @@
import Link from 'next/link'
import { Container } from '../components/Container'
function NavLink({ href, children }) {
return (
<Link
href={href}
className="transition hover:text-teal-500 dark:hover:text-teal-400"
>
{children}
</Link>
)
}
export function Footer() {
return (
<footer className="mt-32">
<Container.Outer>
<div className="border-t border-zinc-100 pb-16 pt-10 dark:border-zinc-700/40">
<Container.Inner>
<div className="flex flex-col items-center justify-between gap-6 sm:flex-row">
<p className="text-sm font-medium text-zinc-800 dark:text-zinc-200">
Built with <a href='https://portaljs.org'>PortalJS 🌀</a>
</p>
<p className="text-sm text-zinc-400 dark:text-zinc-500">
&copy; {new Date().getFullYear()} Leon Derczynski. All rights
reserved.
</p>
</div>
</Container.Inner>
</div>
</Container.Outer>
</footer>
)
}

View File

@@ -0,0 +1,265 @@
import { Fragment, useEffect, useRef } from 'react'
import Image from 'next/image'
import Link from 'next/link'
import { useRouter } from 'next/router'
import { Popover, Transition } from '@headlessui/react'
import clsx from 'clsx'
import { Container } from '../components/Container'
function CloseIcon(props) {
return (
<svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
<path
d="m17.25 6.75-10.5 10.5M6.75 6.75l10.5 10.5"
fill="none"
stroke="currentColor"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function ChevronDownIcon(props) {
return (
<svg viewBox="0 0 8 6" aria-hidden="true" {...props}>
<path
d="M1.75 1.75 4 4.25l2.25-2.5"
fill="none"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function SunIcon(props) {
return (
<svg
viewBox="0 0 24 24"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
aria-hidden="true"
{...props}
>
<path d="M8 12.25A4.25 4.25 0 0 1 12.25 8v0a4.25 4.25 0 0 1 4.25 4.25v0a4.25 4.25 0 0 1-4.25 4.25v0A4.25 4.25 0 0 1 8 12.25v0Z" />
<path
d="M12.25 3v1.5M21.5 12.25H20M18.791 18.791l-1.06-1.06M18.791 5.709l-1.06 1.06M12.25 20v1.5M4.5 12.25H3M6.77 6.77 5.709 5.709M6.77 17.73l-1.061 1.061"
fill="none"
/>
</svg>
)
}
function MoonIcon(props) {
return (
<svg viewBox="0 0 24 24" aria-hidden="true" {...props}>
<path
d="M17.25 16.22a6.937 6.937 0 0 1-9.47-9.47 7.451 7.451 0 1 0 9.47 9.47ZM12.75 7C17 7 17 2.75 17 2.75S17 7 21.25 7C17 7 17 11.25 17 11.25S17 7 12.75 7Z"
strokeWidth="1.5"
strokeLinecap="round"
strokeLinejoin="round"
/>
</svg>
)
}
function GithubIcon(props) {
return (
<svg
viewBox="0 0 24 24"
aria-hidden="true"
className="h-6 w-6 fill-slate-900 dark:fill-zinc-200"
>
<path
fillRule="evenodd"
clipRule="evenodd"
d="M12 2C6.477 2 2 6.463 2 11.97c0 4.404 2.865 8.14 6.839 9.458.5.092.682-.216.682-.48 0-.236-.008-.864-.013-1.695-2.782.602-3.369-1.337-3.369-1.337-.454-1.151-1.11-1.458-1.11-1.458-.908-.618.069-.606.069-.606 1.003.07 1.531 1.027 1.531 1.027.892 1.524 2.341 1.084 2.91.828.092-.643.35-1.083.636-1.332-2.22-.251-4.555-1.107-4.555-4.927 0-1.088.39-1.979 1.029-2.675-.103-.252-.446-1.266.098-2.638 0 0 .84-.268 2.75 1.022A9.607 9.607 0 0 1 12 6.82c.85.004 1.705.114 2.504.336 1.909-1.29 2.747-1.022 2.747-1.022.546 1.372.202 2.386.1 2.638.64.696 1.028 1.587 1.028 2.675 0 3.83-2.339 4.673-4.566 4.92.359.307.678.915.678 1.846 0 1.332-.012 2.407-.012 2.734 0 .267.18.577.688.48 3.97-1.32 6.833-5.054 6.833-9.458C22 6.463 17.522 2 12 2Z"
></path>
</svg>
)
}
function MobileNavItem({ href, children }) {
return (
<li>
<Popover.Button
as={Link}
href={href}
className="flex items-center gap-x-2 py-2"
>
{children}
</Popover.Button>
</li>
)
}
function MobileNavigation(props) {
return (
<Popover {...props}>
<Popover.Button className="group flex items-center rounded-full bg-white/90 px-4 py-2 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 dark:hover:ring-white/20">
Menu
<ChevronDownIcon className="ml-3 h-auto w-2 stroke-zinc-500 group-hover:stroke-zinc-700 dark:group-hover:stroke-zinc-400" />
</Popover.Button>
<Transition.Root>
<Transition.Child
as={Fragment}
enter="duration-150 ease-out"
enterFrom="opacity-0"
enterTo="opacity-100"
leave="duration-150 ease-in"
leaveFrom="opacity-100"
leaveTo="opacity-0"
>
<Popover.Overlay className="fixed inset-0 z-50 bg-zinc-800/40 backdrop-blur-sm dark:bg-black/80" />
</Transition.Child>
<Transition.Child
as={Fragment}
enter="duration-150 ease-out"
enterFrom="opacity-0 scale-95"
enterTo="opacity-100 scale-100"
leave="duration-150 ease-in"
leaveFrom="opacity-100 scale-100"
leaveTo="opacity-0 scale-95"
>
<Popover.Panel
focus
className="fixed inset-x-4 top-8 z-50 origin-top rounded-3xl bg-white p-8 ring-1 ring-zinc-900/5 dark:bg-zinc-900 dark:ring-zinc-800"
>
<div className="flex flex-row-reverse items-center justify-between">
<Popover.Button aria-label="Close menu" className="-m-1 p-1">
<CloseIcon className="h-6 w-6 text-zinc-500 dark:text-zinc-400" />
</Popover.Button>
<h2 className="text-sm font-medium text-zinc-600 dark:text-zinc-400">
Navigation
</h2>
</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/leondz/hatespeechdata">
View on Github <GithubIcon />
</MobileNavItem>
</ul>
</nav>
</Popover.Panel>
</Transition.Child>
</Transition.Root>
</Popover>
)
}
function NavItem({ href, children }) {
let isActive = useRouter().pathname === href
return (
<li>
<Link
href={href}
className={clsx(
'relative flex items-center gap-x-2 px-3 py-2 transition',
isActive
? 'text-teal-500 dark:text-teal-400'
: 'hover:text-teal-500 dark:hover:text-teal-400'
)}
>
{children}
{isActive && (
<span className="absolute inset-x-1 -bottom-px h-px bg-gradient-to-r from-teal-500/0 via-teal-500/40 to-teal-500/0 dark:from-teal-400/0 dark:via-teal-400/40 dark:to-teal-400/0" />
)}
</Link>
</li>
)
}
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/leondz/hatespeechdata">
View on Github <GithubIcon />
</NavItem>
</ul>
</nav>
)
}
function ModeToggle() {
function disableTransitionsTemporarily() {
document.documentElement.classList.add('[&_*]:!transition-none')
window.setTimeout(() => {
document.documentElement.classList.remove('[&_*]:!transition-none')
}, 0)
}
function toggleMode() {
disableTransitionsTemporarily()
let darkModeMediaQuery = window.matchMedia('(prefers-color-scheme: dark)')
let isSystemDarkMode = darkModeMediaQuery.matches
let isDarkMode = document.documentElement.classList.toggle('dark')
if (isDarkMode === isSystemDarkMode) {
delete window.localStorage.isDarkMode
} else {
window.localStorage.isDarkMode = isDarkMode
}
}
return (
<button
type="button"
aria-label="Toggle dark mode"
className="group rounded-full bg-white/90 px-3 py-2 shadow-lg shadow-zinc-800/5 ring-1 ring-zinc-900/5 backdrop-blur transition dark:bg-zinc-800/90 dark:ring-white/10 dark:hover:ring-white/20"
onClick={toggleMode}
>
<SunIcon className="h-6 w-6 fill-zinc-100 stroke-zinc-500 transition group-hover:fill-zinc-200 group-hover:stroke-zinc-700 dark:hidden [@media(prefers-color-scheme:dark)]:fill-teal-50 [@media(prefers-color-scheme:dark)]:stroke-teal-500 [@media(prefers-color-scheme:dark)]:group-hover:fill-teal-50 [@media(prefers-color-scheme:dark)]:group-hover:stroke-teal-600" />
<MoonIcon className="hidden h-6 w-6 fill-zinc-700 stroke-zinc-500 transition dark:block [@media(prefers-color-scheme:dark)]:group-hover:stroke-zinc-400 [@media_not_(prefers-color-scheme:dark)]:fill-teal-400/10 [@media_not_(prefers-color-scheme:dark)]:stroke-teal-500" />
</button>
)
}
function clamp(number, a, b) {
let min = Math.min(a, b)
let max = Math.max(a, b)
return Math.min(Math.max(number, min), max)
}
export function Header() {
return (
<>
<header
className="pointer-events-none relative z-50 flex flex-col"
style={{
height: 'var(--header-height)',
marginBottom: 'var(--header-mb)',
}}
>
<div
className="top-0 z-10 h-16 pt-6"
style={{ position: 'var(--header-position)' }}
>
<Container
className="top-[var(--header-top,theme(spacing.6))] w-full"
style={{ position: 'var(--header-inner-position)' }}
>
<div className="relative flex gap-4">
<div className="flex flex-1">
<MobileNavigation className="pointer-events-auto md:hidden" />
<DesktopNavigation className="pointer-events-auto hidden md:block" />
</div>
<div className="flex justify-end md:flex-1">
<div className="pointer-events-auto">
<ModeToggle />
</div>
</div>
</div>
</Container>
</div>
</header>
</>
)
}

View File

@@ -0,0 +1,5 @@
---
title: About
---
This is an about page, left here as an example

View File

@@ -0,0 +1,14 @@
---
title: AbuseEval v1.0
link-to-publication: http://www.lrec-conf.org/proceedings/lrec2020/pdf/2020.lrec-1.760.pdf
link-to-data: https://github.com/tommasoc80/AbuseEval
task-description: Explicitness annotation of offensive and abusive content
details-of-task: "Enriched versions of the OffensEval/OLID dataset with the distinction of explicit/implicit offensive messages and the new dimension for abusive messages. Labels for offensive language: EXPLICIT, IMPLICT, NOT; Labels for abusive language: EXPLICIT, IMPLICT, NOTABU"
size-of-dataset: 14100
percentage-abusive: 20.75
language: English
level-of-annotation: ["Tweets"]
platform: ["Twitter"]
medium: ["Text"]
reference: "Caselli, T., Basile, V., Jelena, M., Inga, K., and Michael, G. 2020. \"I feel offended, dont be abusive! implicit/explicit messages in offensive and abusive language\". The 12th Language Resources and Evaluation Conference (pp. 6193-6202). European Language Resources Association."
---

View File

@@ -0,0 +1,16 @@
---
title: "Abusive Language Detection on Arabic Social Media (Al Jazeera)"
link-to-publication: https://www.aclweb.org/anthology/W17-3008
link-to-data: http://alt.qcri.org/~hmubarak/offensive/AJCommentsClassification-CF.xlsx
task-description: Ternary (Obscene, Offensive but not obscene, Clean)
details-of-task: Incivility
size-of-dataset: 32000
percentage-abusive: 0.81
language: Arabic
level-of-annotation: ["Posts"]
platform: ["AlJazeera"]
medium: ["Text"]
reference: "Mubarak, H., Darwish, K. and Magdy, W., 2017. Abusive Language Detection on Arabic Social Media. In: Proceedings of the First Workshop on Abusive Language Online. Vancouver, Canada: Association for Computational Linguistics, pp.52-56."
---
SOMETHING TEST

View File

@@ -0,0 +1,14 @@
---
title: "CoRAL: a Context-aware Croatian Abusive Language Dataset"
link-to-publication: https://aclanthology.org/2022.findings-aacl.21/
link-to-data: https://github.com/shekharRavi/CoRAL-dataset-Findings-of-the-ACL-AACL-IJCNLP-2022
task-description: Multi-class based on context dependency categories (CDC)
details-of-task: Detectioning CDC from abusive comments
size-of-dataset: 2240
percentage-abusive: 100
language: "Croatian"
level-of-annotation: ["Posts"]
platform: ["Posts"]
medium: ["Newspaper Comments"]
reference: "Ravi Shekhar, Mladen Karan and Matthew Purver (2022). CoRAL: a Context-aware Croatian Abusive Language Dataset. Findings of the ACL: AACL-IJCNLP."
---

View File

@@ -0,0 +1,14 @@
---
title: Detecting Abusive Albanian
link-to-publication: https://arxiv.org/abs/2107.13592
link-to-data: https://doi.org/10.6084/m9.figshare.19333298.v1
task-description: Hierarchical (offensive/not; untargeted/targeted; person/group/other)
details-of-task: Detect and categorise abusive language in social media data
size-of-dataset: 11874
percentage-abusive: 13.2
language: Albanian
level-of-annotation: ["Posts"]
platform: ["Instagram", "Youtube"]
medium: ["Text"]
reference: "Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592"
---

View File

@@ -0,0 +1,15 @@
---
title: "Hate Speech Detection in the Bengali language: A Dataset and its Baseline Evaluation"
link-to-publication: https://arxiv.org/pdf/2012.09686.pdf
link-to-data: https://www.kaggle.com/naurosromim/bengali-hate-speech-dataset
task-description: Binary (hateful, not)
details-of-task: "Several categories: sports, entertainment, crime, religion, politics, celebrity and meme"
size-of-dataset: 30000
percentage-abusive: 0.33
language: Bengali
level-of-annotation: ["Posts"]
platform: ["Youtube", "Facebook"]
medium: ["Text"]
reference: "Romim, N., Ahmed, M., Talukder, H., & Islam, M. S. (2021). Hate speech detection in the bengali language: A dataset and its baseline evaluation. In Proceedings of International Joint Conference on Advances in Computational Intelligence (pp. 457-468). Springer, Singapore."
---

View File

@@ -0,0 +1,14 @@
---
title: Large-Scale Hate Speech Detection with Cross-Domain Transfer
link-to-publication: https://aclanthology.org/2022.lrec-1.238/
link-to-data: https://github.com/avaapm/hatespeech
task-description: Three-class (Hate speech, Offensive language, None)
details-of-task: Hate speech detection on social media (Twitter) including 5 target groups (gender, race, religion, politics, sports)
size-of-dataset: "100k English (27593 hate, 30747 offensive, 41660 none)"
percentage-abusive: 58.3
language: English
level-of-annotation: ["Posts"]
platform: ["Twitter"]
medium: ["Text", "Image"]
reference: "Cagri Toraman, Furkan Şahinuç, Eyup Yilmaz. 2022. Large-Scale Hate Speech Detection with Cross-Domain Transfer. In Proceedings of the Thirteenth Language Resources and Evaluation Conference, pages 22152225, Marseille, France. European Language Resources Association."
---

View File

@@ -0,0 +1,14 @@
---
title: "Let-Mi: An Arabic Levantine Twitter Dataset for Misogynistic Language"
link-to-publication: https://arxiv.org/abs/2103.10195
link-to-data: https://drive.google.com/file/d/1mM2vnjsy7QfUmdVUpKqHRJjZyQobhTrW/view
task-description: Binary (misogyny/none) and Multi-class (none, discredit, derailing, dominance, stereotyping & objectification, threat of violence, sexual harassment, damning)
details-of-task: Introducing an Arabic Levantine Twitter dataset for Misogynistic language
size-of-dataset: 6603
percentage-abusive: 48.76
language: Arabic
level-of-annotation: ["Posts"]
platform: ["Twitter"]
medium: ["Text", "Images"]
reference: "Hala Mulki and Bilal Ghanem. 2021. Let-Mi: An Arabic Levantine Twitter Dataset for Misogynistic Language. In Proceedings of the Sixth Arabic Natural Language Processing Workshop, pages 154163, Kyiv, Ukraine (Virtual). Association for Computational Linguistics"
---

View File

@@ -0,0 +1,14 @@
---
title: Measuring Hate Speech
link-to-publication: https://arxiv.org/abs/2009.10277
link-to-data: https://huggingface.co/datasets/ucberkeley-dlab/measuring-hate-speech
task-description: 10 ordinal labels (sentiment, (dis)respect, insult, humiliation, inferior status, violence, dehumanization, genocide, attack/defense, hate speech), which are debiased and aggregated into a continuous hate speech severity score (hate_speech_score) that includes a region for counterspeech & supportive speeech. Includes 8 target identity groups (race/ethnicity, religion, national origin/citizenship, gender, sexual orientation, age, disability, political ideology) and 42 identity subgroups.
details-of-task: Hate speech measurement on social media in English
size-of-dataset: "39,565 comments annotated by 7,912 annotators on 10 ordinal labels, for 1,355,560 total labels."
percentage-abusive: 25
language: English
level-of-annotation: ["Social media comment"]
platform: ["Twitter", "Reddit", "Youtube"]
medium: ["Text"]
reference: "Kennedy, C. J., Bacon, G., Sahn, A., & von Vacano, C. (2020). Constructing interval variables via faceted Rasch measurement and multitask deep learning: a hate speech application. arXiv preprint arXiv:2009.10277."
---

View File

@@ -0,0 +1,14 @@
---
title: Offensive Language and Hate Speech Detection for Danish
link-to-publication: http://www.derczynski.com/papers/danish_hsd.pdf
link-to-data: https://figshare.com/articles/Danish_Hate_Speech_Abusive_Language_data/12220805
task-description: "Branching structure of tasks: Binary (Offensive, Not), Within Offensive (Target, Not), Within Target (Individual, Group, Other)"
details-of-task: Group-directed + Person-directed
size-of-dataset: 3600
percentage-abusive: 0.12
language: Danish
level-of-annotation: ["Posts"]
platform: ["Twitter", "Reddit", "Newspaper comments"]
medium: ["Text"]
reference: "Sigurbergsson, G. and Derczynski, L., 2019. Offensive Language and Hate Speech Detection for Danish. ArXiv."
---

View File

@@ -0,0 +1,52 @@
---
title: Hate Speech Dataset Catalogue
---
This page catalogues datasets annotated for hate speech, online abuse, and offensive language. They may be useful for e.g. training a natural language processing system to detect this language.
The list is maintained by [Leon Derczynski](https://www.derczynski.com/), [Bertie Vidgen](https://www.turing.ac.uk/people/researchers/bertie-vidgen), [Hannah Rose Kirk](https://www.hannahrosekirk.com/), Pica Johansson, [Yi-Ling Chung](https://yilingchung.github.io/), Mads Guldborg Kjeldgaard Kongsbak, [Laila Sprejer](https://www.turing.ac.uk/people/researchers/laila-sprejer), and Philine Zeinert.
We provide a list of [datasets](#Datasets-header) and [keywords](#Keywords-header). If you would like to contribute to our catalogue or add your dataset, please see the [instructions for contributing](#Contributing-header).
If you use these resources, please cite (and read!) our paper: [Directions in Abusive Language Training Data: Garbage In, Garbage Out](https://journals.plos.org/plosone/article?id=10.1371/journal.pone.0243300). And if you would like to find other resources for researching online hate, visit The Alan Turing Institute's [Online Hate Research Hub](https://www.turing.ac.uk/research/research-programmes/public-policy/online-hate-research-hub) or read The Alan Turing Institute's [Reading List on Online Hate and Abuse Research](https://docs.google.com/document/d/1WVkVGp29Jt6d-4fBnZ5OWVYuFn_03rzz-KBqPsu6gTM/edit?usp=sharing).
If you're looking for a good paper on online hate training datasets (beyond our paper, of course!) then have a look at ['Resources and benchmark corpora for hate speech detection: a systematic review'](https://link.springer.com/article/10.1007/s10579-020-09502-8) by Poletto et al. in *Language Resources and Evaluation*.
Accompanying [data statements](https://www.mitpressjournals.org/doi/abs/10.1162/tacl_a_00041) preferred for all corpora.
<a href="#Datasets-header" className="w-fit mx-auto no-underline rounded-md py-3 px-6 outline-offset-2 transition !active:transition-none bg-zinc-800 !font-semibold !text-zinc-100 hover:bg-zinc-700 active:bg-zinc-800 active:text-zinc-100/70 dark:bg-zinc-700 dark:hover:bg-zinc-600 !dark:active:bg-zinc-700 dark:active:text-zinc-100/70">See datasets</a>
<h2 id="Contributing-header">How to contribute</h2>
We accept entries to our catalogue based on pull requests to the content folder. The dataset must be avaliable for download to be included in the list. If you want to add an entry, follow these steps!
Please send just one dataset addition/edit at a time - edit it in, then save. This will make everyones life easier (including yours!)
### Create file
Go to the repo url file and click the "Add file" dropdown and then click on "Create new file".
![](https://i.imgur.com/2PR0ZgL.png)
### Choose location
In the following page type `content/datasets/<name-of-the-file>.md`. if you want to add an entry to the datasets catalog or `content/keywords/<name-of-the-file>.md` if you want to add an entry to the lists of abusive keywords, if you want to just add an static page you can leave in the root of `content` it will automatically get assigned an url eg: `/content/about.md` becomes the `/about` page
![](https://i.imgur.com/rr3uSYu.png)
### 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
![](https://i.imgur.com/x6JIjhz.png)
### Commit changes
Click on "Commit changes", on the popup make sure you give some brief detail on the proposed change. and then click on Propose changes
<img src='https://i.imgur.com/BxuxKEJ.png' style={{ maxWidth: '50%', margin: '0 auto' }}/>
### Submit PR
Submit the pull request on the next page when prompted.

View File

@@ -0,0 +1,10 @@
---
title: Hurtlex
description: HurtLex is a lexicon of offensive, aggressive, and hateful words in over 50 languages. The words are divided into 17 categories, plus a macro-category indicating whether there is stereotype involved.
data-link: https://github.com/valeriobasile/hurtlex
reference: http://ceur-ws.org/Vol-2253/paper49.pdf, Proc. CLiC-it 2018
---
## Markdown TEST
Some text

View File

@@ -0,0 +1,5 @@
---
title: SexHateLex is a Chinese lexicon of hateful and sexist words.
data-link: https://doi.org/10.5281/zenodo.4773875
reference: http://ceur-ws.org/Vol-2253/paper49.pdf, Journal of OSNEM, Vol.27, 2022, 100182, ISSN 2468-6964.
---

View File

@@ -0,0 +1,11 @@
{
"compilerOptions": {
"baseUrl": ".",
"paths": {
"@/components/*": ["components/*"],
"@/pages/*": ["pages/*"],
"@/lib/*": ["lib/*"]
}
}
}

View File

@@ -0,0 +1,8 @@
export function formatDate(dateString) {
return new Date(`${dateString}T00:00:00Z`).toLocaleDateString('en-US', {
day: 'numeric',
month: 'long',
year: 'numeric',
timeZone: 'UTC',
})
}

View File

@@ -0,0 +1,98 @@
import matter from "gray-matter";
import mdxmermaid from "mdx-mermaid";
import { h } from "hastscript";
import remarkCallouts from "@flowershow/remark-callouts";
import remarkEmbed from "@flowershow/remark-embed";
import remarkGfm from "remark-gfm";
import remarkMath from "remark-math";
import remarkSmartypants from "remark-smartypants";
import remarkToc from "remark-toc";
import remarkWikiLink from "@flowershow/remark-wiki-link";
import rehypeAutolinkHeadings from "rehype-autolink-headings";
import rehypeKatex from "rehype-katex";
import rehypeSlug from "rehype-slug";
import rehypePrismPlus from "rehype-prism-plus";
import { serialize } from "next-mdx-remote/serialize";
/**
* Parse a markdown or MDX file to an MDX source form + front matter data
*
* @source: the contents of a markdown or mdx file
* @format: used to indicate to next-mdx-remote which format to use (md or mdx)
* @returns: { mdxSource: mdxSource, frontMatter: ...}
*/
const parse = async function (source, format) {
const { content, data } = matter(source);
const mdxSource = await serialize(
{ value: content, path: format },
{
// Optionally pass remark/rehype plugins
mdxOptions: {
remarkPlugins: [
remarkEmbed,
remarkGfm,
[remarkSmartypants, { quotes: false, dashes: "oldschool" }],
remarkMath,
remarkCallouts,
remarkWikiLink,
[
remarkToc,
{
heading: "Table of contents",
tight: true,
},
],
[mdxmermaid, {}],
],
rehypePlugins: [
rehypeSlug,
[
rehypeAutolinkHeadings,
{
properties: { className: "heading-link" },
test(element) {
return (
["h2", "h3", "h4", "h5", "h6"].includes(element.tagName) &&
element.properties?.id !== "table-of-contents" &&
element.properties?.className !== "blockquote-heading"
);
},
content() {
return [
h(
"svg",
{
xmlns: "http:www.w3.org/2000/svg",
fill: "#ab2b65",
viewBox: "0 0 20 20",
className: "w-5 h-5",
},
[
h("path", {
fillRule: "evenodd",
clipRule: "evenodd",
d: "M9.493 2.853a.75.75 0 00-1.486-.205L7.545 6H4.198a.75.75 0 000 1.5h3.14l-.69 5H3.302a.75.75 0 000 1.5h3.14l-.435 3.148a.75.75 0 001.486.205L7.955 14h2.986l-.434 3.148a.75.75 0 001.486.205L12.456 14h3.346a.75.75 0 000-1.5h-3.14l.69-5h3.346a.75.75 0 000-1.5h-3.14l.435-3.147a.75.75 0 00-1.486-.205L12.045 6H9.059l.434-3.147zM8.852 7.5l-.69 5h2.986l.69-5H8.852z",
}),
]
),
];
},
},
],
[rehypeKatex, { output: "mathml" }],
[rehypePrismPlus, { ignoreMissing: true }],
],
format,
},
}
);
return {
mdxSource: mdxSource,
frontMatter: data,
};
};
export default parse;

View File

@@ -0,0 +1,14 @@
import { MarkdownDB } from "@flowershow/markdowndb";
const dbPath = "markdown.db";
const client = new MarkdownDB({
client: "sqlite3",
connection: {
filename: dbPath,
},
});
const clientPromise = client.init();
export default clientPromise;

Binary file not shown.

View File

@@ -0,0 +1,5 @@
/// <reference types="next" />
/// <reference types="next/image-types/global" />
// NOTE: This file should not be edited
// see https://nextjs.org/docs/basic-features/typescript for more information.

View File

@@ -0,0 +1,3 @@
module.exports = {
swcMinify: true,
};

22977
examples/alan-turing-portal/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,71 @@
{
"name": "tailwindui-template",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint",
"prebuild": "npm run mddb",
"mddb": "mddb ./content"
},
"browserslist": "defaults, not ie <= 11",
"dependencies": {
"@flowershow/core": "^0.4.10",
"@flowershow/markdowndb": "^0.1.1",
"@flowershow/remark-callouts": "^1.0.0",
"@flowershow/remark-embed": "^1.0.0",
"@flowershow/remark-wiki-link": "^1.1.2",
"@headlessui/react": "^1.7.13",
"@heroicons/react": "^2.0.17",
"@mapbox/rehype-prism": "^0.8.0",
"@mdx-js/loader": "^2.1.5",
"@mdx-js/react": "^2.1.5",
"@next/mdx": "^13.0.2",
"@opentelemetry/api": "^1.4.0",
"@tailwindcss/forms": "^0.5.3",
"@tailwindcss/typography": "^0.5.4",
"@tanstack/react-table": "^8.8.5",
"autoprefixer": "^10.4.12",
"clsx": "^1.2.1",
"fast-glob": "^3.2.11",
"feed": "^4.2.2",
"flexsearch": "^0.7.31",
"focus-visible": "^5.2.0",
"gray-matter": "^4.0.3",
"hastscript": "^7.2.0",
"mdx-mermaid": "^2.0.0-rc7",
"mermaid": "^10.1.0",
"next": "13.2.1",
"next-mdx-remote": "^4.4.1",
"next-router-mock": "^0.9.3",
"next-superjson-plugin": "^0.5.7",
"papaparse": "^5.4.1",
"postcss-focus-visible": "^6.0.4",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-markdown": "^8.0.7",
"react-vega": "^7.6.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex": "^6.0.3",
"rehype-prism-plus": "^1.5.1",
"rehype-slug": "^5.1.0",
"remark-gfm": "^3.0.1",
"remark-math": "^5.1.1",
"remark-smartypants": "^2.0.0",
"remark-toc": "^8.0.1",
"superjson": "^1.12.3",
"tailwindcss": "^3.3.0"
},
"devDependencies": {
"eslint": "8.26.0",
"eslint-config-next": "13.0.2",
"prettier": "^2.8.7",
"prettier-plugin-tailwindcss": "^0.2.6",
"@types/node": "18.16.0",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0"
}
}

View File

@@ -0,0 +1,107 @@
import { Container } from '../components/Container'
import clientPromise from '../lib/mddb'
import { promises as fs } from 'fs';
import { MDXRemote } from 'next-mdx-remote'
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('/') : ''
const mddb = await clientPromise
const dbFile = await mddb.getFileByUrl(urlPath)
const source = await fs.readFile(dbFile.file_path,'utf-8')
let mdxSource = await parse(source, '.mdx')
return {
props: {
mdxSource,
},
}
}
export async function getStaticPaths() {
const mddb = await clientPromise
const allDocuments = await mddb.getFiles({ extensions: ['md', 'mdx'] })
const paths = allDocuments.filter(document => document.url_path !== '/').map((page) => {
const parts = page.url_path.split('/')
return { params: { slug: parts } }
})
return {
paths,
fallback: false,
}
}
const isValidUrl = (urlString) => {
try {
return Boolean(new URL(urlString))
} catch (e) {
return false
}
}
const Meta = ({keyValuePairs}) => {
const prettifyMetaValue = (value) => value.replaceAll('-',' ').charAt(0).toUpperCase() + value.replaceAll('-',' ').slice(1);
return (
<>
{keyValuePairs.map((entry) => {
return isValidUrl(entry[1]) ? (
<Card.Description>
<span className="font-semibold">
{prettifyMetaValue(entry[0])}: {' '}
</span>
<a
className="text-ellipsis underline transition hover:text-teal-400 dark:hover:text-teal-900"
href={entry[1]}
>
{entry[1]}
</a>
</Card.Description>
) : (
<Card.Description>
<span className="font-semibold">{prettifyMetaValue(entry[0])}: </span>
{Array.isArray(entry[1]) ? entry[1].join(', ') : entry[1]}
</Card.Description>
)
})}
</>
)
}
export default function DRDPage({ mdxSource }) {
const meta = mdxSource.frontMatter
const keyValuePairs = Object.entries(meta).filter(
(entry) => entry[0] !== 'title'
)
return (
<>
<Header />
<Head>
<title>{meta.title}</title>
</Head>
<Container className="mt-16 lg:mt-32 relative">
<Header />
<article>
<header className="flex flex-col">
<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">
<Meta keyValuePairs={keyValuePairs} />
</Card>
</header>
<div className="prose dark:prose-invert">
<MDXRemote {...mdxSource.mdxSource} components={{mermaid: Mermaid}} />
</div>
</article>
</Container>
</>
)
}

View File

@@ -0,0 +1,38 @@
import { useEffect, useRef } from 'react'
import { Footer } from '../components/Footer'
import { Header } from '../components/Header'
import '../styles/tailwind.css'
import 'focus-visible'
function usePrevious(value) {
let ref = useRef()
useEffect(() => {
ref.current = value
}, [value])
return ref.current
}
export default function App({ Component, pageProps, router }) {
let previousPathname = usePrevious(router.pathname)
return (
<>
<div className="fixed inset-0 flex justify-center sm:px-8">
<div className="flex w-full max-w-7xl lg:px-8">
<div className="w-full bg-white ring-1 ring-zinc-100 dark:bg-zinc-900 dark:ring-zinc-300/20" />
</div>
</div>
<div className="relative">
<Header />
<main>
<Component previousPathname={previousPathname} {...pageProps} />
</main>
<Footer />
</div>
</>
)
}

View File

@@ -0,0 +1,52 @@
import { Head, Html, Main, NextScript } from 'next/document'
const modeScript = `
updateMode()
window.addEventListener('storage', updateModeWithoutTransitions)
function updateMode() {
let isDarkMode = window.localStorage.isDarkMode === 'true'
if (isDarkMode) {
document.documentElement.classList.add('dark')
} else {
document.documentElement.classList.remove('dark')
}
}
function disableTransitionsTemporarily() {
document.documentElement.classList.add('[&_*]:!transition-none')
window.setTimeout(() => {
document.documentElement.classList.remove('[&_*]:!transition-none')
}, 0)
}
function updateModeWithoutTransitions() {
disableTransitionsTemporarily()
updateMode()
}
`
export default function Document() {
return (
<Html className="h-full antialiased" lang="en">
<Head>
<script dangerouslySetInnerHTML={{ __html: modeScript }} />
<link
rel="alternate"
type="application/rss+xml"
href={`${process.env.NEXT_PUBLIC_SITE_URL}/rss/feed.xml`}
/>
<link
rel="alternate"
type="application/feed+json"
href={`${process.env.NEXT_PUBLIC_SITE_URL}/rss/feed.json`}
/>
</Head>
<body className="flex h-full flex-col bg-zinc-50 dark:bg-black">
<Main />
<NextScript />
</body>
</Html>
)
}

View File

@@ -0,0 +1,296 @@
import Head from 'next/head'
import fs from 'fs'
import { Card } from '../components/Card'
import { Container } from '../components/Container'
import clientPromise from '../lib/mddb'
import { Index } from 'flexsearch'
import { useForm } from 'react-hook-form'
import Link from 'next/link'
import { serialize } from 'next-mdx-remote/serialize'
import { MDXRemote } from 'next-mdx-remote'
function DatasetCard({ dataset }) {
return (
<Card as="article">
<Card.Title>
<Link href={dataset.url}>{dataset.title}</Link>
</Card.Title>
<Card.Description>
<span className="font-semibold">Link to publication: </span>{' '}
<a
className="text-ellipsis underline transition hover:text-teal-400 dark:hover:text-teal-900"
href={dataset['link-to-publication']}
>
{dataset['link-to-publication']}
</a>
</Card.Description>
<Card.Description>
<span className="font-semibold">Link to data: </span>
<a
className="text-ellipsis underline transition hover:text-teal-600 dark:hover:text-teal-900"
href={dataset['link-to-data']}
>
{dataset['link-to-data']}
</a>
</Card.Description>
<Card.Description>
<span className="font-semibold">Task Description: </span>
{dataset['task-description']}
</Card.Description>
<Card.Description>
<span className="font-semibold">Details of Task: </span>{' '}
{dataset['details-of-task']}
</Card.Description>
<Card.Description>
<span className="font-semibold">Size of Dataset: </span>{' '}
{dataset['size-of-dataset']}
</Card.Description>
<Card.Description>
<span className="font-semibold">Percentage Abusive: </span>
{dataset['percentage-abusive']}%
</Card.Description>
<Card.Description>
<span className="font-semibold">Language: </span>
{dataset['language']}
</Card.Description>
<Card.Description>
<span className="font-semibold">Level of Annotation: </span>
{dataset['level-of-annotation'].join(', ')}
</Card.Description>
<Card.Description>
<span className="font-semibold">Platform: </span>
{dataset['platform'].join(', ')}
</Card.Description>
<Card.Description>
<span className="font-semibold">Medium: </span>
{dataset['medium'].join(', ')}
</Card.Description>
<Card.Description>
<span className="font-semibold">Reference: </span>
{dataset['reference']}
</Card.Description>
</Card>
)
}
function ListOfAbusiveKeywordsCard({ list }) {
return (
<Card as="article">
<Card.Title>
<Link href={list.url}>{list.title}</Link>
</Card.Title>
{list.description && (
<Card.Description>
<span className="font-semibold">List Description: </span>{' '}
{list.description}
</Card.Description>
)}
<Card.Description>
<span className="font-semibold">Data Link: </span>
<a
className="text-ellipsis underline transition hover:text-teal-600 dark:hover:text-teal-900"
href={list['data-link']}
>
{list['data-link']}
</a>
</Card.Description>
<Card.Description>
<span className="font-semibold">Reference: </span>
<a
className="text-ellipsis underline transition hover:text-teal-600 dark:hover:text-teal-900"
href={list.reference}
>
{list.reference}
</a>
</Card.Description>
</Card>
)
}
export default function Home({
datasets,
indexText,
listsOfKeywords,
availableLanguages,
availablePlatforms,
}) {
const index = new Index()
datasets.forEach((dataset) =>
index.add(
dataset.id,
`${dataset.title} ${dataset['task-description']} ${dataset['details-of-task']} ${dataset['reference']}`
)
)
const { register, watch, handleSubmit, reset } = useForm({
defaultValues: {
searchTerm: '',
lang: '',
platform: '',
},
})
return (
<>
<Head>
<title>Hate Speech Dataset Catalogue</title>
<meta
name="description"
content="Catalog of abusive language data (PLoS 2020)"
/>
</Head>
<Container className="mt-9">
<div className="max-w-2xl">
<h1 className="text-4xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
{indexText.frontmatter.title}
</h1>
<article className="index-text prose mt-6 flex flex-col gap-y-2 text-base text-zinc-600 dark:prose-invert prose-h3:mt-4 prose-a:font-normal prose-a:text-zinc-600 prose-a:decoration-inherit prose-img:rounded-none dark:text-zinc-400 prose-a:dark:text-zinc-400 hover:prose-a:text-teal-600 hover:prose-a:dark:text-teal-900">
<MDXRemote {...indexText} />
</article>
</div>
</Container>
<Container className="mt-12 md:mt-14">
<div className="mx-auto grid max-w-7xl grid-cols-1 gap-y-8 lg:max-w-none">
<h2
id="Datasets-header"
className="text-xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl"
>
Datasets
</h2>
<form
onSubmit={handleSubmit(() => reset())}
className="rounded-2xl border border-zinc-100 px-4 py-6 dark:border-zinc-700/40 sm:p-6"
>
<p className="mt-2 text-lg font-semibold text-zinc-600 dark:text-zinc-100">
Search for datasets
</p>
<div className="mt-6 flex flex-col gap-3 sm:flex-row">
<input
placeholder="Search here"
aria-label="Hate speech on Twitter"
{...register('searchTerm')}
className="min-w-0 flex-auto appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-[calc(theme(spacing.2)-1px)] shadow-md shadow-zinc-800/5 placeholder:text-zinc-600 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-200 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
/>
<select
placeholder="Language"
defaultValue=""
className="min-w-0 flex-auto appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-[calc(theme(spacing.2)-1px)] text-zinc-600 shadow-md shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
{...register('lang')}
>
<option value="" disabled hidden>
Filter by language
</option>
{availableLanguages.map((lang) => (
<option
key={lang}
className="dark:bg-white dark:text-black"
value={lang}
>
{lang}
</option>
))}
</select>
<select
placeholder="Platform"
defaultValue=""
className="min-w-0 flex-auto appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-[calc(theme(spacing.2)-1px)] text-zinc-600 shadow-md shadow-zinc-800/5 placeholder:text-zinc-400 focus:border-teal-500 focus:outline-none focus:ring-4 focus:ring-teal-500/10 dark:border-zinc-700 dark:bg-zinc-700/[0.15] dark:text-zinc-200 dark:placeholder:text-zinc-500 dark:focus:border-teal-400 dark:focus:ring-teal-400/10 sm:text-sm"
{...register('platform')}
>
<option value="" disabled hidden>
Filter by platform
</option>
{availablePlatforms.map((platform) => (
<option
key={platform}
className="dark:bg-white dark:text-black"
value={platform}
>
{platform}
</option>
))}
</select>
<button
type="submit"
className="inline-flex flex-none items-center justify-center gap-2 rounded-md bg-zinc-800 px-3 py-2 text-sm font-semibold text-zinc-100 outline-offset-2 transition hover:bg-zinc-700 active:bg-zinc-800 active:text-zinc-100/70 active:transition-none dark:bg-zinc-700 dark:hover:bg-zinc-600 dark:active:bg-zinc-700 dark:active:text-zinc-100/70"
>
Clear filters
</button>
</div>
</form>
<div className="flex flex-col gap-16">
{datasets
.filter((dataset) =>
watch().searchTerm && watch().searchTerm !== ''
? index.search(watch().searchTerm).includes(dataset.id)
: true
)
.filter((dataset) =>
watch().lang && watch().lang !== ''
? dataset.language === watch().lang
: true
)
.filter((dataset) =>
watch().platform && watch().platform !== ''
? dataset.platform.includes(watch().platform)
: true
)
.map((dataset) => (
<DatasetCard key={dataset.title} dataset={dataset} />
))}
</div>
</div>
</Container>
<Container className="mt-16">
<h2 id="Keywords-header" className="text-xl font-bold tracking-tight text-zinc-800 dark:text-zinc-100 sm:text-5xl">
Lists of Abusive Keywords
</h2>
<div className="mt-3 flex flex-col gap-16">
{listsOfKeywords.map((list) => (
<ListOfAbusiveKeywordsCard key={list.title} list={list} />
))}
</div>
</Container>
</>
)
}
export async function getStaticProps() {
const mddb = await clientPromise
const datasetPages = await mddb.getFiles({
folder: 'datasets',
extensions: ['md', 'mdx'],
})
const datasets = datasetPages.map((page) => ({
...page.metadata,
id: page._id,
url: page.url_path,
}))
const listsOfKeywordsPages = await mddb.getFiles({
folder: 'keywords',
extensions: ['md', 'mdx'],
})
const listsOfKeywords = listsOfKeywordsPages.map((page) => ({
...page.metadata,
id: page._id,
url: page.url_path,
}))
const index = await mddb.getFileByUrl('/')
let indexSource = fs.readFileSync(index.file_path, { encoding: 'utf-8' })
indexSource = await serialize(indexSource, { parseFrontmatter: true })
const availableLanguages = [
...new Set(datasets.map((dataset) => dataset.language)),
]
const availablePlatforms = [
...new Set(datasets.map((dataset) => dataset.platform).flat()),
]
return {
props: {
datasets,
listsOfKeywords,
indexText: indexSource,
availableLanguages,
availablePlatforms,
},
}
}

View File

@@ -0,0 +1,9 @@
module.exports = {
plugins: {
tailwindcss: {},
'postcss-focus-visible': {
replaceWith: '[data-focus-visible-added]',
},
autoprefixer: {},
},
}

View File

@@ -0,0 +1,5 @@
module.exports = {
singleQuote: true,
semi: false,
plugins: [require('prettier-plugin-tailwindcss')],
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 566 B

View File

@@ -0,0 +1,47 @@
pre[class*='language-'] {
color: theme('colors.zinc.100');
}
.token.tag,
.token.class-name,
.token.selector,
.token.selector .class,
.token.selector.class,
.token.function {
color: theme('colors.pink.400');
}
.token.attr-name,
.token.keyword,
.token.rule,
.token.pseudo-class,
.token.important {
color: theme('colors.zinc.300');
}
.token.module {
color: theme('colors.pink.400');
}
.token.attr-value,
.token.class,
.token.string,
.token.property {
color: theme('colors.teal.300');
}
.token.punctuation,
.token.attr-equals {
color: theme('colors.zinc.500');
}
.token.unit,
.language-css .token.function {
color: theme('colors.sky.200');
}
.token.comment,
.token.operator,
.token.combinator {
color: theme('colors.zinc.400');
}

View File

@@ -0,0 +1,13 @@
@import 'tailwindcss/base';
@import 'tailwindcss/components';
@import './prism.css';
@import 'tailwindcss/utilities';
.index-text ul,
.index-text p {
margin: 0;
}
.index-text h2 {
margin-top: 1rem;
}

View File

@@ -0,0 +1,308 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
"./app/**/*.{js,ts,jsx,tsx,mdx}",
"./content/**/*.{js,ts,jsx,tsx,mdx}",
"./pages/**/*.{js,ts,jsx,tsx,mdx}",
"./components/**/*.{js,ts,jsx,tsx,mdx}",
],
darkMode: 'class',
plugins: [require('@tailwindcss/typography'), require('@tailwindcss/forms')],
theme: {
fontSize: {
xs: ['0.8125rem', { lineHeight: '1.5rem' }],
sm: ['0.875rem', { lineHeight: '1.5rem' }],
base: ['1rem', { lineHeight: '1.75rem' }],
lg: ['1.125rem', { lineHeight: '1.75rem' }],
xl: ['1.25rem', { lineHeight: '2rem' }],
'2xl': ['1.5rem', { lineHeight: '2rem' }],
'3xl': ['1.875rem', { lineHeight: '2.25rem' }],
'4xl': ['2rem', { lineHeight: '2.5rem' }],
'5xl': ['3rem', { lineHeight: '3.5rem' }],
'6xl': ['3.75rem', { lineHeight: '1' }],
'7xl': ['4.5rem', { lineHeight: '1' }],
'8xl': ['6rem', { lineHeight: '1' }],
'9xl': ['8rem', { lineHeight: '1' }],
},
typography: (theme) => ({
invert: {
css: {
'--tw-prose-body': 'var(--tw-prose-invert-body)',
'--tw-prose-headings': 'var(--tw-prose-invert-headings)',
'--tw-prose-links': 'var(--tw-prose-invert-links)',
'--tw-prose-links-hover': 'var(--tw-prose-invert-links-hover)',
'--tw-prose-underline': 'var(--tw-prose-invert-underline)',
'--tw-prose-underline-hover':
'var(--tw-prose-invert-underline-hover)',
'--tw-prose-bold': 'var(--tw-prose-invert-bold)',
'--tw-prose-counters': 'var(--tw-prose-invert-counters)',
'--tw-prose-bullets': 'var(--tw-prose-invert-bullets)',
'--tw-prose-hr': 'var(--tw-prose-invert-hr)',
'--tw-prose-quote-borders': 'var(--tw-prose-invert-quote-borders)',
'--tw-prose-captions': 'var(--tw-prose-invert-captions)',
'--tw-prose-code': 'var(--tw-prose-invert-code)',
'--tw-prose-code-bg': 'var(--tw-prose-invert-code-bg)',
'--tw-prose-pre-code': 'var(--tw-prose-invert-pre-code)',
'--tw-prose-pre-bg': 'var(--tw-prose-invert-pre-bg)',
'--tw-prose-pre-border': 'var(--tw-prose-invert-pre-border)',
'--tw-prose-th-borders': 'var(--tw-prose-invert-th-borders)',
'--tw-prose-td-borders': 'var(--tw-prose-invert-td-borders)',
},
},
DEFAULT: {
css: {
'--tw-prose-body': theme('colors.zinc.600'),
'--tw-prose-headings': theme('colors.zinc.900'),
'--tw-prose-links': theme('colors.teal.500'),
'--tw-prose-links-hover': theme('colors.teal.600'),
'--tw-prose-underline': theme('colors.teal.500 / 0.2'),
'--tw-prose-underline-hover': theme('colors.teal.500'),
'--tw-prose-bold': theme('colors.zinc.900'),
'--tw-prose-counters': theme('colors.zinc.900'),
'--tw-prose-bullets': theme('colors.zinc.900'),
'--tw-prose-hr': theme('colors.zinc.100'),
'--tw-prose-quote-borders': theme('colors.zinc.200'),
'--tw-prose-captions': theme('colors.zinc.400'),
'--tw-prose-code': theme('colors.zinc.700'),
'--tw-prose-code-bg': theme('colors.zinc.300 / 0.2'),
'--tw-prose-pre-code': theme('colors.zinc.100'),
'--tw-prose-pre-bg': theme('colors.zinc.900'),
'--tw-prose-pre-border': 'transparent',
'--tw-prose-th-borders': theme('colors.zinc.200'),
'--tw-prose-td-borders': theme('colors.zinc.100'),
'--tw-prose-invert-body': theme('colors.zinc.400'),
'--tw-prose-invert-headings': theme('colors.zinc.200'),
'--tw-prose-invert-links': theme('colors.teal.400'),
'--tw-prose-invert-links-hover': theme('colors.teal.400'),
'--tw-prose-invert-underline': theme('colors.teal.400 / 0.3'),
'--tw-prose-invert-underline-hover': theme('colors.teal.400'),
'--tw-prose-invert-bold': theme('colors.zinc.200'),
'--tw-prose-invert-counters': theme('colors.zinc.200'),
'--tw-prose-invert-bullets': theme('colors.zinc.200'),
'--tw-prose-invert-hr': theme('colors.zinc.700 / 0.4'),
'--tw-prose-invert-quote-borders': theme('colors.zinc.500'),
'--tw-prose-invert-captions': theme('colors.zinc.500'),
'--tw-prose-invert-code': theme('colors.zinc.300'),
'--tw-prose-invert-code-bg': theme('colors.zinc.200 / 0.05'),
'--tw-prose-invert-pre-code': theme('colors.zinc.100'),
'--tw-prose-invert-pre-bg': 'rgb(0 0 0 / 0.4)',
'--tw-prose-invert-pre-border': theme('colors.zinc.200 / 0.1'),
'--tw-prose-invert-th-borders': theme('colors.zinc.700'),
'--tw-prose-invert-td-borders': theme('colors.zinc.800'),
// Base
color: 'var(--tw-prose-body)',
lineHeight: theme('lineHeight.7'),
'> *': {
marginTop: theme('spacing.10'),
marginBottom: theme('spacing.10'),
},
p: {
marginTop: theme('spacing.7'),
marginBottom: theme('spacing.7'),
},
// Headings
'h2, h3': {
color: 'var(--tw-prose-headings)',
fontWeight: theme('fontWeight.semibold'),
},
h2: {
fontSize: theme('fontSize.xl')[0],
lineHeight: theme('lineHeight.7'),
marginTop: theme('spacing.20'),
marginBottom: theme('spacing.4'),
},
h3: {
fontSize: theme('fontSize.base')[0],
lineHeight: theme('lineHeight.7'),
marginTop: theme('spacing.16'),
marginBottom: theme('spacing.4'),
},
':is(h2, h3) + *': {
marginTop: 0,
},
// Images
img: {
borderRadius: theme('borderRadius.3xl'),
},
// Inline elements
a: {
color: 'var(--tw-prose-links)',
fontWeight: theme('fontWeight.semibold'),
textDecoration: 'underline',
textDecorationColor: 'var(--tw-prose-underline)',
transitionProperty: 'color, text-decoration-color',
transitionDuration: theme('transitionDuration.150'),
transitionTimingFunction: theme('transitionTimingFunction.in-out'),
},
'a:hover': {
color: 'var(--tw-prose-links-hover)',
textDecorationColor: 'var(--tw-prose-underline-hover)',
},
strong: {
color: 'var(--tw-prose-bold)',
fontWeight: theme('fontWeight.semibold'),
},
code: {
display: 'inline-block',
color: 'var(--tw-prose-code)',
fontSize: theme('fontSize.sm')[0],
fontWeight: theme('fontWeight.semibold'),
backgroundColor: 'var(--tw-prose-code-bg)',
borderRadius: theme('borderRadius.lg'),
paddingLeft: theme('spacing.1'),
paddingRight: theme('spacing.1'),
},
'a code': {
color: 'inherit',
},
':is(h2, h3) code': {
fontWeight: theme('fontWeight.bold'),
},
// Quotes
blockquote: {
paddingLeft: theme('spacing.6'),
borderLeftWidth: theme('borderWidth.2'),
borderLeftColor: 'var(--tw-prose-quote-borders)',
fontStyle: 'italic',
},
// Figures
figcaption: {
color: 'var(--tw-prose-captions)',
fontSize: theme('fontSize.sm')[0],
lineHeight: theme('lineHeight.6'),
marginTop: theme('spacing.3'),
},
'figcaption > p': {
margin: 0,
},
// Lists
ul: {
listStyleType: 'disc',
},
ol: {
listStyleType: 'decimal',
},
'ul, ol': {
paddingLeft: theme('spacing.6'),
},
li: {
marginTop: theme('spacing.6'),
marginBottom: theme('spacing.6'),
paddingLeft: theme('spacing[3.5]'),
},
'li::marker': {
fontSize: theme('fontSize.sm')[0],
fontWeight: theme('fontWeight.semibold'),
},
'ol > li::marker': {
color: 'var(--tw-prose-counters)',
},
'ul > li::marker': {
color: 'var(--tw-prose-bullets)',
},
'li :is(ol, ul)': {
marginTop: theme('spacing.4'),
marginBottom: theme('spacing.4'),
},
'li :is(li, p)': {
marginTop: theme('spacing.3'),
marginBottom: theme('spacing.3'),
},
// Code blocks
pre: {
color: 'var(--tw-prose-pre-code)',
fontSize: theme('fontSize.sm')[0],
fontWeight: theme('fontWeight.medium'),
backgroundColor: 'var(--tw-prose-pre-bg)',
borderRadius: theme('borderRadius.3xl'),
padding: theme('spacing.8'),
overflowX: 'auto',
border: '1px solid',
borderColor: 'var(--tw-prose-pre-border)',
},
'pre code': {
display: 'inline',
color: 'inherit',
fontSize: 'inherit',
fontWeight: 'inherit',
backgroundColor: 'transparent',
borderRadius: 0,
padding: 0,
},
// Horizontal rules
hr: {
marginTop: theme('spacing.20'),
marginBottom: theme('spacing.20'),
borderTopWidth: '1px',
borderColor: 'var(--tw-prose-hr)',
'@screen lg': {
marginLeft: `calc(${theme('spacing.12')} * -1)`,
marginRight: `calc(${theme('spacing.12')} * -1)`,
},
},
// Tables
table: {
width: '100%',
tableLayout: 'auto',
textAlign: 'left',
fontSize: theme('fontSize.sm')[0],
},
thead: {
borderBottomWidth: '1px',
borderBottomColor: 'var(--tw-prose-th-borders)',
},
'thead th': {
color: 'var(--tw-prose-headings)',
fontWeight: theme('fontWeight.semibold'),
verticalAlign: 'bottom',
paddingBottom: theme('spacing.2'),
},
'thead th:not(:first-child)': {
paddingLeft: theme('spacing.2'),
},
'thead th:not(:last-child)': {
paddingRight: theme('spacing.2'),
},
'tbody tr': {
borderBottomWidth: '1px',
borderBottomColor: 'var(--tw-prose-td-borders)',
},
'tbody tr:last-child': {
borderBottomWidth: 0,
},
'tbody td': {
verticalAlign: 'baseline',
},
tfoot: {
borderTopWidth: '1px',
borderTopColor: 'var(--tw-prose-th-borders)',
},
'tfoot td': {
verticalAlign: 'top',
},
':is(tbody, tfoot) td': {
paddingTop: theme('spacing.2'),
paddingBottom: theme('spacing.2'),
},
':is(tbody, tfoot) td:not(:first-child)': {
paddingLeft: theme('spacing.2'),
},
':is(tbody, tfoot) td:not(:last-child)': {
paddingRight: theme('spacing.2'),
},
},
},
}),
},
}

View File

@@ -0,0 +1,14 @@
---
title: string
link-to-publication: url
link-to-data: url
task-description: string
details-of-task: string
size-of-dataset: number
percentage-abusive: number
language: string
level-of-annotation: list eg: ["Posts", "Comments", ...]
platform: list eg: ["Youtube", "Facebook", ...]
medium: list eg: ["Text", "Emojis", "Images", ...]
reference: string
---

View File

@@ -0,0 +1,5 @@
---
title: string
data-link: url
reference: string
---

View File

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

View File

@@ -1,49 +0,0 @@
import VegaLite from "./VegaLite";
export default function LineChart({
data = [],
fullWidth = false,
title = "",
}) {
var tmp = data;
if (Array.isArray(data)) {
tmp = data.map((r, i) => {
return { x: r[0], y: r[1] };
});
}
const vegaData = { table: tmp };
const spec = {
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
title,
width: 500,
height: 300,
mark: {
type: "line",
color: "black",
strokeWidth: 1,
tooltip: true,
},
data: {
name: "table",
},
selection: {
grid: {
type: "interval",
bind: "scales",
},
},
encoding: {
x: {
field: "x",
timeUnit: "year",
type: "temporal",
},
y: {
field: "y",
type: "quantitative",
},
},
};
return <VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />;
}

View File

@@ -1,6 +0,0 @@
// Wrapper for the Vega Lite component
import { VegaLite as VegaLiteOg } from "react-vega";
export default function VegaLite(props) {
return <VegaLiteOg {...props} />;
}

View File

@@ -1,11 +0,0 @@
# Data
This is the README.md this project.
## Table
<Table url="data_1.csv" />
## Vega Lite Line Chart from URL
<VegaLite spec={ { "$schema": "https://vega.github.io/schema/vega-lite/v5.json", "data": {"url": "data_2.csv"}, "width": 550, "height": 250, "mark": "line", "encoding": { "x": {"field": "Time", "type": "temporal"}, "y": {"field": "Anomaly (deg C)", "type": "quantitative"}, "tooltip": {"field": "Anomaly (deg C)", "type": "quantitative"} } } } />

View File

@@ -1,16 +0,0 @@
import papa from "papaparse";
const parseCsv = (csv) => {
csv = csv.trim();
const rawdata = papa.parse(csv, { header: true });
const cols = rawdata.meta.fields.map((r, i) => {
return { key: r, name: r };
});
return {
rows: rawdata.data,
fields: cols,
};
};
export default parseCsv;

View File

@@ -1,42 +0,0 @@
import { GetStaticProps } from 'next';
import { promises as fs } from 'fs';
import path from 'path';
import parse from '../lib/markdown';
import DRD from '../components/DRD';
export const getServerSideProps = async (context) => {
const indexFile = path.join(process.cwd(), '/content/' + context.params.path.join('/') + '/index.md');
const readme = await fs.readFile(indexFile, 'utf8');
let { mdxSource, frontMatter } = await parse(readme, '.mdx');
return {
props: {
mdxSource,
frontMatter,
},
};
};
export default function DatasetPage({ mdxSource, frontMatter }) {
return (
<div className="prose mx-auto">
<header>
<div className="mb-6">
<>
<h1>{frontMatter.title}</h1>
{frontMatter.author && (
<div className="-mt-6">
<p className="opacity-60 pl-1">{frontMatter.author}</p>
</div>
)}
{frontMatter.description && (
<p className="description">{frontMatter.description}</p>
)}
</>
</div>
</header>
<main>
<DRD source={mdxSource} />
</main>
</div>
);
}

View File

@@ -1,20 +0,0 @@
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
import type { NextApiRequest, NextApiResponse } from 'next'
import { promises as fs } from 'fs';
import path from 'path';
export default async function handler(
req: NextApiRequest,
res: NextApiResponse<string>
) {
const contentDir = path.join(process.cwd(), '/content');
const datasets = await fs.readdir(contentDir);
const query = req.query;
const { fileName } = query;
const dataFile = path.join(
process.cwd(),
'/content/' + datasets[0] + '/' + fileName
);
const data = await fs.readFile(dataFile, 'utf8');
res.status(200).send(data)
}

View File

@@ -1,42 +0,0 @@
import { GetStaticProps } from 'next';
import { promises as fs } from 'fs';
import path from 'path';
import parse from '../lib/markdown';
import DRD from '../components/DRD';
export const getStaticProps = async (context) => {
const indexFile = path.join(process.cwd(), '/content/index.md');
const readme = await fs.readFile(indexFile, 'utf8');
let { mdxSource, frontMatter } = await parse(readme, '.mdx');
return {
props: {
mdxSource,
frontMatter,
},
};
};
export default function DatasetPage({ mdxSource, frontMatter }) {
return (
<div className="prose mx-auto">
<header>
<div className="mb-6">
<>
<h1>{frontMatter.title}</h1>
{frontMatter.author && (
<div className="-mt-6">
<p className="opacity-60 pl-1">{frontMatter.author}</p>
</div>
)}
{frontMatter.description && (
<p className="description">{frontMatter.description}</p>
)}
</>
</div>
</header>
<main>
<DRD source={mdxSource} />
</main>
</div>
);
}

View File

@@ -1,3 +0,0 @@
Year,Temp Anomaly
1850,-0.418
2020,0.923
1 Year Temp Anomaly
2 1850 -0.418
3 2020 0.923

View File

@@ -1,173 +0,0 @@
Time,Anomaly (deg C),Lower confidence limit (2.5%),Upper confidence limit (97.5%)
1850,-0.41765878,-0.589203,-0.24611452
1851,-0.2333498,-0.41186792,-0.054831687
1852,-0.22939907,-0.40938243,-0.04941572
1853,-0.27035445,-0.43000934,-0.110699534
1854,-0.29163003,-0.43282393,-0.15043613
1855,-0.2969512,-0.43935776,-0.15454465
1856,-0.32035372,-0.46809322,-0.1726142
1857,-0.46723005,-0.61632216,-0.31813794
1858,-0.3887657,-0.53688604,-0.24064532
1859,-0.28119546,-0.42384982,-0.13854107
1860,-0.39016518,-0.5389766,-0.24135375
1861,-0.42927712,-0.5972301,-0.26132414
1862,-0.53639776,-0.7037096,-0.36908585
1863,-0.3443432,-0.5341645,-0.1545219
1864,-0.4654367,-0.6480974,-0.282776
1865,-0.33258784,-0.5246526,-0.14052312
1866,-0.34126064,-0.52183825,-0.16068307
1867,-0.35696334,-0.55306214,-0.16086453
1868,-0.35196072,-0.52965826,-0.17426313
1869,-0.31657043,-0.47642276,-0.15671812
1870,-0.32789087,-0.46867347,-0.18710826
1871,-0.3685807,-0.5141493,-0.22301209
1872,-0.32804197,-0.4630833,-0.19300064
1873,-0.34133235,-0.4725396,-0.21012507
1874,-0.3732512,-0.5071426,-0.2393598
1875,-0.37562594,-0.514041,-0.23721085
1876,-0.42410994,-0.56287116,-0.28534868
1877,-0.101108834,-0.22982001,0.027602348
1878,-0.011315193,-0.13121258,0.10858219
1879,-0.30363432,-0.43406433,-0.1732043
1880,-0.31583208,-0.44015095,-0.19151321
1881,-0.23224552,-0.35793498,-0.10655605
1882,-0.29553008,-0.4201501,-0.17091006
1883,-0.3464744,-0.4608177,-0.23213111
1884,-0.49232006,-0.6026686,-0.38197154
1885,-0.47112358,-0.5830682,-0.35917896
1886,-0.42090362,-0.5225382,-0.31926903
1887,-0.49878576,-0.61655986,-0.3810117
1888,-0.37937889,-0.49332377,-0.265434
1889,-0.24989556,-0.37222093,-0.12757017
1890,-0.50685817,-0.6324095,-0.3813068
1891,-0.40131494,-0.5373699,-0.26525995
1892,-0.5075585,-0.64432853,-0.3707885
1893,-0.49461925,-0.6315314,-0.35770702
1894,-0.48376393,-0.6255681,-0.34195974
1895,-0.4487516,-0.58202064,-0.3154826
1896,-0.28400728,-0.4174015,-0.15061308
1897,-0.25980017,-0.39852425,-0.12107607
1898,-0.48579213,-0.6176492,-0.35393503
1899,-0.35543364,-0.48639694,-0.22447036
1900,-0.23447904,-0.3669676,-0.10199049
1901,-0.29342857,-0.42967388,-0.15718324
1902,-0.43898427,-0.5754281,-0.30254042
1903,-0.5333264,-0.66081935,-0.40583345
1904,-0.5975614,-0.7288325,-0.46629035
1905,-0.40775132,-0.5350291,-0.28047356
1906,-0.3191393,-0.45052385,-0.18775477
1907,-0.5041577,-0.6262818,-0.38203365
1908,-0.5138707,-0.63748026,-0.3902612
1909,-0.5357649,-0.6526296,-0.41890016
1910,-0.5310242,-0.6556868,-0.40636164
1911,-0.5392051,-0.66223973,-0.4161705
1912,-0.47567302,-0.5893311,-0.36201498
1913,-0.46715254,-0.5893755,-0.34492958
1914,-0.2625924,-0.38276345,-0.1424214
1915,-0.19184391,-0.32196194,-0.06172589
1916,-0.42020997,-0.5588941,-0.28152588
1917,-0.54301953,-0.6921192,-0.3939199
1918,-0.42458433,-0.58198184,-0.26718682
1919,-0.32551822,-0.48145813,-0.1695783
1920,-0.2985808,-0.44860035,-0.14856121
1921,-0.24067703,-0.38175339,-0.09960067
1922,-0.33922812,-0.46610323,-0.21235302
1923,-0.31793055,-0.444173,-0.1916881
1924,-0.3120622,-0.4388317,-0.18529275
1925,-0.28242525,-0.4147755,-0.15007503
1926,-0.12283547,-0.25264767,0.006976739
1927,-0.22940508,-0.35135695,-0.10745319
1928,-0.20676155,-0.33881804,-0.074705064
1929,-0.39275664,-0.52656746,-0.25894582
1930,-0.1768054,-0.29041144,-0.06319936
1931,-0.10339768,-0.2126916,0.0058962475
1932,-0.14546166,-0.25195515,-0.0389682
1933,-0.32234442,-0.4271004,-0.21758842
1934,-0.17433685,-0.27400395,-0.07466974
1935,-0.20605922,-0.30349734,-0.10862111
1936,-0.16952093,-0.26351926,-0.07552261
1937,-0.01919893,-0.11975875,0.08136089
1938,-0.012200732,-0.11030374,0.08590227
1939,-0.040797167,-0.14670466,0.065110326
1940,0.07593584,-0.04194966,0.19382134
1941,0.038129337,-0.16225387,0.23851255
1942,0.0014060909,-0.1952124,0.19802457
1943,0.0064140745,-0.19959097,0.21241911
1944,0.14410514,-0.054494828,0.3427051
1945,0.043088365,-0.15728289,0.24345961
1946,-0.1188128,-0.2659574,0.028331792
1947,-0.091205545,-0.23179041,0.04937931
1948,-0.12466127,-0.25913337,0.009810844
1949,-0.14380224,-0.2540775,-0.033526987
1950,-0.22662179,-0.33265698,-0.12058662
1951,-0.06115397,-0.15035024,0.028042298
1952,0.015354565,-0.08293597,0.11364509
1953,0.07763074,-0.020529618,0.1757911
1954,-0.11675021,-0.20850271,-0.024997713
1955,-0.19730993,-0.28442997,-0.1101899
1956,-0.2631656,-0.33912563,-0.18720557
1957,-0.035334926,-0.10056862,0.029898768
1958,-0.017632553,-0.083074555,0.04780945
1959,-0.048004825,-0.11036375,0.0143540995
1960,-0.115487024,-0.17416587,-0.056808177
1961,-0.019997388,-0.07078052,0.030785747
1962,-0.06405444,-0.11731443,-0.010794453
1963,-0.03680589,-0.09057008,0.016958294
1964,-0.30586675,-0.34949213,-0.26224136
1965,-0.2043879,-0.25357357,-0.15520222
1966,-0.14888458,-0.19839221,-0.09937696
1967,-0.11751631,-0.16062479,-0.07440783
1968,-0.1686323,-0.21325313,-0.124011464
1969,-0.031366713,-0.07186544,0.009132013
1970,-0.08510657,-0.12608096,-0.04413217
1971,-0.20593274,-0.24450706,-0.16735843
1972,-0.0938271,-0.13171694,-0.05593726
1973,0.04993336,0.013468528,0.086398184
1974,-0.17253734,-0.21022376,-0.1348509
1975,-0.11075424,-0.15130512,-0.07020335
1976,-0.21586166,-0.25588378,-0.17583954
1977,0.10308852,0.060056705,0.14612034
1978,0.0052557723,-0.034576867,0.04508841
1979,0.09085813,0.062358618,0.119357646
1980,0.19607207,0.162804,0.22934014
1981,0.25001204,0.21939126,0.28063282
1982,0.034263328,-0.005104665,0.07363132
1983,0.22383861,0.18807402,0.2596032
1984,0.04800471,0.011560736,0.08444869
1985,0.04972978,0.015663471,0.08379609
1986,0.09568697,0.064408,0.12696595
1987,0.2430264,0.21218552,0.27386728
1988,0.28215173,0.2470353,0.31726816
1989,0.17925027,0.14449838,0.21400215
1990,0.36056247,0.32455227,0.39657268
1991,0.33889654,0.30403617,0.3737569
1992,0.124896795,0.09088206,0.15891153
1993,0.16565846,0.12817313,0.2031438
1994,0.23354977,0.19841294,0.2686866
1995,0.37686616,0.34365577,0.41007656
1996,0.2766894,0.24318004,0.31019878
1997,0.4223085,0.39009082,0.4545262
1998,0.57731646,0.54304415,0.6115888
1999,0.32448497,0.29283476,0.35613516
2000,0.3310848,0.29822788,0.36394167
2001,0.48928034,0.4580683,0.5204924
2002,0.5434665,0.51278186,0.57415116
2003,0.5441702,0.5112426,0.5770977
2004,0.46737072,0.43433833,0.5004031
2005,0.60686255,0.5757053,0.6380198
2006,0.5725527,0.541973,0.60313237
2007,0.5917013,0.56135315,0.6220495
2008,0.46564984,0.43265733,0.49864236
2009,0.5967817,0.56525564,0.6283077
2010,0.68037146,0.649076,0.7116669
2011,0.53769773,0.5060012,0.5693943
2012,0.5776071,0.5448553,0.6103589
2013,0.6235754,0.5884838,0.6586669
2014,0.67287165,0.63890487,0.7068384
2015,0.82511437,0.79128706,0.8589417
2016,0.93292713,0.90176356,0.96409065
2017,0.84517425,0.81477475,0.87557375
2018,0.762654,0.731052,0.79425603
2019,0.8910726,0.85678726,0.92535794
2020,0.9227938,0.8882121,0.9573755
2021,0.6640137,0.5372486,0.79077876
1 Time Anomaly (deg C) Lower confidence limit (2.5%) Upper confidence limit (97.5%)
2 1850 -0.41765878 -0.589203 -0.24611452
3 1851 -0.2333498 -0.41186792 -0.054831687
4 1852 -0.22939907 -0.40938243 -0.04941572
5 1853 -0.27035445 -0.43000934 -0.110699534
6 1854 -0.29163003 -0.43282393 -0.15043613
7 1855 -0.2969512 -0.43935776 -0.15454465
8 1856 -0.32035372 -0.46809322 -0.1726142
9 1857 -0.46723005 -0.61632216 -0.31813794
10 1858 -0.3887657 -0.53688604 -0.24064532
11 1859 -0.28119546 -0.42384982 -0.13854107
12 1860 -0.39016518 -0.5389766 -0.24135375
13 1861 -0.42927712 -0.5972301 -0.26132414
14 1862 -0.53639776 -0.7037096 -0.36908585
15 1863 -0.3443432 -0.5341645 -0.1545219
16 1864 -0.4654367 -0.6480974 -0.282776
17 1865 -0.33258784 -0.5246526 -0.14052312
18 1866 -0.34126064 -0.52183825 -0.16068307
19 1867 -0.35696334 -0.55306214 -0.16086453
20 1868 -0.35196072 -0.52965826 -0.17426313
21 1869 -0.31657043 -0.47642276 -0.15671812
22 1870 -0.32789087 -0.46867347 -0.18710826
23 1871 -0.3685807 -0.5141493 -0.22301209
24 1872 -0.32804197 -0.4630833 -0.19300064
25 1873 -0.34133235 -0.4725396 -0.21012507
26 1874 -0.3732512 -0.5071426 -0.2393598
27 1875 -0.37562594 -0.514041 -0.23721085
28 1876 -0.42410994 -0.56287116 -0.28534868
29 1877 -0.101108834 -0.22982001 0.027602348
30 1878 -0.011315193 -0.13121258 0.10858219
31 1879 -0.30363432 -0.43406433 -0.1732043
32 1880 -0.31583208 -0.44015095 -0.19151321
33 1881 -0.23224552 -0.35793498 -0.10655605
34 1882 -0.29553008 -0.4201501 -0.17091006
35 1883 -0.3464744 -0.4608177 -0.23213111
36 1884 -0.49232006 -0.6026686 -0.38197154
37 1885 -0.47112358 -0.5830682 -0.35917896
38 1886 -0.42090362 -0.5225382 -0.31926903
39 1887 -0.49878576 -0.61655986 -0.3810117
40 1888 -0.37937889 -0.49332377 -0.265434
41 1889 -0.24989556 -0.37222093 -0.12757017
42 1890 -0.50685817 -0.6324095 -0.3813068
43 1891 -0.40131494 -0.5373699 -0.26525995
44 1892 -0.5075585 -0.64432853 -0.3707885
45 1893 -0.49461925 -0.6315314 -0.35770702
46 1894 -0.48376393 -0.6255681 -0.34195974
47 1895 -0.4487516 -0.58202064 -0.3154826
48 1896 -0.28400728 -0.4174015 -0.15061308
49 1897 -0.25980017 -0.39852425 -0.12107607
50 1898 -0.48579213 -0.6176492 -0.35393503
51 1899 -0.35543364 -0.48639694 -0.22447036
52 1900 -0.23447904 -0.3669676 -0.10199049
53 1901 -0.29342857 -0.42967388 -0.15718324
54 1902 -0.43898427 -0.5754281 -0.30254042
55 1903 -0.5333264 -0.66081935 -0.40583345
56 1904 -0.5975614 -0.7288325 -0.46629035
57 1905 -0.40775132 -0.5350291 -0.28047356
58 1906 -0.3191393 -0.45052385 -0.18775477
59 1907 -0.5041577 -0.6262818 -0.38203365
60 1908 -0.5138707 -0.63748026 -0.3902612
61 1909 -0.5357649 -0.6526296 -0.41890016
62 1910 -0.5310242 -0.6556868 -0.40636164
63 1911 -0.5392051 -0.66223973 -0.4161705
64 1912 -0.47567302 -0.5893311 -0.36201498
65 1913 -0.46715254 -0.5893755 -0.34492958
66 1914 -0.2625924 -0.38276345 -0.1424214
67 1915 -0.19184391 -0.32196194 -0.06172589
68 1916 -0.42020997 -0.5588941 -0.28152588
69 1917 -0.54301953 -0.6921192 -0.3939199
70 1918 -0.42458433 -0.58198184 -0.26718682
71 1919 -0.32551822 -0.48145813 -0.1695783
72 1920 -0.2985808 -0.44860035 -0.14856121
73 1921 -0.24067703 -0.38175339 -0.09960067
74 1922 -0.33922812 -0.46610323 -0.21235302
75 1923 -0.31793055 -0.444173 -0.1916881
76 1924 -0.3120622 -0.4388317 -0.18529275
77 1925 -0.28242525 -0.4147755 -0.15007503
78 1926 -0.12283547 -0.25264767 0.006976739
79 1927 -0.22940508 -0.35135695 -0.10745319
80 1928 -0.20676155 -0.33881804 -0.074705064
81 1929 -0.39275664 -0.52656746 -0.25894582
82 1930 -0.1768054 -0.29041144 -0.06319936
83 1931 -0.10339768 -0.2126916 0.0058962475
84 1932 -0.14546166 -0.25195515 -0.0389682
85 1933 -0.32234442 -0.4271004 -0.21758842
86 1934 -0.17433685 -0.27400395 -0.07466974
87 1935 -0.20605922 -0.30349734 -0.10862111
88 1936 -0.16952093 -0.26351926 -0.07552261
89 1937 -0.01919893 -0.11975875 0.08136089
90 1938 -0.012200732 -0.11030374 0.08590227
91 1939 -0.040797167 -0.14670466 0.065110326
92 1940 0.07593584 -0.04194966 0.19382134
93 1941 0.038129337 -0.16225387 0.23851255
94 1942 0.0014060909 -0.1952124 0.19802457
95 1943 0.0064140745 -0.19959097 0.21241911
96 1944 0.14410514 -0.054494828 0.3427051
97 1945 0.043088365 -0.15728289 0.24345961
98 1946 -0.1188128 -0.2659574 0.028331792
99 1947 -0.091205545 -0.23179041 0.04937931
100 1948 -0.12466127 -0.25913337 0.009810844
101 1949 -0.14380224 -0.2540775 -0.033526987
102 1950 -0.22662179 -0.33265698 -0.12058662
103 1951 -0.06115397 -0.15035024 0.028042298
104 1952 0.015354565 -0.08293597 0.11364509
105 1953 0.07763074 -0.020529618 0.1757911
106 1954 -0.11675021 -0.20850271 -0.024997713
107 1955 -0.19730993 -0.28442997 -0.1101899
108 1956 -0.2631656 -0.33912563 -0.18720557
109 1957 -0.035334926 -0.10056862 0.029898768
110 1958 -0.017632553 -0.083074555 0.04780945
111 1959 -0.048004825 -0.11036375 0.0143540995
112 1960 -0.115487024 -0.17416587 -0.056808177
113 1961 -0.019997388 -0.07078052 0.030785747
114 1962 -0.06405444 -0.11731443 -0.010794453
115 1963 -0.03680589 -0.09057008 0.016958294
116 1964 -0.30586675 -0.34949213 -0.26224136
117 1965 -0.2043879 -0.25357357 -0.15520222
118 1966 -0.14888458 -0.19839221 -0.09937696
119 1967 -0.11751631 -0.16062479 -0.07440783
120 1968 -0.1686323 -0.21325313 -0.124011464
121 1969 -0.031366713 -0.07186544 0.009132013
122 1970 -0.08510657 -0.12608096 -0.04413217
123 1971 -0.20593274 -0.24450706 -0.16735843
124 1972 -0.0938271 -0.13171694 -0.05593726
125 1973 0.04993336 0.013468528 0.086398184
126 1974 -0.17253734 -0.21022376 -0.1348509
127 1975 -0.11075424 -0.15130512 -0.07020335
128 1976 -0.21586166 -0.25588378 -0.17583954
129 1977 0.10308852 0.060056705 0.14612034
130 1978 0.0052557723 -0.034576867 0.04508841
131 1979 0.09085813 0.062358618 0.119357646
132 1980 0.19607207 0.162804 0.22934014
133 1981 0.25001204 0.21939126 0.28063282
134 1982 0.034263328 -0.005104665 0.07363132
135 1983 0.22383861 0.18807402 0.2596032
136 1984 0.04800471 0.011560736 0.08444869
137 1985 0.04972978 0.015663471 0.08379609
138 1986 0.09568697 0.064408 0.12696595
139 1987 0.2430264 0.21218552 0.27386728
140 1988 0.28215173 0.2470353 0.31726816
141 1989 0.17925027 0.14449838 0.21400215
142 1990 0.36056247 0.32455227 0.39657268
143 1991 0.33889654 0.30403617 0.3737569
144 1992 0.124896795 0.09088206 0.15891153
145 1993 0.16565846 0.12817313 0.2031438
146 1994 0.23354977 0.19841294 0.2686866
147 1995 0.37686616 0.34365577 0.41007656
148 1996 0.2766894 0.24318004 0.31019878
149 1997 0.4223085 0.39009082 0.4545262
150 1998 0.57731646 0.54304415 0.6115888
151 1999 0.32448497 0.29283476 0.35613516
152 2000 0.3310848 0.29822788 0.36394167
153 2001 0.48928034 0.4580683 0.5204924
154 2002 0.5434665 0.51278186 0.57415116
155 2003 0.5441702 0.5112426 0.5770977
156 2004 0.46737072 0.43433833 0.5004031
157 2005 0.60686255 0.5757053 0.6380198
158 2006 0.5725527 0.541973 0.60313237
159 2007 0.5917013 0.56135315 0.6220495
160 2008 0.46564984 0.43265733 0.49864236
161 2009 0.5967817 0.56525564 0.6283077
162 2010 0.68037146 0.649076 0.7116669
163 2011 0.53769773 0.5060012 0.5693943
164 2012 0.5776071 0.5448553 0.6103589
165 2013 0.6235754 0.5884838 0.6586669
166 2014 0.67287165 0.63890487 0.7068384
167 2015 0.82511437 0.79128706 0.8589417
168 2016 0.93292713 0.90176356 0.96409065
169 2017 0.84517425 0.81477475 0.87557375
170 2018 0.762654 0.731052 0.79425603
171 2019 0.8910726 0.85678726 0.92535794
172 2020 0.9227938 0.8882121 0.9573755
173 2021 0.6640137 0.5372486 0.79077876

View File

@@ -1,4 +0,0 @@
<svg width="283" height="64" viewBox="0 0 283 64" fill="none"
xmlns="http://www.w3.org/2000/svg">
<path d="M141.04 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.46 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM248.72 16c-11.04 0-19 7.2-19 18s8.96 18 20 18c6.67 0 12.55-2.64 16.19-7.09l-7.65-4.42c-2.02 2.21-5.09 3.5-8.54 3.5-4.79 0-8.86-2.5-10.37-6.5h28.02c.22-1.12.35-2.28.35-3.5 0-10.79-7.96-17.99-19-17.99zm-9.45 14.5c1.25-3.99 4.67-6.5 9.45-6.5 4.79 0 8.21 2.51 9.45 6.5h-18.9zM200.24 34c0 6 3.92 10 10 10 4.12 0 7.21-1.87 8.8-4.92l7.68 4.43c-3.18 5.3-9.14 8.49-16.48 8.49-11.05 0-19-7.2-19-18s7.96-18 19-18c7.34 0 13.29 3.19 16.48 8.49l-7.68 4.43c-1.59-3.05-4.68-4.92-8.8-4.92-6.07 0-10 4-10 10zm82.48-29v46h-9V5h9zM36.95 0L73.9 64H0L36.95 0zm92.38 5l-27.71 48L73.91 5H84.3l17.32 30 17.32-30h10.39zm58.91 12v9.69c-1-.29-2.06-.49-3.2-.49-5.81 0-10 4-10 10V51h-9V17h9v9.2c0-5.08 5.91-9.2 13.2-9.2z" fill="#000"/>
</svg>

Before

Width:  |  Height:  |  Size: 1.1 KiB

View File

@@ -1,129 +0,0 @@
.container {
padding: 0 2rem;
}
.main {
min-height: 100vh;
padding: 4rem 0;
flex: 1;
display: flex;
flex-direction: column;
justify-content: center;
align-items: center;
}
.footer {
display: flex;
flex: 1;
padding: 2rem 0;
border-top: 1px solid #eaeaea;
justify-content: center;
align-items: center;
}
.footer a {
display: flex;
justify-content: center;
align-items: center;
flex-grow: 1;
}
.title a {
color: #0070f3;
text-decoration: none;
}
.title a:hover,
.title a:focus,
.title a:active {
text-decoration: underline;
}
.title {
margin: 0;
line-height: 1.15;
font-size: 4rem;
}
.title,
.description {
text-align: center;
}
.description {
margin: 4rem 0;
line-height: 1.5;
font-size: 1.5rem;
}
.code {
background: #fafafa;
border-radius: 5px;
padding: 0.75rem;
font-size: 1.1rem;
font-family: Menlo, Monaco, Lucida Console, Liberation Mono, DejaVu Sans Mono,
Bitstream Vera Sans Mono, Courier New, monospace;
}
.grid {
display: flex;
align-items: center;
justify-content: center;
flex-wrap: wrap;
max-width: 800px;
}
.card {
margin: 1rem;
padding: 1.5rem;
text-align: left;
color: inherit;
text-decoration: none;
border: 1px solid #eaeaea;
border-radius: 10px;
transition: color 0.15s ease, border-color 0.15s ease;
max-width: 300px;
}
.card:hover,
.card:focus,
.card:active {
color: #0070f3;
border-color: #0070f3;
}
.card h2 {
margin: 0 0 1rem 0;
font-size: 1.5rem;
}
.card p {
margin: 0;
font-size: 1.25rem;
line-height: 1.5;
}
.logo {
height: 1em;
margin-left: 0.5rem;
}
@media (max-width: 600px) {
.grid {
width: 100%;
flex-direction: column;
}
}
@media (prefers-color-scheme: dark) {
.card,
.footer {
border-color: #222;
}
.code {
background: #111;
}
.logo img {
filter: invert(1);
}
}

View File

@@ -10,24 +10,24 @@
},
"dependencies": {
"@heroicons/react": "^2.0.17",
"@types/node": "18.16.0",
"@types/react": "18.0.38",
"@types/react-dom": "18.0.11",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"next": "13.3.1",
"next-seo": "^6.0.0",
"octokit": "^2.0.14",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-markdown": "^8.0.7",
"remark-gfm": "^3.0.1",
"typescript": "5.0.4"
"remark-gfm": "^3.0.1"
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"autoprefixer": "^10.4.14",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.1"
"tailwindcss": "^3.3.1",
"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

@@ -0,0 +1,3 @@
{
"extends": "next/core-web-vitals"
}

View File

@@ -0,0 +1,35 @@
# 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

@@ -8,6 +8,8 @@ First, run the development server:
npm run dev
# or
yarn dev
# or
pnpm dev
```
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
@@ -18,6 +20,8 @@ You can start editing the page by modifying `pages/index.tsx`. The page auto-upd
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:

File diff suppressed because it is too large Load Diff

View File

@@ -1,7 +1,6 @@
/** @type {import('next').NextConfig} */
const nextConfig = {
reactStrictMode: true,
swcMinify: true,
}
module.exports = nextConfig

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,26 @@
{
"name": "fiverthirtyeight-example",
"version": "0.1.0",
"private": true,
"scripts": {
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
},
"dependencies": {
"@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",
"next": "13.4.1",
"postcss": "8.4.23",
"react": "18.2.0",
"react-dom": "18.2.0",
"tailwindcss": "3.3.2",
"timeago.js": "^4.0.2",
"typescript": "5.0.4"
}
}

View File

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

View File

@@ -0,0 +1,13 @@
import { Html, Head, Main, NextScript } from 'next/document'
export default function Document() {
return (
<Html lang="en">
<Head />
<body>
<Main />
<NextScript />
</body>
</Html>
)
}

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

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 394 80"><path fill="#000" d="M262 0h68.5v12.7h-27.2v66.6h-13.6V12.7H262V0ZM149 0v12.7H94v20.4h44.3v12.6H94v21h55v12.6H80.5V0h68.7zm34.3 0h-17.8l63.8 79.4h17.9l-32-39.7 32-39.6h-17.9l-23 28.6-23-28.6zm18.3 56.7-9-11-27.1 33.7h17.8l18.3-22.7z"/><path fill="#000" d="M81 79.3 17 0H0v79.3h13.6V17l50.2 62.3H81Zm252.6-.4c-1 0-1.8-.4-2.5-1s-1.1-1.6-1.1-2.6.3-1.8 1-2.5 1.6-1 2.6-1 1.8.3 2.5 1a3.4 3.4 0 0 1 .6 4.3 3.7 3.7 0 0 1-3 1.8zm23.2-33.5h6v23.3c0 2.1-.4 4-1.3 5.5a9.1 9.1 0 0 1-3.8 3.5c-1.6.8-3.5 1.3-5.7 1.3-2 0-3.7-.4-5.3-1s-2.8-1.8-3.7-3.2c-.9-1.3-1.4-3-1.4-5h6c.1.8.3 1.6.7 2.2s1 1.2 1.6 1.5c.7.4 1.5.5 2.4.5 1 0 1.8-.2 2.4-.6a4 4 0 0 0 1.6-1.8c.3-.8.5-1.8.5-3V45.5zm30.9 9.1a4.4 4.4 0 0 0-2-3.3 7.5 7.5 0 0 0-4.3-1.1c-1.3 0-2.4.2-3.3.5-.9.4-1.6 1-2 1.6a3.5 3.5 0 0 0-.3 4c.3.5.7.9 1.3 1.2l1.8 1 2 .5 3.2.8c1.3.3 2.5.7 3.7 1.2a13 13 0 0 1 3.2 1.8 8.1 8.1 0 0 1 3 6.5c0 2-.5 3.7-1.5 5.1a10 10 0 0 1-4.4 3.5c-1.8.8-4.1 1.2-6.8 1.2-2.6 0-4.9-.4-6.8-1.2-2-.8-3.4-2-4.5-3.5a10 10 0 0 1-1.7-5.6h6a5 5 0 0 0 3.5 4.6c1 .4 2.2.6 3.4.6 1.3 0 2.5-.2 3.5-.6 1-.4 1.8-1 2.4-1.7a4 4 0 0 0 .8-2.4c0-.9-.2-1.6-.7-2.2a11 11 0 0 0-2.1-1.4l-3.2-1-3.8-1c-2.8-.7-5-1.7-6.6-3.2a7.2 7.2 0 0 1-2.4-5.7 8 8 0 0 1 1.7-5 10 10 0 0 1 4.3-3.5c2-.8 4-1.2 6.4-1.2 2.3 0 4.4.4 6.2 1.2 1.8.8 3.2 2 4.3 3.4 1 1.4 1.5 3 1.5 5h-5.8z"/></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

View File

@@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" fill="none" viewBox="0 0 283 64"><path fill="black" d="M141 16c-11 0-19 7-19 18s9 18 20 18c7 0 13-3 16-7l-7-5c-2 3-6 4-9 4-5 0-9-3-10-7h28v-3c0-11-8-18-19-18zm-9 15c1-4 4-7 9-7s8 3 9 7h-18zm117-15c-11 0-19 7-19 18s9 18 20 18c6 0 12-3 16-7l-8-5c-2 3-5 4-8 4-5 0-9-3-11-7h28l1-3c0-11-8-18-19-18zm-10 15c2-4 5-7 10-7s8 3 9 7h-19zm-39 3c0 6 4 10 10 10 4 0 7-2 9-5l8 5c-3 5-9 8-17 8-11 0-19-7-19-18s8-18 19-18c8 0 14 3 17 8l-8 5c-2-3-5-5-9-5-6 0-10 4-10 10zm83-29v46h-9V5h9zM37 0l37 64H0L37 0zm92 5-27 48L74 5h10l18 30 17-30h10zm59 12v10l-3-1c-6 0-10 4-10 10v15h-9V17h9v9c0-5 6-9 13-9z"/></svg>

After

Width:  |  Height:  |  Size: 629 B

View File

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

View File

@@ -0,0 +1,18 @@
/** @type {import('tailwindcss').Config} */
module.exports = {
content: [
'./pages/**/*.{js,ts,jsx,tsx,mdx}',
'./components/**/*.{js,ts,jsx,tsx,mdx}',
'./app/**/*.{js,ts,jsx,tsx,mdx}',
],
theme: {
extend: {
backgroundImage: {
'gradient-radial': 'radial-gradient(var(--tw-gradient-stops))',
'gradient-conic':
'conic-gradient(from 180deg at 50% 50%, var(--tw-gradient-stops))',
},
},
},
plugins: [],
}

View File

@@ -0,0 +1,23 @@
{
"compilerOptions": {
"target": "es5",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,
"strict": true,
"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

@@ -0,0 +1 @@
PortalJS Learn Example - https://portaljs.org/docs

View File

@@ -7,13 +7,12 @@ import { Mermaid } from '@flowershow/core';
// to handle import statements. Instead, you must include components in scope
// here.
const components = {
Table: dynamic(() => import('./Table')),
Table: dynamic(() => import('@portaljs/components').then(mod => mod.Table)),
Catalog: dynamic(() => import('@portaljs/components').then(mod => mod.Catalog)),
mermaid: Mermaid,
// Excel: dynamic(() => import('../components/Excel')),
// TODO: try and make these dynamic ...
Vega: dynamic(() => import('./Vega')),
VegaLite: dynamic(() => import('./VegaLite')),
LineChart: dynamic(() => import('./LineChart')),
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 }) {

View File

@@ -4,5 +4,4 @@ Built with PortalJS
## Table
<Table url="data_1.csv" />
<Table url="data.csv" />

View File

@@ -22,7 +22,7 @@ import { serialize } from "next-mdx-remote/serialize";
* @format: used to indicate to next-mdx-remote which format to use (md or mdx)
* @returns: { mdxSource: mdxSource, frontMatter: ...}
*/
const parse = async function (source, format) {
const parse = async function (source, format, scope) {
const { content, data, excerpt } = matter(source, {
excerpt: (file, options) => {
// Generate an excerpt for the file
@@ -91,7 +91,7 @@ const parse = async function (source, format) {
],
format,
},
scope: data,
scope,
}
);

View File

@@ -0,0 +1,14 @@
import { MarkdownDB } from "@flowershow/markdowndb";
const dbPath = "markdown.db";
const client = new MarkdownDB({
client: "sqlite3",
connection: {
filename: dbPath,
},
});
const clientPromise = client.init();
export default clientPromise;

View File

@@ -6,21 +6,22 @@
"dev": "next dev",
"build": "next build",
"start": "next start",
"lint": "next lint"
"lint": "next lint",
"export": "npm run build && next export -o out",
"prebuild": "npm run mddb",
"mddb": "mddb ./content"
},
"dependencies": {
"@flowershow/core": "^0.4.10",
"@flowershow/markdowndb": "^0.1.1",
"@flowershow/remark-callouts": "^1.0.0",
"@flowershow/remark-embed": "^1.0.0",
"@flowershow/remark-wiki-link": "^1.1.2",
"@heroicons/react": "^2.0.17",
"@opentelemetry/api": "^1.4.0",
"@portaljs/components": "^0.1.0",
"@tanstack/react-table": "^8.8.5",
"@types/node": "18.16.0",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"flexsearch": "0.7.21",
"gray-matter": "^4.0.3",
"hastscript": "^7.2.0",
"mdx-mermaid": "2.0.0-rc7",
@@ -29,6 +30,7 @@
"papaparse": "^5.4.1",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-vega": "^7.6.0",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex": "^6.0.3",
@@ -42,7 +44,13 @@
},
"devDependencies": {
"@tailwindcss/typography": "^0.5.9",
"@types/flexsearch": "^0.7.3",
"@types/node": "18.16.0",
"@types/react": "18.2.0",
"@types/react-dom": "18.2.0",
"autoprefixer": "^10.4.14",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"postcss": "^8.4.23",
"tailwindcss": "^3.3.1"
}

View File

@@ -0,0 +1,126 @@
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';
export const getStaticPaths = async () => {
const contentDir = path.join(process.cwd(), '/content/');
const contentFolders = await fs.readdir(contentDir, 'utf8');
const paths = contentFolders.map((folder: string) =>
folder === 'index.md'
? { params: { path: [] } }
: { params: { path: [folder] } }
);
return {
paths,
fallback: false,
};
};
export const getStaticProps = async (context) => {
let pathToFile = 'index.md';
if (context.params.path) {
pathToFile = context.params.path.join('/') + '/index.md';
}
let datasets = [];
const mddbFileExists = existsSync('markdown.db');
if (mddbFileExists) {
const mddb = await clientPromise;
const datasetsFiles = await mddb.getFiles({
extensions: ['md', 'mdx'],
});
datasets = datasetsFiles
.filter((dataset) => dataset.url_path !== '/')
.map((dataset) => ({
_id: dataset._id,
url_path: dataset.url_path,
file_path: dataset.file_path,
metadata: dataset.metadata,
}));
}
const indexFile = path.join(process.cwd(), '/content/' + pathToFile);
const readme = await fs.readFile(indexFile, 'utf8');
let { mdxSource, frontMatter } = await parse(readme, '.mdx', { datasets });
return {
props: {
mdxSource,
frontMatter: JSON.stringify(frontMatter),
},
};
};
export default function DatasetPage({ mdxSource, frontMatter }) {
frontMatter = JSON.parse(frontMatter);
return (
<div className="prose dark:prose-invert 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>
);
}

View File

@@ -0,0 +1,8 @@
import '../styles/globals.css'
import '@portaljs/components/styles.css'
import type { AppProps } from 'next/app'
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
}

View File

@@ -0,0 +1,19 @@
import Document, { Html, Main, Head, NextScript } from 'next/document';
class MyDocument extends Document {
render() {
return (
<Html>
<Head>
<link rel="icon" href="/favicon.png" />
</Head>
<body className='bg-white dark:bg-gray-900'>
<Main />
<NextScript />
</body>
</Html>
);
}
}
export default MyDocument;

View File

@@ -0,0 +1,6 @@
module.exports = {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

View File

@@ -0,0 +1,6 @@
Year,Rating
2008,86
2009,96
2010,100
2011,100
2012,97
1 Year Rating
2 2008 86
3 2009 96
4 2010 100
5 2011 100
6 2012 97

Binary file not shown.

After

Width:  |  Height:  |  Size: 37 KiB

View File

@@ -1,6 +1,6 @@
{
"compilerOptions": {
"target": "es5",
"target": "es6",
"lib": ["dom", "dom.iterable", "esnext"],
"allowJs": true,
"skipLibCheck": true,

1424
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -4,11 +4,10 @@
"license": "MIT",
"scripts": {},
"private": true,
"dependencies": {},
"devDependencies": {
"@babel/preset-react": "^7.14.5",
"@nrwl/cypress": "15.9.2",
"@nrwl/eslint-plugin-nx": "15.9.2",
"@nrwl/eslint-plugin-nx": "^16.0.2",
"@nrwl/jest": "15.9.2",
"@nrwl/js": "15.9.2",
"@nrwl/linter": "15.9.2",

View File

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.8 KiB

View File

Before

Width:  |  Height:  |  Size: 627 B

After

Width:  |  Height:  |  Size: 627 B

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