Compare commits
3 Commits
facets-2
...
part-3-tut
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2bb567e88d | ||
|
|
77da0d5693 | ||
|
|
b52aa38249 |
@@ -1,119 +1,40 @@
|
|||||||
import { Index } from 'flexsearch';
|
import { Index } from 'flexsearch';
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import DebouncedInput from './DebouncedInput';
|
import DebouncedInput from './DebouncedInput';
|
||||||
import { useForm } from 'react-hook-form';
|
|
||||||
|
|
||||||
export default function Catalog({
|
export default function Catalog({ datasets }: { datasets: any[] }) {
|
||||||
datasets,
|
|
||||||
facets,
|
|
||||||
}: {
|
|
||||||
datasets: any[];
|
|
||||||
facets: string[];
|
|
||||||
}) {
|
|
||||||
const [indexFilter, setIndexFilter] = useState('');
|
const [indexFilter, setIndexFilter] = useState('');
|
||||||
const index = new Index({ tokenize: 'full' });
|
const index = new Index({ tokenize: "full"});
|
||||||
datasets.forEach((dataset) =>
|
datasets.forEach((dataset) =>
|
||||||
index.add(
|
index.add(
|
||||||
dataset._id,
|
dataset._id,
|
||||||
//This will join every metadata value + the url_path into one big string and index that
|
|
||||||
Object.entries(dataset.metadata).reduce(
|
Object.entries(dataset.metadata).reduce(
|
||||||
(acc, curr) => acc + ' ' + curr[1].toString(),
|
(acc, curr) => acc + ' ' + curr.toString(),
|
||||||
''
|
''
|
||||||
) +
|
) + ' ' + dataset.url_path
|
||||||
' ' +
|
|
||||||
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 (
|
return (
|
||||||
<>
|
<>
|
||||||
<DebouncedInput
|
<DebouncedInput
|
||||||
value={indexFilter ?? ''}
|
value={indexFilter ?? ''}
|
||||||
onChange={(value) => setIndexFilter(String(value))}
|
onChange={(value) => setIndexFilter(String(value))}
|
||||||
className="p-2 text-sm shadow border border-block mr-1"
|
className="p-2 text-sm shadow border border-block"
|
||||||
placeholder="Search all datasets..."
|
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>
|
<ul>
|
||||||
{filteredDatasets.map((dataset) => (
|
{datasets
|
||||||
<li key={dataset._id}>
|
.filter((dataset) =>
|
||||||
<a href={dataset.url_path}>
|
indexFilter !== ''
|
||||||
{dataset.metadata.title
|
? index.search(indexFilter).includes(dataset._id)
|
||||||
? dataset.metadata.title
|
: true
|
||||||
: dataset.url_path}
|
)
|
||||||
</a>
|
.map((dataset) => (
|
||||||
|
<li key={dataset.id}>
|
||||||
|
<a href={dataset.url_path}>{dataset.metadata.title ? dataset.metadata.title : dataset.url_path}</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
</>
|
</>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -7,12 +7,14 @@ import { Mermaid } from '@flowershow/core';
|
|||||||
// to handle import statements. Instead, you must include components in scope
|
// to handle import statements. Instead, you must include components in scope
|
||||||
// here.
|
// here.
|
||||||
const components = {
|
const components = {
|
||||||
Table: dynamic(() => import('@portaljs/components').then(mod => mod.Table)),
|
Table: dynamic(() => import('./Table')),
|
||||||
Catalog: dynamic(() => import('./Catalog')),
|
Catalog: dynamic(() => import('./Catalog')),
|
||||||
mermaid: Mermaid,
|
mermaid: Mermaid,
|
||||||
Vega: dynamic(() => import('@portaljs/components').then(mod => mod.Vega)),
|
// Excel: dynamic(() => import('../components/Excel')),
|
||||||
VegaLite: dynamic(() => import('@portaljs/components').then(mod => mod.VegaLite)),
|
// TODO: try and make these dynamic ...
|
||||||
LineChart: dynamic(() => import('@portaljs/components').then(mod => mod.LineChart)),
|
Vega: dynamic(() => import('./Vega')),
|
||||||
|
VegaLite: dynamic(() => import('./VegaLite')),
|
||||||
|
LineChart: dynamic(() => import('./LineChart')),
|
||||||
} as any;
|
} as any;
|
||||||
|
|
||||||
export default function DRD({ source }: { source: any }) {
|
export default function DRD({ source }: { source: any }) {
|
||||||
55
examples/learn-example/components/LineChart.tsx
Normal file
55
examples/learn-example/components/LineChart.tsx
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import VegaLite from "./VegaLite";
|
||||||
|
|
||||||
|
export default function LineChart({
|
||||||
|
data = [],
|
||||||
|
fullWidth = false,
|
||||||
|
title = "",
|
||||||
|
xAxis = "x",
|
||||||
|
yAxis = "y",
|
||||||
|
}) {
|
||||||
|
var tmp = data;
|
||||||
|
if (Array.isArray(data)) {
|
||||||
|
tmp = data.map((r, i) => {
|
||||||
|
return { x: r[0], y: r[1] };
|
||||||
|
});
|
||||||
|
}
|
||||||
|
const vegaData = { table: tmp };
|
||||||
|
const spec = {
|
||||||
|
$schema: "https://vega.github.io/schema/vega-lite/v5.json",
|
||||||
|
title,
|
||||||
|
width: "container",
|
||||||
|
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} />;
|
||||||
|
}
|
||||||
189
examples/learn-example/components/Table.tsx
Normal file
189
examples/learn-example/components/Table.tsx
Normal file
@@ -0,0 +1,189 @@
|
|||||||
|
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";
|
||||||
|
|
||||||
|
const Table = ({
|
||||||
|
data: ogData = [],
|
||||||
|
cols: ogCols = [],
|
||||||
|
csv = "",
|
||||||
|
url = "",
|
||||||
|
fullWidth = false,
|
||||||
|
}) => {
|
||||||
|
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(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) => setGlobalFilter(String(value))}
|
||||||
|
className="p-2 text-sm shadow border border-block"
|
||||||
|
placeholder="Search all columns..."
|
||||||
|
/>
|
||||||
|
<table>
|
||||||
|
<thead>
|
||||||
|
{table.getHeaderGroups().map((hg) => (
|
||||||
|
<tr key={hg.id}>
|
||||||
|
{hg.headers.map((h) => (
|
||||||
|
<th key={h.id}>
|
||||||
|
<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}>
|
||||||
|
{r.getVisibleCells().map((c) => (
|
||||||
|
<td key={c.id}>
|
||||||
|
{flexRender(c.column.columnDef.cell, c.getContext())}
|
||||||
|
</td>
|
||||||
|
))}
|
||||||
|
</tr>
|
||||||
|
))}
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
<div className="flex gap-2 items-center justify-center">
|
||||||
|
<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);
|
||||||
|
};
|
||||||
|
|
||||||
|
export default Table;
|
||||||
6
examples/learn-example/components/Vega.tsx
Normal file
6
examples/learn-example/components/Vega.tsx
Normal file
@@ -0,0 +1,6 @@
|
|||||||
|
// Wrapper for the Vega component
|
||||||
|
import { Vega as VegaOg } from "react-vega";
|
||||||
|
|
||||||
|
export default function Vega(props) {
|
||||||
|
return <VegaOg {...props} />;
|
||||||
|
}
|
||||||
9
examples/learn-example/components/VegaLite.tsx
Normal file
9
examples/learn-example/components/VegaLite.tsx
Normal file
@@ -0,0 +1,9 @@
|
|||||||
|
// Wrapper for the Vega Lite component
|
||||||
|
import { VegaLite as VegaLiteOg } from "react-vega";
|
||||||
|
import applyFullWidthDirective from "../lib/applyFullWidthDirective";
|
||||||
|
|
||||||
|
export default function VegaLite(props) {
|
||||||
|
const Component = applyFullWidthDirective({ Component: VegaLiteOg });
|
||||||
|
|
||||||
|
return <Component {...props} />;
|
||||||
|
}
|
||||||
21
examples/learn-example/lib/applyFullWidthDirective.tsx
Normal file
21
examples/learn-example/lib/applyFullWidthDirective.tsx
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
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} />;
|
||||||
|
};
|
||||||
|
}
|
||||||
5
examples/learn-example/lib/loadData.tsx
Normal file
5
examples/learn-example/lib/loadData.tsx
Normal file
@@ -0,0 +1,5 @@
|
|||||||
|
export default async function loadData(url: string) {
|
||||||
|
const response = await fetch(url)
|
||||||
|
const data = await response.text()
|
||||||
|
return data
|
||||||
|
}
|
||||||
@@ -91,7 +91,7 @@ const parse = async function (source, format, scope) {
|
|||||||
],
|
],
|
||||||
format,
|
format,
|
||||||
},
|
},
|
||||||
scope,
|
scope: { ...scope, ...data},
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
16
examples/learn-example/lib/parseCsv.ts
Normal file
16
examples/learn-example/lib/parseCsv.ts
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
import papa from "papaparse";
|
||||||
|
|
||||||
|
const parseCsv = (csv) => {
|
||||||
|
csv = csv.trim();
|
||||||
|
const rawdata = papa.parse(csv, { header: true });
|
||||||
|
const cols = rawdata.meta.fields.map((r, i) => {
|
||||||
|
return { key: r, name: r };
|
||||||
|
});
|
||||||
|
|
||||||
|
return {
|
||||||
|
rows: rawdata.data,
|
||||||
|
fields: cols,
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
export default parseCsv;
|
||||||
39
examples/learn-example/package-lock.json
generated
39
examples/learn-example/package-lock.json
generated
@@ -15,14 +15,14 @@
|
|||||||
"@flowershow/remark-wiki-link": "^1.1.2",
|
"@flowershow/remark-wiki-link": "^1.1.2",
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
"@opentelemetry/api": "^1.4.0",
|
"@opentelemetry/api": "^1.4.0",
|
||||||
"@portaljs/components": "^0.0.3",
|
|
||||||
"@tanstack/react-table": "^8.8.5",
|
"@tanstack/react-table": "^8.8.5",
|
||||||
|
"@types/flexsearch": "^0.7.3",
|
||||||
"@types/node": "18.16.0",
|
"@types/node": "18.16.0",
|
||||||
"@types/react": "18.2.0",
|
"@types/react": "18.2.0",
|
||||||
"@types/react-dom": "18.2.0",
|
"@types/react-dom": "18.2.0",
|
||||||
"eslint": "8.39.0",
|
"eslint": "8.39.0",
|
||||||
"eslint-config-next": "13.3.1",
|
"eslint-config-next": "13.3.1",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "^0.7.31",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"hastscript": "^7.2.0",
|
"hastscript": "^7.2.0",
|
||||||
"mdx-mermaid": "2.0.0-rc7",
|
"mdx-mermaid": "2.0.0-rc7",
|
||||||
@@ -31,7 +31,6 @@
|
|||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hook-form": "^7.43.9",
|
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"rehype-autolink-headings": "^6.1.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-katex": "^6.0.3",
|
"rehype-katex": "^6.0.3",
|
||||||
@@ -45,7 +44,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@types/flexsearch": "^0.7.3",
|
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"tailwindcss": "^3.3.1"
|
"tailwindcss": "^3.3.1"
|
||||||
@@ -1978,15 +1976,6 @@
|
|||||||
"url": "https://opencollective.com/unts"
|
"url": "https://opencollective.com/unts"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@portaljs/components": {
|
|
||||||
"version": "0.0.3",
|
|
||||||
"resolved": "https://registry.npmjs.org/@portaljs/components/-/components-0.0.3.tgz",
|
|
||||||
"integrity": "sha512-SRinOO800oA58akBlni5ahs3PxE+AyqFqgtYN/3ZqYt3CT1JhXOfeXxb+Kbz2QHr/GsAZcUr3DMneB4EzvBx7g==",
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^18.2.0",
|
|
||||||
"react-dom": "^18.2.0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/@protobufjs/aspromise": {
|
"node_modules/@protobufjs/aspromise": {
|
||||||
"version": "1.1.2",
|
"version": "1.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/@protobufjs/aspromise/-/aspromise-1.1.2.tgz",
|
||||||
@@ -2229,8 +2218,7 @@
|
|||||||
"node_modules/@types/flexsearch": {
|
"node_modules/@types/flexsearch": {
|
||||||
"version": "0.7.3",
|
"version": "0.7.3",
|
||||||
"resolved": "https://registry.npmjs.org/@types/flexsearch/-/flexsearch-0.7.3.tgz",
|
"resolved": "https://registry.npmjs.org/@types/flexsearch/-/flexsearch-0.7.3.tgz",
|
||||||
"integrity": "sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg==",
|
"integrity": "sha512-HXwADeHEP4exXkCIwy2n1+i0f1ilP1ETQOH5KDOugjkTFZPntWo0Gr8stZOaebkxsdx+k0X/K6obU/+it07ocg=="
|
||||||
"dev": true
|
|
||||||
},
|
},
|
||||||
"node_modules/@types/geojson": {
|
"node_modules/@types/geojson": {
|
||||||
"version": "7946.0.10",
|
"version": "7946.0.10",
|
||||||
@@ -4971,9 +4959,9 @@
|
|||||||
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
|
"integrity": "sha512-5nqDSxl8nn5BSNxyR3n4I6eDmbolI6WT+QqR547RwxQapgjQBmtktdP+HTBb/a/zLsbzERTONyUB5pefh5TtjQ=="
|
||||||
},
|
},
|
||||||
"node_modules/flexsearch": {
|
"node_modules/flexsearch": {
|
||||||
"version": "0.7.21",
|
"version": "0.7.31",
|
||||||
"resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.21.tgz",
|
"resolved": "https://registry.npmjs.org/flexsearch/-/flexsearch-0.7.31.tgz",
|
||||||
"integrity": "sha512-W7cHV7Hrwjid6lWmy0IhsWDFQboWSng25U3VVywpHOTJnnAZNPScog67G+cVpeX9f7yDD21ih0WDrMMT+JoaYg=="
|
"integrity": "sha512-XGozTsMPYkm+6b5QL3Z9wQcJjNYxp0CYn3U1gO7dwD6PAqU1SVWZxI9CCg3z+ml3YfqdPnrBehaBrnH2AGKbNA=="
|
||||||
},
|
},
|
||||||
"node_modules/for-each": {
|
"node_modules/for-each": {
|
||||||
"version": "0.3.3",
|
"version": "0.3.3",
|
||||||
@@ -9302,21 +9290,6 @@
|
|||||||
"react": "^18.2.0"
|
"react": "^18.2.0"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/react-hook-form": {
|
|
||||||
"version": "7.43.9",
|
|
||||||
"resolved": "https://registry.npmjs.org/react-hook-form/-/react-hook-form-7.43.9.tgz",
|
|
||||||
"integrity": "sha512-AUDN3Pz2NSeoxQ7Hs6OhQhDr6gtF9YRuutGDwPQqhSUAHJSgGl2VeY3qN19MG0SucpjgDiuMJ4iC5T5uB+eaNQ==",
|
|
||||||
"engines": {
|
|
||||||
"node": ">=12.22.0"
|
|
||||||
},
|
|
||||||
"funding": {
|
|
||||||
"type": "opencollective",
|
|
||||||
"url": "https://opencollective.com/react-hook-form"
|
|
||||||
},
|
|
||||||
"peerDependencies": {
|
|
||||||
"react": "^16.8.0 || ^17 || ^18"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"node_modules/react-is": {
|
"node_modules/react-is": {
|
||||||
"version": "16.13.1",
|
"version": "16.13.1",
|
||||||
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
|
||||||
|
|||||||
@@ -19,14 +19,14 @@
|
|||||||
"@flowershow/remark-wiki-link": "^1.1.2",
|
"@flowershow/remark-wiki-link": "^1.1.2",
|
||||||
"@heroicons/react": "^2.0.17",
|
"@heroicons/react": "^2.0.17",
|
||||||
"@opentelemetry/api": "^1.4.0",
|
"@opentelemetry/api": "^1.4.0",
|
||||||
"@portaljs/components": "^0.0.3",
|
|
||||||
"@tanstack/react-table": "^8.8.5",
|
"@tanstack/react-table": "^8.8.5",
|
||||||
|
"@types/flexsearch": "^0.7.3",
|
||||||
"@types/node": "18.16.0",
|
"@types/node": "18.16.0",
|
||||||
"@types/react": "18.2.0",
|
"@types/react": "18.2.0",
|
||||||
"@types/react-dom": "18.2.0",
|
"@types/react-dom": "18.2.0",
|
||||||
"eslint": "8.39.0",
|
"eslint": "8.39.0",
|
||||||
"eslint-config-next": "13.3.1",
|
"eslint-config-next": "13.3.1",
|
||||||
"flexsearch": "0.7.21",
|
"flexsearch": "^0.7.31",
|
||||||
"gray-matter": "^4.0.3",
|
"gray-matter": "^4.0.3",
|
||||||
"hastscript": "^7.2.0",
|
"hastscript": "^7.2.0",
|
||||||
"mdx-mermaid": "2.0.0-rc7",
|
"mdx-mermaid": "2.0.0-rc7",
|
||||||
@@ -35,7 +35,6 @@
|
|||||||
"papaparse": "^5.4.1",
|
"papaparse": "^5.4.1",
|
||||||
"react": "18.2.0",
|
"react": "18.2.0",
|
||||||
"react-dom": "18.2.0",
|
"react-dom": "18.2.0",
|
||||||
"react-hook-form": "^7.43.9",
|
|
||||||
"react-vega": "^7.6.0",
|
"react-vega": "^7.6.0",
|
||||||
"rehype-autolink-headings": "^6.1.1",
|
"rehype-autolink-headings": "^6.1.1",
|
||||||
"rehype-katex": "^6.0.3",
|
"rehype-katex": "^6.0.3",
|
||||||
@@ -49,7 +48,6 @@
|
|||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@tailwindcss/typography": "^0.5.9",
|
"@tailwindcss/typography": "^0.5.9",
|
||||||
"@types/flexsearch": "^0.7.3",
|
|
||||||
"autoprefixer": "^10.4.14",
|
"autoprefixer": "^10.4.14",
|
||||||
"postcss": "^8.4.23",
|
"postcss": "^8.4.23",
|
||||||
"tailwindcss": "^3.3.1"
|
"tailwindcss": "^3.3.1"
|
||||||
|
|||||||
@@ -1,8 +1,7 @@
|
|||||||
import { existsSync, promises as fs } from 'fs';
|
import { existsSync, promises as fs } from 'fs';
|
||||||
import path from 'path';
|
import path from 'path';
|
||||||
import parse from '../lib/markdown';
|
import parse from '../lib/markdown';
|
||||||
|
import DRD from '../components/DRD';
|
||||||
import DataRichDocument from '../components/DataRichDocument';
|
|
||||||
import clientPromise from '../lib/mddb';
|
import clientPromise from '../lib/mddb';
|
||||||
|
|
||||||
export const getStaticPaths = async () => {
|
export const getStaticPaths = async () => {
|
||||||
@@ -74,7 +73,7 @@ export default function DatasetPage({ mdxSource, frontMatter }) {
|
|||||||
</div>
|
</div>
|
||||||
</header>
|
</header>
|
||||||
<main>
|
<main>
|
||||||
<DataRichDocument source={mdxSource} />
|
<DRD source={mdxSource} />
|
||||||
</main>
|
</main>
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import '../styles/globals.css'
|
import '../styles/globals.css'
|
||||||
import '@portaljs/components/styles.css'
|
|
||||||
|
|
||||||
import type { AppProps } from 'next/app'
|
import type { AppProps } from 'next/app'
|
||||||
|
|
||||||
export default function App({ Component, pageProps }: AppProps) {
|
export default function App({ Component, pageProps }: AppProps) {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"compilerOptions": {
|
"compilerOptions": {
|
||||||
"target": "es6",
|
"target": "es5",
|
||||||
"lib": ["dom", "dom.iterable", "esnext"],
|
"lib": ["dom", "dom.iterable", "esnext"],
|
||||||
"allowJs": true,
|
"allowJs": true,
|
||||||
"skipLibCheck": true,
|
"skipLibCheck": true,
|
||||||
|
|||||||
@@ -1,29 +1,32 @@
|
|||||||
# PortalJS React Components
|
# `components` package
|
||||||
|
|
||||||
**Storybook:** https://storybook.portaljs.org
|
**See live:** https://storybook.portaljs.org
|
||||||
**Docs**: https://portaljs.org/docs
|
|
||||||
|
|
||||||
## Usage
|
|
||||||
|
|
||||||
To install this package on your project:
|
|
||||||
|
|
||||||
```bash
|
|
||||||
npm i @portaljs/components
|
|
||||||
```
|
|
||||||
|
|
||||||
> Note: React 18 is required.
|
|
||||||
|
|
||||||
You'll also have to import the styles CSS file in your project:
|
|
||||||
|
|
||||||
```ts
|
|
||||||
// E.g.: Next.js => pages/_app.tsx
|
|
||||||
import '@portaljs/components/styles.css'
|
|
||||||
```
|
|
||||||
|
|
||||||
## Dev
|
## Dev
|
||||||
|
|
||||||
Use Storybook to work on components by running:
|
Use Storybook to work on components by running:
|
||||||
|
|
||||||
```bash
|
```bash
|
||||||
npm run storybook
|
yarn storybook
|
||||||
|
```
|
||||||
|
|
||||||
|
## Build
|
||||||
|
|
||||||
|
To build this project, run:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
yarn build
|
||||||
|
```
|
||||||
|
|
||||||
|
## Install
|
||||||
|
|
||||||
|
TODO: command to install the package
|
||||||
|
|
||||||
|
### Next.js
|
||||||
|
|
||||||
|
Add this line at the start of `_app.tsx`:
|
||||||
|
|
||||||
|
```ts
|
||||||
|
// pages/_app.tsx
|
||||||
|
import "dist/styles.css";
|
||||||
```
|
```
|
||||||
24752
packages/components/package-lock.json
generated
24752
packages/components/package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -1,18 +1,11 @@
|
|||||||
{
|
{
|
||||||
"name": "@portaljs/components",
|
"name": "components",
|
||||||
"version": "0.0.3",
|
"private": true,
|
||||||
|
"version": "0.0.1",
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"description": "https://portaljs.org",
|
|
||||||
"keywords": [
|
|
||||||
"data portal",
|
|
||||||
"data catalog",
|
|
||||||
"table",
|
|
||||||
"charts",
|
|
||||||
"visualization"
|
|
||||||
],
|
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"dev": "npm run storybook",
|
"dev": "yarn storybook",
|
||||||
"build": "tsc && vite build && npm run build-tailwind",
|
"build": "tsc && vite build && yarn build-tailwind",
|
||||||
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
|
||||||
"prepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"",
|
"prepack": "json -f package.json -I -e \"delete this.devDependencies; delete this.dependencies\"",
|
||||||
"storybook": "storybook dev -p 6006",
|
"storybook": "storybook dev -p 6006",
|
||||||
@@ -72,12 +65,6 @@
|
|||||||
".": {
|
".": {
|
||||||
"import": "./dist/components.es.js",
|
"import": "./dist/components.es.js",
|
||||||
"require": "./dist/components.umd.js"
|
"require": "./dist/components.umd.js"
|
||||||
},
|
}
|
||||||
"./styles.css": {
|
|
||||||
"import": "./dist/styles.css"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"publishConfig": {
|
|
||||||
"access": "public"
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
8947
packages/components/yarn.lock
Normal file
8947
packages/components/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user