[site][lg] - integrate demenech changes into monorepo

This commit is contained in:
Luccas Mateus de Medeiros Gomes
2023-04-11 08:19:58 -03:00
parent fda6c4b827
commit 97c1dc0d59
32 changed files with 8815 additions and 319 deletions

View File

@@ -1,9 +1,9 @@
import Link from 'next/link'
import Link from "next/link";
export default function CustomLink({ as, href, ...otherProps }) {
return (
<>
<Link as={as} href={href}>
<Link legacyBehavior as={as} href={href}>
<a {...otherProps} />
</Link>
<style jsx>{`
@@ -12,5 +12,5 @@ export default function CustomLink({ as, href, ...otherProps }) {
}
`}</style>
</>
)
);
}

View File

@@ -0,0 +1,34 @@
import { NextSeo } from "next-seo";
import Nav from "./Nav";
export default function Layout({
children,
title,
}: {
children;
title?: string;
}) {
return (
<>
{title && <NextSeo title={title} />}
<Nav />
<div className="mx-auto p-6">{children}</div>
<footer className="flex items-center justify-center w-full h-24 border-t">
<a
className="flex items-center justify-center"
href="https://datopian.com/"
target="_blank"
rel="noopener noreferrer"
>
Built by{" "}
<img
src="/datopian-logo.png"
alt="Datopian Logo"
className="h-6 ml-2"
/>
</a>
</footer>
</>
);
}

View File

@@ -0,0 +1,40 @@
import { MDXRemote } from "next-mdx-remote";
import layouts from "layouts";
export default function DRD({ source, frontMatter }) {
const Layout = ({ children }) => {
if (frontMatter.layout) {
let LayoutComponent = layouts[frontMatter.layout];
return <LayoutComponent {...frontMatter}>{children}</LayoutComponent>;
}
return <>{children}</>;
};
return (
<div className="prose mx-auto">
<header>
<div className="mb-6">
{/* Default layout */}
{!frontMatter.layout && (
<>
<h1>{frontMatter.title}</h1>
{frontMatter.author && (
<div className="-mt-6">
<p className="opacity-60 pl-1">{frontMatter.author}</p>
</div>
)}
{frontMatter.description && (
<p className="description">{frontMatter.description}</p>
)}
</>
)}
</div>
</header>
<main>
<Layout>
<MDXRemote {...source} />
</Layout>
</main>
</div>
);
}

View File

