From 8cb3cd4ddbd6aea072fa2ed7f932bfa9ad2aba2c Mon Sep 17 00:00:00 2001
From: deme
Date: Wed, 17 May 2023 18:43:19 -0300
Subject: [PATCH] [examples/openspending,home][xl]: removes datasets table,
implement dataset cards grid, implement country facet
---
examples/openspending/components/Button.tsx | 12 +-
.../openspending/components/DatasetCard.tsx | 80 ++++++++++
.../openspending/components/DatasetsGrid.tsx | 19 +++
.../components/DatasetsSearch.tsx | 107 +++++++++++++
examples/openspending/components/Header.tsx | 1 -
examples/openspending/components/Hero.tsx | 4 +-
examples/openspending/lib/loader.ts | 21 +--
.../openspending/lib/project.interface.ts | 11 +-
examples/openspending/pages/index.tsx | 151 ++++--------------
.../openspending/public/assets/org-icon.svg | 11 ++
10 files changed, 277 insertions(+), 140 deletions(-)
create mode 100644 examples/openspending/components/DatasetCard.tsx
create mode 100644 examples/openspending/components/DatasetsGrid.tsx
create mode 100644 examples/openspending/components/DatasetsSearch.tsx
create mode 100644 examples/openspending/public/assets/org-icon.svg
diff --git a/examples/openspending/components/Button.tsx b/examples/openspending/components/Button.tsx
index 966b39a3..f74fbe5c 100644
--- a/examples/openspending/components/Button.tsx
+++ b/examples/openspending/components/Button.tsx
@@ -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 ? (
-
+
) : (
- )
+ );
}
diff --git a/examples/openspending/components/DatasetCard.tsx b/examples/openspending/components/DatasetCard.tsx
new file mode 100644
index 00000000..c89491b4
--- /dev/null
+++ b/examples/openspending/components/DatasetCard.tsx
@@ -0,0 +1,80 @@
+import Link from 'next/link';
+import { Project } from '../lib/project.interface';
+import ExternalLinkIcon from './icons/ExternalLinkIcon';
+
+export default function DatasetCard({ dataset }: { dataset: Project }) {
+ return (
+
+
+
+
+
{dataset.title}
+
+ {dataset.owner.title}
+
+
+
+
+
+
Name
+
+
+ {dataset.name}
+
+
+
+
+
Country
+
+
+ {dataset.countryCode}
+
+
+
+
+
Fiscal Period
+
+ {dataset.fiscalPeriod?.start && (
+
+ {dataset.fiscalPeriod.start}
+
+ )}
+ {dataset.fiscalPeriod?.start && (
+ <>
+ {' - '}
+
+ {dataset.fiscalPeriod.start}
+
+ >
+ )}
+
+
+
+
Metadata
+
+
+
+ datapackage.json
+
+
+
+
+
+
+ );
+}
diff --git a/examples/openspending/components/DatasetsGrid.tsx b/examples/openspending/components/DatasetsGrid.tsx
new file mode 100644
index 00000000..f9d40536
--- /dev/null
+++ b/examples/openspending/components/DatasetsGrid.tsx
@@ -0,0 +1,19 @@
+import { Project } from '../lib/project.interface';
+import DatasetCard from './DatasetCard';
+
+export default function DatasetsGrid({ datasets }: { datasets: Project[] }) {
+ return (
+
+ {datasets.map((dataset, idx) => {
+ return (
+
+
+
+ );
+ })}
+
+ );
+}
diff --git a/examples/openspending/components/DatasetsSearch.tsx b/examples/openspending/components/DatasetsSearch.tsx
new file mode 100644
index 00000000..aee84f1d
--- /dev/null
+++ b/examples/openspending/components/DatasetsSearch.tsx
@@ -0,0 +1,107 @@
+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: '',
+ fiscalPeriodStart: '',
+ fiscalPeriodEnd: '',
+ },
+ });
+
+ 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 (
+ <>
+
+
+
+ {watch().searchTerm !== '' && (
+ resetField('searchTerm')}
+ className="absolute right-3 top-1/2 -translate-y-1/2 text-gray-500"
+ >
+
+
+ )}
+
+
+ {/* TODO: nicer select e.g. headlessui example */}
+
+ All
+ {allCountries.map((country) => {
+ return (
+
+ {country.title}
+
+ );
+ })}
+
+
+
+
+
+ watch().searchTerm && watch().searchTerm !== ''
+ ? index.search(watch().searchTerm).includes(dataset.name)
+ : true
+ )
+ .filter((dataset) =>
+ watch().country && watch().country !== ''
+ ? dataset.countryCode === watch().country
+ : true
+ )}
+ />
+
+ >
+ );
+}
+
+const CloseIcon = () => {
+ return (
+
+
+
+ );
+};
diff --git a/examples/openspending/components/Header.tsx b/examples/openspending/components/Header.tsx
index 12d16fea..c9fb47a0 100644
--- a/examples/openspending/components/Header.tsx
+++ b/examples/openspending/components/Header.tsx
@@ -46,7 +46,6 @@ export function Header() {
))}
- View on GitHub
diff --git a/examples/openspending/components/Hero.tsx b/examples/openspending/components/Hero.tsx
index 8baf0450..b09b321c 100644
--- a/examples/openspending/components/Hero.tsx
+++ b/examples/openspending/components/Hero.tsx
@@ -23,8 +23,8 @@ export function Hero() {
fiscal data in the public sphere.
-
- View on GitHub
+
+ Search datasets
{[
diff --git a/examples/openspending/lib/loader.ts b/examples/openspending/lib/loader.ts
index e690c144..2d5243b2 100644
--- a/examples/openspending/lib/loader.ts
+++ b/examples/openspending/lib/loader.ts
@@ -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,
};
}
diff --git a/examples/openspending/lib/project.interface.ts b/examples/openspending/lib/project.interface.ts
index 7da52ae1..05c894cf 100644
--- a/examples/openspending/lib/project.interface.ts
+++ b/examples/openspending/lib/project.interface.ts
@@ -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;
}
diff --git a/examples/openspending/pages/index.tsx b/examples/openspending/pages/index.tsx
index 0e0b771c..bb163944 100644
--- a/examples/openspending/pages/index.tsx
+++ b/examples/openspending/pages/index.tsx
@@ -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 (
@@ -65,101 +73,8 @@ export function Datasets({ projects }) {
Find spending data about countries all around the world.
-
-
-
-
-
-
-
-
-
-
- Name
-
-
- Repository
-
-
- Author
-
-
- Fiscal Year
-
-
-
-
-
- {projects
- .filter((project: Project) =>
- watch().searchTerm && watch().searchTerm !== ''
- ? index
- .search(watch().searchTerm)
- .includes(project.name)
- : true
- )
- .map((project: Project) => (
-
-
- {project.name}
-
-
-
- @{project.owner.name}/{project.repo.name}{' '}
-
-
-
-
- {project.author}
-
- {project.fiscalPeriod ? (
-
- {project.fiscalPeriod.start} -{' '}
- {project.fiscalPeriod.end}
-
- ) : (
-
- No data
-
- )}
-
-
- info
-
-
-
- ))}
-
-
-
-
+
+
diff --git a/examples/openspending/public/assets/org-icon.svg b/examples/openspending/public/assets/org-icon.svg
new file mode 100644
index 00000000..bb7d9158
--- /dev/null
+++ b/examples/openspending/public/assets/org-icon.svg
@@ -0,0 +1,11 @@
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file