[refactor][xs]: rename docs directory to site reflecting fact this is the full website.
This commit is contained in:
34
site/.gitignore
vendored
Normal file
34
site/.gitignore
vendored
Normal file
@@ -0,0 +1,34 @@
|
||||
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
|
||||
|
||||
# dependencies
|
||||
/node_modules
|
||||
/.pnp
|
||||
.pnp.js
|
||||
|
||||
# testing
|
||||
/coverage
|
||||
|
||||
# next.js
|
||||
/.next/
|
||||
/out/
|
||||
|
||||
# production
|
||||
/build
|
||||
|
||||
# misc
|
||||
.DS_Store
|
||||
*.pem
|
||||
|
||||
# debug
|
||||
npm-debug.log*
|
||||
yarn-debug.log*
|
||||
yarn-error.log*
|
||||
|
||||
# local env files
|
||||
.env.local
|
||||
.env.development.local
|
||||
.env.test.local
|
||||
.env.production.local
|
||||
|
||||
# vercel
|
||||
.vercel
|
||||
19
site/README.md
Normal file
19
site/README.md
Normal file
@@ -0,0 +1,19 @@
|
||||
This the Portal.JS website.
|
||||
|
||||
It is built on [Next.js](https://nextjs.org/).
|
||||
|
||||
## Getting Started
|
||||
|
||||
First, run the development server:
|
||||
|
||||
```bash
|
||||
npm run dev
|
||||
# or
|
||||
yarn dev
|
||||
```
|
||||
|
||||
Open [http://localhost:3000](http://localhost:3000) with your browser to see the result.
|
||||
|
||||
## Deployment
|
||||
|
||||
We currently deploy on Vercel.
|
||||
52
site/components/Nav/index.jsx
Normal file
52
site/components/Nav/index.jsx
Normal file
@@ -0,0 +1,52 @@
|
||||
import { useState } from 'react'
|
||||
import Link from 'next/link'
|
||||
|
||||
export default function Nav() {
|
||||
const [open, setOpen] = useState(false);
|
||||
const handleClick = (event) => {
|
||||
event.preventDefault();
|
||||
setOpen(!open);
|
||||
};
|
||||
|
||||
const navMenu = [
|
||||
{ title: 'Docs', path: '/docs' },
|
||||
{ title: 'Components', path: '/docs/components' },
|
||||
{ title: 'Learn', path: '/learn' },
|
||||
{ title: 'Gallery', path: '/gallery' },
|
||||
{ title: 'Github', path: 'https://github.com/datopian/portal.js' }
|
||||
]
|
||||
|
||||
return (
|
||||
<nav className="flex items-center justify-between flex-wrap bg-white p-4 border-b border-gray-200">
|
||||
<div className="flex items-center flex-shrink-0 text-gray-700 mr-6">
|
||||
<Link href="/">
|
||||
<img src="/logo.svg" alt="portal logo" width="110" />
|
||||
</Link>
|
||||
</div>
|
||||
<div className="block lg:hidden mx-4">
|
||||
<button
|
||||
onClick={handleClick}
|
||||
className="flex items-center px-3 py-2 border rounded text-gray-700 border-orange-400 hover:text-black hover:border-black"
|
||||
>
|
||||
<svg
|
||||
className="fill-current h-3 w-3"
|
||||
viewBox="0 0 20 20"
|
||||
xmlns="http://www.w3.org/2000/svg"
|
||||
>
|
||||
<title>Menu</title>
|
||||
<path d="M0 3h20v2H0V3zm0 6h20v2H0V9zm0 6h20v2H0v-2z" />
|
||||
</svg>
|
||||
</button>
|
||||
</div>
|
||||
<div className={`${open ? `block` : `hidden`} lg:block`}>
|
||||
{navMenu.map((menu, index) => {
|
||||
return (<Link href={menu.path} key={index}>
|
||||
<a className="block mt-4 lg:inline-block lg:mt-0 active:bg-primary-background text-gray-700 hover:text-black mr-6">
|
||||
{menu.title}
|
||||
</a>
|
||||
</Link>)
|
||||
})}
|
||||
</div>
|
||||
</nav>
|
||||
)
|
||||
}
|
||||
35
site/components/layout.js
Normal file
35
site/components/layout.js
Normal file
@@ -0,0 +1,35 @@
|
||||
import Link from 'next/link'
|
||||
import Head from 'next/head'
|
||||
|
||||
import Nav from '../components/Nav'
|
||||
|
||||
export default function Layout({
|
||||
children,
|
||||
title = 'Portal.JS',
|
||||
}) {
|
||||
return (
|
||||
<div>
|
||||
<Head>
|
||||
<title>{title}</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
<meta charSet="utf-8" />
|
||||
<meta name="viewport" content="initial-scale=1.0, width=device-width" />
|
||||
</Head>
|
||||
<Nav />
|
||||
|
||||
{children}
|
||||
|
||||
<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>
|
||||
</div>
|
||||
)
|
||||
}
|
||||
13
site/components/prose.js
Normal file
13
site/components/prose.js
Normal file
@@ -0,0 +1,13 @@
|
||||
export default function Prose({
|
||||
children,
|
||||
mdFile=null
|
||||
}) {
|
||||
return (
|
||||
<main className="prose mx-auto my-24">
|
||||
{mdFile &&
|
||||
<div dangerouslySetInnerHTML={{ __html: mdFile }} />
|
||||
}
|
||||
{children}
|
||||
</main>
|
||||
)
|
||||
}
|
||||
13
site/lib/utils.js
Normal file
13
site/lib/utils.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import remark from 'remark'
|
||||
import html from 'remark-html'
|
||||
import fs from 'fs'
|
||||
|
||||
export async function formatMD(mdFilePath) {
|
||||
const mdFile = fs.readFileSync(mdFilePath, "utf-8")
|
||||
const processed = await remark()
|
||||
.use(html)
|
||||
.process(mdFile)
|
||||
|
||||
const readmeHtml = processed.toString()
|
||||
return readmeHtml
|
||||
}
|
||||
589
site/markdowns/docs/components.md
Normal file
589
site/markdowns/docs/components.md
Normal file
@@ -0,0 +1,589 @@
|
||||
# Components Reference
|
||||
|
||||
Portal.js supports many components that can help you build amazing data portals similar to [this](https://catalog-portal-js.vercel.app/) and [this](https://portal-js.vercel.app/).
|
||||
|
||||
In this section, we'll cover all supported components in depth, and help you understand their use as well as the expected properties.
|
||||
|
||||
Components are grouped under the following sections:
|
||||
* [UI](https://github.com/datopian/portal.js/tree/main/src/components/ui): Components like Nav bar, Footer, e.t.c
|
||||
* [Dataset](https://github.com/datopian/portal.js/tree/main/src/components/dataset): Components used for displaying a Frictionless dataset and resources
|
||||
* [Search](https://github.com/datopian/portal.js/tree/main/src/components/search): Components used for building a search interface for datasets
|
||||
* [Blog](https://github.com/datopian/portal.js/tree/main/src/components/blog): Components for building a simple blog for datasets
|
||||
* [Views](https://github.com/datopian/portal.js/tree/main/src/components/views): Components like charts, tables, maps for generating data views
|
||||
* [Misc](https://github.com/datopian/portal.js/tree/main/src/components/misc): Miscellaneos components like errors, custom links, etc used for extra design.
|
||||
|
||||
### UI Components
|
||||
|
||||
In the UI we group all components that can be used for building generic page sections. These are components for building sections like the Navigation bar, Footer, Side pane, Recent datasets, e.t.c.
|
||||
|
||||
#### [Nav Component](https://github.com/datopian/portal.js/blob/main/src/components/ui/Nav.js)
|
||||
|
||||
To build a navigation bar, you can use the `Nav` component as demonstrated below:
|
||||
|
||||
```javascript
|
||||
import { Nav } from 'portal'
|
||||
|
||||
export default function Home(){
|
||||
|
||||
const navMenu = [{ title: 'Blog', path: '/blog' },
|
||||
{ title: 'Search', path: '/search' }]
|
||||
|
||||
return (
|
||||
<>
|
||||
<Nav logo="/images/logo.png" navMenu={navMenu}/>
|
||||
...
|
||||
</>
|
||||
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Nav Component Prop Types
|
||||
|
||||
Nav component accepts two properties:
|
||||
* **logo**: A string to an image path. Can be relative or absolute.
|
||||
* **navMenu**: An array of objects with title and path. E.g : [{ title: 'Blog', path: '/blog' },{ title: 'Search', path: '/search' }]
|
||||
|
||||
|
||||
#### [Recent Component](https://github.com/datopian/portal.js/blob/main/src/components/ui/Recent.js)
|
||||
|
||||
The `Recent` component is used to display a list of recent [datasets](#Dataset) in the home page. This useful if you want to display the most recent dataset users have interacted with in your home page.
|
||||
To build a recent dataset section, you can use the `Recent` component as demonstrated below:
|
||||
|
||||
```javascript
|
||||
import { Recent } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const datasets = [
|
||||
{
|
||||
organization: {
|
||||
name: "Org1",
|
||||
title: "This is the first org",
|
||||
description: "A description of the organization 1"
|
||||
},
|
||||
title: "Data package title",
|
||||
name: "dataset1",
|
||||
description: "description of data package",
|
||||
resources: [],
|
||||
},
|
||||
{
|
||||
organization: {
|
||||
name: "Org2",
|
||||
title: "This is the second org",
|
||||
description: "A description of the organization 2"
|
||||
},
|
||||
title: "Data package title",
|
||||
name: "dataset2",
|
||||
description: "description of data package",
|
||||
resources: [],
|
||||
},
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Use Recent component */}
|
||||
<Recent datasets={datasets} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
Note: The `Recent` component is hyperlinked with the dataset name of the organization and the dataset name in the following format:
|
||||
|
||||
> `/@<org name>/<dataset name>`
|
||||
|
||||
For instance, using the example dataset above, the first component will be link to page:
|
||||
|
||||
> `/@org1/dataset1`
|
||||
|
||||
and the second will be linked to:
|
||||
|
||||
> `/@org2/dataset2`
|
||||
|
||||
This is useful to know when generating dynamic pages for each dataset.
|
||||
|
||||
#### Recent Component Prop Types
|
||||
|
||||
The `Recent` component accepts the following properties:
|
||||
* **datasets**: An array of [datasets](#Dataset)
|
||||
|
||||
### Dataset Components
|
||||
|
||||
The dataset component groups together components that can be used for building a dataset UI. These includes components for displaying info about a dataset, resources in a dataset as well as dataset ReadMe.
|
||||
|
||||
#### [KeyInfo Component](https://github.com/datopian/portal.js/blob/main/src/components/dataset/KeyInfo.js)
|
||||
|
||||
The `KeyInfo` components displays key properties like the number of resources, size, format, licences of in a dataset in tabular form. See example in the `Key Info` section [here](https://portal-js.vercel.app/). To use it, you can import the `KeyInfo` component as demonstrated below:
|
||||
```javascript
|
||||
import { KeyInfo } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const datapackage = {
|
||||
"name": "finance-vix",
|
||||
"title": "VIX - CBOE Volatility Index",
|
||||
"homepage": "http://www.cboe.com/micro/VIX/",
|
||||
"version": "0.1.0",
|
||||
"license": "PDDL-1.0",
|
||||
"sources": [
|
||||
{
|
||||
"title": "CBOE VIX Page",
|
||||
"name": "CBOE VIX Page",
|
||||
"web": "http://www.cboe.com/micro/vix/historical.aspx"
|
||||
}
|
||||
],
|
||||
"resources": [
|
||||
{
|
||||
"name": "vix-daily",
|
||||
"path": "vix-daily.csv",
|
||||
"format": "csv",
|
||||
"size": 20982,
|
||||
"mediatype": "text/csv",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Use KeyInfo component */}
|
||||
<KeyInfo descriptor={datapackage} resources={datapackage.resources} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### KeyInfo Component Prop Types
|
||||
|
||||
KeyInfo component accepts two properties:
|
||||
* **descriptor**: A [Frictionless data package descriptor](https://specs.frictionlessdata.io/data-package/#descriptor)
|
||||
* **resources**: An [Frictionless data package resource](https://specs.frictionlessdata.io/data-resource/#introduction)
|
||||
|
||||
|
||||
#### [ResourceInfo Component](https://github.com/datopian/portal.js/blob/main/src/components/dataset/ResourceInfo.js)
|
||||
|
||||
The `ResourceInfo` components displays key properties like the name, size, format, modification dates, as well as a download link in a resource object. See an example of a `ResourceInfo` component in the `Data Files` section [here](https://portal-js.vercel.app/).
|
||||
|
||||
You can import and use the`ResourceInfo` component as demonstrated below:
|
||||
```javascript
|
||||
import { ResourceInfo } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const resources = [
|
||||
{
|
||||
"name": "vix-daily",
|
||||
"path": "vix-daily.csv",
|
||||
"format": "csv",
|
||||
"size": 20982,
|
||||
"mediatype": "text/csv",
|
||||
},
|
||||
{
|
||||
"name": "vix-daily 2",
|
||||
"path": "vix-daily2.csv",
|
||||
"format": "csv",
|
||||
"size": 2082,
|
||||
"mediatype": "text/csv",
|
||||
}
|
||||
]
|
||||
|
||||
return (
|
||||
<div>
|
||||
{/* Use Recent component */}
|
||||
<ResourceInfo resources={resources} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### ResourceInfo Component Prop Types
|
||||
|
||||
ResourceInfo component accepts a single property:
|
||||
* **resources**: An [Frictionless data package resource](https://specs.frictionlessdata.io/data-resource/#introduction)
|
||||
|
||||
|
||||
#### [ReadMe Component](https://github.com/datopian/portal.js/blob/main/src/components/dataset/Readme.js)
|
||||
|
||||
The `ReadMe` component is used for displaying a compiled dataset Readme in a readable format. See example in the `README` section [here](https://portal-js.vercel.app/).
|
||||
|
||||
> Note: By compiled ReadMe, we mean ReadMe that has been converted to plain string using a package like [remark](https://www.npmjs.com/package/remark).
|
||||
|
||||
You can import and use the`ReadMe` component as demonstrated below:
|
||||
```javascript
|
||||
import { ReadMe } from 'portal'
|
||||
import remark from 'remark'
|
||||
import html from 'remark-html'
|
||||
import { useEffect, useState } from 'react'
|
||||
|
||||
|
||||
const readMeMarkdown = `
|
||||
CBOE Volatility Index (VIX) time-series dataset including daily open, close,
|
||||
high and low. The CBOE Volatility Index (VIX) is a key measure of market
|
||||
expectations of near-term volatility conveyed by S&P 500 stock index option
|
||||
prices introduced in 1993.
|
||||
|
||||
## Data
|
||||
|
||||
From the [VIX FAQ][faq]:
|
||||
|
||||
> In 1993, the Chicago Board Options Exchange® (CBOE®) introduced the CBOE
|
||||
> Volatility Index®, VIX®, and it quickly became the benchmark for stock market
|
||||
> volatility. It is widely followed and has been cited in hundreds of news
|
||||
> articles in the Wall Street Journal, Barron's and other leading financial
|
||||
> publications. Since volatility often signifies financial turmoil, VIX is
|
||||
> often referred to as the "investor fear gauge".
|
||||
|
||||
[faq]: http://www.cboe.com/micro/vix/faq.aspx
|
||||
|
||||
## License
|
||||
|
||||
No obvious statement on [historical data page][historical]. Given size and
|
||||
factual nature of the data and its source from a US company would imagine this
|
||||
was public domain and as such have licensed the Data Package under the Public
|
||||
Domain Dedication and License (PDDL).
|
||||
|
||||
[historical]: http://www.cboe.com/micro/vix/historical.aspx
|
||||
`
|
||||
|
||||
export default function Home() {
|
||||
const [readMe, setreadMe] = useState("")
|
||||
|
||||
useEffect(() => {
|
||||
async function processReadMe() {
|
||||
const processed = await remark()
|
||||
.use(html)
|
||||
.process(readMeMarkdown)
|
||||
setreadMe(processed.toString())
|
||||
}
|
||||
processReadMe()
|
||||
}, [])
|
||||
|
||||
return (
|
||||
<div>
|
||||
<ReadMe readme={readMe} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
#### ReadMe Component Prop Types
|
||||
|
||||
The `ReadMe` component accepts a single property:
|
||||
* **readme**: A string of a compiled ReadMe in html format.
|
||||
|
||||
### [View Components](https://github.com/datopian/portal.js/tree/main/src/components/views)
|
||||
|
||||
View components is a set of components that can be used for displaying dataset views like charts, tables, maps, e.t.c.
|
||||
|
||||
#### [Chart Component](https://github.com/datopian/portal.js/blob/main/src/components/views/Chart.js)
|
||||
|
||||
The `Chart` components exposes different chart components like Plotly Chart, Vega charts, which can be used for showing graphs. See example in the `Graph` section [here](https://portal-js.vercel.app/).
|
||||
To use a chart component, you need to compile and pass a view spec as props to the chart component.
|
||||
Each Chart type have their specific spec, as explained in this [doc](https://specs.frictionlessdata.io/views/#graph-spec).
|
||||
|
||||
In the example below, we assume there's a compiled Plotly spec:
|
||||
|
||||
```javascript
|
||||
import { PlotlyChart } from 'portal'
|
||||
|
||||
export default function Home({plotlySpec}) {
|
||||
|
||||
return (
|
||||
< div >
|
||||
<PlotlyChart spec={plotlySpec} />
|
||||
</div>
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
> Note: You can compile views using the [datapackage-render](https://github.com/datopian/datapackage-views-js) library, as demonstrated in [this example](https://github.com/datopian/portal.js/blob/main/examples/dataset-frictionless/lib/utils.js).
|
||||
|
||||
|
||||
#### Chart Component Prop Types
|
||||
|
||||
KeyInfo component accepts two properties:
|
||||
* **spec**: A compiled view spec depending on the chart type.
|
||||
|
||||
#### [Table Component](https://github.com/datopian/portal.js/blob/main/examples/dataset-frictionless/components/Table.js)
|
||||
|
||||
The `Table` component is used for displaying dataset resources as a tabular grid. See example in the `Data Preview` section [here](https://portal-js.vercel.app/).
|
||||
To use a Table component, you have to pass an array of data and columns as demonstrated below:
|
||||
|
||||
```javascript
|
||||
import { Table } from 'portal' //import Table component
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const columns = [
|
||||
{ field: 'id', headerName: 'ID' },
|
||||
{ field: 'firstName', headerName: 'First name' },
|
||||
{ field: 'lastName', headerName: 'Last name' },
|
||||
{ field: 'age', headerName: 'Age' }
|
||||
];
|
||||
|
||||
const data = [
|
||||
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
|
||||
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
|
||||
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
|
||||
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
|
||||
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
|
||||
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
|
||||
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
|
||||
];
|
||||
|
||||
return (
|
||||
<Table data={data} columns={columns} />
|
||||
)
|
||||
}
|
||||
|
||||
```
|
||||
> Note: Under the hood, Table component uses the [DataGrid Material UI table](https://material-ui.com/components/data-grid/), and as such all supported params in data and columns are supported.
|
||||
|
||||
|
||||
#### Table Component Prop Types
|
||||
|
||||
Table component accepts two properties:
|
||||
* **data**: An array of column names with properties: e.g [{field: "col1", headerName: "col1"}, {field: "col2", headerName: "col2"}]
|
||||
* **columns**: An array of data objects e.g. [ {col1: 1, col2: 2}, {col1: 5, col2: 7} ]
|
||||
|
||||
|
||||
### [Search Components](https://github.com/datopian/portal.js/tree/main/src/components/search)
|
||||
|
||||
Search components groups together components that can be used for creating a search interface. This includes search forms, search item as well as search result list.
|
||||
|
||||
#### [Form Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Form.js)
|
||||
|
||||
The search`Form` component is a simple search input and submit button. See example of a search form [here](https://catalog-portal-js.vercel.app/search).
|
||||
|
||||
The search `form` requires a submit handler (`handleSubmit`). This handler function receives the search term, and handles actual search.
|
||||
|
||||
In the example below, we demonstrate how to use the `Form` component.
|
||||
|
||||
```javascript
|
||||
import { Form } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const handleSearchSubmit = (searchQuery) => {
|
||||
// Write your custom code to perform search in db
|
||||
console.log(searchQuery);
|
||||
}
|
||||
|
||||
return (
|
||||
<Form
|
||||
handleSubmit={handleSearchSubmit} />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Form Component Prop Types
|
||||
|
||||
The `Form` component accepts a single property:
|
||||
* **handleSubmit**: A function that receives the search text, and can be customize to perform the actual search.
|
||||
|
||||
#### [Item Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Item.js)
|
||||
|
||||
The search`Item` component can be used to display a single search result.
|
||||
|
||||
In the example below, we demonstrate how to use the `Item` component.
|
||||
|
||||
```javascript
|
||||
import { Item } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
const datapackage = {
|
||||
"name": "finance-vix",
|
||||
"title": "VIX - CBOE Volatility Index",
|
||||
"homepage": "http://www.cboe.com/micro/VIX/",
|
||||
"version": "0.1.0",
|
||||
"description": "This is a test organization description",
|
||||
"resources": [
|
||||
{
|
||||
"name": "vix-daily",
|
||||
"path": "vix-daily.csv",
|
||||
"format": "csv",
|
||||
"size": 20982,
|
||||
"mediatype": "text/csv",
|
||||
}
|
||||
]
|
||||
}
|
||||
|
||||
return (
|
||||
<Item dataset={datapackage} />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Item Component Prop Types
|
||||
|
||||
The `Item` component accepts a single property:
|
||||
* **dataset**: A [Frictionless data package descriptor](https://specs.frictionlessdata.io/data-package/#descriptor)
|
||||
|
||||
|
||||
#### [ItemTotal Component](https://github.com/datopian/portal.js/blob/main/src/components/search/Item.js)
|
||||
|
||||
The search`ItemTotal` is a simple component for displaying the total search result
|
||||
|
||||
In the example below, we demonstrate how to use the `ItemTotal` component.
|
||||
|
||||
```javascript
|
||||
import { ItemTotal } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
//do some custom search to get results
|
||||
const search = (text) => {
|
||||
return [{ name: "data1" }, { name: "data2" }]
|
||||
}
|
||||
//get the total result count
|
||||
const searchTotal = search("some text").length
|
||||
|
||||
return (
|
||||
<ItemTotal count={searchTotal} />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### ItemTotal Component Prop Types
|
||||
|
||||
The `ItemTotal` component accepts a single property:
|
||||
* **count**: An integer of the total number of results.
|
||||
|
||||
|
||||
### [Blog Components](https://github.com/datopian/portal.js/tree/main/src/components/blog)
|
||||
|
||||
These are group of components for building a portal blog. See example of portal blog [here](https://catalog-portal-js.vercel.app/blog)
|
||||
|
||||
#### [PostList Components](https://github.com/datopian/portal.js/tree/main/src/components/misc)
|
||||
|
||||
The `PostList` component is used to display a list of blog posts with the title and a short excerpts from the content.
|
||||
|
||||
In the example below, we demonstrate how to use the `PostList` component.
|
||||
|
||||
```javascript
|
||||
import { PostList } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const posts = [
|
||||
{ title: "Blog post 1", excerpt: "This is the first blog excerpts in this list." },
|
||||
{ title: "Blog post 2", excerpt: "This is the second blog excerpts in this list." },
|
||||
{ title: "Blog post 3", excerpt: "This is the third blog excerpts in this list." },
|
||||
]
|
||||
return (
|
||||
<PostList posts={posts} />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### PostList Component Prop Types
|
||||
|
||||
The `PostList` component accepts a single property:
|
||||
* **posts**: An array of post list objects with the following properties:
|
||||
```javascript
|
||||
[
|
||||
{
|
||||
title: "The title of the blog post",
|
||||
excerpt: "A short excerpt from the post content",
|
||||
},
|
||||
]
|
||||
```
|
||||
|
||||
#### [Post Components](https://github.com/datopian/portal.js/tree/main/src/components/misc)
|
||||
|
||||
The `Post` component is used to display a blog post. See an example of a blog post [here](https://catalog-portal-js.vercel.app/blog/nyt-pa-platformen-opdateringsfrekvens-og-andres-data)
|
||||
|
||||
In the example below, we demonstrate how to use the `Post` component.
|
||||
|
||||
```javascript
|
||||
import { Post } from 'portal'
|
||||
import * as dayjs from 'dayjs' //For converting UTC time to relative format
|
||||
import relativeTime from 'dayjs/plugin/relativeTime'
|
||||
|
||||
dayjs.extend(relativeTime)
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const post = {
|
||||
title: "This is a sample blog post",
|
||||
content: `<h1>A simple header</h1>
|
||||
The PostList component is used to display a list of blog posts
|
||||
with the title and a short excerpts from the content.
|
||||
In the example below, we demonstrate how to use the PostList component.`,
|
||||
createdAt: dayjs().to(dayjs(1620649596902)),
|
||||
featuredImage: "https://pixabay.com/get/ge9a766d1f7b5fe0eccbf0f439501a2cf2b191997290e7ab15e6a402574acc2fdba48a82d278dca3547030e0202b7906d_640.jpg"
|
||||
}
|
||||
|
||||
return (
|
||||
<Post post={post} />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Post Component Prop Types
|
||||
|
||||
The `Post` component accepts a single property:
|
||||
* **post**: An object with the following properties:
|
||||
```javascript
|
||||
{
|
||||
title: <The title of the blog post>
|
||||
content: <The body of the blog post. Can be plain text or html>
|
||||
createdAt: <The utc date when the post was last modified>
|
||||
featuredImage: < Url/relative url to post cover image>
|
||||
}
|
||||
```
|
||||
|
||||
|
||||
### [Misc Components](https://github.com/datopian/portal.js/tree/main/src/components/misc)
|
||||
|
||||
These are group of miscellaneous/extra components for extending your portal. They include components like Errors, custom links, etc.
|
||||
|
||||
#### [Error Component](https://github.com/datopian/portal.js/blob/main/src/components/misc/Error.js)
|
||||
|
||||
The `Error` component is used to display a custom error message.
|
||||
|
||||
In the example below, we demonstrate how to use the `Error` component.
|
||||
|
||||
```javascript
|
||||
import { Error } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
return (
|
||||
<Error message="An error occured when loading the file!" />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### Error Component Prop Types
|
||||
|
||||
The `Error` component accepts a single property:
|
||||
* **message**: A string with the error message to display.
|
||||
|
||||
|
||||
#### [Custom Component](https://github.com/datopian/portal.js/blob/main/src/components/misc/Error.js)
|
||||
|
||||
The `CustomLink` component is used to create a link with a consistent style to other portal components.
|
||||
|
||||
In the example below, we demonstrate how to use the `CustomLink` component.
|
||||
|
||||
```javascript
|
||||
import { CustomLink } from 'portal'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
return (
|
||||
<CustomLink url="/blog" title="Goto Blog" />
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
#### CustomLink Component Prop Types
|
||||
|
||||
The `CustomLink` component accepts the following properties:
|
||||
|
||||
* **url**: A string. The relative or absolute url of the link.
|
||||
* **title**: A string. The title of the link
|
||||
|
||||
132
site/markdowns/docs/index.md
Normal file
132
site/markdowns/docs/index.md
Normal file
@@ -0,0 +1,132 @@
|
||||
# 🌀 Portal.JS: The JavaScript framework for data portals
|
||||
|
||||
🌀 `portal.js` is a framework for rapidly building rich data portal frontends using a modern frontend approach. `portal.js` can be used to present a single dataset or build a full-scale data catalog/portal.
|
||||
|
||||
`portal.js` is built in Javascript and React on top of the popular [Next.js](https://nextjs.com/) framework. `portal` assumes a "decoupled" approach where the frontend is a separate service from the backend and interacts with backend(s) via an API. It can be used with any backend and has out of the box support for [CKAN](https://ckan.org/).
|
||||
|
||||
## Features
|
||||
|
||||
- 🗺️ Unified sites: present data and content in one seamless site, pulling datasets from a DMS (e.g. CKAN) and content from a CMS (e.g. wordpress) with a common internal API.
|
||||
- 👩💻 Developer friendly: built with familiar frontend tech Javascript, React etc
|
||||
- 🔋 Batteries included: Full set of portal components out of the box e.g. catalog search, dataset showcase, blog etc.
|
||||
- 🎨 Easy to theme and customize: installable themes, use standard CSS and React+CSS tooling. Add new routes quickly.
|
||||
- 🧱 Extensible: quickly extend and develop/import your own React components
|
||||
- 📝 Well documented: full set of documentation plus the documentation of NextJS and Apollo.
|
||||
|
||||
### For developers
|
||||
|
||||
- 🏗 Build with modern, familiar frontend tech such as Javascript and React.
|
||||
- 🚀 NextJS framework: so everything in NextJS for free React, SSR, static site generation, huge number of examples and integrations etc.
|
||||
- SSR => unlimited number of pages, SEO etc whilst still using React.
|
||||
- Static Site Generation (SSG) (good for small sites) => ultra-simple deployment, great performance and lighthouse scores etc
|
||||
|
||||
## Installation and setup
|
||||
|
||||
Before installation, ensure your system satisfies the following requirements:
|
||||
|
||||
- Node.js 10.13 or later
|
||||
- Nextjs 10.0.3
|
||||
- MacOS, Windows (including WSL), and Linux are supported
|
||||
|
||||
> Note: We also recommend instead of npm using `yarn` instead of `npm`.
|
||||
>
|
||||
Portal.js is built with React on top of Nextjs framework, so for a quick setup, you can bootstrap a Nextjs app and install portal.js as demonstrated in the code below:
|
||||
|
||||
```bash=
|
||||
## Create a react app
|
||||
npx create-next-app
|
||||
# or
|
||||
yarn create next-app
|
||||
```
|
||||
After the installation is complete, follow the instructions to start the development server. Try editing pages/index.js and see the result on your browser.
|
||||
|
||||
> For more information on how to use create-next-app, you can review the [create-next-app](https://nextjs.org/docs/api-reference/create-next-app) documentation.
|
||||
|
||||
Once you have Nextjs created, you can install portal.js:
|
||||
|
||||
```bash=
|
||||
yarn add https://github.com/datopian/portal.js.git
|
||||
```
|
||||
|
||||
You're now ready to use portal.js in your next app. To test portal.js, open your `index.js` file in the pages folder. By default you should have some autogenerated code in the `index.js` file:
|
||||
|
||||
|
||||
Which outputs a page with the following content:
|
||||
|
||||

|
||||
|
||||
Now, we are going to do some clean up and add a table component. In the `index.js` file, import a [Table]() component from portal as shown below:
|
||||
|
||||
```javascript
|
||||
import Head from 'next/head'
|
||||
import { Table } from 'portal' //import Table component
|
||||
import styles from '../styles/Home.module.css'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
const columns = [
|
||||
{ field: 'id', headerName: 'ID' },
|
||||
{ field: 'firstName', headerName: 'First name' },
|
||||
{ field: 'lastName', headerName: 'Last name' },
|
||||
{ field: 'age', headerName: 'Age' }
|
||||
];
|
||||
|
||||
const rows = [
|
||||
{ id: 1, lastName: 'Snow', firstName: 'Jon', age: 35 },
|
||||
{ id: 2, lastName: 'Lannister', firstName: 'Cersei', age: 42 },
|
||||
{ id: 3, lastName: 'Lannister', firstName: 'Jaime', age: 45 },
|
||||
{ id: 4, lastName: 'Stark', firstName: 'Arya', age: 16 },
|
||||
{ id: 7, lastName: 'Clifford', firstName: 'Ferrara', age: 44 },
|
||||
{ id: 8, lastName: 'Frances', firstName: 'Rossini', age: 36 },
|
||||
{ id: 9, lastName: 'Roxie', firstName: 'Harvey', age: 65 },
|
||||
];
|
||||
|
||||
return (
|
||||
<div className={styles.container}>
|
||||
<Head>
|
||||
<title>Create Portal App</title>
|
||||
<link rel="icon" href="/favicon.ico" />
|
||||
</Head>
|
||||
|
||||
<h1 className={styles.title}>
|
||||
Welcome to <a href="https://nextjs.org">Portal.JS</a>
|
||||
</h1>
|
||||
|
||||
{/* Use table component */}
|
||||
<Table data={rows} columns={columns} />
|
||||
|
||||
</div>
|
||||
)
|
||||
}
|
||||
```
|
||||
|
||||
Now, your page should look like the following:
|
||||
|
||||

|
||||
|
||||
> **Note**: You can learn more about individual portal components, as well as their prop types in the [components reference](/docs/components).
|
||||
|
||||
|
||||
## Next Steps
|
||||
|
||||
You can check out the following examples built with Portal.js.
|
||||
|
||||
* [A portal for a single Frictionless dataset](#Build-a-single-Frictionless-dataset-portal)
|
||||
* [A portal with a CKAN backend](#Build-a-CKAN-powered-dataset-portal)
|
||||
|
||||
> The [`examples` directory](https://github.com/datopian/portal.js/tree/main/examples) is regularly updated with different portal examples.
|
||||
|
||||
You can also look at the full list of the available components that are provided by Portal.JS in [Components](/docs/components).
|
||||
|
||||
|
||||
## Reference Information
|
||||
|
||||
* [Full list of the available components that are provided by Portal.JS](/docs/components)
|
||||
* [Reference](/docs/references)
|
||||
|
||||
|
||||
## Getting Help
|
||||
|
||||
If you have questions about anything related to Portal.js, you're always welcome to ask our community on [GitHub Discussions](https://github.com/datopian/portal.js/discussions).
|
||||
|
||||
|
||||
54
site/markdowns/docs/references.md
Normal file
54
site/markdowns/docs/references.md
Normal file
@@ -0,0 +1,54 @@
|
||||
# Concepts and Terms
|
||||
|
||||
In this section, we explain some of the terms and concepts used throughtout the portal.js documentation.
|
||||
|
||||
> Some of these concepts are part of official specs, and when appropriate, we'll link to the sources where you can get more details.
|
||||
|
||||
### Dataset
|
||||
|
||||
A dataset extends the [Frictionless data package](https://specs.frictionlessdata.io/data-package/#metadata) to add an extra organization property. The organization property describes the organization the dataset belongs to, and it should have the following properties:
|
||||
|
||||
```javascript
|
||||
organization = {
|
||||
name: "some org name",
|
||||
title: "Some optional org title",
|
||||
description: "A description of the organization"
|
||||
}
|
||||
```
|
||||
|
||||
An example of dataset with organization properties is given below:
|
||||
|
||||
```javascript
|
||||
datasets = [{
|
||||
organization: {
|
||||
name: "some org name",
|
||||
title: "Some optional org title",
|
||||
description: "A description of the organization"
|
||||
},
|
||||
title: "Data package title",
|
||||
name: "Data package name",
|
||||
description: "description of data package",
|
||||
resources: [...],
|
||||
licences: [...],
|
||||
sources: [...]
|
||||
}
|
||||
]
|
||||
```
|
||||
|
||||
### Resource
|
||||
|
||||
TODO
|
||||
|
||||
### View spec
|
||||
|
||||
---
|
||||
|
||||
## Deploying portal build to github pages
|
||||
|
||||
* [Deploying single frictionless dataset to Github](./scripts/README.md)
|
||||
|
||||
## Showcases
|
||||
|
||||
### Single Dataset with Default Theme
|
||||
|
||||

|
||||
69
site/markdowns/tutorial-doc/learn.md
Normal file
69
site/markdowns/tutorial-doc/learn.md
Normal file
@@ -0,0 +1,69 @@
|
||||
# Getting Started
|
||||
|
||||
It's no secret that creating data portals and data-driven applications can be quite complex nowadays. Fortunately, there are some projects available which simplify things and help you build platforms faster.
|
||||
|
||||
[CKAN](https://ckan.org/), [Jupyter](https://jupyter.org/) and other tools are very good examples of that.
|
||||
|
||||
Even still, there's a high learning curve before you can build a proper application. That's because you need to learn about Python, templating, data loading and so on. If you'd like to integrate content or rich visualizations things are even more complex.
|
||||
|
||||
**So, we need something simple but customizable.**
|
||||
|
||||
Think about how apps are created as a frontend developer. You create some files, write some code, load some data and then simply deploy it. We don't have to worry about Docker, Kubernetes, data storage, Postgres etc.
|
||||
|
||||
<img src="/logo.svg" alt="Portal.JS logo" style="height: 40px" />
|
||||
|
||||
That's exactly what we do with Portal.js. Built in pure Javascript and React on top of the awesome Next.js framework. Here are some the cool features Portal.js brings to the table:
|
||||
|
||||
- 🗺️ Unified sites: present data and content in one seamless site, pulling datasets from a DMS (e.g. CKAN) and content from a CMS (e.g. wordpress)
|
||||
- 👩💻 Developer friendly: built with familiar frontend tech Javascript, React etc
|
||||
- 🔋 Batteries included: Full set of presentation and portal components out of the box e.g. data tables, graphs, maps plus catalog search, dataset showcase, blog etc.
|
||||
- 🎨 Easy to theme and customize: installable themes, use standard CSS and React+CSS tooling. Add new routes quickly.
|
||||
- 🧱 Extensible: quickly extend and develop/import your own React components
|
||||
- 📝 Well documented: full set of documentation plus the documentation of NextJS and Apollo.
|
||||
- 🚀 Built on NextJS framework: so everything in NextJS for free React, SSR, static site generation, huge number of examples and integrations etc.
|
||||
- SSR => unlimited number of pages, SEO etc whilst still using React.
|
||||
- Static Site Generation (SSG) (good for small sites) => ultra-simple deployment, great performance and lighthouse scores etc
|
||||
|
||||
Sounds great, right? Let's give it a try.
|
||||
|
||||
> This tutorial assumes basic knowledge of JavaScript, React and Nextjs. If you are not familiar with React or Nextjs, it is advisable to learn them first. We provide some links below to get you started:
|
||||
>
|
||||
> * [Learn NextJS](https://nextjs.org/docs/getting-started)
|
||||
> * [Getting started with React](https://reactjs.org/docs/getting-started.html#learn-react)
|
||||
|
||||
## Create a Portal.JS app
|
||||
|
||||
### Setup
|
||||
|
||||
First, let’s make sure that your development environment is ready.
|
||||
|
||||
* If you don’t have Node.js installed, [install it from here](https://nodejs.org/en/). You’ll need Node.js version 10.13 or later.
|
||||
* You’ll be using your own text editor and terminal app for this tutorial.
|
||||
|
||||
If you are on Windows, we recommend downloading Git for Windows and use Git Bash that comes with it, which supports the UNIX-specific commands in this tutorial. Windows Subsystem for Linux (WSL) is another option.
|
||||
|
||||
### Create a Portal.js App
|
||||
|
||||
To create a Portal.js app, open your terminal, cd into the directory you’d like to create the app in, and run the following command:
|
||||
|
||||
```
|
||||
npx create-next-app portaljs-dataset --use-npm --example "https://github.com/datopian/portal.js/tree/main/examples/default"
|
||||
```
|
||||
|
||||
### Run the development server
|
||||
|
||||
You now have a new directory called portaljs-dataset. Let’s cd into it:
|
||||
|
||||
```
|
||||
cd portaljs-dataset
|
||||
```
|
||||
|
||||
Then, run the following command:
|
||||
|
||||
```
|
||||
npm run dev
|
||||
```
|
||||
|
||||
This starts your Portal.js app’s "development server" (more on this later) on port 3000.
|
||||
|
||||
Let’s check to see if it’s working. Open http://localhost:3000 from your browser.
|
||||
24
site/package.json
Normal file
24
site/package.json
Normal file
@@ -0,0 +1,24 @@
|
||||
{
|
||||
"name": "docs",
|
||||
"version": "0.1.0",
|
||||
"private": true,
|
||||
"scripts": {
|
||||
"dev": "next dev",
|
||||
"build": "next build",
|
||||
"start": "next start"
|
||||
},
|
||||
"dependencies": {
|
||||
"@mdx-js/loader": "^1.6.22",
|
||||
"@next/mdx": "^10.2.0",
|
||||
"@tailwindcss/typography": "^0.4.0",
|
||||
"autoprefixer": "^10.0.4",
|
||||
"frictionless.js": "^0.13.4",
|
||||
"next": "10.2.0",
|
||||
"postcss": "^8.2.10",
|
||||
"react": "17.0.2",
|
||||
"react-dom": "17.0.2",
|
||||
"remark": "^13.0.0",
|
||||
"remark-html": "^13.0.1",
|
||||
"tailwindcss": "^2.0.2"
|
||||
}
|
||||
}
|
||||
8
site/pages/_app.js
Normal file
8
site/pages/_app.js
Normal file
@@ -0,0 +1,8 @@
|
||||
import '../styles/globals.css'
|
||||
import '../styles/tailwind.css'
|
||||
|
||||
function MyApp({ Component, pageProps }) {
|
||||
return <Component {...pageProps} />
|
||||
}
|
||||
|
||||
export default MyApp
|
||||
5
site/pages/api/hello.js
Normal file
5
site/pages/api/hello.js
Normal file
@@ -0,0 +1,5 @@
|
||||
// Next.js API route support: https://nextjs.org/docs/api-routes/introduction
|
||||
|
||||
export default (req, res) => {
|
||||
res.status(200).json({ name: 'John Doe' })
|
||||
}
|
||||
52
site/pages/docs/[[...id]].js
Normal file
52
site/pages/docs/[[...id]].js
Normal file
@@ -0,0 +1,52 @@
|
||||
import path from 'path'
|
||||
import * as fs from 'fs'
|
||||
import Link from 'next/link'
|
||||
|
||||
import Layout from '../../components/layout'
|
||||
import Prose from '../../components/prose'
|
||||
import { formatMD } from '../../lib/utils'
|
||||
|
||||
export default function Docs({ title, mdFile }) {
|
||||
return (
|
||||
<Layout title="Portal.js Documentation - {title}">
|
||||
<Prose mdFile={mdFile}>
|
||||
</Prose>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
const postsDirectory = 'markdowns/docs'
|
||||
|
||||
export async function getStaticProps({params}) {
|
||||
const postId = params.id ? params.id : 'index'
|
||||
const mdFilePath = path.join(postsDirectory, postId + '.md')
|
||||
const mdFile = await formatMD(mdFilePath)
|
||||
return {
|
||||
props: {
|
||||
mdFile
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
export async function getStaticPaths() {
|
||||
const fileNames = fs.readdirSync(postsDirectory)
|
||||
const paths = fileNames.map(fileName => {
|
||||
if (fileName == 'index.md') {
|
||||
return {
|
||||
params: {
|
||||
id: null
|
||||
}
|
||||
}
|
||||
} else {
|
||||
return {
|
||||
params: {
|
||||
id: [ fileName.replace(/\.md$/, '') ]
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
return {
|
||||
paths: paths,
|
||||
fallback: false
|
||||
}
|
||||
}
|
||||
13
site/pages/gallery.js
Normal file
13
site/pages/gallery.js
Normal file
@@ -0,0 +1,13 @@
|
||||
import Layout from '../components/layout'
|
||||
import Prose from '../components/prose'
|
||||
|
||||
export default function Gallery() {
|
||||
|
||||
return (
|
||||
<Layout title="Portal.js Gallery">
|
||||
<Prose>
|
||||
<p className="text-center">Come back soon!</p>
|
||||
</Prose>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
62
site/pages/index.js
Normal file
62
site/pages/index.js
Normal file
@@ -0,0 +1,62 @@
|
||||
import Layout from '../components/layout'
|
||||
|
||||
export default function Home() {
|
||||
|
||||
return (
|
||||
<Layout>
|
||||
<main className="flex flex-col items-center justify-center w-full flex-1 px-20 text-center py-10">
|
||||
<h1 className="text-6xl font-bold">
|
||||
<a href="https://portaljs.com/">
|
||||
<img src="/logo.svg" alt="PortalJS Logo" className="h-28" />
|
||||
</a>
|
||||
</h1>
|
||||
|
||||
<h2 className="mt-6 text-4xl font-normal leading-snug">
|
||||
Rapidly build rich data portals using a modern frontend framework
|
||||
</h2>
|
||||
|
||||
<div className="flex flex-wrap items-center justify-around max-w-4xl mt-6 sm:w-full">
|
||||
<a
|
||||
href="/docs/"
|
||||
className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
|
||||
>
|
||||
<h3 className="text-2xl font-semibold">▸ Documentation</h3>
|
||||
<p className="mt-4 text-xl">
|
||||
Find in-depth information about Portal.js features and API.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/learn/"
|
||||
className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
|
||||
>
|
||||
<h3 className="text-2xl font-semibold">▸ Learn</h3>
|
||||
<p className="mt-4 text-xl">
|
||||
Learn about Portal.js in an interactive course.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="/gallery/"
|
||||
className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
|
||||
>
|
||||
<h3 className="text-2xl font-semibold">▸ Gallery</h3>
|
||||
<p className="mt-4 text-xl">
|
||||
Discover examples of Portal.js projects.
|
||||
</p>
|
||||
</a>
|
||||
|
||||
<a
|
||||
href="https://github.com/datopian/portal.js"
|
||||
className="p-6 mt-6 text-left border w-96 rounded-xl hover:text-blue-600 focus:text-blue-600"
|
||||
>
|
||||
<h3 className="text-2xl font-semibold">▸ Contribute</h3>
|
||||
<p className="mt-4 text-xl">
|
||||
Checkout the Portal.js repository on github
|
||||
</p>
|
||||
</a>
|
||||
</div>
|
||||
</main>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
30
site/pages/learn.js
Normal file
30
site/pages/learn.js
Normal file
@@ -0,0 +1,30 @@
|
||||
import Link from 'next/link'
|
||||
import path from 'path'
|
||||
|
||||
import Layout from '../components/layout'
|
||||
import Prose from '../components/prose'
|
||||
import { formatMD } from '../lib/utils'
|
||||
|
||||
export default function Docs({ mdFile }) {
|
||||
return (
|
||||
<Layout title="Portal.js - Learn">
|
||||
<Prose mdFile={mdFile}>
|
||||
<p className="text-center">
|
||||
<Link href="/references">
|
||||
<button>Next Page</button>
|
||||
</Link>
|
||||
</p>
|
||||
</Prose>
|
||||
</Layout>
|
||||
)
|
||||
}
|
||||
|
||||
export async function getStaticProps() {
|
||||
const mdFilePath = path.join(process.cwd(), "markdowns/tutorial-doc/learn.md")
|
||||
const mdFile = await formatMD(mdFilePath)
|
||||
return {
|
||||
props: {
|
||||
mdFile
|
||||
}
|
||||
}
|
||||
}
|
||||
8
site/postcss.config.js
Normal file
8
site/postcss.config.js
Normal file
@@ -0,0 +1,8 @@
|
||||
// If you want to use other PostCSS plugins, see the following:
|
||||
// https://tailwindcss.com/docs/using-with-preprocessors
|
||||
module.exports = {
|
||||
plugins: {
|
||||
tailwindcss: {},
|
||||
autoprefixer: {},
|
||||
},
|
||||
}
|
||||
BIN
site/public/datopian-logo.png
Normal file
BIN
site/public/datopian-logo.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 33 KiB |
BIN
site/public/favicon.ico
Normal file
BIN
site/public/favicon.ico
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 15 KiB |
25
site/public/logo.svg
Normal file
25
site/public/logo.svg
Normal file
@@ -0,0 +1,25 @@
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="571" height="146" viewBox="0 0 571 146">
|
||||
<g id="Group_45" data-name="Group 45" transform="translate(-1091 -562)">
|
||||
<text id="P_RTAL.JS" data-name="P RTAL.JS" transform="translate(1091 678)" font-size="120" font-family="Montserrat-Regular, Montserrat"><tspan x="0" y="0" xml:space="preserve">P RTAL</tspan><tspan y="0" font-size="60">.JS</tspan></text>
|
||||
<g id="portaljs-balloon" transform="translate(1167.42 575.265)">
|
||||
<g id="Group_38" data-name="Group 38" transform="translate(13.425 12.18)">
|
||||
<g id="Group_34" data-name="Group 34" transform="translate(47.305)">
|
||||
<path id="Path_833" data-name="Path 833" d="M70.658,58.514V14.931c0-.749-.5-1.747.333-2.163,1-.5,1.913.333,2.745.749,16.3,8.234,22.706,20.627,21.292,36.181-1.248,13.89-7.236,26.7-13.557,39.341-2.246,4.575-4.658,8.983-6.987,13.557-.582,1.164-1.164,2.329-2.994,1.913-1.663-.416-.832-1.58-.832-2.412C70.575,87.625,70.658,73.07,70.658,58.514Z" transform="translate(-70.325 -12.253)" fill="#fdd036"/>
|
||||
<path id="Path_834" data-name="Path 834" d="M70.633,58.441l-.083-25.2L70.466,20.6V15.856a8.553,8.553,0,0,0-.083-1.5c0-.25-.083-.5-.083-.832a1.386,1.386,0,0,1,.333-.915,1.847,1.847,0,0,1,1.83-.333,5.652,5.652,0,0,1,1.414.749l1.414.749a47.5,47.5,0,0,1,10.4,7.236,31.366,31.366,0,0,1,7.4,10.314A33.708,33.708,0,0,1,95.918,43.8a58.59,58.59,0,0,1-1.081,12.642,89.125,89.125,0,0,1-3.493,12.227,118.932,118.932,0,0,1-4.907,11.644c-3.576,7.652-7.652,14.971-11.561,22.457a5.149,5.149,0,0,1-.915,1.414,2.067,2.067,0,0,1-1.663.582,2.461,2.461,0,0,1-.832-.166,1.958,1.958,0,0,1-.832-.416,1.386,1.386,0,0,1-.333-.915,2.461,2.461,0,0,1,.166-.832,8.553,8.553,0,0,0,.083-1.5V96.2l.083-12.642Zm0,0,.083,25.2L70.882,96.2v5.489a2.829,2.829,0,0,1-.083.832c-.083.5-.25,1,.083,1.248a2.77,2.77,0,0,0,1.248.416,1.645,1.645,0,0,0,1.164-.416,3.132,3.132,0,0,0,.749-1.248C77.786,95.038,81.695,87.552,85.1,79.9a104.531,104.531,0,0,0,8.151-23.621A51.758,51.758,0,0,0,94.42,43.886a33.44,33.44,0,0,0-2.662-12.06,31.631,31.631,0,0,0-6.987-10.147,43.958,43.958,0,0,0-10.064-7.319l-1.248-.665c-.5-.25-.915-.582-1.331-.749a1.137,1.137,0,0,0-1.164.166c-.25.25-.166.749-.083,1.248a10.008,10.008,0,0,1,0,1.58V20.68L70.8,33.323Z" transform="translate(-70.3 -12.18)" fill="#fff"/>
|
||||
</g>
|
||||
<g id="Group_35" data-name="Group 35" transform="translate(20.075 0.183)">
|
||||
<path id="Path_835" data-name="Path 835" d="M62.512,58.543c0,14.389,0,28.778-.083,43.167,0,.915,1,2.412-1,2.828-1.913.333-2-1.164-2.5-2.163C52.032,89.067,44.713,75.843,40.8,61.62c-2.828-10.314-3.992-20.71.832-30.857,3.66-7.735,10.314-13.225,18.631-17.466,2.828-1.414,2.246.416,2.246,1.58Z" transform="translate(-37.694 -12.464)" fill="#fdd036"/>
|
||||
<path id="Path_836" data-name="Path 836" d="M62.379,58.478,62.463,83.6l.083,12.559v5.489c0,.25.083.5.083.749.083.25.083.5.166.832a1.287,1.287,0,0,1-.25.915,1.677,1.677,0,0,1-.749.582,2.955,2.955,0,0,1-.832.166,3.73,3.73,0,0,1-.915-.083,1.327,1.327,0,0,1-.749-.582,6.3,6.3,0,0,1-.749-1.5C54.644,95.407,50.569,88,47.075,80.436a112.936,112.936,0,0,1-8.317-23.7,53.836,53.836,0,0,1-1.164-12.642A35.407,35.407,0,0,1,40.421,31.7a31.228,31.228,0,0,1,7.236-10.4A47.342,47.342,0,0,1,57.971,13.98c.5-.25.915-.5,1.414-.749a8.167,8.167,0,0,1,1.5-.665,2.955,2.955,0,0,1,.832-.166,1.055,1.055,0,0,1,.5.083,1,1,0,0,1,.416.416,1.95,1.95,0,0,1,.166.915l-.083.749L62.629,20.8,62.546,33.36Zm0,0L62.3,33.443l-.083-12.559-.166-6.238a3.811,3.811,0,0,0-.083-1.414c-.083-.166-.166-.166-.416-.166a2.571,2.571,0,0,0-.665.166,9.929,9.929,0,0,0-1.331.665c-.5.25-.915.5-1.331.749a41.491,41.491,0,0,0-9.981,7.4A32.062,32.062,0,0,0,41.42,32.2a34.722,34.722,0,0,0-2.578,11.977,47.635,47.635,0,0,0,1.248,12.31A107.863,107.863,0,0,0,48.157,80.02c3.41,7.652,7.319,14.971,11.062,22.457a10.5,10.5,0,0,0,.582,1.331,1.083,1.083,0,0,0,1.081.416c.416-.083,1-.166,1.164-.5.25-.25.166-.832,0-1.331a2.564,2.564,0,0,1-.083-.832V96.073l.25-12.476Z" transform="translate(-37.562 -12.4)" fill="#fff"/>
|
||||
</g>
|
||||
<g id="Group_36" data-name="Group 36" transform="translate(53.011 1.326)">
|
||||
<path id="Path_837" data-name="Path 837" d="M80.822,13.8a17.422,17.422,0,0,1,5.573,1c17.383,4.491,28.695,16.053,30.358,31.107.832,7.9-1.5,15.387-6.321,22.124-8.983,12.393-19.379,23.871-29.36,35.682-.665.749-1.5,1.414-2.578.915-1.164-.582-.083-1.414.25-2,5.989-11.561,12.227-23.039,16.219-35.266,3.244-9.9,5.406-19.879,3.077-30.192-2-9.066-7.486-16.385-16.136-22.041C81.571,14.713,80.905,14.547,80.822,13.8Z" transform="translate(-77.296 -13.777)" fill="#fdd036"/>
|
||||
<path id="Path_838" data-name="Path 838" d="M80.687,13.8a10.066,10.066,0,0,1,3.493.416c1.164.25,2.329.582,3.41.915l1.747.5c.582.166,1.081.416,1.663.582s1.164.416,1.663.582l1.663.665A41.117,41.117,0,0,1,106.3,25.024a33.1,33.1,0,0,1,10.979,25.534,28.561,28.561,0,0,1-1.164,7.07,38.642,38.642,0,0,1-2.745,6.654,57.634,57.634,0,0,1-3.992,5.989c-1.414,1.913-2.828,3.826-4.325,5.656C99.234,83.412,93.08,90.565,86.925,97.718l-4.658,5.406c-.416.5-.749.832-1.164,1.331a2.882,2.882,0,0,1-2,1,1.91,1.91,0,0,1-1.164-.333,1.559,1.559,0,0,1-.582-.5,1.219,1.219,0,0,1-.166-.915,3.5,3.5,0,0,1,.582-1c.083-.083.166-.25.25-.333a.631.631,0,0,1,.166-.333c2.163-4.159,4.408-8.4,6.488-12.559a165.626,165.626,0,0,0,10.9-26.033A70.138,70.138,0,0,0,98.4,49.644,41.682,41.682,0,0,0,97.321,35.67,32.256,32.256,0,0,0,91,23.194a45.56,45.56,0,0,0-4.907-4.907c-.915-.749-1.83-1.5-2.745-2.163l-1.414-1a3.906,3.906,0,0,1-.749-.5A1.012,1.012,0,0,1,80.687,13.8Zm0,0a.873.873,0,0,0,.416.749,3.372,3.372,0,0,0,.749.416l1.5,1c1,.665,1.913,1.414,2.828,2.163a35.969,35.969,0,0,1,5.074,4.99,33.7,33.7,0,0,1,6.737,12.476,42.611,42.611,0,0,1,1.331,14.14A66.862,66.862,0,0,1,96.656,63.7c-2.578,9.149-6.571,17.8-10.729,26.283-2.079,4.242-4.325,8.4-6.488,12.642a1.108,1.108,0,0,1-.25.416,1.46,1.46,0,0,1-.333.416c-.166.25-.333.416-.333.5v-.083l.083.083a1.182,1.182,0,0,0,.5.166,1.993,1.993,0,0,0,1.081-.582c.333-.333.749-.915,1.164-1.331L85.927,96.8C92.081,89.65,98.32,82.5,104.142,75.095c1.5-1.83,2.911-3.743,4.325-5.573a44.5,44.5,0,0,0,3.909-5.822,30.876,30.876,0,0,0,3.909-13.225,32.458,32.458,0,0,0-10.4-25.035A41.048,41.048,0,0,0,94.161,17.7l-1.58-.749a13.2,13.2,0,0,0-1.663-.582c-.582-.166-1.081-.416-1.663-.582l-1.663-.5c-1.164-.333-2.246-.665-3.41-1A10.158,10.158,0,0,0,80.687,13.8Z" transform="translate(-77.161 -13.775)" fill="#fff"/>
|
||||
</g>
|
||||
<g id="Group_37" data-name="Group 37" transform="translate(0 1.43)">
|
||||
<path id="Path_839" data-name="Path 839" d="M49.913,13.9c-9.648,6.321-15.72,14.306-17.633,24.536-1.414,7.4-.5,14.639,1.248,21.875,3.66,14.472,10.9,27.863,17.8,41.337.5.915,2,2.246.749,2.911-1.663.832-2.246-1-3.077-1.913-8.983-10.23-17.8-20.627-26.117-31.273-8.4-10.729-11.811-22.291-6.321-34.767C22.3,23.715,34.11,16.645,49.913,13.9Z" transform="translate(-13.504 -13.9)" fill="#fdd036"/>
|
||||
<path id="Path_840" data-name="Path 840" d="M49.834,13.9a49.042,49.042,0,0,0-10.48,9.4,33.267,33.267,0,0,0-6.238,12.476,41.029,41.029,0,0,0-1.081,13.89A70.4,70.4,0,0,0,34.78,63.388a156.877,156.877,0,0,0,10.813,25.95l3.244,6.321,1.58,3.161.832,1.58a8.665,8.665,0,0,0,.832,1.5,6.292,6.292,0,0,1,1,1.663,1.154,1.154,0,0,1,0,.749,1.608,1.608,0,0,1-.416.749,2.09,2.09,0,0,1-1.164.5,1.639,1.639,0,0,1-1.248-.25,7.5,7.5,0,0,1-.832-.749c-.416-.5-.665-1-1-1.414l-4.658-5.323c-6.155-7.153-12.227-14.389-18.049-21.708-2.911-3.66-5.989-7.4-8.151-11.644a34.16,34.16,0,0,1-4.076-13.64,25.721,25.721,0,0,1,.5-7.153,38.284,38.284,0,0,1,2.163-6.82,35.239,35.239,0,0,1,3.493-6.238l.5-.749.582-.665c.416-.5.749-.915,1.164-1.414.832-.832,1.58-1.747,2.5-2.578A40.857,40.857,0,0,1,36.36,17.726,53.237,53.237,0,0,1,49.834,13.9Zm0,0A62.8,62.8,0,0,0,36.36,17.892a39,39,0,0,0-11.644,7.735A33.141,33.141,0,0,0,16.9,37.105a32.144,32.144,0,0,0-2,6.654,27.3,27.3,0,0,0-.333,6.9,31.921,31.921,0,0,0,1.331,6.82,36.226,36.226,0,0,0,2.745,6.4c2.163,4.159,5.157,7.735,8.151,11.395C32.7,82.6,38.772,89.754,44.927,96.907l4.658,5.323c.416.5.749,1.081,1.081,1.414a2.205,2.205,0,0,0,.5.416.75.75,0,0,0,.416.083c.166,0,.416-.166.5-.166h0v-.083a6.561,6.561,0,0,0-.832-1.331,16.493,16.493,0,0,1-.915-1.663l-.832-1.58-1.58-3.161-3.161-6.321c-4.159-8.4-8.151-17.051-10.729-26.2a72.546,72.546,0,0,1-2.578-13.973A42.569,42.569,0,0,1,32.7,35.525a34.169,34.169,0,0,1,6.654-12.476A42.57,42.57,0,0,1,49.834,13.9Z" transform="translate(-13.425 -13.9)" fill="#fff"/>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</g>
|
||||
</svg>
|
||||
|
After Width: | Height: | Size: 8.2 KiB |
16
site/styles/globals.css
Normal file
16
site/styles/globals.css
Normal file
@@ -0,0 +1,16 @@
|
||||
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;
|
||||
}
|
||||
3
site/styles/tailwind.css
Normal file
3
site/styles/tailwind.css
Normal file
@@ -0,0 +1,3 @@
|
||||
@tailwind base;
|
||||
@tailwind components;
|
||||
@tailwind utilities;
|
||||
33
site/tailwind.config.js
Normal file
33
site/tailwind.config.js
Normal file
@@ -0,0 +1,33 @@
|
||||
const defaultTheme = require("tailwindcss/defaultTheme");
|
||||
|
||||
module.exports = {
|
||||
mode: 'jit',
|
||||
// purge: ['./pages/**/*.{js,ts,jsx,tsx}', './components/**/*.{js,ts,jsx,tsx}'],
|
||||
purge: [
|
||||
"./pages/**/*.js",
|
||||
"./pages/**/*.ts",
|
||||
"./pages/**/*.jsx",
|
||||
"./pages/**/*.tsx",
|
||||
"./components/**/*.js",
|
||||
"./components/**/*.ts",
|
||||
"./components/**/*.jsx",
|
||||
"./components/**/*.tsx"
|
||||
],
|
||||
darkMode: false, // or 'media' or 'class'
|
||||
theme: {
|
||||
container: {
|
||||
center: true,
|
||||
},
|
||||
extend: {
|
||||
fontFamily: {
|
||||
mono: ["Inconsolata", ...defaultTheme.fontFamily.mono]
|
||||
}
|
||||
},
|
||||
},
|
||||
variants: {
|
||||
extend: {},
|
||||
},
|
||||
plugins: [
|
||||
require('@tailwindcss/typography'),
|
||||
],
|
||||
}
|
||||
3591
site/yarn.lock
Normal file
3591
site/yarn.lock
Normal file
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user