Compare commits

..

16 Commits

Author SHA1 Message Date
Ola Rubaj
a580c2dc0a [guide/index.md][xs]: headings adjstmts 2023-07-28 15:35:18 +02:00
Ola Rubaj
a997a956b5 [site/content][xs]: minor fixes 2023-07-28 15:33:26 +02:00
Ola Rubaj
540a84d3f7 [site/content][s]: list howtos on the guide home page 2023-07-28 15:27:17 +02:00
Ola Rubaj
178659c6fe [site/content][s]: mv some files 2023-07-28 15:03:06 +02:00
Ola Rubaj
d8dfa8b682 [site/content][s]: rm duplicate howtos 2023-07-28 15:01:58 +02:00
Ola Rubaj
907ef9cbd3 [site/content][s]: delete duplicate howtos 2023-07-28 14:52:28 +02:00
Ola Rubaj
a8e399c59f [content/blog][s]: mv howto on formatting a perfect blog post from
markdownbased repo
2023-07-28 14:46:52 +02:00
Ola Rubaj
e7b71ec5c4 [content/blog][s]: mv howto on adding images from markdownbased repo 2023-07-28 14:31:04 +02:00
Ola Rubaj
eb987e139e [blog/*][xs]: add authors and dates 2023-07-28 14:11:08 +02:00
Ola Rubaj
845b98cca3 [site/content/blog/quicly-create-a-sandbox-website][xs]: adjust wiki links 2023-07-28 14:01:08 +02:00
Ola Rubaj
365bb3dfd3 [site/content][s]: mv howto on editing a page with code editor to
obsidian from markdownbased repo
2023-07-28 14:01:08 +02:00
Ola Rubaj
59a01f0f6f [site/content][s]: mv howto on adding a simple md page from
markdownbased repo
2023-07-28 14:01:08 +02:00
Ola Rubaj
a491fef5d0 [site/content][s]: mv howto on quickly creating a sandbox website from
markdownbased repo
2023-07-28 14:01:08 +02:00
Ola Rubaj
af0bc9da58 [site/content][s]: mv howto on editing and adding md pages locally from
markdownbased repo
2023-07-28 14:01:08 +02:00
Ola Rubaj
0b123a04ca [site/content][s]: mv howto on publishing obsidian vault to gh from
markdownbased repo
2023-07-28 14:01:08 +02:00
Ola Rubaj
0e2e2221fd [site/content][s]: mv howto on editing text on a single md page to blog
from markdownbased repo
2023-07-27 17:52:24 +02:00
38 changed files with 1412 additions and 14652 deletions

21
nx.json
View File

@@ -5,13 +5,7 @@
"default": {
"runner": "nx/tasks-runners/default",
"options": {
"cacheableOperations": [
"build",
"lint",
"test",
"e2e",
"build-storybook"
]
"cacheableOperations": ["build", "lint", "test", "e2e"]
}
}
},
@@ -36,14 +30,6 @@
"{workspaceRoot}/.eslintrc.json",
"{workspaceRoot}/.eslintignore"
]
},
"build-storybook": {
"inputs": [
"default",
"^production",
"{projectRoot}/.storybook/**/*",
"{projectRoot}/tsconfig.storybook.json"
]
}
},
"namedInputs": {
@@ -53,10 +39,7 @@
"!{projectRoot}/**/?(*.)+(spec|test).[jt]s?(x)?(.snap)",
"!{projectRoot}/tsconfig.spec.json",
"!{projectRoot}/jest.config.[jt]s",
"!{projectRoot}/.eslintrc.json",
"!{projectRoot}/**/*.stories.@(js|jsx|ts|tsx|mdx)",
"!{projectRoot}/.storybook/**/*",
"!{projectRoot}/tsconfig.storybook.json"
"!{projectRoot}/.eslintrc.json"
],
"sharedGlobals": ["{workspaceRoot}/babel.config.json"]
},

15315
package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@@ -20,20 +20,10 @@
"@nrwl/js": "15.9.2",
"@nrwl/linter": "15.9.2",
"@nrwl/next": "15.9.2",
"@nrwl/react": "^15.9.2",
"@nrwl/react": "15.9.2",
"@nrwl/rollup": "15.9.2",
"@nrwl/storybook": "15.9.2",
"@nrwl/webpack": "15.9.2",
"@nrwl/workspace": "15.9.2",
"@nx/js": "16.6.0",
"@rollup/plugin-url": "^7.0.0",
"@storybook/addon-essentials": "7.0.18",
"@storybook/addon-interactions": "7.0.18",
"@storybook/core-server": "7.0.18",
"@storybook/jest": "~0.1.0",
"@storybook/react-webpack5": "^7.0.18",
"@storybook/test-runner": "^0.11.0",
"@storybook/testing-library": "~0.2.0",
"@svgr/rollup": "^6.1.2",
"@swc/core": "^1.2.173",
"@swc/helpers": "~0.5.0",
@@ -49,7 +39,6 @@
"@typescript-eslint/parser": "^5.36.1",
"babel-jest": "^29.4.1",
"chai": "^4.3.7",
"core-js": "^3.6.5",
"cypress": "^12.2.0",
"eslint": "~8.15.0",
"eslint-config-next": "13.1.1",
@@ -69,16 +58,11 @@
"react-test-renderer": "18.2.0",
"rehype-stringify": "^9.0.3",
"remark": "^14.0.3",
"storybook-tailwind-dark-mode": "^1.0.22",
"swc-loader": "0.1.15",
"ts-jest": "^29.0.5",
"ts-node": "10.9.1",
"typescript": "~4.9.5",
"unist-util-select": "^4.0.3",
"unist-util-visit": "^4.1.2"
},
"dependencies": {
"react": "^18.2.0",
"react-dom": "^18.2.0"
}
}

