Compare commits

...

14 Commits

Author SHA1 Message Date
Luccas Mateus de Medeiros Gomes
8a7be6e402 Remove things from openspending 2023-05-18 13:48:01 -03:00
Luccas Mateus de Medeiros Gomes
fa05e374c9 [docs][howto] - [!info] on vegalite 2023-05-18 13:45:07 -03:00
Luccas Mateus de Medeiros Gomes
f52832624f [docs][howto] - added catalog code 2023-05-18 13:43:29 -03:00
Luccas Mateus
f2e7f157b9 Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:26:43 -03:00
Luccas Mateus
ddc954d6bb Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:26:33 -03:00
Luccas Mateus
7c62a8c93f Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:26:08 -03:00
Luccas Mateus
64cc1355bb Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:25:56 -03:00
Luccas Mateus
8945e7dd85 Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:25:37 -03:00
Luccas Mateus
92f6c5eb47 Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:25:29 -03:00
Luccas Mateus
ff8157bf57 Update site/content/howto/drd.md
Co-authored-by: Ola Rubaj <52197250+olayway@users.noreply.github.com>
2023-05-18 13:25:16 -03:00
Luccas Mateus de Medeiros Gomes
ba3efc9ec7 [docs][xs] - remove my version of files 2023-05-18 11:51:01 -03:00
Luccas Mateus de Medeiros Gomes
87c46aba04 [docs][xs] - added catalog example 2023-05-18 11:48:59 -03:00
Luccas Mateus de Medeiros Gomes
964eb5b3ee [docs][m] - start of drd page 2023-05-18 07:57:20 -03:00
Luccas Mateus de Medeiros Gomes
f93d4aa6bd [site][m] - start of developer faq 2023-05-17 19:41:27 -03:00
14 changed files with 620 additions and 141 deletions

View File

@@ -1,15 +1,15 @@
import Link from 'next/link'
import clsx from 'clsx'
import Link from 'next/link';
import clsx from 'clsx';
export function Button({ href, className = "", ...props }) {
export function Button({ href, className = '', ...props }) {
className = clsx(
'inline-flex justify-center rounded-2xl bg-emerald-600 p-4 text-base font-semibold text-white hover:bg-emerald-500 focus:outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-emerald-500 active:text-white/70',
className
)
);
return href ? (
<Link href={href} className={className} {...props} />
<Link scroll={false} href={href} className={className} {...props} />
) : (
<button className={className} {...props} />
)
);
}

View File

@@ -0,0 +1,76 @@
import Link from 'next/link';
import { Project } from '../lib/project.interface';
import ExternalLinkIcon from './icons/ExternalLinkIcon';
export default function DatasetCard({ dataset }: { dataset: Project }) {
return (
<div
key={dataset.name}
className="overflow-hidden rounded-xl border border-gray-200"
>
<Link
href=""
className="flex items-center gap-x-4 border-b border-gray-900/5 bg-gray-50 p-6"
>
<img
src={dataset.owner.logo || '/assets/org-icon.svg'}
alt={dataset.owner.name}
className="h-12 w-12 flex-none rounded-lg bg-white object-cover ring-1 ring-gray-900/10 p-2"
/>
<div className="text-sm font-medium leading-6">
<div className="text-gray-900 line-clamp-1">{dataset.title}</div>
<div className="text-gray-500 line-clamp-1">
{dataset.owner.title}
</div>
</div>
</Link>
<dl className="-my-3 divide-y divide-gray-100 px-6 py-4 text-sm leading-6">
<div className="flex justify-between gap-x-4 py-3">
<dt className="text-gray-500">Name</dt>
<dd className="flex items-start gap-x-2">
<div className="font-medium text-gray-900 line-clamp-1">
{dataset.name}
</div>
</dd>
</div>
<div className="flex justify-between gap-x-4 py-3">
<dt className="text-gray-500">Country</dt>
<dd className="flex items-start gap-x-2">
<div className="font-medium text-gray-900">
{dataset.countryCode}
</div>
</dd>
</div>
<div className="flex justify-between gap-x-4 py-3">
<dt className="text-gray-500">Fiscal Period</dt>
<dd className="text-gray-700">
{dataset.fiscalPeriod?.start &&
new Date(dataset.fiscalPeriod.start).getFullYear()}
{dataset.fiscalPeriod?.end &&
dataset.fiscalPeriod?.start !== dataset.fiscalPeriod?.end && (
<>
{' - '}
{new Date(dataset.fiscalPeriod.end).getFullYear()}
</>
)}
</dd>
</div>
<div className="flex justify-between gap-x-4 py-3">
<dt className="text-gray-500">Metadata</dt>
<dd className="flex items-start gap-x-2">
<div className="font-medium text-gray-900">
<Link
// TODO: where do we get the info needed for this link?
href=""
target="_blank"
className="flex items-center hover:text-gray-700"
>
datapackage.json <ExternalLinkIcon className="ml-1" />
</Link>
</div>
</dd>
</div>
</dl>
</div>
);
}

