Merge pull request #784 from datopian/feature/content-structure
Content structure
This commit is contained in:
commit
ebb1bc09c4
@ -44,7 +44,6 @@ Access the Portal.JS documentation at:
|
||||
|
||||
https://portaljs.org/docs
|
||||
|
||||
- [Components](https://portaljs.org/docs/components)
|
||||
- [Examples](https://portaljs.org/docs#examples)
|
||||
|
||||
# Community
|
||||
|
||||
@ -17,8 +17,7 @@ const config = {
|
||||
},
|
||||
navLinks: [
|
||||
{ name: "Docs", href: "/docs" },
|
||||
{ name: "Components", href: "/docs/components" },
|
||||
{ name: "Learn", href: "/learn" },
|
||||
// { name: "Components", href: "/docs/components" },
|
||||
{ name: "Blog", href: "/blog" },
|
||||
// { name: "Gallery", href: "/gallery" },
|
||||
// { name: "Data Literate", href: "/data-literate" },
|
||||
|
||||
@ -1,589 +0,0 @@
|
||||
# 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
|
||||
|
||||
@ -31,11 +31,6 @@ You can check out the following examples built with Portal.js.
|
||||
|
||||
> The [`examples` directory](https://github.com/datopian/portal.js/tree/main/examples) is regularly updated with different portal examples.
|
||||
|
||||
|
||||
## Reference Information
|
||||
|
||||
* [Full list of the available components that are provided by Portal.JS](/docs/components)
|
||||
|
||||
## 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) or on our [Discord server](https://discord.gg/An7Bu5x8).
|
||||
|
||||
@ -1,95 +0,0 @@
|
||||
# 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.
|
||||
|
||||
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 and you should see the following page:
|
||||
|
||||

|
||||
|
||||
### Edit the page
|
||||
|
||||
Portal.js app is a Next.js/React.js based project. To edit the page follow these steps:
|
||||
|
||||
1. Open the project in your text editor.
|
||||
2. Go to `/pages/index.js` file.
|
||||
3. Find the `h2` tag with text that says **"Yay, the portal is open 🌀"** and change it to **"Hello World!"**.
|
||||
4. Save the file.
|
||||
|
||||
Once you've changed the file and saved it, the page on `localhost:3000` should update:
|
||||
|
||||

|
||||
|
||||
We won't dive into details of how to edit the pages as our focus is presenting data. To learn more about how to use Next.js and/or React, please visit the following sites:
|
||||
|
||||
* [Learn NextJS](https://nextjs.org/docs/getting-started)
|
||||
* [Getting started with React](https://reactjs.org/docs/getting-started.html#learn-react)
|
||||
|
||||
## Next steps
|
||||
|
||||
* [Presenting a dataset]()
|
||||
* [Putting your portal online]()
|
||||
* Deploy to GitHub Pages - [learn/deploy-to-gh-pages](/learn/deploy-to-gh-pages).
|
||||
* Learn how to build a portal for a single frictionless dataset - [learn/single-frictionless-dataset](/learn/single-frictionless-dataset).
|
||||
* Learn how to use Portal.js as a frontend for CKAN - [learn/ckan](/learn/ckan).
|
||||
@ -1,218 +0,0 @@
|
||||
Live DEMOs:
|
||||
|
||||
- https://catalog-portal-js.vercel.app
|
||||
- https://ckan-enterprise-frontend.vercel.app/
|
||||
|
||||
## Create a Portal app for CKAN
|
||||
|
||||
To create a Portal app, run the following command in your terminal:
|
||||
|
||||
```console
|
||||
npx create-next-app -e https://github.com/datopian/portal.js/tree/main/examples/ckan
|
||||
```
|
||||
|
||||
> NB: Under the hood, this uses the tool called create-next-app, which bootstraps an app for you based on our CKAN example.
|
||||
|
||||
## Guide
|
||||
|
||||
### Styling 🎨
|
||||
|
||||
We use Tailwind as a CSS framework. Take a look at `/styles/globals.css` to see what we're importing from Tailwind bundle. You can also configure Tailwind using `tailwind.config.js` file.
|
||||
|
||||
Have a look at Next.js support of CSS and ways of writing CSS:
|
||||
|
||||
https://nextjs.org/docs/basic-features/built-in-css-support
|
||||
|
||||
### Backend
|
||||
|
||||
So far the app is running with mocked data behind. You can connect CMS and DMS backends easily via environment variables:
|
||||
|
||||
```console
|
||||
$ export DMS=http://ckan:5000
|
||||
$ export CMS=http://myblog.wordpress.com
|
||||
```
|
||||
|
||||
> Note that we don't yet have implementations for the following CKAN features:
|
||||
>
|
||||
> - Activities
|
||||
> - Auth
|
||||
> - Groups
|
||||
> - Facets
|
||||
|
||||
### Routes
|
||||
|
||||
These are the default routes set up in the "starter" app.
|
||||
|
||||
- Home `/`
|
||||
- Search `/search`
|
||||
- Dataset `/@org/dataset`
|
||||
- Resource `/@org/dataset/r/resource`
|
||||
- Organization `/@org`
|
||||
- Collection (aka group in CKAN) (?) - suggest to merge into org
|
||||
- Static pages, eg, `/about` etc. from CMS or can do it without external CMS, e.g., in Next.js.
|
||||
|
||||
### New Routes
|
||||
|
||||
You can create new routes in `/pages` directory where each file is associated with a route based on its name. We suggest using [Next.JS docs][] for more detailed information.
|
||||
|
||||
[next.js docs]: https://nextjs.org/docs/basic-features/pages
|
||||
|
||||
### Data fetching
|
||||
|
||||
We use Apollo client which allows us to query data with GraphQL. We have setup CKAN API for the demo (it uses demo.ckan.org as DMS):
|
||||
|
||||
http://portal.datopian1.now.sh/
|
||||
|
||||
Note that we don't have Apollo Server but we connect CKAN API using [`apollo-link-rest`](https://www.apollographql.com/docs/link/links/rest/) module. You can see how it works in [lib/apolloClient.ts](https://github.com/datopian/portal/blob/master/lib/apolloClient.ts) and then have a look at [pages/\_app.tsx](https://github.com/datopian/portal/blob/master/pages/_app.tsx).
|
||||
|
||||
For development/debugging purposes, we suggest installing the Chrome extension - https://chrome.google.com/webstore/detail/apollo-client-developer-t/jdkknkkbebbapilgoeccciglkfbmbnfm.
|
||||
|
||||
### I18n configuration
|
||||
|
||||
Portal.js is configured by default to support both `English` and `French` subpath for language translation. But for subsequent users, this following steps can be used to configure i18n for other languages;
|
||||
|
||||
1. Update `next.config.js`, to add more languages to the i18n locales
|
||||
|
||||
```js
|
||||
i18n: {
|
||||
locales: ['en', 'fr', 'nl-NL'], // add more language to the list
|
||||
defaultLocale: 'en', // set the default language to use
|
||||
},
|
||||
```
|
||||
|
||||
2. Create a folder for the language in `locales` --> `locales/en-Us`
|
||||
|
||||
3. In the language folder, different namespace files (json) can be created for each translation. For the `index.js` use-case, I named it `common.json`
|
||||
|
||||
```json
|
||||
// locales/en/common.json
|
||||
{
|
||||
"title" : "Portal js in English",
|
||||
}
|
||||
|
||||
// locales/fr/common.json
|
||||
{
|
||||
"title" : "Portal js in French",
|
||||
}
|
||||
```
|
||||
|
||||
4. To use on pages using Server-side Props.
|
||||
|
||||
```js
|
||||
import { loadNamespaces } from './_app';
|
||||
import useTranslation from 'next-translate/useTranslation';
|
||||
|
||||
const Home: React.FC = ()=> {
|
||||
const { t } = useTranslation();
|
||||
return (
|
||||
<div>{t(`common:title`)}</div> // we use common and title base on the common.json data
|
||||
);
|
||||
};
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async ({ locale }) => {
|
||||
........ ........
|
||||
return {
|
||||
props : {
|
||||
_ns: await loadNamespaces(['common'], locale),
|
||||
}
|
||||
};
|
||||
};
|
||||
|
||||
```
|
||||
|
||||
5. Go to the browser and view the changes using language subpath like this `http://localhost:3000` and `http://localhost:3000/fr`. **Note** The subpath also activate chrome language Translator
|
||||
|
||||
### Pre-fetch data in the server-side
|
||||
|
||||
When visiting a dataset page, you may want to fetch the dataset metadata in the server-side. To do so, you can use `getServerSideProps` function from NextJS:
|
||||
|
||||
```javascript
|
||||
import { GetServerSideProps } from 'next';
|
||||
import { initializeApollo } from '../lib/apolloClient';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
const QUERY = gql`
|
||||
query dataset($id: String) {
|
||||
dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
|
||||
result
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
...
|
||||
|
||||
export const getServerSideProps: GetServerSideProps = async (context) => {
|
||||
const apolloClient = initializeApollo();
|
||||
|
||||
await apolloClient.query({
|
||||
query: QUERY,
|
||||
variables: {
|
||||
id: 'my-dataset'
|
||||
},
|
||||
});
|
||||
|
||||
return {
|
||||
props: {
|
||||
initialApolloState: apolloClient.cache.extract(),
|
||||
},
|
||||
};
|
||||
};
|
||||
```
|
||||
|
||||
This would fetch the data from DMS and save it in the Apollo cache so that we can query it again from the components.
|
||||
|
||||
### Access data from a component
|
||||
|
||||
Consider situation when rendering a component for org info on the dataset page. We already have pre-fetched dataset metadata that includes `organization` property with attributes such as `name`, `title` etc. We can now query only organization part for our `Org` component:
|
||||
|
||||
```javascript
|
||||
import { useQuery } from '@apollo/react-hooks';
|
||||
import gql from 'graphql-tag';
|
||||
|
||||
export const GET_ORG_QUERY = gql`
|
||||
query dataset($id: String) {
|
||||
dataset(id: $id) @rest(type: "Response", path: "package_show?{args}") {
|
||||
result {
|
||||
organization {
|
||||
name
|
||||
title
|
||||
image_url
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
`;
|
||||
|
||||
export default function Org({ variables }) {
|
||||
const { loading, error, data } = useQuery(
|
||||
GET_ORG_QUERY,
|
||||
{
|
||||
variables: { id: 'my-dataset' }
|
||||
}
|
||||
);
|
||||
|
||||
...
|
||||
|
||||
const { organization } = data.dataset.result;
|
||||
|
||||
return (
|
||||
<>
|
||||
{organization ? (
|
||||
<>
|
||||
<img
|
||||
src={
|
||||
organization.image_url
|
||||
}
|
||||
className="h-5 w-5 mr-2 inline-block"
|
||||
/>
|
||||
<Link href={`/@${organization.name}`} className="font-semibold text-primary underline">
|
||||
{organization.title || organization.name}
|
||||
</Link>
|
||||
</>
|
||||
) : (
|
||||
''
|
||||
)}
|
||||
</>
|
||||
);
|
||||
}
|
||||
```
|
||||
@ -1,251 +0,0 @@
|
||||
# Deploying data on Github using Portal.js and Github pages
|
||||
---
|
||||
**Use Case:**
|
||||
---
|
||||
You have some data in a Github repo and you'd like to deploy it online using "portal" so that it is easy for others to view, explore and use.
|
||||
---
|
||||
Here we show how you can use portal.js plus github actions to deploy your dataset in minutes and keep it updated as you make changes.
|
||||
|
||||
The example focuses on the case of a [Frictionless dataset][fd] but it works for any dataset type supported by portal.js.
|
||||
|
||||
We provide three options on how to do this and recommend using the first one unless you really want to get hands on:
|
||||
|
||||
* Deploying datasets automatically by setting up a github actions script.
|
||||
* Deploying datasets from a local bash script with portal code commits
|
||||
* Deploying datasets from a local bash script without portal code commits
|
||||
|
||||
[fd]: https://frictionlessdata.io/data-packages/
|
||||
|
||||
## Deploy datasets automatically by setting up a github actions script
|
||||
|
||||
The github actions below will automatically build and deploy a single page, Frictionless dataset to `gh-pages` branch. Follow the steps below to achieve this:
|
||||
|
||||
1. Create a secret so we can automatically commit to gh-pages branch (see below)
|
||||
2. Set up the github action to build portal to your dataset and deploy it (see below)
|
||||
3. Wait for your page to build and then setup github pages (see below)
|
||||
4. View the results: visit `https://<your github username>/github.io/<dataset repo name>/`
|
||||
|
||||
### Step 1
|
||||
|
||||
In the dataset repository you want to deploy, create a github secret with the name `PORTAL_REPO_NAME` and the value should be the name of the repository.
|
||||
|
||||
See steps on creating a secret [here](https://docs.github.com/en/actions/reference/encrypted-secrets)
|
||||
|
||||
<img src="/scripts/assets/secrets.png" />
|
||||
|
||||
### Step 2
|
||||
|
||||
In the dataset repository you want deploy create a `.github/workflow` directory and add a `main.yml` file with the following content (you can also view/download this [action file here](scripts/actions/single-dataset-ssg.yml):
|
||||
|
||||
```bash
|
||||
name: github pages
|
||||
|
||||
on:
|
||||
push:
|
||||
branches:
|
||||
- master
|
||||
- main
|
||||
|
||||
jobs:
|
||||
run:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Setup Node
|
||||
uses: actions/setup-node@v2.1.2
|
||||
with:
|
||||
node-version: '12.x'
|
||||
|
||||
- name: Build datasets
|
||||
env:
|
||||
PORTAL_REPO_NAME: ${{ secrets.PORTAL_REPO_NAME }}
|
||||
run: |
|
||||
curl https://raw.githubusercontent.com/datopian/portal.js/main/site/public/scripts/single-dataset-no-commit.sh > portal.sh
|
||||
git config --local user.email "$(git log --format='%ae' HEAD^!)"
|
||||
git config --local user.name "$(git log --format='%an' HEAD^!)"
|
||||
source ./portal.sh
|
||||
|
||||
```
|
||||
|
||||
Then, commit and push your code.
|
||||
|
||||
```bash
|
||||
git add .
|
||||
git commit -m "Build dataset page"
|
||||
git push
|
||||
```
|
||||
|
||||
### Step 3
|
||||
|
||||
Wait for a while as your page builds, and once you see the green check mark, navigate to your repository's github `pages` in settings, set the `source` to `gh-pages` and folder to `/root`:
|
||||
|
||||
<img src='/scripts/assets/sdnocommit.png' />
|
||||
|
||||
|
||||
## Deploy single dataset without commiting portal.js code
|
||||
|
||||
Users who want to deploy datasets from a local bash script without saving/commiting the portal.js code, can use the script shown below.
|
||||
|
||||
Using this script means you do not have access to the portal.js code used to generate the dataset page, and as such cannot modify/extend it.
|
||||
|
||||
This script creates and commit only the build/output files to the gh-pages branch. Follow the steps below to achieve this.
|
||||
|
||||
### Step 1
|
||||
|
||||
Clone/Pull the dataset repository you want deploy. For example:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/datasets/finance-vix
|
||||
cd finance-vix
|
||||
```
|
||||
|
||||
### Step 2
|
||||
|
||||
In a terminal, export an env variable with the name of your dataset github repo. For example if deploying https://github.com/datasets/finance-vix, then export the name as:
|
||||
|
||||
```bash
|
||||
export PORTAL_REPO_NAME=finance-vix
|
||||
```
|
||||
|
||||
### Step 3
|
||||
|
||||
In the dataset repository's root folder, create a file called `portal.sh` and paste the following [content](/scripts/single-dataset-no-commit.sh):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
git checkout -b gh-pages
|
||||
git rm -r --cached .
|
||||
rm -rf portal
|
||||
mkdir -p portal
|
||||
npx create-next-app portal -e https://github.com/datopian/portal.js/tree/main/examples/dataset-frictionless
|
||||
mkdir portal/public/dataset
|
||||
|
||||
cp -a ./data portal/public/dataset
|
||||
cp -a ./datapackage.json portal/public/dataset
|
||||
cp -a ./README.md portal/public/dataset
|
||||
|
||||
PORTAL_DATASET_PATH=$PWD"/portal/public/dataset"
|
||||
export PORTAL_DATASET_PATH
|
||||
|
||||
cd portal
|
||||
assetPrefix='"/'$PORTAL_REPO_NAME'/"'
|
||||
basePath='"/'$PORTAL_REPO_NAME'"'
|
||||
echo 'module.exports = {assetPrefix:' ${assetPrefix}', basePath: '${basePath}' }' > next.config.js ## This ensures css and public folder works
|
||||
yarn export
|
||||
|
||||
cd ..
|
||||
cp -R -a portal/out/* ./
|
||||
touch .nojekyll
|
||||
git add $PWD'/_next' $PWD'/index.html' $PWD'/dataset' $PWD'/404.html' $PWD'/.nojekyll' $PWD'/favicon.ico'
|
||||
git commit -m "Build new dataset page"
|
||||
git push origin gh-pages
|
||||
```
|
||||
|
||||
### Step 4
|
||||
|
||||
Run the bash script in a terminal with:
|
||||
|
||||
```bash
|
||||
source portal.sh
|
||||
```
|
||||
|
||||
> Note: Use `source` instead of `bash` so that the script can work well with environment variables.
|
||||
|
||||
### Step 5
|
||||
|
||||
Go to your repository's github `pages` in setting and set the Branch to gh-pages and folder to root:
|
||||
|
||||
<img src='/scripts/assets/sdnocommit.png' />
|
||||
|
||||
### Step 6
|
||||
|
||||
Open your deployed site at `https://<your github username>/github.io/<dataset repo name>`
|
||||
|
||||
|
||||
## Deploy single dataset with portal commit
|
||||
|
||||
Users who want access to the portal.js code used for generating the dataset page can use the script shown in the following section.
|
||||
|
||||
This script creates and commits the portal.js code to the root branch and also adds an automated script to deploy to gh-page. Follow the steps below to use this script.
|
||||
|
||||
### Step 1
|
||||
|
||||
Create a Github Personal Access Token (PAT). See steps [here](https://docs.github.com/en/github/authenticating-to-github/creating-a-personal-access-token)
|
||||
|
||||
### Step 2
|
||||
|
||||
In the dataset repository you want to deploy, create a github secret with the name `PORTAL_NEXT_TOKEN`. The value should be the PAT created in step 1. See steps on creating a secret [here](https://docs.github.com/en/actions/reference/encrypted-secrets)
|
||||
|
||||
> Note: Without the PAT and the secret configured, the automatic build will fail.
|
||||
|
||||
### Step 3
|
||||
|
||||
Clone/Pull the dataset repository you want deploy. For example:
|
||||
|
||||
```bash
|
||||
git clone https://github.com/datasets/finance-vix
|
||||
cd finance-vix
|
||||
```
|
||||
|
||||
### Step 4
|
||||
|
||||
In your computer's terminal/command prompt, export an environment variable with the name of your dataset's github repo.
|
||||
|
||||
For example if you want to deploy the dataset at https://github.com/datasets/finance-vix, then export the name using the command:
|
||||
|
||||
```bash
|
||||
export PORTAL_REPO_NAME=finance-vix
|
||||
```
|
||||
|
||||
### Step 5
|
||||
|
||||
Create a file called `portal.sh` and paste the following [content](/scripts/single-dataset-commit.sh):
|
||||
|
||||
```bash
|
||||
#!/bin/bash
|
||||
rm -rf portal
|
||||
mkdir -p portal
|
||||
npx create-next-app portal -e https://github.com/datopian/portal.js/tree/main/examples/dataset-frictionless
|
||||
mkdir portal/public/dataset
|
||||
|
||||
cp -a ./data portal/public/dataset
|
||||
cp -a ./datapackage.json portal/public/dataset
|
||||
cp -a ./README.md portal/public/dataset
|
||||
|
||||
PORTAL_DATASET_PATH=$PWD"/portal/public/dataset"
|
||||
export PORTAL_DATASET_PATH
|
||||
|
||||
mkdir -p .github && mkdir -p .github/workflows && touch .github/workflows/main.yml
|
||||
curl https://raw.githubusercontent.com/datopian/portal.js/main/site/public/scripts/gh-page-builder-action.yml > .github/workflows/main.yml
|
||||
|
||||
cd portal
|
||||
assetPrefix='"/'$PORTAL_REPO_NAME'/"'
|
||||
basePath='"/'$PORTAL_REPO_NAME'"'
|
||||
echo 'module.exports = {assetPrefix:' ${assetPrefix}', basePath: '${basePath}' }' > next.config.js ## This ensures css and public folder works
|
||||
|
||||
cd ..
|
||||
git add .
|
||||
git commit -m "Add dataset build feature"
|
||||
git push
|
||||
echo "Portal generated, please push your code to github"
|
||||
```
|
||||
|
||||
### Step 6
|
||||
|
||||
Run the bash script with:
|
||||
|
||||
```bash
|
||||
source portal.sh
|
||||
```
|
||||
|
||||
> Note: Use `source` instead of `bash` so that the script can work well with environment variables.
|
||||
|
||||
### Step 7
|
||||
|
||||
Go to your repository's github `pages` in setting and set the Branch to gh-pages and folder to root:
|
||||
|
||||
<img src='/scripts/assets/sdnocommit.png' />
|
||||
|
||||
### Step 8
|
||||
|
||||
Open your deployed site at `https://<your github username>/github.io/<dataset repo name>`
|
||||
@ -1,32 +0,0 @@
|
||||
Live Demo:
|
||||
- https://portal-js.vercel.app/
|
||||
|
||||
## Create a single frictionless dataset portal
|
||||
|
||||
The dataset should be a frictionless dataset i.e. it should have a [datapackage.json](https://specs.frictionlessdata.io/data-package/)
|
||||
|
||||
|
||||
Create a frictionless dataset portal app from the default template by executing the following command in your terminal:
|
||||
```
|
||||
$ npx create-next-app -e https://github.com/datopian/portal.js/tree/main/examples/dataset-frictionless
|
||||
```
|
||||
> Choose a name for your portal when prompted e.g. your-portal
|
||||
|
||||
Next, connect the frictionless dataset to `your-portal` by declaring the path to the directory level that contains the `datapackage.json` via an environment variable by executing the following command in your terminal:
|
||||
```
|
||||
$ cd your-portal
|
||||
$ export PORTAL_DATASET_PATH=path/to/your/dataset
|
||||
```
|
||||
In `your-portal` directory, run the command below in your terminal to start the portal:
|
||||
```
|
||||
$ yarn dev
|
||||
```
|
||||
Open the page in your browser via the localhost url(usually http://localhost:3000) returned in the terminal to see your frictionless dataset portal.
|
||||
|
||||
### Styling 🎨
|
||||
|
||||
We use Tailwind as a CSS framework. Take a look at `/styles/tailwind.css` to see what we're importing from Tailwind bundle. You can also configure Tailwind using `tailwind.config.js` file.
|
||||
|
||||
Have a look at Next.js support of CSS and ways of writing CSS:
|
||||
|
||||
https://nextjs.org/docs/basic-features/built-in-css-support
|
||||
@ -21,6 +21,17 @@ export async function getStaticProps() {
|
||||
extensions: ['md', 'mdx'],
|
||||
});
|
||||
|
||||
// Temporary, while MarkdownDB doesn't support filetypes
|
||||
// Merges docs that have the "blog" filetype
|
||||
let docs = await mddb.getFiles({
|
||||
folder: 'docs',
|
||||
extensions: ['md', 'mdx'],
|
||||
});
|
||||
|
||||
docs = docs.filter((doc) => doc.metadata.filetype === 'blog');
|
||||
|
||||
blogs = [...blogs, ...docs];
|
||||
|
||||
const blogsSorted = blogs.sort(
|
||||
(a, b) =>
|
||||
new Date(b.metadata.date).getTime() - new Date(a.metadata.date).getTime()
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user