View File

@@ -1,3 +0,0 @@
User-agent: *
Allow: /$
Disallow: /

View File

@@ -16,7 +16,7 @@
"build": "tsc && vite build && npm run build-tailwind && npm run fix-leaflet",
"lint": "eslint src --ext ts,tsx --report-unused-disable-directives --max-warnings 0",
"storybook": "storybook dev -p 6006",
"build-storybook": "storybook build && cp ./.storybook/robots.txt ./storybook-static",
"build-storybook": "storybook build",
"build-tailwind": "NODE_ENV=production npx tailwindcss --postcss -c tailwind.config.js -i src/index.css -o ./dist/style.css --minify",
"prepare": "npm run build",
"fix-leaflet": "node ./scripts/fix-leaflet.cjs"

View File

@@ -1,21 +0,0 @@
import type { StorybookConfig } from '@storybook/react-webpack5';
const config: StorybookConfig = {
stories: ['../src/**/*.stories.@(js|jsx|ts|tsx|mdx)'],
addons: [
'@storybook/addon-essentials',
'@storybook/addon-interactions',
'@nrwl/react/plugins/storybook',
'storybook-tailwind-dark-mode'
],
framework: {
name: '@storybook/react-webpack5',
options: {},
},
};
export default config;
// To customize your webpack configuration you can use the webpackFinal field.
// Check https://storybook.js.org/docs/react/builders/webpack#extending-storybooks-webpack-config
// and https://nx.dev/packages/storybook/documents/custom-builder-configs

View File

@@ -1,14 +0,0 @@
import './tailwind-imports.css';
const preview = {
globalTypes: {
darkMode: {
defaultValue: false, // Enable dark mode by default on all stories
},
className: {
defaultValue: 'dark', // Set your custom dark mode class name
},
},
};
export default preview;

View File

@@ -1,3 +0,0 @@
@tailwind base;
@tailwind components;
@tailwind utilities;

View File

@@ -1,31 +0,0 @@
{
"extends": "../tsconfig.json",
"compilerOptions": {
"emitDecoratorMetadata": true,
"outDir": ""
},
"files": [
"../../node_modules/@nx/react/typings/styled-jsx.d.ts",
"../../node_modules/@nx/react/typings/cssmodule.d.ts",
"../../node_modules/@nx/react/typings/image.d.ts"
],
"exclude": [
"src/**/*.spec.ts",
"src/**/*.test.ts",
"src/**/*.spec.js",
"src/**/*.test.js",
"src/**/*.spec.tsx",
"src/**/*.test.tsx",
"src/**/*.spec.jsx",
"src/**/*.test.js"
],
"include": [
"src/**/*.stories.ts",
"src/**/*.stories.js",
"src/**/*.stories.jsx",
"src/**/*.stories.tsx",
"src/**/*.stories.mdx",
".storybook/*.js",
".storybook/*.ts"
]
}

View File

@@ -1,11 +0,0 @@
// libs/shared/ui/postcss.config.js
const { join } = require('path');
module.exports = {
plugins: {
tailwindcss: {
config: join(__dirname, 'tailwind.config.js'),
},
autoprefixer: {},
},
};

View File

@@ -34,37 +34,6 @@
"jestConfig": "packages/core/jest.config.ts",
"passWithNoTests": true
}
},
"storybook": {
"executor": "@nrwl/storybook:storybook",
"options": {
"port": 4400,
"configDir": "packages/core/.storybook"
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"build-storybook": {
"executor": "@nrwl/storybook:build",
"outputs": ["{options.outputDir}"],
"options": {
"outputDir": "dist/storybook/core",
"configDir": "packages/core/.storybook"
},
"configurations": {
"ci": {
"quiet": true
}
}
},
"test-storybook": {
"executor": "nx:run-commands",
"options": {
"command": "test-storybook -c packages/core/.storybook --url=http://localhost:4400"
}
}
}
}

View File