View File

@@ -0,0 +1,19 @@
import { Project } from '../lib/project.interface';
import DatasetCard from './DatasetCard';
export default function DatasetsGrid({ datasets }: { datasets: Project[] }) {
return (
<ul
className="grid gap-x-6 gap-y-8 grid-cols-1 sm:grid-cols-2 md:grid-cols-3"
role="list"
>
{datasets.map((dataset, idx) => {
return (
<li key={`datasets-grid-item-${idx}`}>
<DatasetCard dataset={dataset} />
</li>
);
})}
</ul>
);
}

View File

@@ -0,0 +1,163 @@
import { useForm } from 'react-hook-form';
import DatasetsGrid from './DatasetsGrid';
import { Project } from '../lib/project.interface';
import { Index } from 'flexsearch';
export default function DatasetsSearch({ datasets }: { datasets: Project[] }) {
const index = new Index({ tokenize: 'full' });
datasets.forEach((dataset: Project) =>
index.add(
dataset.name,
`${dataset.repo} ${dataset.name} ${dataset.title} ${dataset.author} ${dataset.title} ${dataset.cityCode} ${dataset.fiscalPeriod?.start} ${dataset.fiscalPeriod?.end}`
)
);
const { register, watch, handleSubmit, reset, resetField } = useForm({
defaultValues: {
searchTerm: '',
country: '',
minDate: '',
maxDate: '',
},
});
const allCountries = datasets
.map((item) => item.countryCode)
.filter((v) => v) // Filters false values
.filter((v, i, a) => a.indexOf(v) === i) // Remove duplicates
// TODO: title should be the full name
.map((code) => ({ code, title: code }));
return (
<>
<div className="flex flex-col gap-3 sm:flex-row">
<div className="min-w-0 flex-auto">
<br />
<div className="relative">
<input
placeholder="Search datasets"
aria-label="Search datasets"
{...register('searchTerm')}
className="h-[3em] relative w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
/>
{watch().searchTerm !== '' && (
<button
onClick={() => resetField('searchTerm')}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500"
>
<CloseIcon />
</button>
)}
</div>
</div>
<div className="sm:basis-1/6">
{/* TODO: nicer select e.g. headlessui example */}
<label className="text-sm text-gray-600 font-medium">Country</label>
<select
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
{...register('country')}
>
<option value="">All</option>
{allCountries.map((country) => {
return (
<option key={country.code} value={country.code}>
{country.title}
</option>
);
})}
</select>
</div>
<div className="sm:basis-1/6">
<label className="text-sm text-gray-600 font-medium">Min. date</label>
<div className="relative">
<input
aria-label="Min. date"
type="date"
{...register('minDate')}
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
/>
{watch().minDate !== '' && (
<button
onClick={() => resetField('minDate')}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500"
>
<CloseIcon />
</button>
)}
</div>
</div>
<div className="sm:basis-1/6">
<label className="text-sm text-gray-600 font-medium">Max. date</label>
<div className="relative">
<input
aria-label="Max. date"
type="date"
{...register('maxDate')}
className="h-[3em] w-full rounded-lg bg-white py-2 pl-3 pr-10 text-left shadow-md focus:outline-none focus-visible:border-emerald-500 focus-visible:ring-2 focus-visible:ring-white focus-visible:ring-opacity-75 focus-visible:ring-offset-2 focus-visible:ring-offset-emerald-400 sm:text-sm"
/>
{watch().maxDate !== '' && (
<button
onClick={() => resetField('maxDate')}
className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500"
>
<CloseIcon />
</button>
)}
</div>
</div>
</div>
<div className="min-w-full mt-10 align-middle">
<DatasetsGrid
datasets={datasets
.filter((dataset: Project) =>
watch().searchTerm && watch().searchTerm !== ''
? index.search(watch().searchTerm).includes(dataset.name)
: true
)
.filter((dataset) =>
watch().country && watch().country !== ''
? dataset.countryCode === watch().country
: true
)
// TODO: Does that really makes sense?
// What if the fiscalPeriod is 2015-2017 and inputs are
// set to 2015-2016. It's going to be filtered out but
// it shouldn't.
.filter((dataset) =>
watch().minDate && watch().minDate !== ''
? dataset.fiscalPeriod?.start >= watch().minDate
: true
)
.filter((dataset) =>
watch().maxDate && watch().maxDate !== ''
? dataset.fiscalPeriod?.end <= watch().maxDate
: true
)}
/>
</div>
</>
);
}
const CloseIcon = () => {
return (
<svg
width={20}
height={20}
viewBox="0 0 24 24"
fill="none"
xmlns="http://www.w3.org/2000/svg"
>
<g id="Menu / Close_MD">
<path
id="Vector"
d="M18 18L12 12M12 12L6 6M12 12L18 6M12 12L6 18"
stroke="currentColor"
stroke-width="2"
stroke-linecap="round"
stroke-linejoin="round"
/>
</g>
</svg>
);
};

