Compare commits

..

23 Commits

Author SHA1 Message Date
Ola Rubaj
af134cac8b Integrate flowershow packages (#923)
* [packages][m]: mv @flowershow/core package here

* [packages/core][xs]: rename to @portaljs/core

* [package.json][xs]: setup npm workspaces

* [packages/core][xs]:replace deprecated rollup executor

* [core/package.json][s]: fix mermaid versions

* [core/tsconfig][xs]: rm extends

* [core/jest.config][xs]: rm coverageDirectory

* [core/package.json][xs]: install core-js

* [packages.json][s]:use same version for all nrwl packages

* [core/.eslintrc][xs]: adjust ignorePatterns

* [core/project.json][xs]: rm publish targets

* [packages][m]: mv @flowershow/remark-wiki-link here

* [packages][m]: mv @flowershow/remark-wiki-link here

* [packages][m]: mv @flowershow/remark-embed here

* [remark-callouts/project.json][xs]: adjst test pattern

* [package.json][s]: install missing deps

* [remark-callouts][xs]: adjst fields in package.json

* [remark-callouts][s]: rm pubish targets and adjst build executor

* [remark-embed/jest.config][xs]: rm unknown option coverageDirectory

* [remark-embed][xs]: rm publish targets

* [remark-embed][s]: rename to @portaljs/remark-embed

* [remark-wiki-link/eslintrc][xs]:adjst ignorePatterns

* [package.json][xs]: install missing deps

* [remark-wiki-link/test][xs]:specify format

- also temporarily force any type on htmlExtension

* [remark-wiki-link/README][xs]: replace @flowershow with @portaljs

* [remark-wiki-link][xs]:rm old changelog

* [remark-wiki-link][xs]: adjst package.json

* [remark-wiki-link/project.json][xs]: rm publish targets

* [core][s]: rm old changelog

* [core/README][xs]:correct scope name

* [remark-callouts/README][xs]: add @portaljs to pckg name

* [remark-embed/README][xs]: add @portaljs to pckg name

* [package-lock.json][xs]: refresh after rebasing on main
2023-06-07 07:21:00 -03:00
github-actions[bot]
0b8c56bcac Version Packages (#934)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-06 22:33:32 -03:00
Luccas Mateus de Medeiros Gomes
20c64222c1 [examples/openspending][xs] - fix styling 2023-06-06 21:59:21 -03:00
João Demenech
683159da02 @portaljs/components improvements (#933)
* [#912,@portaljs/components][s]: create LoadingSpinner component and add that to <Table /> when using the URL parameter

* [#912,@portaljs/components][m]: refactor LineChart and add more params

* [#912,@portaljs/components][m]: possibly fixes 'loading...' size on FlatUiTable on Firefox

* [@portaljs/components][xs]: add storybook-static to .gitignore

* Add changeset
2023-06-06 21:21:31 -03:00
Luccas Mateus de Medeiros Gomes
c0681fdc7f [examples][m] - update examples to use new package version 2023-06-06 13:51:41 -03:00
Luccas Mateus de Medeiros Gomes
ec1910e016 [packages/components][xs] - update version 2023-06-06 13:02:39 -03:00
Luccas Mateus
fc70f6ec66 [examples/openspending][lg] - adding drd support (#928)
* [examples/openspending][lg] - adding drd support

* [examples/openspending][sm] - add data stories to header
2023-06-06 12:58:54 -03:00
João Demenech
8e4428e2f8 github-backed-catalog: improve documentation (#925)
* [examples/github-backed-catalog][m]: improve documentation

* [examples/github-backed-catalog][m]: add info about editing the deployment created on Vercel
2023-06-06 07:28:51 -03:00
github-actions[bot]
1292350aac Version Packages (#926)
Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
2023-06-06 07:26:45 -03:00
João Demenech
e4da3ed672 Merge pull request #924 from datopian/fix-redeclaration-of-formal-parameter-error
[packages/components][m] - fix error on build
2023-06-05 16:22:09 -03:00
Luccas Mateus de Medeiros Gomes
959fe5a588 [packages/components][m] - fix error on build 2023-06-05 14:23:57 -03:00
João Demenech
7a46a6732b [examples/openspending,footer,#897][s]: add PortalJS logo to the footer 2023-06-05 13:13:39 -03:00
Ola Rubaj
688db3e6a6 Changesets setup + auto-publish to npm (#922)
Closes #905 

## Summary

This PR sets up changesets with the aim to simplify the process of documenting changes committed to the codebase, as well as automating versioning packages and publishing them to npm.

## Changes
- initialised [changesets](https://github.com/changesets/changesets) in the repository
- (separately from this PR) installed [changesets bot](https://github.com/apps/changeset-bot) in the repository (it will check if a submitted PR includes a changeset file and inform if found or not)
- added `.github/workflows/release.yml`: The workflow creates a PR with version bumps and related changelog
files' updates, each time a commit containing changeset
file(s) is added to the main branch. After merging this auto-generated PR, this workflow will also auto-publish the released packages to npm and add git tags.
- added the following scripts to the root `package.json`:
  - `changeset`: should be run to generate changeset files, that describe changes made to the code,
  - `prerelease`: runs linting and testing on packages affected by the changes in a PR
  - `release`: runs `changeset publish` and is used by the `release` workflow then the above-mentioned auto-generated PR is merged to the main branch
2023-06-05 17:41:37 +02:00
João Demenech
fa642d8914 [examples/learn,docs][xs]: fix typo 2023-06-02 18:59:04 -03:00
João Demenech
c80b283201 [examples/learn,docs,#910][m]: add conclusions at the end of each tutorial, add page title to each tutorial page, fix hydration error re modified metadata field 2023-06-02 18:52:56 -03:00
Luccas Mateus de Medeiros Gomes
95fd8e72df [examples/openspending][sm] - 5mb to 500kb on preview 2023-06-02 09:38:13 -03:00
João Demenech
e50c76090c [examples/openspending][xs]: make year be displayed in UUTC timezone on DatasetCard 2023-06-01 15:39:15 -03:00
Luccas Mateus de Medeiros Gomes
70012d7c03 [examples/538][m] - added GA 2023-06-01 10:50:59 -03:00
Luccas Mateus de Medeiros Gomes
024c06d9cd [examples/538][xs] - change read more link 2023-06-01 10:41:43 -03:00
Luccas Mateus de Medeiros Gomes
35668c069e [examples/538][xs] - change order of datasets 2023-06-01 10:36:04 -03:00
Luccas Mateus de Medeiros Gomes
2500779499 [examples/538][m] - changes requested by anu 2023-06-01 10:30:17 -03:00
João Demenech
fc8eb95dbc Open Spending: minor improvements (#918)
* [examples/openspending][xs]: center align footer and make file previews wider

* Run prettier

---------

Co-authored-by: deme <deme@deme>
2023-06-01 10:19:39 -03:00
Anuar Ustayev (aka Anu)
45089419da Merge pull request #917 from datopian/fivethirtyeight-v0.2
[examples/538][m] - v0.2
2023-06-01 20:17:04 +07:00
352 changed files with 41567 additions and 7101 deletions

8
.changeset/README.md Normal file
View File

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

14
.changeset/config.json Normal file
View File

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

39
.github/workflows/release.yml vendored Normal file
View File

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

View File

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

View File

@@ -27,7 +27,7 @@ export default function Layout({ children }: { children: React.ReactNode }) {
website.{' '}
<a
className="hover:underline font-bold"
href="https://github.com/datopian/portaljs/tree/main/examples/fivethirtyeight"
href="https://github.com/datopian/portaljs/tree/main/examples/fivethirtyeight#readme"
>
Read more here
</a>{' '}

View File

@@ -1,33 +1,4 @@
[
{
"url": "https://github.com/fivethirtyeight/data/tree/master/polls",
"name": "polls",
"displayName": "<span class=\"lastword\">polls</span>",
"articles": [
{
"date": "2023-05-11T14:35:40.000Z",
"title": "Latest Polls",
"url": "https://projects.fivethirtyeight.com/polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_approval_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls_historical.csv",
"https://projects.fivethirtyeight.com/2020-primary-data/pres_primary_avgs_2020.csv",
"https://projects.fivethirtyeight.com/2020-general-data/presidential_poll_averages_2020.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/congress-generic-ballot",
"name": "congress-generic-ballot",
@@ -195,6 +166,35 @@
}
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/polls",
"name": "polls",
"displayName": "<span class=\"lastword\">polls</span>",
"articles": [
{
"date": "2023-05-11T14:35:40.000Z",
"title": "Latest Polls",
"url": "https://projects.fivethirtyeight.com/polls/"
}
],
"files": [
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_primary_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/senate_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/house_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/governor_polls_historical.csv",
"https://projects.fivethirtyeight.com/polls-page/data/president_approval_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls.csv",
"https://projects.fivethirtyeight.com/polls-page/data/generic_ballot_polls_historical.csv",
"https://projects.fivethirtyeight.com/2020-primary-data/pres_primary_avgs_2020.csv",
"https://projects.fivethirtyeight.com/2020-general-data/presidential_poll_averages_2020.csv"
]
},
{
"url": "https://github.com/fivethirtyeight/data/tree/master/nfl-elo",
"name": "nfl-elo",

File diff suppressed because it is too large Load Diff

View File

@@ -9,9 +9,10 @@
"lint": "next lint"
},
"dependencies": {
"@flowershow/core": "^0.4.13",
"@headlessui/react": "^1.7.14",
"@heroicons/react": "^2.0.18",
"@portaljs/components": "^0.1.7",
"@portaljs/components": "^0.1.8",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "20.1.1",
"@types/react": "18.2.6",

View File

@@ -1,8 +1,49 @@
import '@/styles/globals.css'
import '@portaljs/components/styles.css'
import '@/styles/globals.css';
import '@portaljs/components/styles.css';
import { useEffect } from 'react';
import { pageview } from '@flowershow/core';
import Script from 'next/script';
import Head from 'next/head';
import { useRouter } from 'next/router';
import type { AppProps } from 'next/app'
import type { AppProps } from 'next/app';
export default function App({ Component, pageProps }: AppProps) {
return <Component {...pageProps} />
const router = useRouter();
useEffect(() => {
const handleRouteChange = (url: any) => {
pageview(url);
};
router.events.on('routeChangeComplete', handleRouteChange);
return () => {
router.events.off('routeChangeComplete', handleRouteChange);
};
}, [router.events]);
return (
<>
<Head>
<link rel="shortcut icon" href="/squared_logo.png" />
</Head>
<Script
strategy="afterInteractive"
src="https://www.googletagmanager.com/gtag/js?id=G-3N9SXTC7GS"
/>
<Script
id="gtag-init"
strategy="afterInteractive"
dangerouslySetInnerHTML={{
__html: `
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', 'G-3N9SXTC7GS', {
page_path: window.location.pathname,
});
`,
}}
/>
<Component {...pageProps} />
</>
);
}

View File

@@ -32,10 +32,10 @@ export default function DatasetPage({
<>
<NextSeo title={`${dataset.name} page`} />
<Layout>
<main className="max-w-5xl px-2 prose mx-auto my-8 prose-thead:border-b-4 prose-table:max-w-5xl prose-table:overflow-scroll prose-thead:overflow-scroll prose-tbody:overflow-scroll prose-thead:pb-2 prose-thead:border-zinc-900 prose-th:uppercase prose-th:text-left prose-th:font-light prose-th:text-xs prose-a:no-underline">
<main className="max-w-5xl px-2 prose mx-auto my-8 pb-8 prose-thead:border-b-4 prose-table:max-w-5xl prose-table:overflow-scroll prose-thead:overflow-scroll prose-tbody:overflow-scroll prose-thead:pb-2 prose-thead:border-zinc-900 prose-th:uppercase prose-th:text-left prose-th:font-light prose-th:text-xs prose-a:no-underline">
<Breadcrumbs links={[{ title: dataset.name, href: '' }]} />
<h1 className="uppercase mb-0 mt-16">{dataset.name}</h1>
<table className="w-full my-10 mb-4 hidden md:table">
<table className="w-full my-10 mb-8 hidden md:table">
<thead className="border-b-4 pb-2 border-zinc-900">
<tr>
<th className="uppercase text-left font-normal text-xs pb-3">
@@ -117,7 +117,7 @@ export default function DatasetPage({
</div>
{dataset.files && dataset.files.length > 0 && (
<>
<h2 className="mb-0 mt-10">Data Previews</h2>
<h2 className="mb-0 mt-8">Data Previews</h2>
{dataset.files?.map((file) => (
<div
key={file}

View File

@@ -5,3 +5,7 @@
.preview-table > div {
overflow-y: hidden;
}
.prose h1 {
font-size: 1.5em !important;
}

View File

@@ -7,13 +7,13 @@ import { Mermaid } from '@flowershow/core';
// to handle import statements. Instead, you must include components in scope
// here.
const components = {
Table: dynamic(() => import('../portaljs/components/Table').then(mod => mod.Table)),
Catalog: dynamic(() => import('../portaljs/components/Catalog').then(mod => mod.Catalog)),
Table: dynamic(() => import('@portaljs/components').then(mod => mod.Table)),
Catalog: dynamic(() => import('@portaljs/components').then(mod => mod.Catalog)),
mermaid: Mermaid,
Vega: dynamic(() => import('../portaljs/components/Vega').then(mod => mod.Vega)),
VegaLite: dynamic(() => import('../portaljs/components/VegaLite').then(mod => mod.VegaLite)),
LineChart: dynamic(() => import('../portaljs/components/LineChart').then(mod => mod.LineChart)),
FlatUiTable: dynamic(() => import('../portaljs/components/FlatUiTable').then(mod => mod.FlatUiTable)),
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)),
FlatUiTable: dynamic(() => import('@portaljs/components').then(mod => mod.FlatUiTable)),
} as any;
export default function DRD({ source }: { source: any }) {

File diff suppressed because it is too large Load Diff

View File

@@ -18,7 +18,7 @@
"@flowershow/remark-embed": "^1.0.0",
"@flowershow/remark-wiki-link": "^1.1.2",
"@opentelemetry/api": "^1.4.0",
"@portaljs/components": "^0.1.0",
"@portaljs/components": "^0.1.8",
"gray-matter": "^4.0.3",
"hastscript": "^7.2.0",
"mdx-mermaid": "2.0.0-rc7",

View File

@@ -81,7 +81,7 @@ export default function DatasetPage({ mdxSource, frontMatter }) {
<p className="my-0">
<span className="font-semibold">Modified: </span>
<span className="description my-0">
{new Date(frontMatter.modified).toLocaleDateString()}
{new Date(frontMatter.modified).toLocaleDateString("en-US")}
</span>
</p>
)}

View File

@@ -1,119 +0,0 @@
import { Index } from 'flexsearch';
import { useState } from 'react';
import DebouncedInput from './DebouncedInput';
import { useForm } from 'react-hook-form';
export function Catalog({
datasets,
facets,
}: {
datasets: any[];
facets: string[];
}) {
const [indexFilter, setIndexFilter] = useState('');
const index = new Index({ tokenize: 'full' });
datasets.forEach((dataset) =>
index.add(
dataset._id,
//This will join every metadata value + the url_path into one big string and index that
Object.entries(dataset.metadata).reduce(
(acc, curr) => acc + ' ' + curr[1].toString(),
''
) +
' ' +
dataset.url_path
)
);
const facetValues = facets
? facets.reduce((acc, facet) => {
const possibleValues = datasets.reduce((acc, curr) => {
const facetValue = curr.metadata[facet];
if (facetValue) {
return Array.isArray(facetValue)
? acc.concat(facetValue)
: acc.concat([facetValue]);
}
return acc;
}, []);
acc[facet] = {
possibleValues: [...new Set(possibleValues)],
selectedValue: null,
};
return acc;
}, {})
: [];
const { register, watch } = useForm(facetValues);
const filteredDatasets = datasets
// First filter by flex search
.filter((dataset) =>
indexFilter !== ''
? index.search(indexFilter).includes(dataset._id)
: true
)
//Then check if the selectedValue for the given facet is included in the dataset metadata
.filter((dataset) => {
//Avoids a server rendering breakage
if (!watch() || Object.keys(watch()).length === 0) return true
//This will filter only the key pairs of the metadata values that were selected as facets
const datasetFacets = Object.entries(dataset.metadata).filter((entry) =>
facets.includes(entry[0])
);
//Check if the value present is included in the selected value in the form
return datasetFacets.every((elem) =>
watch()[elem[0]].selectedValue
? (elem[1] as string | string[]).includes(
watch()[elem[0]].selectedValue
)
: true
);
});
return (
<>
<DebouncedInput
value={indexFilter ?? ''}
onChange={(value) => setIndexFilter(String(value))}
className="p-2 text-sm shadow border border-block mr-1"
placeholder="Search all datasets..."
/>
{Object.entries(facetValues).map((elem) => (
<select
key={elem[0]}
defaultValue=""
className="p-2 ml-1 text-sm shadow border border-block"
{...register(elem[0] + '.selectedValue')}
>
<option value="">
Filter by {elem[0]}
</option>
{(elem[1] as { possibleValues: string[] }).possibleValues.map(
(val) => (
<option
key={val}
className="dark:bg-white dark:text-black"
value={val}
>
{val}
</option>
)
)}
</select>
))}
<ul className='mb-5 pl-6 mt-5 list-disc'>
{filteredDatasets.map((dataset) => (
<li className='py-2' key={dataset._id}>
<a className='font-medium underline' href={dataset.url_path}>
{dataset.metadata.title
? dataset.metadata.title
: dataset.url_path}
</a>
</li>
))}
</ul>
</>
);
}

View File

@@ -1,32 +0,0 @@
import { useEffect, useState } from "react";
const DebouncedInput = ({
value: initialValue,
onChange,
debounce = 500,
...props
}) => {
const [value, setValue] = useState(initialValue);
useEffect(() => {
setValue(initialValue);
}, [initialValue]);
useEffect(() => {
const timeout = setTimeout(() => {
onChange(value);
}, debounce);
return () => clearTimeout(timeout);
}, [value]);
return (
<input
{...props}
value={value}
onChange={(e) => setValue(e.target.value)}
/>
);
};
export default DebouncedInput;

View File

@@ -1,113 +0,0 @@
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
import Papa from 'papaparse';
import { Grid } from '@githubocto/flat-ui';
const queryClient = new QueryClient();
export async function getCsv(url: string, corsProxy?: string) {
if (corsProxy) {
url = corsProxy + url
}
const response = await fetch(url, {
headers: {
Range: 'bytes=0-5132288',
},
});
const data = await response.text();
return data;
}
export async function parseCsv(file: string): Promise<any> {
return new Promise((resolve, reject) => {
Papa.parse(file, {
header: true,
dynamicTyping: true,
skipEmptyLines: true,
transform: (value: string): string => {
return value.trim();
},
complete: (results: any) => {
return resolve(results);
},
error: (error: any) => {
return reject(error);
},
});
});
}
const Spinning = () => {
return (
<div role="status w-fit mx-auto">
<svg
aria-hidden="true"
className="w-8 h-8 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-emerald-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);
};
export interface FlatUiTableProps {
url?: string;
data?: { [key: string]: number | string }[];
rawCsv?: string;
corsProxy?: string;
}
export const FlatUiTable: React.FC<FlatUiTableProps> = ({
url,
data,
rawCsv,
corsProxy,
}) => {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<TableInner corsProxy={corsProxy} url={url} data={data} rawCsv={rawCsv} />
</QueryClientProvider>
);
};
const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv, corsProxy }) => {
if (data) {
return (
<div className="w-full" style={{height: '500px'}}>
<Grid data={data} />
</div>
);
}
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
['dataCsv', url],
() => getCsv(url as string, corsProxy),
{ enabled: !!url }
);
const { data: parsedData, isLoading: isParsing } = useQuery(
['dataPreview', csvString],
() => parseCsv(rawCsv ? rawCsv as string : csvString as string),
{ enabled: rawCsv ? true : !!csvString }
);
if (isParsing || isDownloadingCSV)
<div className="w-full">
<Spinning />
</div>;
if (parsedData)
return (
<div className="w-full" style={{height: '500px'}}>
<Grid data={parsedData.data} />
</div>
);
return <Spinning />
};

View File

@@ -1,63 +0,0 @@
import { VegaLite } from './VegaLite';
export type LineChartProps = {
data: Array<Array<string | number>> | string | { x: string; y: number }[];
title?: string;
xAxis?: string;
yAxis?: string;
fullWidth?: boolean;
};
export function LineChart({
data = [],
fullWidth = false,
title = '',
xAxis = 'x',
yAxis = 'y',
}: LineChartProps) {
var tmp = data;
if (Array.isArray(data)) {
tmp = data.map((r) => {
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: 600,
height: 300,
mark: {
type: 'line',
color: 'black',
strokeWidth: 1,
tooltip: true,
},
data: {
name: 'table',
},
selection: {
grid: {
type: 'interval',
bind: 'scales',
},
},
encoding: {
x: {
field: xAxis,
timeUnit: 'year',
type: 'temporal',
},
y: {
field: yAxis,
type: 'quantitative',
},
},
};
if (typeof data === 'string') {
spec.data = { url: data } as any;
return <VegaLite fullWidth={fullWidth} spec={spec} />;
}
return <VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />;
}

View File

@@ -1,195 +0,0 @@
import {
createColumnHelper,
FilterFn,
flexRender,
getCoreRowModel,
getFilteredRowModel,
getPaginationRowModel,
getSortedRowModel,
useReactTable,
} from '@tanstack/react-table';
import {
ArrowDownIcon,
ArrowUpIcon,
ChevronDoubleLeftIcon,
ChevronDoubleRightIcon,
ChevronLeftIcon,
ChevronRightIcon,
} from '@heroicons/react/24/solid';
import React, { useEffect, useMemo, useState } from 'react';
import parseCsv from '../lib/parseCsv';
import DebouncedInput from './DebouncedInput';
import loadData from '../lib/loadData';
export type TableProps = {
data?: Array<{ [key: string]: number | string }>;
cols?: Array<{ [key: string]: string }>;
csv?: string;
url?: string;
fullWidth?: boolean;
};
export const Table = ({
data: ogData = [],
cols: ogCols = [],
csv = '',
url = '',
fullWidth = false,
}: TableProps) => {
if (csv) {
const out = parseCsv(csv);
ogData = out.rows;
ogCols = out.fields;
}
const [data, setData] = React.useState(ogData);
const [cols, setCols] = React.useState(ogCols);
// const [error, setError] = React.useState(""); // TODO: add error handling
const tableCols = useMemo(() => {
const columnHelper = createColumnHelper();
return cols.map((c) =>
columnHelper.accessor<any, string>(c.key, {
header: () => c.name,
cell: (info) => info.getValue(),
})
);
}, [data, cols]);
const [globalFilter, setGlobalFilter] = useState('');
const table = useReactTable({
data,
columns: tableCols,
getCoreRowModel: getCoreRowModel(),
state: {
globalFilter,
},
globalFilterFn: globalFilterFn,
onGlobalFilterChange: setGlobalFilter,
getFilteredRowModel: getFilteredRowModel(),
getPaginationRowModel: getPaginationRowModel(),
getSortedRowModel: getSortedRowModel(),
});
useEffect(() => {
if (url) {
loadData(url).then((data) => {
const { rows, fields } = parseCsv(data);
setData(rows);
setCols(fields);
});
}
}, [url]);
return (
<div className={`${fullWidth ? 'w-[90vw] ml-[calc(50%-45vw)]' : 'w-full'}`}>
<DebouncedInput
value={globalFilter ?? ''}
onChange={(value: any) => setGlobalFilter(String(value))}
className="p-2 text-sm shadow border border-block"
placeholder="Search all columns..."
/>
<table className="w-full mt-10">
<thead className="text-left border-b border-b-slate-300">
{table.getHeaderGroups().map((hg) => (
<tr key={hg.id}>
{hg.headers.map((h) => (
<th key={h.id} className="pr-2 pb-2">
<div
{...{
className: h.column.getCanSort()
? 'cursor-pointer select-none'
: '',
onClick: h.column.getToggleSortingHandler(),
}}
>
{flexRender(h.column.columnDef.header, h.getContext())}
{{
asc: (
<ArrowUpIcon className="inline-block ml-2 h-4 w-4" />
),
desc: (
<ArrowDownIcon className="inline-block ml-2 h-4 w-4" />
),
}[h.column.getIsSorted() as string] ?? (
<div className="inline-block ml-2 h-4 w-4" />
)}
</div>
</th>
))}
</tr>
))}
</thead>
<tbody>
{table.getRowModel().rows.map((r) => (
<tr key={r.id} className="border-b border-b-slate-200">
{r.getVisibleCells().map((c) => (
<td key={c.id} className="py-2">
{flexRender(c.column.columnDef.cell, c.getContext())}
</td>
))}
</tr>
))}
</tbody>
</table>
<div className="flex gap-2 items-center justify-center mt-10">
<button
className={`w-6 h-6 ${
!table.getCanPreviousPage() ? 'opacity-25' : 'opacity-100'
}`}
onClick={() => table.setPageIndex(0)}
disabled={!table.getCanPreviousPage()}
>
<ChevronDoubleLeftIcon />
</button>
<button
className={`w-6 h-6 ${
!table.getCanPreviousPage() ? 'opacity-25' : 'opacity-100'
}`}
onClick={() => table.previousPage()}
disabled={!table.getCanPreviousPage()}
>
<ChevronLeftIcon />
</button>
<span className="flex items-center gap-1">
<div>Page</div>
<strong>
{table.getState().pagination.pageIndex + 1} of{' '}
{table.getPageCount()}
</strong>
</span>
<button
className={`w-6 h-6 ${
!table.getCanNextPage() ? 'opacity-25' : 'opacity-100'
}`}
onClick={() => table.nextPage()}
disabled={!table.getCanNextPage()}
>
<ChevronRightIcon />
</button>
<button
className={`w-6 h-6 ${
!table.getCanNextPage() ? 'opacity-25' : 'opacity-100'
}`}
onClick={() => table.setPageIndex(table.getPageCount() - 1)}
disabled={!table.getCanNextPage()}
>
<ChevronDoubleRightIcon />
</button>
</div>
</div>
);
};
const globalFilterFn: FilterFn<any> = (row, columnId, filterValue: string) => {
const search = filterValue.toLowerCase();
let value = row.getValue(columnId) as string;
if (typeof value === 'number') value = String(value);
return value?.toLowerCase().includes(search);
};

View File

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

View File

@@ -1,9 +0,0 @@
// Wrapper for the Vega Lite component
import { VegaLite as VegaLiteOg } from "react-vega";
import applyFullWidthDirective from "../lib/applyFullWidthDirective";
export function VegaLite(props) {
const Component = applyFullWidthDirective({ Component: VegaLiteOg });
return <Component {...props} />;
}

View File

@@ -1,21 +0,0 @@
export default function applyFullWidthDirective({
Component,
defaultWFull = true,
}) {
return (props) => {
const newProps = { ...props };
let newClassName = newProps.className || "";
if (newProps.fullWidth === true) {
newClassName += " w-[90vw] ml-[calc(50%-45vw)] max-w-none";
} else if (defaultWFull) {
// So that charts and tables will have the
// same width as the text content, but images
// can have its width set using the width prop
newClassName += " w-full";
}
newProps.className = newClassName;
return <Component {...newProps} />;
};
}

View File

@@ -1,5 +0,0 @@
export default async function loadData(url: string) {
const response = await fetch(url)
const data = await response.text()
return data
}

View File

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

View File

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

View File

@@ -45,12 +45,12 @@ export default function DatasetCard({ dataset }: { dataset: Project }) {
<dt className="text-gray-500">Fiscal Period</dt>
<dd className="text-gray-700">
{dataset.fiscalPeriod?.start &&
new Date(dataset.fiscalPeriod.start).getFullYear()}
new Date(dataset.fiscalPeriod.start).getUTCFullYear()}
{dataset.fiscalPeriod?.end &&
dataset.fiscalPeriod?.start !== dataset.fiscalPeriod?.end && (
<>
{' - '}
{new Date(dataset.fiscalPeriod.end).getFullYear()}
{new Date(dataset.fiscalPeriod.end).getUTCFullYear()}
</>
)}
</dd>

View File

@@ -4,10 +4,13 @@ import { Grid } from '@githubocto/flat-ui';
const queryClient = new QueryClient();
export async function getCsv(url: string) {
export async function getCsv(url: string, corsProxy?: string, range?: string) {
if (corsProxy) {
url = corsProxy + url
}
const response = await fetch(url, {
headers: {
Range: 'bytes=0-5132288',
Range: range ? `bytes=0-${range}` : 'bytes=0-512000',
},
});
const data = await response.text();
@@ -61,21 +64,25 @@ export interface FlatUiTableProps {
url?: string;
data?: { [key: string]: number | string }[];
rawCsv?: string;
range?: string;
corsProxy?: string;
}
export const FlatUiTable: React.FC<FlatUiTableProps> = ({
url,
data,
rawCsv,
corsProxy,
range
}) => {
return (
// Provide the client to your App
<QueryClientProvider client={queryClient}>
<TableInner url={url} data={data} rawCsv={rawCsv} />
<TableInner range={range} corsProxy={corsProxy} url={url} data={data} rawCsv={rawCsv} />
</QueryClientProvider>
);
};
const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv }) => {
const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv, corsProxy, range }) => {
if (data) {
return (
<div className="w-full" style={{height: '500px'}}>
@@ -85,12 +92,12 @@ const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv }) => {
}
const { data: csvString, isLoading: isDownloadingCSV } = useQuery(
['dataCsv', url],
() => getCsv(url),
() => getCsv(url as string, corsProxy, range),
{ enabled: !!url }
);
const { data: parsedData, isLoading: isParsing } = useQuery(
['dataPreview', csvString],
() => parseCsv(rawCsv ? rawCsv : csvString),
() => parseCsv(rawCsv ? rawCsv as string : csvString as string),
{ enabled: rawCsv ? true : !!csvString }
);
if (isParsing || isDownloadingCSV)
@@ -103,4 +110,6 @@ const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv }) => {
<Grid data={parsedData.data} />
</div>
);
return <Spinning />
};

View File

@@ -23,6 +23,10 @@ export function Header() {
title: 'Datasets',
href: '/#datasets',
},
{
title: 'Data Stories',
href: '/stories',
},
{
title: 'Blog',
href: '/blog',
@@ -157,7 +161,7 @@ function Dropdown({ navItem }: { navItem: any }) {
>
<div className="py-1">
{navItem.children.map((item) => (
<Menu.Item>
<Menu.Item key={item.href}>
{({ active }) => (
<a
key={item.href}

View File

@@ -2,23 +2,23 @@ import Image from 'next/image';
import Link from 'next/link';
export default function Footer() {
return (
<footer>
<footer className="bg-slate-50 border-t border-slate-100 py-10">
<div className="mx-auto max-w-7xl px-4 sm:px-6 lg:px-8 flex flex-col items-center justify-between md:flex-row">
<div className="flex gap-x-2 items-center">
<p className="mt-8 text-base text-slate-500 md:mt-0">Maintained by</p>
<a href="https://www.datopian.com/">
<div className="flex gap-x-2 items-center justify-center mx-auto">
<p className="text-base text-slate-500">Maintained by</p>
<a href="https://www.datopian.com/" target="_blank">
<Image
alt="Datopian logo"
className="mb-2"
className="mb-1"
src="/datopian-logotype.png"
width={160}
height={40}
width={120}
height={30}
/>
</a>
</div>
<p className="mt-6 text-base text-slate-500 md:mt-0">
Copyright © 2023 Datopian, LLC. All rights reserved.
</p>
<div className="flex gap-x-2 items-center mx-auto h-20">
<p className="mt-8 text-base text-slate-500 md:mt-0">Built with <a href="https://portaljs.org" target="_blank" className='text-xl font-medium'>🌀 PortalJS</a></p>
</div>
</div>
</footer>
);

View File

@@ -3,7 +3,7 @@ import Footer from './Footer';
export default function Layout({ children }) {
return (
<div className="bg-white min-h-screen pb-12">
<div className="bg-white min-h-screen">
<Header />
{children}
<Footer />

View File

@@ -0,0 +1,34 @@
---
title: Sample Data Story
date: 06/06/2023
---
This is a sample data story, you can add charts
<LineChart
data="https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv"
title="Oil Price x Year"
xAxis="Date"
yAxis="Price"
/>
Or you can add previews
<FlatUiTable url="https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv" />
And you can of course add markdown
## Subtitles
- Lists
- Lists
You can also add mermaid charts
```mermaid
graph TD;
A-->B;
A-->C;
B-->D;
C-->D;
```

File diff suppressed because it is too large Load Diff

View File

@@ -12,27 +12,15 @@
"test": "vitest"
},
"dependencies": {
"@flowershow/core": "^0.4.13",
"@flowershow/markdowndb": "^0.1.5",
"@heroicons/react": "^2.0.18",
"@octokit/plugin-throttling": "^5.2.2",
"@portaljs/components": "0.1.4",
"@types/flexsearch": "^0.7.3",
"@types/node": "18.16.0",
"@types/react": "18.0.38",
"@types/react-dom": "18.0.11",
"@vitejs/plugin-react": "^4.0.0",
"clsx": "^1.2.1",
"datapackage": "^1.1.10",
"eslint": "8.39.0",
"eslint-config-next": "13.3.1",
"flexsearch": "0.7.21",
"next": "13.3.0",
"next-seo": "^6.0.0",
"octokit": "^2.0.14",
"prettier": "^2.8.8",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-hook-form": "^7.43.9",
"react-markdown": "^8.0.7",
"react-timeago": "^7.1.0",
@@ -40,6 +28,38 @@
"remark": "^14.0.3",
"remark-gfm": "^3.0.1",
"strip-markdown": "^5.0.1",
"@flowershow/core": "^0.4.13",
"@flowershow/markdowndb": "^0.1.5",
"@flowershow/remark-callouts": "^1.0.0",
"@flowershow/remark-embed": "^1.0.0",
"@githubocto/flat-ui": "^0.14.1",
"@headlessui/react": "^1.7.14",
"@heroicons/react": "^2.0.18",
"@portaljs/ckan": "^0.0.2",
"@portaljs/components": "^0.1.8",
"@tailwindcss/typography": "^0.5.9",
"@types/node": "20.2.3",
"@types/react": "18.2.6",
"@types/react-dom": "18.2.4",
"autoprefixer": "10.4.14",
"eslint": "8.41.0",
"eslint-config-next": "13.4.3",
"isomorphic-unfetch": "^4.0.2",
"next": "13.4.3",
"next-mdx-remote": "^4.4.1",
"papaparse": "^5.4.1",
"postcss": "8.4.23",
"react": "18.2.0",
"react-dom": "18.2.0",
"react-query": "^3.39.3",
"rehype-autolink-headings": "^6.1.1",
"rehype-katex": "^6.0.3",
"rehype-prism-plus": "^1.5.1",
"rehype-slug": "^5.1.0",
"remark-math": "^5.1.1",
"remark-smartypants": "^2.0.0",
"remark-toc": "^8.0.1",
"tailwindcss": "3.3.2",
"typescript": "5.0.4"
},
"devDependencies": {

View File

@@ -184,22 +184,24 @@ export default function ProjectPage({
return (
<div key={file.name}>
{file.path && (
<>
<div className="lg:ml-[calc(50%-37vw)] lg:w-[74vw]">
<h4>
{file.name}
{file.format ? `.${file.format}` : ''}
</h4>
{file.bytes >= 5132288 && (
<span>Previewing 5MB out of {size}</span>
{file.bytes >= 512000 && (
<span>Previewing 500KB out of {size}</span>
)}
<FlatUiTable
url={
file.path.startsWith('http')
? file.path
: `https://raw.githubusercontent.com/${project.owner.name}/${project.repo.name}/main/${file.path}`
}
/>
</>
<div className="mt-5">
<FlatUiTable
url={
file.path.startsWith('http')
? file.path
: `https://raw.githubusercontent.com/${project.owner.name}/${project.repo.name}/main/${file.path}`
}
/>
</div>
</div>
)}
</div>
);

View File

@@ -53,6 +53,7 @@ export async function getStaticPaths() {
const paths = allDocuments
.filter((page) => page.metadata?.isDraft !== true)
.filter((page) => !page.file_path.startsWith('content/stories/'))
.map((page) => {
const parts = page.url_path!.split('/');
return { params: { slug: parts } };

View File

@@ -57,7 +57,7 @@ function CustomApp({ Component, pageProps }: AppProps) {
<NextSeo title="OpenSpending" />
<Script
strategy="afterInteractive"
src={`https://www.googletagmanager.com/gtag/js?id=${GA_TOKEN}`}
src="https://www.googletagmanager.com/gtag/js?id=G-GXZF7NRXX6"
/>
<Script
id="gtag-init"
@@ -67,7 +67,7 @@ function CustomApp({ Component, pageProps }: AppProps) {
window.dataLayer = window.dataLayer || [];
function gtag(){dataLayer.push(arguments);}
gtag('js', new Date());
gtag('config', ${GA_TOKEN}, {
gtag('config', 'G-GXZF7NRXX6', {
page_path: window.location.pathname,
});
`,

View File

@@ -0,0 +1,62 @@
import fs from 'fs';
import clientPromise from '@/lib/mddb';
import { GetStaticProps } from 'next';
import Layout from '../../components/_shared/Layout';
import { formatDate } from '@/utils/formatDate';
import parse from '../../lib/markdown';
import DataRichDocument from '../../components/DataRichDocument';
export default function Page({ source, meta }) {
return (
<Layout>
<article className="docs prose-a:text-primary dark:prose-a:text-primary-dark prose-strong:text-primary dark:prose-strong:text-primary-dark prose-code:text-primary dark:prose-code:text-primary-dark prose-headings:text-primary dark:prose-headings:text-primary-dark prose text-primary dark:text-primary-dark prose-headings:font-headings dark:prose-invert prose-a:break-words mx-auto p-6">
<header>
<div className="mb-4 flex-col items-center">
{meta.title && (
<h1 className="flex justify-center">{meta.title}</h1>
)}
{meta.date && (
<p className="text-sm text-zinc-400 dark:text-zinc-500 flex justify-center">
<time dateTime={meta.date}>{formatDate(meta.date)}</time>
</p>
)}
</div>
</header>
<section>
<DataRichDocument source={source} />
</section>
</article>
</Layout>
);
}
export const getStaticProps: GetStaticProps = async ({ params }) => {
const mddb = await clientPromise;
const dbFile = await mddb.getFileByUrl('stories/' + params?.fileName);
let source = fs.readFileSync(dbFile.file_path, { encoding: 'utf-8' });
let { mdxSource } = await parse(source, '.mdx', {});
return {
props: {
source: mdxSource,
meta: dbFile.metadata,
},
};
};
export async function getStaticPaths() {
const mddb = await clientPromise;
let allDocuments = await mddb.getFiles({ extensions: ['mdx'], folder: 'stories' });
const paths = allDocuments
.filter((page) => page.metadata?.isDraft !== true)
.map((page) => {
const parts = page.url_path!.split('/').slice(-1)[0];
return { params: { fileName: parts } };
});
return {
paths,
fallback: false,
};
}

View File

@@ -0,0 +1,57 @@
import fs from 'fs';
import React from 'react';
import { GetStaticProps } from 'next';
import { BlogsList, SimpleLayout } from '@flowershow/core';
import clientPromise from '../../lib/mddb';
import type { CustomAppProps } from '../_app';
import Layout from '@/components/_shared/Layout';
interface BlogIndexPageProps extends CustomAppProps {
blogs: any[]; // TODO types
}
export default function StoriesList({
stories,
meta: { title, description },
}: BlogIndexPageProps) {
return (
<Layout>
<div className="blog-list">
<SimpleLayout title={title} description={description}>
<BlogsList blogs={stories} />
</SimpleLayout>
</div>
</Layout>
);
}
export const getStaticProps: GetStaticProps = async () => {
const mddb = await clientPromise;
const storiesFiles = await mddb.getFiles({ folder: 'stories' });
const stories = storiesFiles.map((item) => ({
_id: item._id,
file_path: item.file_path,
urlPath: item.url_path,
date: item.metadata.date,
...item.metadata,
}));
return {
props: {
meta: {
title: 'Data Stories',
showSidebar: false,
showToc: false,
showComments: false,
showEditLink: false,
urlPath: '/stories',
},
stories: stories.sort((a, b) => {
const bDate = new Date(b.date);
const aDate = new Date(a.date);
return bDate.getTime() - aDate.getTime();
}),
},
};
};

View File

@@ -82,3 +82,99 @@ pre {
.blog-list button {
color: black;
}
@tailwind base;
@tailwind components;
@tailwind utilities;
@import "@flowershow/remark-callouts/styles.css";
.w-5 {
width: 1.25rem
}
.h-5 {
height: 1.25rem
}
/* mathjax */
.math-inline > mjx-container > svg {
display: inline;
align-items: center;
}
/* smooth scrolling in modern browsers */
html {
scroll-behavior: smooth !important;
}
/* tooltip fade-out clip */
.tooltip-body::after {
content: "";
position: absolute;
right: 0;
top: 3.6rem; /* multiple of $line-height used on the tooltip body (defined in tooltipBodyStyle) */
height: 1.2rem; /* ($top + $height)/$line-height is the number of lines we want to clip tooltip text at*/
width: 10rem;
background: linear-gradient(
to right,
rgba(255, 255, 255, 0),
rgba(255, 255, 255, 1) 100%
);
}
:is(h2, h3, h4, h5, h6):not(.blogitem-title) {
margin-left: -2rem !important;
padding-left: 2rem !important;
scroll-margin-top: 4.5rem;
position: relative;
}
.heading-link {
padding: 1px;
position: absolute;
left: 0;
top: 50%;
transform: translateY(-50%);
margin: auto 0;
border-radius: 5px;
background: #1e293b;
opacity: 0;
transition: opacity 0.2s;
}
.light .heading-link {
/* border: 1px solid #ab2b65; */
/* background: none; */
background: #e2e8f0;
}
:is(h2, h3, h4, h5, h6):not(.blogitem-title):hover .heading-link {
opacity: 100;
}
.heading-link svg {
transform: scale(0.75);
}
@media screen and (max-width: 640px) {
.heading-link {
visibility: hidden;
}
}
html,
body {
padding: 0;
margin: 0;
font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Oxygen,
Ubuntu, Cantarell, Fira Sans, Droid Sans, Helvetica Neue, sans-serif;
}
a {
color: inherit;
text-decoration: none;
}
* {
box-sizing: border-box;
}

31133
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -1,17 +1,26 @@
{
"name": "portaljs",
"workspaces": [
"./packages/*"
],
"version": "0.0.0",
"license": "MIT",
"scripts": {},
"scripts": {
"changeset": "changeset",
"prerelease": "nx affected --targets=lint,test",
"release": "changeset publish"
},
"private": true,
"devDependencies": {
"@babel/preset-react": "^7.14.5",
"@changesets/changelog-github": "^0.4.8",
"@changesets/cli": "^2.26.1",
"@nrwl/cypress": "15.9.2",
"@nrwl/eslint-plugin-nx": "^16.0.2",
"@nrwl/eslint-plugin-nx": "15.9.2",
"@nrwl/jest": "15.9.2",
"@nrwl/js": "15.9.2",
"@nrwl/linter": "15.9.2",
"@nrwl/next": "^15.9.2",
"@nrwl/next": "15.9.2",
"@nrwl/react": "15.9.2",
"@nrwl/rollup": "15.9.2",
"@nrwl/workspace": "15.9.2",
@@ -21,13 +30,16 @@
"@swc/helpers": "~0.5.0",
"@swc/jest": "0.2.20",
"@testing-library/react": "14.0.0",
"@types/chai": "^4.3.5",
"@types/jest": "^29.4.0",
"@types/mocha": "^10.0.1",
"@types/node": "18.14.2",
"@types/react": "18.0.28",
"@types/react-dom": "18.0.11",
"@typescript-eslint/eslint-plugin": "^5.36.1",
"@typescript-eslint/parser": "^5.36.1",
"babel-jest": "^29.4.1",
"chai": "^4.3.7",
"cypress": "^12.2.0",
"eslint": "~8.15.0",
"eslint-config-next": "13.1.1",
@@ -37,14 +49,21 @@
"eslint-plugin-jsx-a11y": "6.7.1",
"eslint-plugin-react": "7.32.2",
"eslint-plugin-react-hooks": "4.6.0",
"htmlparser2": "^9.0.0",
"jest": "^29.4.1",
"jest-environment-jsdom": "^29.4.1",
"micromark": "^3.2.0",
"mocha": "^10.2.0",
"nx": "15.9.2",
"prettier": "^2.6.2",
"react-test-renderer": "18.2.0",
"rehype-stringify": "^9.0.3",
"remark": "^14.0.3",
"swc-loader": "0.1.15",
"ts-jest": "^29.0.5",
"ts-node": "10.9.1",
"typescript": "~4.9.5"
"typescript": "~4.9.5",
"unist-util-select": "^4.0.3",
"unist-util-visit": "^4.1.2"
}
}

View File

@@ -9,6 +9,7 @@ lerna-debug.log*
node_modules
dist
storybook-static
dist-ssr
*.local

View File

@@ -1,4 +1,5 @@
import 'tailwindcss/tailwind.css'
import '../src/index.css'
import type { Preview } from '@storybook/react';

View File

@@ -0,0 +1,13 @@
# @portaljs/components
## 0.1.9
### Patch Changes
- [#933](https://github.com/datopian/portaljs/pull/933) [`683159d`](https://github.com/datopian/portaljs/commit/683159da02708ce520e9aad9707f2b96b598ec8b) Thanks [@demenech](https://github.com/demenech)! - More params added to <LineChart />, loading spinners added to <Table /> and <LineChart />, minor fixes
## 0.1.8
### Patch Changes
- [#924](https://github.com/datopian/portaljs/pull/924) [`959fe5a`](https://github.com/datopian/portaljs/commit/959fe5a588b12786e3f2e642c24009d77bceac46) Thanks [@luccasmmg](https://github.com/luccasmmg)! - Fixed redeclaration of formal parameter "x" error after next build

File diff suppressed because it is too large Load Diff

View File

@@ -1,6 +1,6 @@
{
"name": "@portaljs/components",
"version": "0.1.6",
"version": "0.1.9",
"type": "module",
"description": "https://portaljs.org",
"keywords": [
@@ -34,8 +34,10 @@
"react-hook-form": "^7.43.9",
"react-query": "^3.39.3",
"react-vega": "^7.6.0",
"rollup-plugin-re": "^1.0.7",
"vega": "5.25.0",
"vega-lite": "5.1.0"
"vega-lite": "5.1.0",
"vitest": "^0.31.4"
},
"devDependencies": {
"@storybook/addon-essentials": "^7.0.7",

View File

@@ -1,12 +1,13 @@
import { QueryClient, QueryClientProvider, useQuery } from 'react-query';
import Papa from 'papaparse';
import { Grid } from '@githubocto/flat-ui';
import LoadingSpinner from './LoadingSpinner';
const queryClient = new QueryClient();
export async function getCsv(url: string, corsProxy?: string) {
if (corsProxy) {
url = corsProxy + url
url = corsProxy + url;
}
const response = await fetch(url, {
headers: {
@@ -36,30 +37,6 @@ export async function parseCsv(file: string): Promise<any> {
});
}
const Spinning = () => {
return (
<div role="status w-fit mx-auto">
<svg
aria-hidden="true"
className="w-8 h-8 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-emerald-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);
};
export interface FlatUiTableProps {
url?: string;
data?: { [key: string]: number | string }[];
@@ -80,10 +57,15 @@ export const FlatUiTable: React.FC<FlatUiTableProps> = ({
);
};
const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv, corsProxy }) => {
const TableInner: React.FC<FlatUiTableProps> = ({
url,
data,
rawCsv,
corsProxy,
}) => {
if (data) {
return (
<div className="w-full" style={{height: '500px'}}>
<div className="w-full" style={{ height: '500px' }}>
<Grid data={data} />
</div>
);
@@ -95,19 +77,22 @@ const TableInner: React.FC<FlatUiTableProps> = ({ url, data, rawCsv, corsProxy }
);
const { data: parsedData, isLoading: isParsing } = useQuery(
['dataPreview', csvString],
() => parseCsv(rawCsv ? rawCsv as string : csvString as string),
() => parseCsv(rawCsv ? (rawCsv as string) : (csvString as string)),
{ enabled: rawCsv ? true : !!csvString }
);
if (isParsing || isDownloadingCSV)
<div className="w-full">
<Spinning />
<div className="w-full flex justify-center items-center h-[500px]">
<LoadingSpinner />
</div>;
if (parsedData)
return (
<div className="w-full" style={{height: '500px'}}>
<div className="w-full" style={{ height: '500px' }}>
<Grid data={parsedData.data} />
</div>
);
return <Spinning />
return (
<div className="w-full flex justify-center items-center h-[500px]">
<LoadingSpinner />
</div>
);
};

View File

@@ -1,10 +1,19 @@
import { useEffect, useState } from 'react';
import LoadingSpinner from './LoadingSpinner';
import { VegaLite } from './VegaLite';
import loadData from '../lib/loadData';
type AxisType = 'quantitative' | 'temporal';
type TimeUnit = 'year' | undefined; // or ...
export type LineChartProps = {
data: Array<Array<string | number>> | string | { x: string; y: number }[];
title?: string;
xAxis?: string;
xAxisType?: AxisType;
xAxisTimeUnit: TimeUnit;
yAxis?: string;
yAxisType?: AxisType;
fullWidth?: boolean;
};
@@ -13,15 +22,16 @@ export function LineChart({
fullWidth = false,
title = '',
xAxis = 'x',
xAxisType = 'temporal',
xAxisTimeUnit = 'year', // TODO: defaults to undefined would probably work better... keeping it as it's for compatibility purposes
yAxis = 'y',
yAxisType = 'quantitative',
}: LineChartProps) {
var tmp = data;
if (Array.isArray(data)) {
tmp = data.map((r) => {
return { x: r[0], y: r[1] };
});
}
const vegaData = { table: tmp };
const [isLoading, setIsLoading] = useState<boolean>(false);
// By default, assumes data is an Array...
const [specData, setSpecData] = useState<any>({ name: 'table' });
const spec = {
$schema: 'https://vega.github.io/schema/vega-lite/v5.json',
title,
@@ -33,9 +43,7 @@ export function LineChart({
strokeWidth: 1,
tooltip: true,
},
data: {
name: 'table',
},
data: specData,
selection: {
grid: {
type: 'interval',
@@ -45,19 +53,44 @@ export function LineChart({
encoding: {
x: {
field: xAxis,
timeUnit: 'year',
type: 'temporal',
timeUnit: xAxisTimeUnit,
type: xAxisType,
},
y: {
field: yAxis,
type: 'quantitative',
type: yAxisType,
},
},
};
if (typeof data === 'string') {
spec.data = { url: data } as any;
return <VegaLite fullWidth={fullWidth} spec={spec} />;
} as any;
useEffect(() => {
// If data is string, assume it's a URL
if (typeof data === 'string') {
setIsLoading(true);
// Manualy loading the data allows us to do other kinds
// of stuff later e.g. load a file partially
loadData(data).then((res: any) => {
setSpecData({ values: res, format: { type: 'csv' } });
setIsLoading(false);
});
}
}, []);
var vegaData = {};
if (Array.isArray(data)) {
var dataObj;
dataObj = data.map((r) => {
return { x: r[0], y: r[1] };
});
vegaData = { table: dataObj };
}
return <VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />;
return isLoading ? (
<div className="w-full flex items-center justify-center w-[600px] h-[300px]">
<LoadingSpinner />
</div>
) : (
<VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />
);
}

View File

@@ -0,0 +1,23 @@
export default function LoadingSpinner() {
return (
<div role="status w-fit mx-auto">
<svg
aria-hidden="true"
className="w-16 h-16 mr-2 text-gray-200 animate-spin dark:text-gray-600 fill-slate-600"
viewBox="0 0 100 101"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<path
d="M100 50.5908C100 78.2051 77.6142 100.591 50 100.591C22.3858 100.591 0 78.2051 0 50.5908C0 22.9766 22.3858 0.59082 50 0.59082C77.6142 0.59082 100 22.9766 100 50.5908ZM9.08144 50.5908C9.08144 73.1895 27.4013 91.5094 50 91.5094C72.5987 91.5094 90.9186 73.1895 90.9186 50.5908C90.9186 27.9921 72.5987 9.67226 50 9.67226C27.4013 9.67226 9.08144 27.9921 9.08144 50.5908Z"
fill="currentColor"
/>
<path
d="M93.9676 39.0409C96.393 38.4038 97.8624 35.9116 97.0079 33.5539C95.2932 28.8227 92.871 24.3692 89.8167 20.348C85.8452 15.1192 80.8826 10.7238 75.2124 7.41289C69.5422 4.10194 63.2754 1.94025 56.7698 1.05124C51.7666 0.367541 46.6976 0.446843 41.7345 1.27873C39.2613 1.69328 37.813 4.19778 38.4501 6.62326C39.0873 9.04874 41.5694 10.4717 44.0505 10.1071C47.8511 9.54855 51.7191 9.52689 55.5402 10.0491C60.8642 10.7766 65.9928 12.5457 70.6331 15.2552C75.2735 17.9648 79.3347 21.5619 82.5849 25.841C84.9175 28.9121 86.7997 32.2913 88.1811 35.8758C89.083 38.2158 91.5421 39.6781 93.9676 39.0409Z"
fill="currentFill"
/>
</svg>
<span className="sr-only">Loading...</span>
</div>
);
}

View File

@@ -23,6 +23,7 @@ import React, { useEffect, useMemo, useState } from 'react';
import parseCsv from '../lib/parseCsv';
import DebouncedInput from './DebouncedInput';
import loadData from '../lib/loadData';
import LoadingSpinner from './LoadingSpinner';
export type TableProps = {
data?: Array<{ [key: string]: number | string }>;
@@ -39,6 +40,8 @@ export const Table = ({
url = '',
fullWidth = false,
}: TableProps) => {
const [isLoading, setIsLoading] = useState<boolean>(false);
if (csv) {
const out = parseCsv(csv);
ogData = out.rows;
@@ -77,15 +80,22 @@ export const Table = ({
useEffect(() => {
if (url) {
setIsLoading(true);
// TODO: exception handling. What if the file doesn't exist? What if fetching was not possible?
loadData(url).then((data) => {
const { rows, fields } = parseCsv(data);
setData(rows);
setCols(fields);
setIsLoading(false);
});
}
}, [url]);
return (
return isLoading ? (
<div className="w-full h-full min-h-[500px] flex items-center justify-center">
<LoadingSpinner />
</div>
) : (
<div className={`${fullWidth ? 'w-[90vw] ml-[calc(50%-45vw)]' : 'w-full'}`}>
<DebouncedInput
value={globalFilter ?? ''}

View File

@@ -1,3 +1,10 @@
@tailwind base;
@tailwind components;
@tailwind utilities;
@tailwind utilities;
/* Temporary fix for a size issue with FlatUiTable loading indicator on Firefox */
@layer base {
svg[tw^='animate-pulse w-12'] {
max-width: 100px;
}
}

View File

@@ -19,10 +19,19 @@ const meta: Meta = {
description:
'Name of the X axis on the data. Required when the "data" parameter is an URL.',
},
xAxisType: {
description: 'Type of the X axis',
},
xAxisTimeUnit: {
description: 'Time unit of the X axis (optional)',
},
yAxis: {
description:
'Name of the Y axis on the data. Required when the "data" parameter is an URL.',
},
yAxisType: {
description: 'Type of the Y axis',
},
fullWidth: {
description:
'Whether the component should be rendered as full bleed or not',

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
import{j as p}from"./jsx-runtime-94f6e698.js";import{r as u}from"./index-8db94870.js";const a=({value:e,onChange:o,debounce:s=500,...c})=>{const[t,r]=u.useState(e);return u.useEffect(()=>{r(e)},[e]),u.useEffect(()=>{const n=setTimeout(()=>{o(t)},s);return()=>clearTimeout(n)},[t]),p.jsx("input",{...c,value:t,onChange:n=>r(n.target.value)})};try{a.displayName="DebouncedInput",a.__docgenInfo={description:"",displayName:"DebouncedInput",props:{value:{defaultValue:null,description:"",name:"value",required:!0,type:{name:"any"}},onChange:{defaultValue:null,description:"",name:"onChange",required:!0,type:{name:"any"}},debounce:{defaultValue:{value:"500"},description:"",name:"debounce",required:!1,type:{name:"number"}}}}}catch{}export{a as D};
//# sourceMappingURL=DebouncedInput-c720676c.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"DebouncedInput-c720676c.js","sources":["../../src/components/DebouncedInput.tsx"],"sourcesContent":["import { useEffect, useState } from \"react\";\n\nconst DebouncedInput = ({\n value: initialValue,\n onChange,\n debounce = 500,\n ...props\n}) => {\n const [value, setValue] = useState(initialValue);\n\n useEffect(() => {\n setValue(initialValue);\n }, [initialValue]);\n\n useEffect(() => {\n const timeout = setTimeout(() => {\n onChange(value);\n }, debounce);\n\n return () => clearTimeout(timeout);\n }, [value]);\n\n return (\n <input\n {...props}\n value={value}\n onChange={(e) => setValue(e.target.value)}\n />\n );\n};\n\nexport default DebouncedInput;\n"],"names":["DebouncedInput","initialValue","onChange","debounce","props","value","setValue","useState","useEffect","timeout","jsx","e"],"mappings":"sFAEA,MAAAA,EAAA,CAAA,CAAwB,MAAAC,EACf,SAAAC,EACP,SAAAC,EAAA,IACW,GAAAC,CAEb,IAAA,CACE,KAAA,CAAAC,EAAAC,CAAA,EAAAC,EAAA,SAAAN,CAAA,EAEAO,OAAAA,EAAAA,UAAA,IAAA,CACEF,EAAAL,CAAA,CAAqB,EAAA,CAAAA,CAAA,CAAA,EAGvBO,EAAAA,UAAA,IAAA,CACE,MAAAC,EAAA,WAAA,IAAA,CACEP,EAAAG,CAAA,CAAc,EAAAF,CAAA,EAGhB,MAAA,IAAA,aAAAM,CAAA,CAAiC,EAAA,CAAAJ,CAAA,CAAA,EAGnCK,EAAA,IACE,QAAC,CAAA,GAAAN,EACK,MAAAC,EACJ,SAAAM,GAAAL,EAAAK,EAAA,OAAA,KAAA,CACwC,CAAA,CAG9C"}

View File

@@ -1,2 +0,0 @@
import{_ as p}from"./iframe-1eda5ccb.js";import{R as e,r as a}from"./index-8db94870.js";import{r as c,u}from"./react-18-ff2c0a32.js";import{C as h,A as l,H as E,D as d}from"./index-89936ab1.js";import"../sb-preview/runtime.js";import"./_commonjsHelpers-042e6b4d.js";import"./index-8ce4a492.js";import"./index-d475d2ea.js";import"./isNativeReflectConstruct-099dc9ad.js";import"./index-d37d4223.js";import"./index-6e6be2d5.js";import"./index-356e4a49.js";var x={code:h,a:l,...E},_=class extends a.Component{constructor(){super(...arguments),this.state={hasError:!1}}static getDerivedStateFromError(){return{hasError:!0}}componentDidCatch(t){let{showException:r}=this.props;r(t)}render(){let{hasError:t}=this.state,{children:r}=this.props;return t?null:r}},S=class{constructor(){this.render=async(t,r,o)=>{let n={...x,...r==null?void 0:r.components};return new Promise((s,m)=>{p(()=>import("./index-186b3228.js"),["./index-186b3228.js","./index-1d576ef5.js","./index-8db94870.js","./_commonjsHelpers-042e6b4d.js"],import.meta.url).then(({MDXProvider:i})=>c(e.createElement(_,{showException:m,key:Math.random()},e.createElement(i,{components:n},e.createElement(d,{context:t,docsParameter:r}))),o)).then(s)})},this.unmount=t=>{u(t)}}};export{S as DocsRenderer,x as defaultComponents};
//# sourceMappingURL=DocsRenderer-EYKKDMVH-b61c696a.js.map

View File

@@ -1 +0,0 @@
{"version":3,"mappings":"qcAIG,IAACA,EAAkB,CAAC,KAAKC,EAAgB,EAAEC,EAAU,GAAGC,CAAU,EAAEC,EAAc,cAAcC,WAAS,CAAC,aAAa,CAAC,MAAM,GAAG,SAAS,EAAE,KAAK,MAAM,CAAC,SAAS,EAAE,CAAE,CAAC,OAAO,0BAA0B,CAAC,MAAO,CAAC,SAAS,EAAE,CAAC,CAAC,kBAAkBC,EAAI,CAAC,GAAG,CAAC,cAAAC,CAAa,EAAE,KAAK,MAAMA,EAAcD,CAAG,CAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,SAAAE,CAAQ,EAAE,KAAK,MAAM,CAAC,SAAAC,CAAQ,EAAE,KAAK,MAAM,OAAOD,EAAS,KAAKC,CAAQ,CAAC,EAAEC,EAAa,KAAK,CAAC,aAAa,CAAC,KAAK,OAAO,MAAMC,EAAQC,EAAcC,IAAU,CAAC,IAAIC,EAAW,CAAC,GAAGd,EAAkB,GAAGY,GAAA,YAAAA,EAAe,UAAU,EAAE,OAAO,IAAI,QAAQ,CAACG,EAAQC,IAAS,CAAAC,EAAA,IAAC,OAAO,qBAAe,EAAC,sHAAC,KAAK,CAAC,CAAC,YAAAC,CAAW,IAAIC,EAAcC,EAAM,cAAchB,EAAc,CAAC,cAAcY,EAAO,IAAI,KAAK,OAAM,CAAE,EAAEI,EAAM,cAAcF,EAAY,CAAC,WAAAJ,CAAU,EAAEM,EAAM,cAAcC,EAAK,CAAC,QAAAV,EAAQ,cAAAC,CAAa,CAAC,CAAC,CAAC,EAAEC,CAAO,CAAC,EAAE,KAAKE,CAAO,CAAE,CAAC,CAAC,EAAE,KAAK,QAAQF,GAAS,CAACS,EAAeT,CAAO,CAAE,CAAE,CAAC","names":["defaultComponents","CodeOrSourceMdx","AnchorMdx","HeadersMdx","ErrorBoundary","Component","err","showException","hasError","children","DocsRenderer","context","docsParameter","element","components","resolve","reject","__vitePreload","MDXProvider","renderElement","React","Docs","unmountElement"],"sources":["../../node_modules/@storybook/addon-docs/dist/chunk-PCJTTTQV.mjs"],"sourcesContent":["import React, { Component } from 'react';\nimport { renderElement, unmountElement } from '@storybook/react-dom-shim';\nimport { CodeOrSourceMdx, AnchorMdx, HeadersMdx, Docs } from '@storybook/blocks';\n\nvar defaultComponents={code:CodeOrSourceMdx,a:AnchorMdx,...HeadersMdx},ErrorBoundary=class extends Component{constructor(){super(...arguments);this.state={hasError:!1};}static getDerivedStateFromError(){return {hasError:!0}}componentDidCatch(err){let{showException}=this.props;showException(err);}render(){let{hasError}=this.state,{children}=this.props;return hasError?null:children}},DocsRenderer=class{constructor(){this.render=async(context,docsParameter,element)=>{let components={...defaultComponents,...docsParameter?.components};return new Promise((resolve,reject)=>{import('@mdx-js/react').then(({MDXProvider})=>renderElement(React.createElement(ErrorBoundary,{showException:reject,key:Math.random()},React.createElement(MDXProvider,{components},React.createElement(Docs,{context,docsParameter}))),element)).then(resolve);})},this.unmount=element=>{unmountElement(element);};}};\n\nexport { DocsRenderer, defaultComponents };\n"],"file":"assets/DocsRenderer-EYKKDMVH-b61c696a.js"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,6 +0,0 @@
import{j as o}from"./jsx-runtime-94f6e698.js";import{M as i}from"./index-89936ab1.js";import{u as s}from"./index-1d576ef5.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";import"./iframe-1eda5ccb.js";import"../sb-preview/runtime.js";import"./index-d475d2ea.js";import"./isNativeReflectConstruct-099dc9ad.js";import"./index-8ce4a492.js";import"./index-d37d4223.js";import"./index-6e6be2d5.js";import"./index-356e4a49.js";function M(t={}){const{wrapper:n}=Object.assign({},s(),t.components);return n?o.jsx(n,Object.assign({},t,{children:o.jsx(e,{})})):e();function e(){const r=Object.assign({h1:"h1",p:"p",strong:"strong",a:"a",br:"br"},s(),t.components);return o.jsxs(o.Fragment,{children:[o.jsx(i,{title:"Components/Introduction"}),`
`,o.jsx(r.h1,{id:"welcome-to-the-portaljs-components-guide",children:"Welcome to the PortalJS components guide"}),`
`,o.jsxs(r.p,{children:[o.jsx(r.strong,{children:"Official Website:"})," ",o.jsx(r.a,{href:"https://portaljs.org",target:"_blank",rel:"nofollow noopener noreferrer",children:"portaljs.org"}),o.jsx(r.br,{}),`
`,o.jsx(r.strong,{children:"Docs:"})," ",o.jsx(r.a,{href:"https://portaljs.org/docs",target:"_blank",rel:"nofollow noopener noreferrer",children:"portaljs.org/docs"}),o.jsx(r.br,{}),`
`,o.jsx(r.strong,{children:"GitHub:"})," ",o.jsx(r.a,{href:"https://github.com/datopian/portaljs",target:"_blank",rel:"nofollow noopener noreferrer",children:"github.com/datopian/portaljs"})]})]})}}export{M as default};
//# sourceMappingURL=Introduction-7f71f7c8.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Introduction-7f71f7c8.js","sources":["../../stories/Introduction.mdx"],"sourcesContent":["import { Meta } from '@storybook/blocks';\n\n<Meta title=\"Components/Introduction\" />\n\n# Welcome to the PortalJS components guide\n\n**Official Website:** [portaljs.org](https://portaljs.org) \n**Docs:** [portaljs.org/docs](https://portaljs.org/docs) \n**GitHub:** [github.com/datopian/portaljs](https://github.com/datopian/portaljs)"],"names":["MDXContent","props","MDXLayout","_provideComponents","_jsx","_createMdxContent","_components","_jsxs","_Fragment","Meta"],"mappings":"0bAIA,SAASA,EAAWC,EAAQ,GAAI,CAC9B,KAAM,CAAC,QAASC,CAAS,EAAI,OAAO,OAAO,CAAE,EAAEC,EAAoB,EAAEF,EAAM,UAAU,EACrF,OAAOC,EAAYE,EAAAA,IAAKF,EAAW,OAAO,OAAO,CAAE,EAAED,EAAO,CAC1D,SAAUG,EAAAA,IAAKC,EAAmB,EAAE,CACxC,CAAG,CAAC,EAAIA,IACN,SAASA,GAAoB,CAC3B,MAAMC,EAAc,OAAO,OAAO,CAChC,GAAI,KACJ,EAAG,IACH,OAAQ,SACR,EAAG,IACH,GAAI,IACL,EAAEH,EAAoB,EAAEF,EAAM,UAAU,EACzC,OAAOM,EAAAA,KAAMC,EAAAA,SAAW,CACtB,SAAU,CAACJ,EAAI,IAACK,EAAM,CACpB,MAAO,yBACR,CAAA,EAAG;AAAA,EAAML,MAAKE,EAAY,GAAI,CAC7B,GAAI,2CACJ,SAAU,0CACX,CAAA,EAAG;AAAA,EAAMC,OAAMD,EAAY,EAAG,CAC7B,SAAU,CAACF,EAAAA,IAAKE,EAAY,OAAQ,CAClC,SAAU,mBACX,CAAA,EAAG,IAAKF,MAAKE,EAAY,EAAG,CAC3B,KAAM,uBACN,OAAQ,SACR,IAAK,+BACL,SAAU,cACpB,CAAS,EAAGF,EAAAA,IAAKE,EAAY,GAAI,CAAA,CAAE,EAAG;AAAA,EAAMF,EAAAA,IAAKE,EAAY,OAAQ,CAC3D,SAAU,OACX,CAAA,EAAG,IAAKF,MAAKE,EAAY,EAAG,CAC3B,KAAM,4BACN,OAAQ,SACR,IAAK,+BACL,SAAU,mBACpB,CAAS,EAAGF,EAAAA,IAAKE,EAAY,GAAI,CAAA,CAAE,EAAG;AAAA,EAAMF,EAAAA,IAAKE,EAAY,OAAQ,CAC3D,SAAU,SACX,CAAA,EAAG,IAAKF,MAAKE,EAAY,EAAG,CAC3B,KAAM,uCACN,OAAQ,SACR,IAAK,+BACL,SAAU,8BACpB,CAAS,CAAC,CACV,CAAO,CAAC,CACR,CAAK,CACF,CACH"}

View File

@@ -1,21 +0,0 @@
import{j as d}from"./jsx-runtime-94f6e698.js";import{V as c}from"./VegaLite-30eeb950.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";import"./Vega-d925c94f.js";import"./index-1fc0ca9a.js";function i({data:e=[],fullWidth:n=!1,title:f="",xAxis:x="x",yAxis:g="y"}){var s=e;Array.isArray(e)&&(s=e.map(o=>({x:o[0],y:o[1]})));const v={table:s},r={$schema:"https://vega.github.io/schema/vega-lite/v5.json",title:f,width:"container",height:300,mark:{type:"line",color:"black",strokeWidth:1,tooltip:!0},data:{name:"table"},selection:{grid:{type:"interval",bind:"scales"}},encoding:{x:{field:x,timeUnit:"year",type:"temporal"},y:{field:g,type:"quantitative"}}};return typeof e=="string"?(r.data={url:e},d.jsx(c,{fullWidth:n,spec:r})):d.jsx(c,{fullWidth:n,data:v,spec:r})}try{i.displayName="LineChart",i.__docgenInfo={description:"",displayName:"LineChart",props:{data:{defaultValue:{value:"[]"},description:"",name:"data",required:!1,type:{name:"string | (string | number)[][] | { x: string; y: number; }[]"}},title:{defaultValue:{value:""},description:"",name:"title",required:!1,type:{name:"string"}},xAxis:{defaultValue:{value:"x"},description:"",name:"xAxis",required:!1,type:{name:"string"}},yAxis:{defaultValue:{value:"y"},description:"",name:"yAxis",required:!1,type:{name:"string"}},fullWidth:{defaultValue:{value:"false"},description:"",name:"fullWidth",required:!1,type:{name:"boolean"}}}}}catch{}const w={title:"Components/LineChart",component:i,tags:["autodocs"],argTypes:{data:{description:`Data to be displayed.
E.g.: [["1990", 1], ["1991", 2]]
OR
"https://url.to/data.csv"`},title:{description:"Title to display on the chart. Optional."},xAxis:{description:'Name of the X axis on the data. Required when the "data" parameter is an URL.'},yAxis:{description:'Name of the Y axis on the data. Required when the "data" parameter is an URL.'},fullWidth:{description:"Whether the component should be rendered as full bleed or not"}}},t={name:"Line chart from array of data points",args:{data:[["1850",-.41765878],["1851",-.2333498],["1852",-.22939907],["1853",-.27035445],["1854",-.29163003]]}},a={name:"Line chart from URL",args:{title:"Oil Price x Year",data:"https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv",xAxis:"Date",yAxis:"Price"}};var l,p,m;t.parameters={...t.parameters,docs:{...(l=t.parameters)==null?void 0:l.docs,source:{originalSource:`{
name: 'Line chart from array of data points',
args: {
data: [['1850', -0.41765878], ['1851', -0.2333498], ['1852', -0.22939907], ['1853', -0.27035445], ['1854', -0.29163003]]
}
}`,...(m=(p=t.parameters)==null?void 0:p.docs)==null?void 0:m.source}}};var u,h,y;a.parameters={...a.parameters,docs:{...(u=a.parameters)==null?void 0:u.docs,source:{originalSource:`{
name: 'Line chart from URL',
args: {
title: 'Oil Price x Year',
data: 'https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv',
xAxis: 'Date',
yAxis: 'Price'
}
}`,...(y=(h=a.parameters)==null?void 0:h.docs)==null?void 0:y.source}}};const U=["FromDataPoints","FromURL"];export{t as FromDataPoints,a as FromURL,U as __namedExportsOrder,w as default};
//# sourceMappingURL=LineChart.stories-de9527a1.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"LineChart.stories-de9527a1.js","sources":["../../src/components/LineChart.tsx"],"sourcesContent":["import { VegaLite } from './VegaLite';\n\nexport type LineChartProps = {\n data: Array<Array<string | number>> | string | { x: string; y: number }[];\n title?: string;\n xAxis?: string;\n yAxis?: string;\n fullWidth?: boolean;\n};\n\nexport function LineChart({\n data = [],\n fullWidth = false,\n title = '',\n xAxis = 'x',\n yAxis = 'y',\n}: LineChartProps) {\n var tmp = data;\n if (Array.isArray(data)) {\n tmp = data.map((r) => {\n return { x: r[0], y: r[1] };\n });\n }\n const vegaData = { table: tmp };\n const spec = {\n $schema: 'https://vega.github.io/schema/vega-lite/v5.json',\n title,\n width: 'container',\n height: 300,\n mark: {\n type: 'line',\n color: 'black',\n strokeWidth: 1,\n tooltip: true,\n },\n data: {\n name: 'table',\n },\n selection: {\n grid: {\n type: 'interval',\n bind: 'scales',\n },\n },\n encoding: {\n x: {\n field: xAxis,\n timeUnit: 'year',\n type: 'temporal',\n },\n y: {\n field: yAxis,\n type: 'quantitative',\n },\n },\n };\n if (typeof data === 'string') {\n spec.data = { url: data } as any;\n return <VegaLite fullWidth={fullWidth} spec={spec} />;\n }\n\n return <VegaLite fullWidth={fullWidth} data={vegaData} spec={spec} />;\n}\n"],"names":["LineChart","data","fullWidth","title","xAxis","yAxis","tmp","r","vegaData","spec","jsx","VegaLite"],"mappings":"mNAUO,SAAAA,EAAA,CAAmB,KAAAC,EAAA,CAAA,EAChB,UAAAC,EAAA,GACI,MAAAC,EAAA,GACJ,MAAAC,EAAA,IACA,MAAAC,EAAA,GAEV,EAAA,CACE,IAAAC,EAAAL,EACA,MAAA,QAAAA,CAAA,IACEK,EAAAL,EAAA,IAAAM,IACE,CAAA,EAAAA,EAAA,CAAA,EAAA,EAAAA,EAAA,CAAA,GAA0B,GAG9B,MAAAC,EAAA,CAAA,MAAAF,GACAG,EAAA,CAAa,QAAA,kDACF,MAAAN,EACT,MAAA,YACO,OAAA,IACC,KAAA,CACF,KAAA,OACE,MAAA,QACC,YAAA,EACM,QAAA,EACJ,EACX,KAAA,CACM,KAAA,OACE,EACR,UAAA,CACW,KAAA,CACH,KAAA,WACE,KAAA,QACA,CACR,EACF,SAAA,CACU,EAAA,CACL,MAAAC,EACM,SAAA,OACG,KAAA,UACJ,EACR,EAAA,CACG,MAAAC,EACM,KAAA,cACD,CACR,CACF,EAEF,OAAA,OAAAJ,GAAA,UACEQ,EAAA,KAAA,CAAA,IAAAR,CAAA,EACAS,EAAA,IAAAC,EAAA,CAAA,UAAAT,EAAA,KAAAO,CAAA,CAAA,GAGFC,EAAAA,IAAAC,EAAA,CAAA,UAAAT,EAAA,KAAAM,EAAA,KAAAC,CAAA,CAAA,CACF;;;;;;;;;;;;;;;;;;;"}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,32 +0,0 @@
import{j as i}from"./jsx-runtime-94f6e698.js";import{V as s}from"./Vega-d925c94f.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";import"./index-1fc0ca9a.js";function e(t){return i.jsx(s,{...t})}try{e.displayName="Vega",e.__docgenInfo={description:"",displayName:"Vega",props:{}}}catch{}const l={title:"Components/Vega",component:e,tags:["autodocs"]},a={name:"Chart built with Vega",args:{data:{table:[{y:-.418,x:1850},{y:.923,x:2020}]},spec:{$schema:"https://vega.github.io/schema/vega-lite/v4.json",mark:"bar",data:{name:"table"},encoding:{x:{field:"x",type:"ordinal"},y:{field:"y",type:"quantitative"}}}}};var n,r,o;a.parameters={...a.parameters,docs:{...(n=a.parameters)==null?void 0:n.docs,source:{originalSource:`{
name: 'Chart built with Vega',
args: {
data: {
table: [{
y: -0.418,
x: 1850
}, {
y: 0.923,
x: 2020
}]
},
spec: {
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
mark: 'bar',
data: {
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative'
}
}
}
}
}`,...(o=(r=a.parameters)==null?void 0:r.docs)==null?void 0:o.source}}};const y=["Primary"];export{a as Primary,y as __namedExportsOrder,l as default};
//# sourceMappingURL=Vega.stories-751bd69b.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"Vega.stories-751bd69b.js","sources":["../../src/components/Vega.tsx"],"sourcesContent":["// Wrapper for the Vega component\nimport { Vega as VegaOg } from \"react-vega\";\n\nexport function Vega(props) {\n return <VegaOg {...props} />;\n}\n"],"names":["Vega","props","jsx","VegaOg"],"mappings":"oLAGO,SAAAA,EAAAC,EAAA,CACL,OAAAC,EAAA,IAAAC,EAAA,CAAA,GAAAF,CAAA,CAAA,CACF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@@ -1,2 +0,0 @@
import{j as p}from"./jsx-runtime-94f6e698.js";import{R as s}from"./index-8db94870.js";import{V as u}from"./Vega-d925c94f.js";function l(){return l=Object.assign||function(e){for(var r=1;r<arguments.length;r++){var a=arguments[r];for(var t in a)Object.prototype.hasOwnProperty.call(a,t)&&(e[t]=a[t])}return e},l.apply(this,arguments)}function c(e){return s.createElement(u,l({},e,{mode:"vega-lite"}))}function o({Component:e,defaultWFull:r=!0}){return a=>{const t={...a};let n=t.className||"";return t.fullWidth===!0?n+=" w-[90vw] ml-[calc(50%-45vw)] max-w-none":r&&(n+=" w-full"),t.className=n,p.jsx(e,{...t})}}try{o.displayName="applyFullWidthDirective",o.__docgenInfo={description:"",displayName:"applyFullWidthDirective",props:{Component:{defaultValue:null,description:"",name:"Component",required:!0,type:{name:"any"}},defaultWFull:{defaultValue:{value:"true"},description:"",name:"defaultWFull",required:!1,type:{name:"boolean"}}}}}catch{}function i(e){const r=o({Component:c});return p.jsx(r,{...e})}try{i.displayName="VegaLite",i.__docgenInfo={description:"",displayName:"VegaLite",props:{}}}catch{}export{i as V};
//# sourceMappingURL=VegaLite-30eeb950.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"VegaLite-30eeb950.js","sources":["../../node_modules/react-vega/esm/VegaLite.js","../../src/lib/applyFullWidthDirective.tsx","../../src/components/VegaLite.tsx"],"sourcesContent":["function _extends() { _extends = Object.assign || function (target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i]; for (var key in source) { if (Object.prototype.hasOwnProperty.call(source, key)) { target[key] = source[key]; } } } return target; }; return _extends.apply(this, arguments); }\n\nimport React from 'react';\nimport Vega from './Vega';\n\n/**\n * Syntactic sugar for using vega-lite with Vega\n * @param props\n */\nexport default function VegaLite(props) {\n return /*#__PURE__*/React.createElement(Vega, _extends({}, props, {\n mode: \"vega-lite\"\n }));\n}","export default function applyFullWidthDirective({\n Component,\n defaultWFull = true,\n}) {\n return (props) => {\n const newProps = { ...props };\n\n let newClassName = newProps.className || \"\";\n if (newProps.fullWidth === true) {\n newClassName += \" w-[90vw] ml-[calc(50%-45vw)] max-w-none\";\n } else if (defaultWFull) {\n // So that charts and tables will have the\n // same width as the text content, but images\n // can have its width set using the width prop\n newClassName += \" w-full\";\n }\n newProps.className = newClassName;\n\n return <Component {...newProps} />;\n };\n}\n","// Wrapper for the Vega Lite component\nimport { VegaLite as VegaLiteOg } from \"react-vega\";\nimport applyFullWidthDirective from \"../lib/applyFullWidthDirective\";\n\nexport function VegaLite(props) {\n const Component = applyFullWidthDirective({ Component: VegaLiteOg });\n\n return <Component {...props} />;\n}\n"],"names":["_extends","target","i","source","key","VegaLite","props","React","Vega","applyFullWidthDirective","Component","defaultWFull","newProps","newClassName","jsx","VegaLiteOg"],"mappings":"6HAAA,SAASA,GAAW,CAAE,OAAAA,EAAW,OAAO,QAAU,SAAUC,EAAQ,CAAE,QAASC,EAAI,EAAGA,EAAI,UAAU,OAAQA,IAAK,CAAE,IAAIC,EAAS,UAAUD,CAAC,EAAG,QAASE,KAAOD,EAAc,OAAO,UAAU,eAAe,KAAKA,EAAQC,CAAG,IAAKH,EAAOG,CAAG,EAAID,EAAOC,CAAG,GAAS,OAAOH,GAAkBD,EAAS,MAAM,KAAM,SAAS,CAAI,CAS9S,SAASK,EAASC,EAAO,CACtC,OAAoBC,EAAM,cAAcC,EAAMR,EAAS,CAAA,EAAIM,EAAO,CAChE,KAAM,WACP,CAAA,CAAC,CACJ,CCbA,SAAAG,EAAA,CAAgD,UAAAC,EAC9C,aAAAC,EAAA,EAEF,EAAA,CACE,OAAAL,GAAA,CACE,MAAAM,EAAA,CAAA,GAAAN,GAEA,IAAAO,EAAAD,EAAA,WAAA,GACA,OAAAA,EAAA,YAAA,GACEC,GAAA,2CAAgBF,IAKhBE,GAAA,WAEFD,EAAA,UAAAC,EAEAC,EAAA,IAAAJ,EAAA,CAAA,GAAAE,CAAA,CAAA,CAAgC,CAEpC,8UChBO,SAAAP,EAAAC,EAAA,CACL,MAAAI,EAAAD,EAAA,CAAA,UAAAM,CAAA,CAAA,EAEA,OAAAD,EAAA,IAAAJ,EAAA,CAAA,GAAAJ,CAAA,CAAA,CACF","x_google_ignoreList":[0]}

View File

@@ -1,32 +0,0 @@
import{V as i}from"./VegaLite-30eeb950.js";import"./jsx-runtime-94f6e698.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";import"./Vega-d925c94f.js";import"./index-1fc0ca9a.js";const c={title:"Components/VegaLite",component:i,tags:["autodocs"],argTypes:{data:{description:"Data to be used by Vega Lite. See the Vega Lite docs: https://vega.github.io/vega-lite/docs/data.html."},spec:{description:"Spec to be used by Vega Lite. See the Vega Lite docs: https://vega.github.io/vega-lite/docs/spec.html."}}},e={name:"Chart built with Vega Lite",args:{data:{table:[{y:-.418,x:1850},{y:.923,x:2020}]},spec:{$schema:"https://vega.github.io/schema/vega-lite/v4.json",mark:"bar",data:{name:"table"},encoding:{x:{field:"x",type:"ordinal"},y:{field:"y",type:"quantitative"}}}}};var t,a,n;e.parameters={...e.parameters,docs:{...(t=e.parameters)==null?void 0:t.docs,source:{originalSource:`{
name: 'Chart built with Vega Lite',
args: {
data: {
table: [{
y: -0.418,
x: 1850
}, {
y: 0.923,
x: 2020
}]
},
spec: {
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
mark: 'bar',
data: {
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative'
}
}
}
}
}`,...(n=(a=e.parameters)==null?void 0:a.docs)==null?void 0:n.source}}};const g=["Primary"];export{e as Primary,g as __namedExportsOrder,c as default};
//# sourceMappingURL=VegaLite.stories-a09b0c5c.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"VegaLite.stories-a09b0c5c.js","sources":[],"sourcesContent":[],"names":[],"mappings":";;;;;;;;;;;;;;;;;;;;;;;;;;;;;;"}

View File

@@ -1,2 +0,0 @@
import{b as W,b,d}from"./index-89936ab1.js";import"./iframe-1eda5ccb.js";import"../sb-preview/runtime.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";import"./index-d475d2ea.js";import"./isNativeReflectConstruct-099dc9ad.js";import"./index-8ce4a492.js";import"./index-d37d4223.js";import"./index-6e6be2d5.js";import"./index-356e4a49.js";export{W as WithToolTipState,b as WithTooltip,d as WithTooltipPure};
//# sourceMappingURL=WithTooltip-FBT32F6Q-518acee3.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"WithTooltip-FBT32F6Q-518acee3.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}

View File

@@ -1,2 +0,0 @@
var f=typeof globalThis<"u"?globalThis:typeof window<"u"?window:typeof global<"u"?global:typeof self<"u"?self:{};function l(e){return e&&e.__esModule&&Object.prototype.hasOwnProperty.call(e,"default")?e.default:e}function a(e){if(e.__esModule)return e;var r=e.default;if(typeof r=="function"){var o=function n(){if(this instanceof n){var t=[null];t.push.apply(t,arguments);var u=Function.bind.apply(r,t);return new u}return r.apply(this,arguments)};o.prototype=r.prototype}else o={};return Object.defineProperty(o,"__esModule",{value:!0}),Object.keys(e).forEach(function(n){var t=Object.getOwnPropertyDescriptor(e,n);Object.defineProperty(o,n,t.get?t:{enumerable:!0,get:function(){return e[n]}})}),o}export{a,f as c,l as g};
//# sourceMappingURL=_commonjsHelpers-042e6b4d.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"_commonjsHelpers-042e6b4d.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@@ -1,2 +0,0 @@
import{M as r,a,u as m,w as n}from"./index-1d576ef5.js";import"./index-8db94870.js";import"./_commonjsHelpers-042e6b4d.js";export{r as MDXContext,a as MDXProvider,m as useMDXComponents,n as withMDXComponents};
//# sourceMappingURL=index-186b3228.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"index-186b3228.js","sources":[],"sourcesContent":[],"names":[],"mappings":""}

View File

@@ -1,2 +0,0 @@
import{R as o}from"./index-8db94870.js";const u=o.createContext({});function c(t){return e;function e(r){const n=a(r.components);return o.createElement(t,{...r,allComponents:n})}}function a(t){const e=o.useContext(u);return o.useMemo(()=>typeof t=="function"?t(e):{...e,...t},[e,t])}const i={};function f({components:t,children:e,disableParentContext:r}){let n;return r?n=typeof t=="function"?t({}):t||i:n=a(t),o.createElement(u.Provider,{value:n},e)}export{u as M,f as a,a as u,c as w};
//# sourceMappingURL=index-1d576ef5.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"index-1d576ef5.js","sources":["../../node_modules/@mdx-js/react/lib/index.js"],"sourcesContent":["/**\n * @typedef {import('react').ReactNode} ReactNode\n * @typedef {import('mdx/types.js').MDXComponents} Components\n *\n * @typedef Props\n * Configuration.\n * @property {Components | MergeComponents | null | undefined} [components]\n * Mapping of names for JSX components to React components.\n * @property {boolean | null | undefined} [disableParentContext=false]\n * Turn off outer component context.\n * @property {ReactNode | null | undefined} [children]\n * Children.\n *\n * @callback MergeComponents\n * Custom merge function.\n * @param {Components} currentComponents\n * Current components from the context.\n * @returns {Components}\n * Merged components.\n */\n\nimport React from 'react'\n\n/**\n * @type {import('react').Context<Components>}\n * @deprecated\n * This export is marked as a legacy feature.\n * That means its no longer recommended for use as it might be removed\n * in a future major release.\n *\n * Please use `useMDXComponents` to get context based components and\n * `MDXProvider` to set context based components instead.\n */\nexport const MDXContext = React.createContext({})\n\n/**\n * @param {import('react').ComponentType<any>} Component\n * @deprecated\n * This export is marked as a legacy feature.\n * That means its no longer recommended for use as it might be removed\n * in a future major release.\n *\n * Please use `useMDXComponents` to get context based components instead.\n */\nexport function withMDXComponents(Component) {\n return boundMDXComponent\n\n /**\n * @param {Record<string, unknown> & {components?: Components | null | undefined}} props\n * @returns {JSX.Element}\n */\n function boundMDXComponent(props) {\n const allComponents = useMDXComponents(props.components)\n return React.createElement(Component, {...props, allComponents})\n }\n}\n\n/**\n * Get current components from the MDX Context.\n *\n * @param {Components | MergeComponents | null | undefined} [components]\n * Additional components to use or a function that takes the current\n * components and filters/merges/changes them.\n * @returns {Components}\n * Current components.\n */\nexport function useMDXComponents(components) {\n const contextComponents = React.useContext(MDXContext)\n\n // Memoize to avoid unnecessary top-level context changes\n return React.useMemo(() => {\n // Custom merge via a function prop\n if (typeof components === 'function') {\n return components(contextComponents)\n }\n\n return {...contextComponents, ...components}\n }, [contextComponents, components])\n}\n\n/** @type {Components} */\nconst emptyObject = {}\n\n/**\n * Provider for MDX context\n *\n * @param {Props} props\n * @returns {JSX.Element}\n */\nexport function MDXProvider({components, children, disableParentContext}) {\n /** @type {Components} */\n let allComponents\n\n if (disableParentContext) {\n allComponents =\n typeof components === 'function'\n ? components({})\n : components || emptyObject\n } else {\n allComponents = useMDXComponents(components)\n }\n\n return React.createElement(\n MDXContext.Provider,\n {value: allComponents},\n children\n )\n}\n"],"names":["MDXContext","React","withMDXComponents","Component","boundMDXComponent","props","allComponents","useMDXComponents","components","contextComponents","emptyObject","MDXProvider","children","disableParentContext"],"mappings":"wCAiCY,MAACA,EAAaC,EAAM,cAAc,EAAE,EAWzC,SAASC,EAAkBC,EAAW,CAC3C,OAAOC,EAMP,SAASA,EAAkBC,EAAO,CAChC,MAAMC,EAAgBC,EAAiBF,EAAM,UAAU,EACvD,OAAOJ,EAAM,cAAcE,EAAW,CAAC,GAAGE,EAAO,cAAAC,CAAa,CAAC,CAChE,CACH,CAWO,SAASC,EAAiBC,EAAY,CAC3C,MAAMC,EAAoBR,EAAM,WAAWD,CAAU,EAGrD,OAAOC,EAAM,QAAQ,IAEf,OAAOO,GAAe,WACjBA,EAAWC,CAAiB,EAG9B,CAAC,GAAGA,EAAmB,GAAGD,CAAU,EAC1C,CAACC,EAAmBD,CAAU,CAAC,CACpC,CAGA,MAAME,EAAc,CAAE,EAQf,SAASC,EAAY,CAAC,WAAAH,EAAY,SAAAI,EAAU,qBAAAC,CAAoB,EAAG,CAExE,IAAIP,EAEJ,OAAIO,EACFP,EACE,OAAOE,GAAe,WAClBA,EAAW,CAAA,CAAE,EACbA,GAAcE,EAEpBJ,EAAgBC,EAAiBC,CAAU,EAGtCP,EAAM,cACXD,EAAW,SACX,CAAC,MAAOM,CAAa,EACrBM,CACD,CACH","x_google_ignoreList":[0]}

View File

@@ -1,2 +0,0 @@
import{g as c}from"./_commonjsHelpers-042e6b4d.js";var p={exports:{}},i="SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED",y=i,m=y;function n(){}function a(){}a.resetWarningCache=n;var T=function(){function e(f,h,l,P,g,s){if(s!==m){var o=new Error("Calling PropTypes validators directly is not supported by the `prop-types` package. Use PropTypes.checkPropTypes() to call them. Read more at http://fb.me/use-check-prop-types");throw o.name="Invariant Violation",o}}e.isRequired=e;function r(){return e}var t={array:e,bigint:e,bool:e,func:e,number:e,object:e,string:e,symbol:e,any:e,arrayOf:r,element:e,elementType:e,instanceOf:r,node:e,objectOf:r,oneOf:r,oneOfType:r,shape:r,exact:r,checkPropTypes:a,resetWarningCache:n};return t.PropTypes=t,t};p.exports=T();var u=p.exports;const R=c(u);export{R as P};
//# sourceMappingURL=index-1fc0ca9a.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"index-1fc0ca9a.js","sources":["../../node_modules/prop-types/lib/ReactPropTypesSecret.js","../../node_modules/prop-types/factoryWithThrowingShims.js","../../node_modules/prop-types/index.js"],"sourcesContent":["/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = 'SECRET_DO_NOT_PASS_THIS_OR_YOU_WILL_BE_FIRED';\n\nmodule.exports = ReactPropTypesSecret;\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\n'use strict';\n\nvar ReactPropTypesSecret = require('./lib/ReactPropTypesSecret');\n\nfunction emptyFunction() {}\nfunction emptyFunctionWithReset() {}\nemptyFunctionWithReset.resetWarningCache = emptyFunction;\n\nmodule.exports = function() {\n function shim(props, propName, componentName, location, propFullName, secret) {\n if (secret === ReactPropTypesSecret) {\n // It is still safe when called from React.\n return;\n }\n var err = new Error(\n 'Calling PropTypes validators directly is not supported by the `prop-types` package. ' +\n 'Use PropTypes.checkPropTypes() to call them. ' +\n 'Read more at http://fb.me/use-check-prop-types'\n );\n err.name = 'Invariant Violation';\n throw err;\n };\n shim.isRequired = shim;\n function getShim() {\n return shim;\n };\n // Important!\n // Keep this list in sync with production version in `./factoryWithTypeCheckers.js`.\n var ReactPropTypes = {\n array: shim,\n bigint: shim,\n bool: shim,\n func: shim,\n number: shim,\n object: shim,\n string: shim,\n symbol: shim,\n\n any: shim,\n arrayOf: getShim,\n element: shim,\n elementType: shim,\n instanceOf: getShim,\n node: shim,\n objectOf: getShim,\n oneOf: getShim,\n oneOfType: getShim,\n shape: getShim,\n exact: getShim,\n\n checkPropTypes: emptyFunctionWithReset,\n resetWarningCache: emptyFunction\n };\n\n ReactPropTypes.PropTypes = ReactPropTypes;\n\n return ReactPropTypes;\n};\n","/**\n * Copyright (c) 2013-present, Facebook, Inc.\n *\n * This source code is licensed under the MIT license found in the\n * LICENSE file in the root directory of this source tree.\n */\n\nif (process.env.NODE_ENV !== 'production') {\n var ReactIs = require('react-is');\n\n // By explicitly using `prop-types` you are opting into new development behavior.\n // http://fb.me/prop-types-in-prod\n var throwOnDirectAccess = true;\n module.exports = require('./factoryWithTypeCheckers')(ReactIs.isElement, throwOnDirectAccess);\n} else {\n // By explicitly using `prop-types` you are opting into new production behavior.\n // http://fb.me/prop-types-in-prod\n module.exports = require('./factoryWithThrowingShims')();\n}\n"],"names":["ReactPropTypesSecret","ReactPropTypesSecret_1","require$$0","emptyFunction","emptyFunctionWithReset","factoryWithThrowingShims","shim","props","propName","componentName","location","propFullName","secret","err","getShim","ReactPropTypes","propTypesModule"],"mappings":"sEASIA,EAAuB,+CAE3BC,EAAiBD,ECFbA,EAAuBE,EAE3B,SAASC,GAAgB,CAAE,CAC3B,SAASC,GAAyB,CAAE,CACpCA,EAAuB,kBAAoBD,EAE3C,IAAAE,EAAiB,UAAW,CAC1B,SAASC,EAAKC,EAAOC,EAAUC,EAAeC,EAAUC,EAAcC,EAAQ,CAC5E,GAAIA,IAAWZ,EAIf,KAAIa,EAAM,IAAI,MACZ,iLAGN,EACI,MAAAA,EAAI,KAAO,sBACLA,EACV,CACEP,EAAK,WAAaA,EAClB,SAASQ,GAAU,CACjB,OAAOR,CAEX,CAEE,IAAIS,EAAiB,CACnB,MAAOT,EACP,OAAQA,EACR,KAAMA,EACN,KAAMA,EACN,OAAQA,EACR,OAAQA,EACR,OAAQA,EACR,OAAQA,EAER,IAAKA,EACL,QAASQ,EACT,QAASR,EACT,YAAaA,EACb,WAAYQ,EACZ,KAAMR,EACN,SAAUQ,EACV,MAAOA,EACP,UAAWA,EACX,MAAOA,EACP,MAAOA,EAEP,eAAgBV,EAChB,kBAAmBD,CACvB,EAEE,OAAAY,EAAe,UAAYA,EAEpBA,CACT,EC/CEC,EAAc,QAAGd","x_google_ignoreList":[0,1,2]}

View File

@@ -1,7 +0,0 @@
function l(o){for(var f=[],i=1;i<arguments.length;i++)f[i-1]=arguments[i];var n=Array.from(typeof o=="string"?[o]:o);n[n.length-1]=n[n.length-1].replace(/\r?\n([\t ]*)$/,"");var s=n.reduce(function(t,g){var a=g.match(/\n([\t ]+|(?!\s).)/g);return a?t.concat(a.map(function(u){var r,e;return(e=(r=u.match(/[\t ]/g))===null||r===void 0?void 0:r.length)!==null&&e!==void 0?e:0})):t},[]);if(s.length){var d=new RegExp(`
[ ]{`+Math.min.apply(Math,s)+"}","g");n=n.map(function(t){return t.replace(d,`
`)})}n[0]=n[0].replace(/^\r?\n/,"");var c=n[0];return f.forEach(function(t,g){var a=c.match(/(?:^|\n)( *)$/),u=a?a[1]:"",r=t;typeof t=="string"&&t.includes(`
`)&&(r=String(t).split(`
`).map(function(e,h){return h===0?e:""+u+e}).join(`
`)),c+=r+n[g+1]}),c}export{l as d};
//# sourceMappingURL=index-356e4a49.js.map

View File

@@ -1 +0,0 @@
{"version":3,"file":"index-356e4a49.js","sources":["../../node_modules/ts-dedent/esm/index.js"],"sourcesContent":["export function dedent(templ) {\n var values = [];\n for (var _i = 1; _i < arguments.length; _i++) {\n values[_i - 1] = arguments[_i];\n }\n var strings = Array.from(typeof templ === 'string' ? [templ] : templ);\n strings[strings.length - 1] = strings[strings.length - 1].replace(/\\r?\\n([\\t ]*)$/, '');\n var indentLengths = strings.reduce(function (arr, str) {\n var matches = str.match(/\\n([\\t ]+|(?!\\s).)/g);\n if (matches) {\n return arr.concat(matches.map(function (match) { var _a, _b; return (_b = (_a = match.match(/[\\t ]/g)) === null || _a === void 0 ? void 0 : _a.length) !== null && _b !== void 0 ? _b : 0; }));\n }\n return arr;\n }, []);\n if (indentLengths.length) {\n var pattern_1 = new RegExp(\"\\n[\\t ]{\" + Math.min.apply(Math, indentLengths) + \"}\", 'g');\n strings = strings.map(function (str) { return str.replace(pattern_1, '\\n'); });\n }\n strings[0] = strings[0].replace(/^\\r?\\n/, '');\n var string = strings[0];\n values.forEach(function (value, i) {\n var endentations = string.match(/(?:^|\\n)( *)$/);\n var endentation = endentations ? endentations[1] : '';\n var indentedValue = value;\n if (typeof value === 'string' && value.includes('\\n')) {\n indentedValue = String(value)\n .split('\\n')\n .map(function (str, i) {\n return i === 0 ? str : \"\" + endentation + str;\n })\n .join('\\n');\n }\n string += indentedValue + strings[i + 1];\n });\n return string;\n}\nexport default dedent;\n//# sourceMappingURL=index.js.map"],"names":["dedent","templ","values","_i","strings","indentLengths","arr","str","matches","match","_a","_b","pattern_1","string","value","i","endentations","endentation","indentedValue"],"mappings":"AAAO,SAASA,EAAOC,EAAO,CAE1B,QADIC,EAAS,CAAA,EACJC,EAAK,EAAGA,EAAK,UAAU,OAAQA,IACpCD,EAAOC,EAAK,CAAC,EAAI,UAAUA,CAAE,EAEjC,IAAIC,EAAU,MAAM,KAAK,OAAOH,GAAU,SAAW,CAACA,CAAK,EAAIA,CAAK,EACpEG,EAAQA,EAAQ,OAAS,CAAC,EAAIA,EAAQA,EAAQ,OAAS,CAAC,EAAE,QAAQ,iBAAkB,EAAE,EACtF,IAAIC,EAAgBD,EAAQ,OAAO,SAAUE,EAAKC,EAAK,CACnD,IAAIC,EAAUD,EAAI,MAAM,qBAAqB,EAC7C,OAAIC,EACOF,EAAI,OAAOE,EAAQ,IAAI,SAAUC,EAAO,CAAE,IAAIC,EAAIC,EAAI,OAAQA,GAAMD,EAAKD,EAAM,MAAM,QAAQ,KAAO,MAAQC,IAAO,OAAS,OAASA,EAAG,UAAY,MAAQC,IAAO,OAASA,EAAK,CAAI,CAAA,CAAC,EAE1LL,CACV,EAAE,CAAE,CAAA,EACL,GAAID,EAAc,OAAQ,CACtB,IAAIO,EAAY,IAAI,OAAO;AAAA,OAAa,KAAK,IAAI,MAAM,KAAMP,CAAa,EAAI,IAAK,GAAG,EACtFD,EAAUA,EAAQ,IAAI,SAAUG,EAAK,CAAE,OAAOA,EAAI,QAAQK,EAAW;AAAA,CAAI,CAAI,CAAA,EAEjFR,EAAQ,CAAC,EAAIA,EAAQ,CAAC,EAAE,QAAQ,SAAU,EAAE,EAC5C,IAAIS,EAAST,EAAQ,CAAC,EACtB,OAAAF,EAAO,QAAQ,SAAUY,EAAOC,EAAG,CAC/B,IAAIC,EAAeH,EAAO,MAAM,eAAe,EAC3CI,EAAcD,EAAeA,EAAa,CAAC,EAAI,GAC/CE,EAAgBJ,EAChB,OAAOA,GAAU,UAAYA,EAAM,SAAS;AAAA,CAAI,IAChDI,EAAgB,OAAOJ,CAAK,EACvB,MAAM;AAAA,CAAI,EACV,IAAI,SAAUP,EAAKQ,EAAG,CACvB,OAAOA,IAAM,EAAIR,EAAM,GAAKU,EAAcV,CAC1D,CAAa,EACI,KAAK;AAAA,CAAI,GAElBM,GAAUK,EAAgBd,EAAQW,EAAI,CAAC,CAC/C,CAAK,EACMF,CACX","x_google_ignoreList":[0]}

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