@@ -1,48 +0,0 @@
import React from 'react';
import type { Meta, StoryObj } from '@storybook/react';
import { Card } from './Card';
const meta: Meta<typeof Card> = {
component: Card,
};
export default meta;
type Story = StoryObj<typeof Card>;
/*
*👇 Render functions are a framework specific feature to allow you control on how the component renders.
* See https://storybook.js.org/docs/react/api/csf
* to learn how to use render functions.
*/
const blog = {
urlPath: "#",
title: "Card title goes here",
date: "2021-01-01",
description: "Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed euismod, diam quis accumsan maximus, quam libero porttitor nisl, vita",
}
export const Primary: Story = {
render: () => (
<Card className="md:col-span-3">
<Card.Title href={`${blog.urlPath}`}>
{blog.title}
</Card.Title>
<Card.Eyebrow
as="time"
dateTime={blog.date}
className="md:hidden"
decorate
>
{blog.date}
</Card.Eyebrow>
{blog.description && (
<Card.Description>
{blog.description}
</Card.Description>
)}
<Card.Cta>Read article</Card.Cta>
</Card>
),
};

View File

@@ -1,44 +0,0 @@
const { createGlobPatternsForDependencies } = require('@nrwl/next/tailwind');
const { join } = require('path');
// const defaultTheme = require("tailwindcss/defaultTheme");
const colors = require("tailwindcss/colors");
module.exports = {
content: [
join(__dirname, './src/**/*.{js,ts,jsx,tsx}'),
...createGlobPatternsForDependencies(__dirname),
],
darkMode: "class",
theme: {
extend: {
// support wider width for large screens >1440px eg. in hero
maxWidth: {
"8xl": "88rem",
},
// fontFamily: {
// sans: ["ui-sans-serif", ...defaultTheme.fontFamily.sans],
// serif: ["ui-serif", ...defaultTheme.fontFamily.serif],
// mono: ["ui-monospace", ...defaultTheme.fontFamily.mono],
// headings: ["-apple-system", ...defaultTheme.fontFamily.sans],
// },
colors: {
background: {
DEFAULT: colors.white,
dark: colors.slate[900],
},
primary: {
DEFAULT: colors.gray[700],
dark: colors.gray[300],
},
secondary: {
DEFAULT: colors.sky[400],
dark: colors.sky[400],
},
},
},
},
/* eslint global-require: off */
// plugins: [
// require("@tailwindcss/typography")
// ],
};

View File

@@ -1,6 +1,5 @@
{
"compilerOptions": {
"baseUrl": ".",
"jsx": "react-jsx",
"module": "es2020",
"moduleResolution": "node",
@@ -23,9 +22,6 @@
},
{
"path": "./tsconfig.spec.json"
},
{
"path": "./.storybook/tsconfig.json"
}
]
}

View File

@@ -17,11 +17,7 @@
"**/*.spec.js",
"**/*.test.js",
"**/*.spec.jsx",
"**/*.test.jsx",
"**/*.stories.ts",
"**/*.stories.js",
"**/*.stories.jsx",
"**/*.stories.tsx"
"**/*.test.jsx"
],
"include": ["**/*.js", "**/*.jsx", "**/*.ts", "**/*.tsx"]
}

View File

@@ -1,65 +0,0 @@
import { ArticleJsonLd } from 'next-seo';
import { useRouter } from 'next/router';
export default function JSONLD({
meta,
source,
}: {
meta: any;
source: string;
}): JSX.Element {
if (!source) {
return <></>;
}
const baseUrl = process.env.NEXT_PUBLIC_SITE_URL || 'https://portaljs.org';
const pageUrl = `${baseUrl}/${meta.urlPath}`;
const imageMatches = source.match(
/(?<=src: ")(.*)\.((png)|(jpg)|(jpeg))(?=")/g
);
let images = [];
if (imageMatches) {
images = [...imageMatches];
images = images.map((img) =>
img.startsWith('http')
? img
: `${baseUrl}${img.startsWith('/') ? '' : '/'}${img}`
);
}
let Component: JSX.Element;
const isBlog: boolean =
/^blog\/.*/.test(meta.urlPath) || meta.filetype === 'blog';
const isDoc: boolean = /^((docs)|(howtos\/)|(guide\/)).*/.test(meta.urlPath);
if (isBlog) {
Component = (
<ArticleJsonLd
type="BlogPosting"
url={pageUrl}
title={meta.title}
datePublished={meta.date}
dateModified={meta.date}
authorName={meta.authors.length ? meta.authors[0].name : 'PortalJS'}
description={meta.description}
images={images}
/>
);
} else if (isDoc) {
Component = (
<ArticleJsonLd
url={pageUrl}
title={meta.title}
images={images}
datePublished={meta.date}
dateModified={meta.date}
authorName={meta.authors.length ? meta.authors[0].name : 'PortalJS'}
description={meta.description}
/>
);
}
return Component;
}

View File