@@ -1,22 +1,15 @@
import { Disclosure, Menu, Transition } from '@headlessui/react'
import { Fragment } from "react";
import { Disclosure, Menu, Transition } from "@headlessui/react";
import { siteConfig } from "config/siteConfig";
import { Bars3Icon, XMarkIcon } from '@heroicons/react/24/outline'
import Link from 'next/link'
import GitHubButton from 'react-next-github-btn'
import Link from "next/link";
import GitHubButton from "react-next-github-btn";
const navigation = [
{ name: 'Docs', href: '/docs' },
{ name: 'Components', href: '/docs/components' },
{ name: 'Learn', href: '/learn' },
{ name: 'Gallery', href: '/gallery' },
{ name: 'Data Literate', href: '/data-literate/', current: false },
{ name: 'DL Demo', href: '/data-literate/demo/', current: false },
{ name: 'Excel Viewer', href: '/excel-viewer/', current: false },
{ name: 'Github', href: 'https://github.com/datopian/portal.js', current: false },
]
const navigation = siteConfig.navLinks;
function classNames(...classes) {
return classes.filter(Boolean).join(' ')
return classes.filter(Boolean).join(" ");
}
export default function Nav() {
@@ -31,29 +24,31 @@ export default function Nav() {
<Disclosure.Button className="inline-flex items-center justify-center p-2 rounded-md text-gray-400 hover:text-white hover:bg-gray-700 focus:outline-none focus:ring-2 focus:ring-inset focus:ring-white">
<span className="sr-only">Open main menu</span>
{open ? (
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
) : (
<Bars3Icon className="block h-6 w-6" aria-hidden="true" />
) : (
<XMarkIcon className="block h-6 w-6" aria-hidden="true" />
)}
</Disclosure.Button>
</div>
<div className="flex-1 flex items-center justify-center sm:items-stretch sm:justify-start">
<div className="flex-shrink-0 flex items-center">
<Link href="/" className="text-white"
>
Portal.JS
<Link href="/" className="text-white">
Portal.JS
</Link>
</div>
<div className="hidden sm:block sm:ml-6">
<div className="flex space-x-4">
{navigation.map((item) => (
<Link href={item.href}
<Link
href={item.href}
key={item.name}
className={classNames(
item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'px-3 py-2 rounded-md text-sm font-medium'
item.current
? "bg-gray-900 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white",
"px-3 py-2 rounded-md text-sm font-medium"
)}
aria-current={item.current ? 'page' : undefined}
aria-current={item.current ? "page" : undefined}
>
{item.name}
</Link>
@@ -62,8 +57,16 @@ export default function Nav() {
</div>
</div>
<div className="mt-2 justify-end">
<GitHubButton href="https://github.com/datopian/portal.js" data-color-scheme="no-preference: light; light: light; dark: dark;" data-size="large" data-show-count="true" aria-label="Star datopian/portal.js on GitHub">Stars</GitHubButton>
</div>
<GitHubButton
href="https://github.com/datopian/portal.js"
data-color-scheme="no-preference: light; light: light; dark: dark;"
data-size="large"
data-show-count="true"
aria-label="Star datopian/portal.js on GitHub"
>
Stars
</GitHubButton>
</div>
</div>
</div>
@@ -74,10 +77,12 @@ export default function Nav() {
key={item.name}
href={item.href}
className={classNames(
item.current ? 'bg-gray-900 text-white' : 'text-gray-300 hover:bg-gray-700 hover:text-white',
'block px-3 py-2 rounded-md text-base font-medium'
item.current
? "bg-gray-900 text-white"
: "text-gray-300 hover:bg-gray-700 hover:text-white",
"block px-3 py-2 rounded-md text-base font-medium"
)}
aria-current={item.current ? 'page' : undefined}
aria-current={item.current ? "page" : undefined}
>
{item.name}
</a>
@@ -87,5 +92,5 @@ export default function Nav() {
</>
)}
</Disclosure>
)
);
}

View File

@@ -0,0 +1,46 @@
import Layout from '../Layout'
import { MDXRemote } from 'next-mdx-remote'
import dynamic from 'next/dynamic'
import Head from 'next/head'
import CustomLink from '../CustomLink'
import { Vega, VegaLite } from 'react-vega'
// 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 = {
a: CustomLink,
Table: dynamic(() => import('./Table')),
Excel: dynamic(() => import('./Excel')),
// TODO: try and make these dynamic ...
Vega: Vega,
VegaLite: VegaLite,
LineChart: dynamic(() => import('./LineChart')),
Head,
}
export default function DataLiterate({ source, frontMatter }) {
return (
<Layout title={frontMatter.title}>
<div className="prose mx-auto">
<header>
<div className="mb-6">
<h1>{frontMatter.title}</h1>
{frontMatter.author && (
<div className="-mt-6"><p className="opacity-60 pl-1">{frontMatter.author}</p></div>
)}
{frontMatter.description && (
<p className="description">{frontMatter.description}</p>
)}
</div>
</header>
<main>
<MDXRemote {...source} components={components} />
</main>
</div>
</Layout>
)
}

View File

@@ -0,0 +1,74 @@
import axios from 'axios'
import XLSX from 'xlsx'
import React, { useEffect, useState } from 'react'
import Table from './Table'
export default function Excel ({ src='' }) {
const [data, setData] = React.useState([])
const [cols, setCols] = React.useState([])
const [workbook, setWorkbook] = React.useState(null)
const [error, setError] = React.useState('')
const [hasMounted, setHasMounted] = React.useState(0)
// so this is here so we re-render this in the browser
// and not just when we build the page statically in nextjs
useEffect(() => {
if (hasMounted==0) {
handleUrl(src)
}
setHasMounted(1)
})
function handleUrl(url) {
// if url is external may have CORS issue so we proxy it ...
if (url.startsWith('http')) {
const PROXY_URL = window.location.origin + '/api/proxy'
url = PROXY_URL + '?url=' + encodeURIComponent(url)
}
axios.get(url, {
responseType: 'arraybuffer'
}).then((res) => {
let out = new Uint8Array(res.data)
let workbook = XLSX.read(out, {type: "array"})
// Get first worksheet
const wsname = workbook.SheetNames[0]
const ws = workbook.Sheets[wsname]
// Convert array of arrays
const datatmp = XLSX.utils.sheet_to_json(ws, {header:1})
const colstmp = make_cols(ws['!ref'])
setData(datatmp)
setCols(colstmp)
setWorkbook(workbook)
}).catch((e) => {
setError(e.message)
})
}
return (
<>
{error &&
<div>
There was an error loading the excel file at {src}:
<p>{error}</p>
</div>
}
{workbook &&
<ul>
{workbook.SheetNames.map((value, index) => {
return <li key={index}>{value}</li>
})}
</ul>
}
<Table data={data} cols={cols} />
</>
)
}
/* generate an array of column objects */
const make_cols = refstr => {
let o = [], C = XLSX.utils.decode_range(refstr).e.c + 1
for(var i = 0; i < C; ++i) o[i] = {name:XLSX.utils.encode_col(i), key:i}
return o
}

View File

@@ -0,0 +1,33 @@
import { Vega, VegaLite } from 'react-vega'
export default function LineChart( { data=[] }) {
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",
"mark": "line",
"data": {
"name": "table"
},
"encoding": {
"x": {
"field": "x",
"timeUnit": "year",
"type": "temporal"
},
"y": {
"field": "y",
"type": "quantitative"
}
}
}
return (
<VegaLite data={ vegaData } spec={ spec } />
)
}

View File

@@ -0,0 +1,83 @@
import axios from 'axios'
import React, { useEffect, useState } from 'react'
const papa = require("papaparse")
/*
Simple HTML Table
usage: <OutTable data={data} cols={cols} />
data:Array<Array<any> >;
cols:Array<{name:string, key:number|string}>;
*/
export default function Table({ data=[], cols=[], csv='', url='' }) {
if (csv) {
const out = parseCsv(csv)
data = out.rows
cols = out.cols
}
const [ourdata, setData] = React.useState(data)
const [ourcols, setCols] = React.useState(cols)
const [error, setError] = React.useState('')
useEffect(() => {
if (url) {
loadUrl(url)
}
}, [url])
function loadUrl(path) {
// HACK: duplicate of Excel code - maybe refactor
// if url is external may have CORS issue so we proxy it ...
if (url.startsWith('http')) {
const PROXY_URL = window.location.origin + '/api/proxy'
url = PROXY_URL + '?url=' + encodeURIComponent(url)
}
axios.get(url).then((res) => {
const { rows, fields } = parseCsv(res.data)
setData(rows)
setCols(fields)
})
}
return (
<>
<SimpleTable data={ourdata} cols={ourcols} />
</>
)
}
/*
Simple HTML Table
usage: <OutTable data={data} cols={cols} />
data:Array<Array<any> >;
cols:Array<{name:string, key:number|string}>;
*/
function SimpleTable({ data=[], cols=[] }) {
return (
<div className="table-responsive">
<table className="table table-striped">
<thead>
<tr>{cols.map((c) => <th key={c.key}>{c.name}</th>)}</tr>
</thead>
<tbody>
{data.map((r,i) => <tr key={i}>
{cols.map(c => <td key={c.key}>{ r[c.key] }</td>)}
</tr>)}
</tbody>
</table>
</div>
)
}
function 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
}
}