View File

@@ -46,7 +46,6 @@ export function Header() {
</li>))}
</ul>
<div className="hidden sm:mt-10 sm:flex lg:mt-0 lg:grow lg:basis-0 lg:justify-end">
<Button href="#">View on GitHub</Button>
</div>
</Container>
</header >

View File

@@ -23,8 +23,8 @@ export function Hero() {
fiscal data in the public sphere.
</p>
</div>
<Button href="#" className="mt-10 w-full sm:hidden">
View on GitHub
<Button href="#datasets" className="mt-10">
Search datasets
</Button>
<dl className="mt-10 grid grid-cols-2 gap-x-10 gap-y-6 sm:mt-16 sm:gap-x-16 sm:gap-y-10 sm:text-center lg:auto-cols-auto lg:grid-flow-col lg:grid-cols-none lg:justify-start lg:text-left">
{[

View File

@@ -1,15 +1,17 @@
import { FiscalDataPackage } from './datapackage.interface';
import { Project } from './project.interface';
export function loadDataPackage(
datapackage: FiscalDataPackage,
owner: string,
repo: string
): Project {
export function loadDataPackage(datapackage: FiscalDataPackage, repo): Project {
return {
name: datapackage.name,
owner: { name: owner },
repo: { name: repo },
title: datapackage.title,
owner: {
name: repo.owner.login,
logo: repo.owner.avatar_url,
// TODO: make this title work
title: repo.owner.login,
},
repo: { name: repo, full_name: repo.full_name },
files: datapackage.resources,
author: datapackage.author ? datapackage.author : null,
cityCode: datapackage.cityCode ? datapackage.cityCode : null,
@@ -17,7 +19,8 @@ export function loadDataPackage(
? (datapackage.countryCode as string)
: null,
fiscalPeriod: datapackage.fiscalPeriod
? { start: datapackage.fiscalPeriod.start
? {
start: datapackage.fiscalPeriod.start
? datapackage.fiscalPeriod.start
: null,
end: datapackage.fiscalPeriod.end
@@ -26,6 +29,6 @@ export function loadDataPackage(
}
: null,
readme: datapackage.readme ? datapackage.readme : '',
datapackage
datapackage,
};
}

View File

@@ -1,8 +1,11 @@
import { FiscalDataPackage, TabularDataResource } from "./datapackage.interface";
import {
FiscalDataPackage,
TabularDataResource,
} from './datapackage.interface';
export interface Project {
owner: { name: string; logo?: string }; // Info about the owner of the data repo
repo: { name: string; logo?: string }; // Info about the the data repo
owner: { name: string; logo?: string; title?: string }; // Info about the owner of the data repo
repo: { name: string; full_name: string }; // Info about the the data repo
files: TabularDataResource[];
name: string;
title?: string;
@@ -14,5 +17,5 @@ export interface Project {
end: string;
};
readme?: string;
datapackage: FiscalDataPackage
datapackage: FiscalDataPackage;
}

View File

@@ -1,6 +1,10 @@
import { promises as fs } from 'fs';
import path from 'path';
import { GithubProject, getProjectDataPackage } from '../lib/octokit';
import {
GithubProject,
getProjectDataPackage,
getProjectMetadata,
} from '../lib/octokit';
import getConfig from 'next/config';
import ExternalLinkIcon from '../components/icons/ExternalLinkIcon';
import TimeAgo from 'react-timeago';
@@ -10,44 +14,48 @@ import { Header } from '../components/Header';
import { Container } from '../components/Container';
import { FiscalDataPackage } from '../lib/datapackage.interface';
import { loadDataPackage } from '../lib/loader';
import { Project } from '../lib/project.interface';
import { Index } from 'flexsearch';
import { useForm } from 'react-hook-form';
import DatasetsSearch from '../components/DatasetsSearch';
export async function getStaticProps() {
const jsonDirectory = path.join(process.cwd(), '/datasets.json');
const repos = await fs.readFile(jsonDirectory, 'utf8');
const github_pat = getConfig().serverRuntimeConfig.github_pat;
const datapackages = await Promise.all(
JSON.parse(repos).map(
async (_repo: GithubProject) =>
await getProjectDataPackage(_repo.owner, _repo.name, 'main', github_pat)
)
JSON.parse(repos).map(async (_repo: GithubProject) => {
const datapackage = await getProjectDataPackage(
_repo.owner,
_repo.name,
'main',
github_pat
);
const repo = await getProjectMetadata(
_repo.owner,
_repo.name,
github_pat
);
return {
datapackage,
repo,
};
})
);
const projects = datapackages.map(
(datapackage: FiscalDataPackage & { repo: string }) =>
loadDataPackage(datapackage, 'os-data', datapackage.name)
(item: { datapackage: FiscalDataPackage & { repo: string }; repo: any }) =>
loadDataPackage(item.datapackage, item.repo)
);
return {
props: {
projects,
projects: JSON.stringify(projects),
},
};
}
export function Datasets({ projects }) {
const index = new Index({ tokenize: 'full' });
projects.forEach((project: Project) =>
index.add(
project.name,
`${project.repo} ${project.name} ${project.title} ${project.author} ${project.title} ${project.cityCode} ${project.fiscalPeriod?.start} ${project.fiscalPeriod?.end}`
)
);
const { register, watch, handleSubmit, reset } = useForm({
defaultValues: {
searchTerm: '',
},
});
projects = JSON.parse(projects);
return (
<div className="bg-white min-h-screen">
<Header />
@@ -65,101 +73,8 @@ export function Datasets({ projects }) {
Find spending data about countries all around the world.
</p>
</div>
<div className="mt-5">
<div className="mt-6 flex flex-col gap-3 sm:flex-row">
<input
placeholder="Search here"
aria-label="Hate speech on Twitter"
{...register('searchTerm')}
className="min-w-0 flex-auto appearance-none rounded-md border border-zinc-900/10 bg-white px-3 py-[calc(theme(spacing.2)-1px)] shadow-md shadow-zinc-800/5 placeholder:text-zinc-600 focus:border-emerald-500 focus:outline-none focus:ring-4 focus:ring-emerald-500/10 sm:text-sm"
/>
</div>
<div className="-mx-4 -my-2 overflow-x-auto sm:-mx-6 lg:-mx-8">
<div className="inline-block min-w-full py-2 align-middle sm:px-6 lg:px-8">
<table className="min-w-full divide-y divide-gray-300">
<thead>
<tr>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Name
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Repository
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Author
</th>
<th
scope="col"
className="px-3 py-3.5 text-left text-sm font-semibold text-gray-900"
>
Fiscal Year
</th>
<th
scope="col"
className="relative py-3.5 pl-3 pr-4 sm:pr-0"
></th>
</tr>
</thead>
<tbody className="divide-y divide-gray-200">
{projects
.filter((project: Project) =>
watch().searchTerm && watch().searchTerm !== ''
? index
.search(watch().searchTerm)
.includes(project.name)
: true
)
.map((project: Project) => (
<tr key={project.name}>
<td className="whitespace-nowrap px-3 py-6 text-sm text-gray-500">
{project.name}
</td>
<td className="whitespace-nowrap px-3 py-6 text-sm group text-gray-500 hover:text-gray-900 transition-all duration-250">
<a
href={`https://github.com/${project.owner.name}/${project.repo.name}`}
target="_blank"
className="flex items-center"
>
@{project.owner.name}/{project.repo.name}{' '}
<ExternalLinkIcon className="ml-1" />
</a>
</td>
<td className="px-3 py-4 text-sm text-gray-500">
{project.author}
</td>
{project.fiscalPeriod ? (
<td className="whitespace-nowrap px-3 py-6 text-sm text-gray-500">
{project.fiscalPeriod.start} -{' '}
{project.fiscalPeriod.end}
</td>
) : (
<td className="whitespace-nowrap px-3 py-6 text-sm text-gray-500">
No data
</td>
)}
<td className="relative whitespace-nowrap py-6 pl-3 pr-4 text-right text-sm font-medium sm:pr-0">
<a
href={`/@${project.owner.name}/${project.repo.name}/`}
className="border border-gray-900 text-gray-900 px-4 py-2 transition-all hover:bg-gray-900 hover:text-white"
>
info
</a>
</td>
</tr>
))}
</tbody>
</table>
</div>
</div>
<div className="mt-10">
<DatasetsSearch datasets={projects} />
</div>
</Container>
</section>

View File

@@ -0,0 +1,11 @@
<?xml version="1.0" encoding="UTF-8"?>
<!-- Uploaded to: SVG Repo, www.svgrepo.com, Generator: SVG Repo Mixer Tools -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg fill="#000000" version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="800px" height="800px" viewBox="0 0 120 120" enable-background="new 0 0 120 120" xml:space="preserve">
<rect x="2" y="108.1" width="116" height="11.9"/>
<rect x="6.744" y="96.582" width="104.979" height="6.543"/>
<rect x="15.288" y="38.532" width="17.639" height="52.925"/>
<rect x="50.484" y="38.532" width="17.639" height="52.925"/>
<rect x="84.33" y="38.532" width="17.639" height="52.925"/>
<polygon points="0,26.96 60,0 120,26.96 119.946,33.912 0,34.01 "/>
</svg>

After

Width:  |  Height:  |  Size: 818 B

View File

@@ -10,5 +10,14 @@
{ "title": "Deploying your PortalJS app", "href": "/docs/deploying-your-portaljs-app" }
]
},
{
"title": "Developer FAQs",
"links": [
{ "title": "Analytics", "href": "/howto/analytics" },
{ "title": "Page Metadata", "href": "/howto/page-metadata" },
{ "title": "Sitemaps", "href": "/howto/sitemaps" },
{ "title": "Data Rich Documents", "href": "/howto/drd" }
]
}
]

281
site/content/howto/drd.md Normal file
View File

@@ -0,0 +1,281 @@
# How to have data rich documents with charts and tables?
PortalJS comes with a library of components that provides essential pieces for your data portal. The best way to explore the components is to look at our [Storybook](https://storybook.portaljs.org/) that contains all the details on how to use them. Below is an overview of available components.
You can install the library with:
```sh
npm i @portaljs/components
```
## Table
An easy-to-use table component with built-in pagination, search, and sorting.
![](https://hackmd.io/_uploads/HyrtR_mS2.png)
### Use with raw data
```js
<Table
cols={[
{
key: 'id',
name: 'ID'
},
{
key: 'firstName',
name: 'First name'
},
{
key: 'lastName',
name: 'Last name'
},
{
key: 'age',
name: 'Age'
}
]}
data={[
{
age: 35,
firstName: 'Jon',
id: 1,
lastName: 'Snow'
},
{
age: 42,
firstName: 'Cersei',
id: 2,
lastName: 'Lannister'
}
]}
/>
```
- It can be used by passing a raw csv string
![](https://hackmd.io/_uploads/SJglXtQrh.png)
```js
<Table
csv="
Year,Temp Anomaly
1850,-0.418
2020,0.923
"
/>
```
- It can be used by passing a URL string
![](https://hackmd.io/_uploads/S19GXYXBn.png)
```js
<Table url="https://raw.githubusercontent.com/datasets/finance-vix/main/data/vix-daily.csv" />
```
- More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-table--docs)
## Charts
### Linecharts
- You can add simple line charts with the `<LineChart>` component
- Here is an example passing in a array of data
![](https://hackmd.io/_uploads/S1TBXYXH3.png)
```js
<LineChart
data={[
[
'1850',
-0.41765878
],
[
'1851',
-0.2333498
],
[
'1852',
-0.22939907
],
[
'1853',
-0.27035445
],
[
'1854',
-0.29163003
]
]}
/>
```
- And here passing an url
![](https://hackmd.io/_uploads/SkHd7KXS3.png)
```js
<LineChart
data="https://raw.githubusercontent.com/datasets/oil-prices/main/data/wti-year.csv"
title="Oil Price x Year"
xAxis="Date"
yAxis="Price"
/>
```
- More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-linechart--docs)
### Vega Charts
You can add Vega charts with the `<Vega />` component like this, it supports all the Vega specification:
![](https://hackmd.io/_uploads/ryN5mYmSh.png)
```js
<Vega
data={{
table: [
{
x: 1850,
y: -0.418
},
{
x: 2020,
y: 0.923
}
]
}}
spec={{
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
data: {
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative'
}
},
mark: 'bar'
}}
/>
```
- More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-vega--docs)
## VegaLite chart
A wrapper around the [Vega Lite specification](https://vega.github.io/vega-lite/) which allows for a more concise grammar than Vega around the building of charts.
![](https://hackmd.io/_uploads/rJ2nQt7B3.png)
```js
<VegaLite
data={{
table: [
{
x: 1850,
y: -0.418
},
{
x: 2020,
y: 0.923
}
]
}}
spec={{
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
data: {
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative'
}
},
mark: 'bar'
}}
/>
```
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-vegalite--docs)
## Catalog
A searchable catalog that will index a list of datasets and allow for contextual searching + filters.
![](https://hackmd.io/_uploads/rJv-d3Xr3.png)
- The dataset object requires the following structure(the metadata field can have any structure that you may want)
```js
<Catalog
datasets={[
{
_id: '07026b22d49916754df1dc8ffb9ccd1c31878aae',
metadata: {
'details-of-task': 'Detect and categorise abusive language in social media data',
language: 'Albanian',
'level-of-annotation': [
'Posts'
],
'link-to-data': 'https://doi.org/10.6084/m9.figshare.19333298.v1',
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
medium: [
'Text'
],
'percentage-abusive': 13.2,
platform: [
'Instagram',
'Youtube'
],
reference: 'Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592',
'size-of-dataset': 11874,
'task-description': 'Hierarchical (offensive/not; untargeted/targeted; person/group/other)',
title: 'Detecting Abusive Albanian'
},
url_path: 'dataset-4'
},
]}
/>
```
- You can also add facets that are going to act as filters for your metadata
![](https://hackmd.io/_uploads/HygOF3XH2.png)
```js
<Catalog
datasets={[
{
_id: '07026b22d49916754df1dc8ffb9ccd1c31878aae',
metadata: {
'details-of-task': 'Detect and categorise abusive language in social media data',
language: 'Albanian',
'level-of-annotation': [
'Posts'
],
'link-to-data': 'https://doi.org/10.6084/m9.figshare.19333298.v1',
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
medium: [
'Text'
],
'percentage-abusive': 13.2,
platform: [
'Instagram',
'Youtube'
],
reference: 'Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592',
'size-of-dataset': 11874,
'task-description': 'Hierarchical (offensive/not; untargeted/targeted; person/group/other)',
title: 'Detecting Abusive Albanian'
},
url_path: 'dataset-4'
},
]}
facets={['platform', 'language']}
/>
```
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-catalog--docs)

View File

@@ -63,7 +63,7 @@ export const getStaticProps: GetStaticProps = async ({
}
// Temporary, docs pages should present the LHS sidebar
if (dbFile.url_path.startsWith('docs')) {
if (dbFile.url_path.startsWith('docs') || dbFile.url_path.startsWith('howto')) {
frontMatter.showSidebar = true;
frontMatter.sidebarTreeFile = 'content/assets/sidebar.json';
}