@@ -54,14 +54,12 @@ function useTableOfContents(tableOfContents) {
export default function Layout({
children,
title,
description,
tableOfContents = [],
isHomePage = false,
sidebarTree = [],
}: {
children;
title?: string;
description?: string;
tableOfContents?;
urlPath?: string;
sidebarTree?: [];
@@ -84,7 +82,7 @@ export default function Layout({
return (
<>
{title && <NextSeo title={title} description={description} />}
{title && <NextSeo title={title} />}
<Nav />
<div className="mx-auto p-6 bg-background dark:bg-background-dark">
{isHomePage && <Hero />}

View File

@@ -264,7 +264,7 @@ The above script will output the following to the terminal:
## Done!
That's it! We've just created a simple catalog of our GitHub projects using markdown files and the MarkdownDB package. You can find the [full code for this tutorial here](https://github.com/datopian/markdowndb/tree/main/examples/basic-example).
That's it! We've just created a simple catalog of our GitHub projects using markdown files and the MarkdownDB package. You can find the full code for this tutorial [here](https://github.com/datopian/markdowndb/tree/main/examples/basic-example).
We look forward to seeing the amazing applications you'll build with this tool!

View File

@@ -1,7 +1,7 @@
const config = {
title: 'PortalJS - The JavaScript framework for data portals.',
description:
'PortalJS is a JavaScript framework for rapidly building rich data portal frontends using a modern frontend approach.',
'PortalJS is a framework for rapidly building rich data portal frontends using a modern frontend approach.',
theme: {
default: 'dark',
toggleIcon: '/images/theme-button.svg',

View File

@@ -1,7 +1,6 @@
---
title: 'Creating new datasets'
description: 'PortalJS Tutorial II - Learn how to create new datasets on a data portal'
---
<NextSeo title="Creating new datasets - PortalJS" />
# Creating new datasets
So far, the PortalJS app we created only has a single page displaying a dataset. Data catalogs and data portals generally showcase many different datasets.
@@ -11,7 +10,7 @@ Let's explore how to add and display more datasets to our portal.
As you have seen, in this example a dataset page is just a markdown file on disk plus a data file.
To create a new data showcase page we just create a new markdown file in the `content/` folder and a new data file in the `public/` folder.
To create a new data showcase page we just create a new markdown file in the `content/` folder and a new data file in the `public/` folder.
Let's do that now. Create a `content/my-incredible-dataset` folder, and inside this new folder create a `index.md` file with the following content:
@@ -20,7 +19,7 @@ Let's do that now. Create a `content/my-incredible-dataset` folder, and inside t
This is my incredible dataset.
## Chart
## Chart
<LineChart
title="US Population By Decade"
@@ -43,7 +42,7 @@ Year,Population (mi)
Note that pages are associated with a route based on their pathname, so, to see the new data page, access http://localhost:3000/my-incredible-dataset from the browser. You should see the following:
<img src="/assets/docs/my-incredible-dataset.png" alt="Page of a new dataset created on a PortalJS data portal" />
<img src="/assets/docs/my-incredible-dataset.png" />
> [!tip]
> In this tutorial we opted for storing content as markdown files and data as CSV files in the app, but PortalJS can have metadata, data and content stored anywhere.
@@ -59,11 +58,12 @@ List of available datasets:
- [My Awesome Dataset](/my-awesome-dataset)
- [My Incredible Dataset](/my-incredible-dataset)
```
From the browser, access http://localhost:3000. You should see the following:
<img src="/assets/docs/datasets-index-page.png" alt="PortalJS data portal with multiple datasets" />
<img src="/assets/docs/datasets-index-page.png" />
At this point, the app has multiple datasets, and users can find and navigate to any dataset they want. In the next lesson, you are going to learn how to improve this experience with search.

View File

@@ -1,7 +1,6 @@
---
title: Getting Started
description: 'Getting started guide and tutorial about data portal-building with PortalJS'
---
<NextSeo title="Getting Started - PortalJS" />
# Getting Started
Welcome to the PortalJS documentation!
@@ -39,7 +38,7 @@ Let's check it's working and what we have! Open http://localhost:3000 from your
You should see a page like this when you access http://localhost:3000. This is the starter template page which shows the most simple data portal you could have: a simple README plus csv file.
<img src="/assets/examples/basic-example.png" alt="Initial state of the PortalJS tutorial project" />
<img src="/assets/examples/basic-example.png" alt="Basic example" />
### Editing the Page
@@ -52,7 +51,7 @@ Lets try editing the starter page.
After refreshing the page, you should see the new text:
<img src="/assets/docs/editing-the-page-1.png" alt="PortalJS tutorial project after a simple change is made by a user" />
<img src="/assets/docs/editing-the-page-1.png" alt="Editing base example" />
Congratulations! The app is up and running and you learned how to edit a page. In the next lesson, you are going to learn how to create new datasets.

View File

@@ -26,7 +26,7 @@ This example makes use of the [markdowndb](https://github.com/datopian/markdownd
From the browser, access http://localhost:3000. You should see the following, you now have a searchable automatic list of your datasets:
![Simple data catalog built with PortalJS](https://i.imgur.com/9HfSPIx.png)
![](https://i.imgur.com/9HfSPIx.png)
To make this catalog look even better, we can change the text that is being displayed for each dataset to a title. Let's do that by adding the "title" [frontmatter field](https://daily-dev-tips.com/posts/what-exactly-is-frontmatter/) to the first dataset in the list. Change `content/my-awesome-dataset/index.md` to the following:
@@ -46,7 +46,7 @@ Built with PortalJS
Rerun `npm run mddb` and, from the browser, access http://localhost:3000. You should see the title appearing instead of the folder name:
![Example of a newly added dataset on a data catalog built with PortalJS](https://i.imgur.com/nvmSnJ5.png)
![](https://i.imgur.com/nvmSnJ5.png)
Any frontmatter attribute that you add will automatically get indexed and be usable in the search box.
@@ -102,7 +102,7 @@ List of available datasets:
You now have a filter in your page with all possible values automatically added to it.
![Data catalog with facets built with PortalJS](https://i.imgur.com/p2miSdg.png)
![](https://i.imgur.com/p2miSdg.png)
In the next lesson, you are going to learn how to display metadata on the dataset page.

View File

@@ -4,7 +4,7 @@
If you go now to `http://localhost:3000/my-awesome-dataset`, you will see that we now have two titles on the page. That's because `title` is one of the default metadata fields supported by PortalJS.
![Example of a page displaying the title metadata twice](https://i.imgur.com/O145uuc.png)
![](https://i.imgur.com/O145uuc.png)
Change the content inside `/content/my-awesome-dataset/index.md` to this.
@@ -15,7 +15,7 @@ author: 'Rufus Pollock'
description: 'An awesome dataset displaying some awesome data'
modified: '2023-05-04'
files: ['data.csv']
group: 'Awesome'
groups: ['Awesome']
---
Built with PortalJS
@@ -27,7 +27,7 @@ Built with PortalJS
Once you refresh the page at `http://localhost:3000/my-awesome-dataset` you should see something like this at the top:
![Example of a dataset page displaying metadata](https://i.imgur.com/nvDYJQT.png)
![](https://i.imgur.com/nvDYJQT.png)
These are the standard metadata fields that will be shown at the top of the page if you add them.
@@ -35,6 +35,6 @@ These are the standard metadata fields that will be shown at the top of the page
- `author`, `description`, and `modified` which gets displayed below the title
- `files` that get displayed as a table with two columns: `File` which is linked directly to the file, and `Format` which show the file format.
Feel free to experiment with these metadata fields. At this point, you might want to deploy the app, and that's what you are going to learn in the next lesson.
Feel free to experiment with these metadata fields. At this point, you might want to deploy the app, and that's what you are going to learn in the next lesson.
<DocsPagination prev="/docs/searching-datasets" next="/docs/deploying-your-portaljs-app" />

View File

@@ -3,7 +3,6 @@ showToc: false
showSidebar: false
title: 'Markdown-based Websites Guide'
disableTitle: true
description: Create markdown-based websites and data portals, update it, add collaborators and discover markdown superpowers with Flowershow and PortalJS
---
<Hero title="Markdown-based Websites" subtitle="Create markdown-based website, update it, add collaborators and discover markdown superpowers" />
@@ -86,105 +85,6 @@ Below is a screenshot of how the final website will look like:
> [!tip]
> Read full tutorial [[edit-a-website-locally|here!]]
### Tutorial 3: Collaborating with others on your website project
In this tutorial, we will guide you through collaborating with others on the same website project using GitHub.
By the end of this tutorial, you will:
- Understand what a branch is and how to create one.
- Understand what a pull request (PR) is and how to create one.
- Learn how to review and merge a PR.
- Know how to resolve conflicts if they arise.
- Collaborate with others using GitHub, following best practices.
#### Create a new branch
- Navigate to your site's repository on GitHub
- Click on the 'Branch' dropdown menu, type a new branch name and press Enter
- Yay! You've created a new branch! 🎉
#### Now, let's make changes in the new branch
- Switch to the new branch in GitHub Desktop
- Open the `/content` folder of the repository in Obsidian
- Edit the `about` page
- Commit the changes in GitHub Desktop app and push them to the remote repository on GitHub
#### Create a pull request (PR)
- Go back to your site's repository on GitHub
- Click on 'New pull request'
- Select your branch from the dropdown menu
- Write a brief description of your changes, then click on 'Create pull request'
- Yay! Your changes are ready to be reviewed! 🎉
#### Review and merge a pull request
- Navigate to the 'Pull requests' tab in your repository
- Open the newly created pull request
- Review the changes, add comments if necessary
- If everything is in order, click 'Merge pull request', then 'Confirm merge'
- Yay! You've merged your changes into the main branch! 🎉
#### Resolving conflicts
- In case of conflicts between your changes and those on the main branch, GitHub will alert you
- Follow the on-screen instructions to resolve the conflicts and merge your changes
> [!tip]
> Read full tutorial [[collaborate-on-website-project|here!]] (TBD)
### Tutorial 4: Customising your website locally and previewing your changes locally
In this tutorial, we will dive into the more technical aspects of website customisation, but this time, everything will be done locally. You'll learn how to preview your site on your own machine before pushing changes to the live site, ensuring everything looks and works exactly as you want.
By the end of this tutorial, you will:
- Understand how to preview your site locally.
- Know how to change your website's title and description.
- Learn how to customise your website's appearance using Tailwind themes.
- Understand how to configure the navbar, navigation links, and logo.
- Learn how to integrate Google Analytics into your website.
- Be aware of additional customisation options for deeper customisation.
#### Previewing the site locally
- Navigate to your website's repository directory on your computer using command line
- Install the site's dependencies
- Start the local development server
- Visit the local address displayed in your command line. Yay! You can now preview your changes locally, live! 🎉
#### Changing the site title and description
- Perfect! You've personalised your site's title and description! 🎉
#### Configuring the title, description and navbar
- Open the `content/config.mjs` file in your code editor
- Edit the `title` and `description` fields
- Edit the fields in the `navbar` field to customise your navbar's title and logo. Then, add navigation links to `navLinks` field (these will be displayed in the navbar). Save and refresh your local site to see the changes.
#### Integrating with Google Analytics
- Still in the `content/config.mjs` file, navigate to the `analytics` field
- Enter your Google Analytics tracking ID, save and refresh your local site to ensure it's integrated correctly
- Excellent! Your website is now integrated with Google Analytics! 🎉
#### Customising the Tailwind theme
- Open `tailwind.config.js` file in your code editor
- Change the light and dark theme colours and fonts to your liking, save and refresh your local site to see the changes
- Awesome! Your website now has a new look! 🎉
When you're happy with all your changes, use GitHub Desktop to commit your changes and push them back to your GitHub repository.
In addition to these topics, the full tutorial shows you what other customisations options are available and where to find information on these.
> [!tip]
> Read full tutorial here! (TBD)
## Howtos
- [[quickly-create-a-sandbox-website|How to quickly create a sandbox website]]

View File

@@ -1,7 +1,4 @@
---
title: How to add Google Analytics?
description: Learn to implement Google Analytics on PortalJS data portals
---
# How to add Google Analytics?
>[!todo] Prerequisites
>- [Google Analytics account](https://support.google.com/analytics/answer/9304153?hl=en)
@@ -77,4 +74,4 @@ export default function MyApp({ Component, pageProps }) {
```
>[!info]
> For more info on measuring pageviews with Google Analytics see [Google Analytics documentation](https://developers.google.com/analytics/devguides/collection/gtagjs/pages).
> For more info on measuring pageviews with Google Analytics see [Google Analytics documentation](https://developers.google.com/analytics/devguides/collection/gtagjs/pages).

View File

@@ -1,7 +1,4 @@
---
title: How to add a simple blog?
description: How to add a simple blog on a PortalJS data portal
---
# How to add a simple blog?
## Setup

View File

@@ -1,7 +1,4 @@
---
title: How to add user comments?
description: Learn how to add user comments on a PortalJS data portal
---
# How to add user comments?
![[comments-example.png]]

View File

@@ -1,7 +1,4 @@
---
title: How to create data-rich documents with charts and tables?
description: Learn how to create a data-rich document with charts and tables on a PortalJS data portal
---
# How to create data-rich documents with charts and tables?
> [!info] Prerequisites
> If you want to enrich your markdown content with charts and tables, you first need to add support for rendering markdown files in your PortalJS app. Follow [[markdown|this guide]] to learn how to do this.
@@ -18,12 +15,12 @@ Now, in order to use these components in your markdown files, we need to pass th
```tsx
// e.g. /blog/[[...slug]].tsx
import fs from 'fs';
import { LineChart, Table, Catalog, Vega, VegaLite } from '@portaljs/components';
import fs from "fs";
import { LineChart, Table, Catalog, Vega, VegaLite } from "@portaljs/components";
import { MdxRemote } from 'next-mdx-remote';
import clientPromise from '@/lib/mddb.mjs';
import parse from '@/lib/markdown';
import { MdxRemote } from "next-mdx-remote";
import clientPromise from "@/lib/mddb.mjs";
import parse from "@/lib/markdown";
const components = {
Table: Table,
@@ -32,35 +29,37 @@ const components = {
LineChart: LineChart,
};
export default function Page({ source }) {
source = JSON.parse(source);
return (
<>
<MdxRemote source={source} components={components} />
</>
);
export default function Page({ source }) {
source = JSON.parse(source);
return (
<>
<MdxRemote source={source} components={components} />
</>
);
}
// Import metadata of a file matching the static path and return its parsed source and frontmatter object
export const getStaticProps = async ({ params }) => {
const urlPath = params?.slug ? (params.slug as string[]).join('/') : '/';
const urlPath = params?.slug ? (params.slug as string[]).join("/") : "/";
const mddb = await clientPromise;
const dbFile = await mddb.getFileByUrl(urlPath);
const filePath = dbFile!.file_path;
// const frontMatter = dbFile!.metadata ?? {};
const mddb = await clientPromise;
const dbFile = await mddb.getFileByUrl(urlPath);
const filePath = dbFile!.file_path;
// const frontMatter = dbFile!.metadata ?? {};
const source = fs.readFileSync(filePath, { encoding: 'utf-8' });
const { mdxSource } = await parse(source, 'mdx', {});
const source = fs.readFileSync(filePath, { encoding: "utf-8" });
const { mdxSource } = await parse(source, "mdx", {});
return {
props: {
source: JSON.stringify(mdxSource),
// frontMatter
},
};
return {
props: {
source: JSON.stringify(mdxSource),
// frontMatter
},
};
};
```
You can now use these components in your markdown, like so:
@@ -94,39 +93,39 @@ Example usage:
cols={[
{
key: 'id',
name: 'ID',
name: 'ID'
},
{
key: 'firstName',
name: 'First name',
name: 'First name'
},
{
key: 'lastName',
name: 'Last name',
name: 'Last name'
},
{
key: 'age',
name: 'Age',
},
name: 'Age'
}
]}
data={[
{
age: 35,
firstName: 'Jon',
id: 1,
lastName: 'Snow',
lastName: 'Snow'
},
{
age: 42,
firstName: 'Cersei',
id: 2,
lastName: 'Lannister',
},
lastName: 'Lannister'
}
]}
/>
```
> [!info]
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-table--docs)
### Linechart
@@ -140,16 +139,31 @@ Example usage:
```js
<LineChart
data={[
['1850', -0.41765878],
['1851', -0.2333498],
['1852', -0.22939907],
['1853', -0.27035445],
['1854', -0.29163003],
[
'1850',
-0.41765878
],
[
'1851',
-0.2333498
],
[
'1852',
-0.22939907
],
[
'1853',
-0.27035445
],
[
'1854',
-0.29163003
]
]}
/>
/>
```
> [!info]
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-linechart--docs)
### Vega chart
@@ -165,30 +179,30 @@ Example usage:
table: [
{
x: 1850,
y: -0.418,
y: -0.418
},
{
x: 2020,
y: 0.923,
},
],
y: 0.923
}
]
}}
spec={{
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
data: {
name: 'table',
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative',
},
type: 'quantitative'
}
},
mark: 'bar',
mark: 'bar'
}}
/>
```
@@ -208,35 +222,35 @@ Example usage:
table: [
{
x: 1850,
y: -0.418,
y: -0.418
},
{
x: 2020,
y: 0.923,
},
],
y: 0.923
}
]
}}
spec={{
$schema: 'https://vega.github.io/schema/vega-lite/v4.json',
data: {
name: 'table',
name: 'table'
},
encoding: {
x: {
field: 'x',
type: 'ordinal',
type: 'ordinal'
},
y: {
field: 'y',
type: 'quantitative',
},
type: 'quantitative'
}
},
mark: 'bar',
mark: 'bar'
}}
/>
```
> [!info]
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-vegalite--docs)
### Catalog
@@ -255,21 +269,28 @@ Example usage:
metadata: {
'details-of-task': 'Detect and categorise abusive language in social media data',
language: 'Albanian',
'level-of-annotation': ['Posts'],
'level-of-annotation': [
'Posts'
],
'link-to-data': 'https://doi.org/10.6084/m9.figshare.19333298.v1',
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
medium: ['Text'],
medium: [
'Text'
],
'percentage-abusive': 13.2,
platform: ['Instagram', 'Youtube'],
platform: [
'Instagram',
'Youtube'
],
reference: 'Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592',
'size-of-dataset': 11874,
'task-description': 'Hierarchical (offensive/not; untargeted/targeted; person/group/other)',
title: 'Detecting Abusive Albanian',
title: 'Detecting Abusive Albanian'
},
url_path: 'dataset-4',
url_path: 'dataset-4'
},
]}
/>
/>
```
You can also add facets that are going to act as filters for your metadata.
@@ -284,23 +305,30 @@ You can also add facets that are going to act as filters for your metadata.
metadata: {
'details-of-task': 'Detect and categorise abusive language in social media data',
language: 'Albanian',
'level-of-annotation': ['Posts'],
'level-of-annotation': [
'Posts'
],
'link-to-data': 'https://doi.org/10.6084/m9.figshare.19333298.v1',
'link-to-publication': 'https://arxiv.org/abs/2107.13592',
medium: ['Text'],
medium: [
'Text'
],
'percentage-abusive': 13.2,
platform: ['Instagram', 'Youtube'],
platform: [
'Instagram',
'Youtube'
],
reference: 'Nurce, E., Keci, J., Derczynski, L., 2021. Detecting Abusive Albanian. arXiv:2107.13592',
'size-of-dataset': 11874,
'task-description': 'Hierarchical (offensive/not; untargeted/targeted; person/group/other)',
title: 'Detecting Abusive Albanian',
title: 'Detecting Abusive Albanian'
},
url_path: 'dataset-4',
url_path: 'dataset-4'
},
]}
facets={['platform', 'language']}
/>
/>
```
> [!info]
>[!info]
> More info on the [storybook page](https://storybook.portaljs.org/?path=/docs/components-catalog--docs)

View File

@@ -1,6 +1,5 @@
---
title: Guides and Tutorials
description: Learn more about how you can achieve different data portal features with PortalJS
---
- [[howtos/analytics|How to add web analytics?]]

View File

@@ -1,7 +1,4 @@
---
title: How to add markdown-based content pages?
description: Learn how to add markdown-based content pages on PortalJS data portals
---
# How to add markdown-based content pages?
## Add content layer to your app

View File

@@ -1,7 +1,4 @@
---
title: How to customize page metadata for SEO?
description: Learn to customize page metadata for SEO on data portals with PortalJS
---
# How to customize page metadata for SEO?
>[!info]
>See [`next-seo` documentation](https://github.com/garmeeh/next-seo) to learn more.
@@ -79,4 +76,4 @@ export default function Page() (
```
>[!info]
> To learn more on per-page SEO configuration with `next-seo`, see [this docs section](https://github.com/garmeeh/next-seo#add-seo-to-page)
> To learn more on per-page SEO configuration with `next-seo`, see [this docs section](https://github.com/garmeeh/next-seo#add-seo-to-page)

View File

@@ -1,7 +1,4 @@
---
title: How to build a sitemap?
description: Learn how to build a sitemap for a data portal with PortalJS
---
# How to build a sitemap?
## Setup
@@ -94,4 +91,4 @@ Add this to the scripts section in your `package.json` to regenerate the sitemap
"prebuild": "node ./scripts/sitemap.mjs",
```
```

View File

@@ -64,6 +64,13 @@ const parse = async function (source, format, scope) {
},
content(node) {
return [
h(
'span.invisible.block.h-0.w-0',
{ ariaLabel: node.properties.id },
'Read the “',
node.properties.id,
'” section'
),
h(
'svg',
{

View File

@@ -2,10 +2,4 @@
module.exports = {
siteUrl: process.env.SITE_URL || 'https://portaljs.org',
generateRobotsTxt: true,
robotsTxtOptions: {
policies: [
{ userAgent: '*', disallow: '/people' },
{ userAgent: '*', disallow: '/?amp=1' },
],
},
};
}

View File

@@ -12,7 +12,6 @@ import { GetStaticProps, GetStaticPropsResult } from 'next';
import { CustomAppProps } from './_app.jsx';
import computeFields from '@/lib/computeFields';
import { getAuthorsDetails } from '@/lib/getAuthorsDetails';
import JSONLD from '@/components/JSONLD';
export default function Page({ source, meta, sidebarTree }) {
source = JSON.parse(source);
@@ -30,18 +29,14 @@ export default function Page({ source, meta, sidebarTree }) {
}, [router.asPath]); // update table of contents on route change with next/link
return (
<>
<JSONLD meta={meta} source={source.compiledSource} />
<Layout
tableOfContents={tableOfContents}
title={meta.title}
description={meta.description}
sidebarTree={sidebarTree}
urlPath={meta.urlPath}
>
<MDXPage source={source} frontMatter={meta} />
</Layout>
</>
<Layout
tableOfContents={tableOfContents}
title={meta.title}
sidebarTree={sidebarTree}
urlPath={meta.urlPath}
>
<MDXPage source={source} frontMatter={meta} />
</Layout>
);
}

View File

@@ -3,15 +3,12 @@ import computeFields from '@/lib/computeFields';
import clientPromise from '@/lib/mddb';
import { BlogsList, SimpleLayout } from '@portaljs/core';
import * as fs from 'fs';
import { NextSeo } from 'next-seo';
import {NextSeo} from 'next-seo';
export default function Blog({ blogs }) {
return (
<>
<NextSeo
title="Blog posts"
description="Find news and more information about rapidly building rich data portals using a modern frontend framework in the PortalJS blog"
/>
<NextSeo title="Blog posts" />
<Layout>
<SimpleLayout title="Blog posts">
<BlogsList blogs={blogs} />
@@ -53,9 +50,12 @@ export async function getStaticProps() {
const blogList = await Promise.all(blogsWithComputedFields);
const blogsSorted = blogList.sort(
(a, b) => new Date(b?.date).getTime() - new Date(a?.date).getTime()
(a, b) =>
new Date(b?.date).getTime() -
new Date(a?.date).getTime()
);
return {
props: {
blogs: blogsSorted,

View File

@@ -8,7 +8,6 @@ import { useRouter } from 'next/router';
import { useEffect, useState } from 'react';
import { collectHeadings } from '@portaljs/core';
import Head from 'next/head';
import { LogoJsonLd } from 'next-seo';
export default function Home({ sidebarTree }) {
const router = useRouter();
@@ -25,10 +24,6 @@ export default function Home({ sidebarTree }) {
return (
<>
<LogoJsonLd
url="https://portaljs.org"
logo="https://portaljs.org/icon.png"
/>
<Layout
isHomePage={true}
tableOfContents={tableOfContents}

View File

@@ -15,10 +15,10 @@
"skipDefaultLibCheck": true,
"baseUrl": ".",
"paths": {
"@portaljs/core": ["packages/core/src/index.ts"],
"@portaljs/portaljs-components": [
"packages/portaljs-components/src/index.ts"
]
],
"@portaljs/core": ["packages/core/src/index.ts"]
}
},
"exclude": ["node_modules", "tmp"]