├── .nvmrc
├── src
├── vite-env.d.ts
├── components
│ ├── rdf-guide
│ │ ├── triple.ttl
│ │ ├── person1.ttl
│ │ ├── organization.ttl
│ │ ├── name-interoperability.ttl
│ │ ├── person2.ttl
│ │ ├── person2-alternate.ttl
│ │ ├── person-shape.shex
│ │ ├── person.ttl
│ │ ├── index.tsx
│ │ ├── 6-querying.mdx
│ │ └── 7-beyond-rdf.mdx
│ ├── demo-list
│ │ └── style.module.css
│ ├── m-ld
│ │ ├── peer
│ │ │ └── styles.module.css
│ │ ├── demo
│ │ │ ├── styles.module.css
│ │ │ ├── code.mdx
│ │ │ └── index.tsx
│ │ ├── solid-demo
│ │ │ └── styles.module.css
│ │ ├── 4-solid-demo.mdx
│ │ ├── init-step
│ │ │ └── index.tsx
│ │ ├── index.tsx
│ │ ├── 2-install.mdx
│ │ └── 5-review.mdx
│ ├── typescript-guide
│ │ ├── types-example.ts
│ │ ├── interfaces-example.ts
│ │ ├── styles.module.css
│ │ ├── 4-interfaces.mdx
│ │ ├── 3-types.mdx
│ │ ├── 5-outro.mdx
│ │ ├── 1-intro.mdx
│ │ ├── index.tsx
│ │ └── 2-install.mdx
│ ├── sparql-guide
│ │ ├── sparql-simple-select.sparql
│ │ ├── sparql-name-select.sparql
│ │ ├── sparql-update-name.sparql
│ │ ├── index.tsx
│ │ ├── 1-intro.mdx
│ │ ├── 3-write.mdx
│ │ ├── 2-read.mdx
│ │ └── 4-sparql-builders.mdx
│ ├── library-header
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── guide-list
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── javascript-guide
│ │ ├── 8-asynchronous.js
│ │ ├── 8-synchronous.js
│ │ ├── 5-classes.js
│ │ ├── 6-modules.js
│ │ ├── 4-functions.js
│ │ ├── 9-outro.mdx
│ │ ├── 2-basics.js
│ │ ├── 7-web-apis.mdx
│ │ ├── index.tsx
│ │ ├── 5-classes.mdx
│ │ ├── 3-controls.js
│ │ ├── 8-asynchronous-code.mdx
│ │ └── 4-functions.mdx
│ ├── react-guide
│ │ ├── jsx-example.tsx
│ │ ├── 1-intro.mdx
│ │ ├── 5-community.mdx
│ │ ├── index.tsx
│ │ ├── 2-install.mdx
│ │ ├── 4-state-handling.mdx
│ │ └── 3-jsx.mdx
│ ├── shex-guide
│ │ ├── shex-example.shex
│ │ ├── 1-intro.mdx
│ │ ├── 4-outro.mdx
│ │ ├── index.tsx
│ │ ├── 2-simple-example.mdx
│ │ └── shex-advanced-example.shex
│ ├── frontpage
│ │ ├── demo
│ │ │ └── index.tsx
│ │ ├── style.module.css
│ │ ├── index.tsx
│ │ ├── 2-guides.mdx
│ │ ├── 1-intro.mdx
│ │ ├── reviews
│ │ │ ├── docs.mdx
│ │ │ ├── community.mdx
│ │ │ ├── devx.mdx
│ │ │ ├── overall.mdx
│ │ │ └── maturity.mdx
│ │ ├── 4-p2p.mdx
│ │ └── 3-local.mdx
│ ├── guide-header
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── rating
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── recommendation-list
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── review-list
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── rating-criteria-title
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── box
│ │ └── index.tsx
│ ├── loading
│ │ └── index.tsx
│ ├── navigation
│ │ ├── styles.module.css
│ │ ├── dropdown
│ │ │ ├── styles.module.css
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── inrupt
│ │ ├── 3-local-demo.mdx
│ │ ├── 4-solid-demo.mdx
│ │ ├── index.tsx
│ │ ├── 6-bias.mdx
│ │ ├── 2-install.mdx
│ │ ├── 1-intro.mdx
│ │ └── solid-demo
│ │ │ ├── useSolidDataset.ts
│ │ │ ├── demo.alternative.tsx
│ │ │ └── index.tsx
│ ├── rdf-ext
│ │ ├── 3-local-demo.mdx
│ │ ├── 2-install.mdx
│ │ ├── 4-solid-demo.mdx
│ │ ├── index.tsx
│ │ ├── 5-typescript-support.mdx
│ │ ├── 6-review.mdx
│ │ ├── solid-demo
│ │ │ └── index.tsx
│ │ └── local-demo
│ │ │ └── index.tsx
│ ├── ldo
│ │ ├── 4-local-demo.mdx
│ │ ├── 2-install.mdx
│ │ ├── 7-bias.mdx
│ │ ├── 1-intro.mdx
│ │ ├── index.tsx
│ │ ├── 5-solid-demo.mdx
│ │ ├── solid-react-demo
│ │ │ └── index.tsx
│ │ ├── 3-shapes.mdx
│ │ └── local-demo
│ │ │ └── index.tsx
│ ├── notification-list
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── soukai
│ │ ├── 4-local-demo.mdx
│ │ ├── Person.ts
│ │ ├── 2-install.mdx
│ │ ├── 5-solid-demo.mdx
│ │ ├── 1-intro.mdx
│ │ ├── index.tsx
│ │ ├── local-demo
│ │ │ └── index.tsx
│ │ ├── 3-models.mdx
│ │ ├── solid-demo
│ │ │ └── index.tsx
│ │ └── 6-review.mdx
│ ├── columns
│ │ ├── index.tsx
│ │ └── styles.module.css
│ ├── rdflib
│ │ ├── 3-local-demo.mdx
│ │ ├── 2-install.mdx
│ │ ├── store-hook.ts
│ │ ├── 7-bias.mdx
│ │ ├── 4-solid-demo.mdx
│ │ ├── 6-react.mdx
│ │ ├── index.tsx
│ │ ├── 1-intro.mdx
│ │ ├── local-demo
│ │ │ ├── index.tsx
│ │ │ └── code.mdx
│ │ └── solid-demo
│ │ │ ├── index.tsx
│ │ │ └── code.mdx
│ ├── quadstore
│ │ ├── 3-local-demo.mdx
│ │ ├── 4-sparql-demo.mdx
│ │ ├── 5-solid-demo.mdx
│ │ ├── 6-review.mdx
│ │ ├── 2-install.mdx
│ │ ├── 1-intro.mdx
│ │ ├── index.tsx
│ │ ├── local-demo
│ │ │ ├── index.tsx
│ │ │ └── code.mdx
│ │ └── sparql-demo
│ │ │ └── index.tsx
│ ├── login
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── logout-button
│ │ └── index.tsx
│ ├── content
│ │ ├── index.tsx
│ │ └── style.module.css
│ ├── solid-guide
│ │ ├── BrowserSolidLdoProvider-example.tsx
│ │ ├── index.tsx
│ │ ├── 3-authorization.mdx
│ │ ├── authentication-demo.tsx
│ │ ├── 5-apps.mdx
│ │ ├── 4-rdf.mdx
│ │ └── 1-intro.mdx
│ ├── card
│ │ ├── index.tsx
│ │ └── style.module.css
│ ├── comunica
│ │ ├── 2-install.mdx
│ │ ├── 6-review.mdx
│ │ ├── 3-solid-demo.mdx
│ │ ├── 1-intro.mdx
│ │ ├── solid-demo
│ │ │ ├── queries.ts
│ │ │ ├── index.tsx
│ │ │ └── code.mdx
│ │ ├── 5-rdf-sparql-builder-demo.mdx
│ │ ├── 4-sparql-builder-demo.mdx
│ │ └── index.tsx
│ ├── crdt-guide
│ │ ├── index.tsx
│ │ ├── 2-rdf.mdx
│ │ ├── 3-outro.mdx
│ │ └── 1-intro.mdx
│ ├── layout
│ │ ├── style.module.css
│ │ ├── footer
│ │ │ ├── style.module.css
│ │ │ └── index.tsx
│ │ └── index.tsx
│ ├── library-list
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── library-section
│ │ └── index.tsx
│ ├── rdf-sparql-builder-demo
│ │ ├── code.mdx
│ │ ├── queries.ts
│ │ └── index.tsx
│ ├── error-message
│ │ └── index.tsx
│ ├── code-link
│ │ └── index.tsx
│ ├── login-gate
│ │ └── index.tsx
│ ├── library-layout
│ │ └── index.tsx
│ ├── review
│ │ └── index.tsx
│ ├── guide-section
│ │ └── index.tsx
│ ├── sparql-builder-demo
│ │ ├── code.mdx
│ │ ├── queries.ts
│ │ └── index.tsx
│ ├── code
│ │ ├── step
│ │ │ └── index.tsx
│ │ └── style.module.css
│ ├── guide-layout
│ │ └── index.tsx
│ ├── notification
│ │ └── index.tsx
│ ├── author-note
│ │ ├── style.module.css
│ │ └── index.tsx
│ ├── serialization-list
│ │ └── index.tsx
│ ├── review-header
│ │ └── index.tsx
│ └── install
│ │ └── index.tsx
├── hooks
│ ├── use-notification
│ │ ├── index.tsx
│ │ ├── context.tsx
│ │ └── provider.tsx
│ ├── use-prism
│ │ └── index.ts
│ └── use-copy-to-clipboard
│ │ └── index.ts
├── libs
│ ├── error.ts
│ └── location.ts
└── namespaces.ts
├── public
├── arne.png
├── crdt.png
├── ldo.png
├── rdf.png
├── shex.png
├── inrupt.webp
├── profile.png
├── rdf-ext.png
├── rdfjs.png
├── shock.jpg
├── triple.png
├── n3_small.gif
├── javascript.png
├── linkeddata.png
├── typescript.png
├── quadstore-logo.png
├── json-ld-data-64.png
├── json-ld-logo-64.png
├── m-ld.svg
├── react.svg
├── rdf.svg
├── vite.svg
└── solid.svg
├── vercel.json
├── tsconfig.node.json
├── .gitignore
├── .eslintrc.cjs
├── typings
├── shims.d.ts
└── rdf-ext.d.ts
├── tsconfig.json
├── LICENSE
└── index.html
/.nvmrc:
--------------------------------------------------------------------------------
1 | v20.7.0
2 |
--------------------------------------------------------------------------------
/src/vite-env.d.ts:
--------------------------------------------------------------------------------
1 | ///
div-element with this text in it.
12 |
13 |
14 | Interfaces describes the shape of objects, and can be extended by other interfaces.
15 |
--------------------------------------------------------------------------------
/src/components/comunica/3-solid-demo.mdx:
--------------------------------------------------------------------------------
1 | import CodeSection from "./solid-demo/code.mdx";
2 | import Content from "../content";
3 | import ComunicaDemo from "./solid-demo";
4 | import LogoutButton from "../logout-button";
5 | import LoginGate from "../login-gate";
6 |
7 |
8 | Solid demo
9 |
10 | This demo requires you to authenticate with a Solid account.
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/guide-header/index.tsx:
--------------------------------------------------------------------------------
1 | import {Guide} from "../../constants";
2 | import {clsx} from "clsx";
3 | import styles from "./style.module.css";
4 |
5 | interface Props {
6 | guide: Guide
7 | }
8 |
9 | export default function GuideHeader({guide}: Props) {
10 | return <>
11 |
12 |
13 |
14 | {guide.name}
15 | >;
16 | }
--------------------------------------------------------------------------------
/src/components/m-ld/init-step/index.tsx:
--------------------------------------------------------------------------------
1 | import Content from "../../content";
2 | import Box from "../../box";
3 | import {HTMLAttributes} from "react";
4 | import {clsx} from "clsx";
5 |
6 | export default function MLdInitStep({className, ...props}: HTMLAttributes) {
7 | return
8 |
9 | This demo requires a bit of setup, so please start it by pressing the button.
10 |
11 |
12 |
13 | }
--------------------------------------------------------------------------------
/src/components/sparql-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {SPARQL_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import Read from "./2-read.mdx";
5 | import Write from "./3-write.mdx";
6 | import SPARQLBuilders from "./4-sparql-builders.mdx";
7 |
8 | export default function SPARQLGuide() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | )
17 | }
--------------------------------------------------------------------------------
/src/components/typescript-guide/3-types.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Code from "../code";
3 | import typesExample from "./types-example.ts?raw";
4 |
5 |
6 | Types
7 |
8 | TypeScript is all about types, and it allows you to define your own. Take the example below:
9 |
10 |
11 |
12 |
13 |
14 | It defines a type `Profile` that has one optional attribute, `name`, that must be a string.
15 |
--------------------------------------------------------------------------------
/src/components/comunica/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import {NavLink} from "react-router-dom";
3 |
4 |
5 | Comunica is a graph querying framework created by researchers at [Ghent University](https://www.ugent.be/ea/idlab/)
6 | and is currently developed by the [Comunica Association](https://comunica.dev/association/). It's focus lies on
7 | queries, which in the field of semantic technologies usually means SPARQL. If you're unfamiliar with SPARQL, I
8 | recommend you reading the SPARQL guide .
9 |
--------------------------------------------------------------------------------
/src/components/shex-guide/4-outro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Hopefully this has given you an idea for what ShEx can do for you. There is a lot more that it supports, such as the
5 | `+` cardinality token (meaning one or more), the referral to shapes (even itself) to create a tree of shapes, nested
6 | properties, and more.
7 |
8 | I encourage you to check out the [official website](https://shex.io/) first and foremost to learn more about ShEx,
9 | but there are other resources I can recommend as well.
10 |
11 |
--------------------------------------------------------------------------------
/src/components/quadstore/6-review.mdx:
--------------------------------------------------------------------------------
1 | import AuthorNote from "../author-note";
2 |
3 |
4 | I haven't used Quadstore enough to confidently review it. But it's low-level API seems to be efficient, and having
5 | SPARQL capabilities is impressive. The fact that you can choose between various backends that implements [the
6 | AbstractLevel interface](https://github.com/level/abstract-level) is also impressive, and should provide a lot of
7 | options to developers looking for low-level tools to handle RDF.
8 |
--------------------------------------------------------------------------------
/src/components/shex-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {SHEX_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import SimpleExample from "./2-simple-example.mdx";
5 | import AdvancedExample from "./3-advanced-example.mdx";
6 | import Outro from "./4-outro.mdx";
7 |
8 | export default function ShExGuide() {
9 | return (
10 |
11 |
12 |
13 |
14 |
15 |
16 | )
17 | }
--------------------------------------------------------------------------------
/src/components/frontpage/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Guides from "./2-guides.mdx";
3 | import Local from "./3-local.mdx";
4 | import P2P from "./4-p2p.mdx";
5 | import Solid from "./5-solid.mdx";
6 | import Reviews from "./6-reviews.mdx";
7 | import Demo from "./7-demo.mdx";
8 | import About from "./8-about.mdx";
9 |
10 | export default function Frontpage() {
11 | return <>
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | >;
21 | }
--------------------------------------------------------------------------------
/src/components/comunica/solid-demo/queries.ts:
--------------------------------------------------------------------------------
1 | export function select(webId: string): string {
2 | return `
3 | PREFIX foaf:
4 | SELECT ?name WHERE {
5 | <${webId}> foaf:name ?name .
6 | } LIMIT 1`;
7 | }
8 |
9 | export function update(webId: string, oldName: string, newName: string) {
10 | return `
11 | PREFIX foaf:
12 | DELETE { <${webId}> foaf:name "${oldName}" }
13 | INSERT { <${webId}> foaf:name "${newName}" }
14 | WHERE { <${webId}> foaf:name "${oldName}" }`;
15 | }
--------------------------------------------------------------------------------
/src/components/notification-list/index.tsx:
--------------------------------------------------------------------------------
1 | import style from "./style.module.css";
2 | import Notification from "../notification";
3 | import useNotification from "../../hooks/use-notification";
4 |
5 | export default function NotificationList() {
6 | const {notifications} = useNotification();
7 |
8 | return (
9 |
10 | {notifications.filter(({hidden}) => !hidden).map((notification, index) => (
11 |
12 | ))}
13 |
14 | )
15 | }
--------------------------------------------------------------------------------
/src/components/quadstore/2-install.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Install from "../install";
3 |
4 |
5 | Installation
6 |
7 | To get started with Quadstore, install it using your favorite package manager.
8 |
9 |
10 |
11 |
12 |
13 | If you want to use the SPARQL features as well, make sure to install `quadstore-comunica` as well:
14 |
15 |
16 |
17 |
18 |
19 | To understand how it can be used, check out the demos.
20 |
--------------------------------------------------------------------------------
/src/components/rdf-sparql-builder-demo/code.mdx:
--------------------------------------------------------------------------------
1 | import demoCode from "./index.tsx?raw";
2 | import Code from "../code";
3 | import CodeStep from "../code/step";
4 |
5 |
6 |
7 | Using the `sparql.select` function we start building our query to get a name.
8 |
9 |
10 | For this query we start off with the `sparql.deleteQuery` function.
11 |
12 |
13 |
--------------------------------------------------------------------------------
/src/components/error-message/index.tsx:
--------------------------------------------------------------------------------
1 | import {HTMLAttributes} from "react";
2 | import {clsx} from "clsx";
3 |
4 | interface Props extends HTMLAttributes {
5 | error?: Error
6 | }
7 |
8 | export default function ErrorMessage({ className, error, ...props }: Props) {
9 | return (
10 |
11 | Error
12 | {error?.message || error?.name || "Error happened (lost context)"}
13 |
14 | );
15 | }
--------------------------------------------------------------------------------
/src/components/typescript-guide/5-outro.mdx:
--------------------------------------------------------------------------------
1 | import AuthorNote from "../author-note";
2 | import {BsFillHeartFill} from "react-icons/bs";
3 | import styles from "./styles.module.css";
4 |
5 | I TypeScript}>
7 | As I mentioned, I enjoy coding with TypeScript. I'll use it in most of my projects, if not all. This website is not
8 | an exemption. So even if you're amongst those that despise TypeScript or find it unnecessary, I hope you find value
9 | in the code I share ^_^
10 |
11 |
--------------------------------------------------------------------------------
/public/react.svg:
--------------------------------------------------------------------------------
1 |
--------------------------------------------------------------------------------
/.eslintrc.cjs:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | root: true,
3 | env: {browser: true, es2020: true},
4 | extends: [
5 | 'eslint:recommended',
6 | 'plugin:@typescript-eslint/recommended',
7 | 'plugin:react-hooks/recommended',
8 | ],
9 | ignorePatterns: ['dist', '.eslintrc.cjs'],
10 | parser: '@typescript-eslint/parser',
11 | plugins: ['react-refresh'],
12 | rules: {
13 | 'react-refresh/only-export-components': [
14 | 'warn',
15 | {allowConstantExport: true},
16 | ],
17 | "@typescript-eslint/no-explicit-any": "warn"
18 | },
19 | }
20 |
--------------------------------------------------------------------------------
/src/components/m-ld/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import P2PDemo from "./3-p2p-demo.mdx";
4 | import SolidDemo from "./4-solid-demo.mdx";
5 | import Review from "./5-review.mdx";
6 | import {LIBRARY_M_LD} from "../../constants";
7 | import LibraryLayout from "../library-layout";
8 |
9 | export default function MLd() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
--------------------------------------------------------------------------------
/src/components/typescript-guide/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | [TypeScript](https://www.typescriptlang.org/) is a superset of JavaScript, adding additional syntax. By allowing us
5 | to type our interfaces we can communicate to other developers how to use our work. Although not often, sometimes
6 | you'll see the use of types in the JavaScript-code on this website. That's because it's actually TypeScript that's
7 | shown. Although not necessary, I find TypeScript eases my workflow as a developer, and I appreciate tools that allow
8 | me to elevate types.
9 |
10 |
--------------------------------------------------------------------------------
/src/components/code-link/index.tsx:
--------------------------------------------------------------------------------
1 | import {NavLink} from "react-router-dom";
2 | import {ReactNode} from "react";
3 |
4 | interface Props {
5 | children?: ReactNode
6 | id: string
7 | lines: string[];
8 | }
9 |
10 | function toCodePart(id: string, line: string, ...lines: string[]): string {
11 | const dataLines = [line, ...lines].map((value) => `data-line=${value}`).join("&");
12 | return `?${dataLines}#${id}`;
13 | }
14 |
15 | export default function CodeLink({children, id, lines}: Props) {
16 | return {children}
17 | }
--------------------------------------------------------------------------------
/src/components/login-gate/index.tsx:
--------------------------------------------------------------------------------
1 | import {useSolidAuth} from "@ldo/solid-react";
2 | import Box from "../box";
3 | import Login from "../login";
4 | import {HTMLAttributes, ReactNode} from "react";
5 |
6 | interface Props extends HTMLAttributes{
7 | children: ReactNode
8 | redirectId?: string
9 | }
10 |
11 | export default function LoginGate({children, redirectId, ...props}: Props) {
12 | const {session, login} = useSolidAuth();
13 | return session.isLoggedIn ? children : (
14 |
15 |
16 |
17 | );
18 | }
--------------------------------------------------------------------------------
/src/components/javascript-guide/2-basics.js:
--------------------------------------------------------------------------------
1 | var variableName = 1337;
2 | let dynamicVariable = 42;
3 | const constantVariable = "This is a constant";
4 |
5 | const numberVariable = 42;
6 | const stringVariable = "Some text";
7 | const dateVariable = new Date();
8 | const booleanVariable = true;
9 |
10 | const arrayVariable = [numberVariable, stringVariable, dateVariable, booleanVariable];
11 | const mapVariable = {
12 | numberKey: numberVariable,
13 | stringKey: stringVariable,
14 | dateKey: dateVariable,
15 | booleanKey: booleanVariable,
16 | }
17 | const setVariable = new Set([numberVariable, numberVariable, stringVariable]);
--------------------------------------------------------------------------------
/src/components/solid-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {SOLID_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import Authentication from "./2-authentication.mdx";
5 | import Authorization from "./3-authorization.mdx";
6 | import RDF from "./4-rdf.mdx";
7 | import Apps from "./5-apps.mdx";
8 |
9 | export default function SolidGuide() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
--------------------------------------------------------------------------------
/src/components/typescript-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {TYPESCRIPT_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import Install from "./2-install.mdx";
5 | import Types from "./3-types.mdx";
6 | import Interfaces from "./4-interfaces.mdx";
7 | import Outro from "./5-outro.mdx";
8 |
9 | export default function TypeScriptGuide() {
10 | return (
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 | )
19 | }
--------------------------------------------------------------------------------
/src/components/react-guide/5-community.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Community
5 |
6 | Another great aspect of using React is being able to partake in the React community. React has a lot of developers
7 | using it, so many problems you face have been solved by the community already.
8 |
9 | There is also a lot of tools being built around it (this website being one example of that), with popular frameworks
10 | such as [Next.js](https://nextjs.org/) serving it explicitly or [Vite](https://vitejs.dev/) that treats it as a
11 | first-class citizen.
12 |
13 |
--------------------------------------------------------------------------------
/src/components/ldo/2-install.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Install from "../install";
3 |
4 |
5 | Installation
6 |
7 | To get started with LDO, install it using your favorite package manager.
8 |
9 |
10 |
11 |
12 |
13 | If you want to design your own ShEx-shapes and generate LDO resources, you'll also need
14 | [@ldo/cli](https://github.com/o-development/ldo/tree/main/packages/cli):
15 |
16 |
17 |
18 |
19 |
20 | To understand how it can be used, check out the demos.
21 |
--------------------------------------------------------------------------------
/src/components/layout/footer/style.module.css:
--------------------------------------------------------------------------------
1 | .footer {
2 | display: flex;
3 | flex-direction: column;
4 | }
5 |
6 | .footerMeta {
7 | align-items: center;
8 | display: flex;
9 | flex-direction: column;
10 | justify-content: center;
11 | gap: 0.5rem;
12 | margin: 0.5rem 0;
13 |
14 | @media screen and (min-width: 800px) {
15 | align-items: revert;
16 | flex-direction: row;
17 | gap: 3rem;
18 | }
19 | }
20 |
21 | .footerItem {
22 | display: flex;
23 | gap: 0.5em;
24 | justify-content: center;
25 | }
26 |
27 | .footerNav {
28 | display: flex;
29 | flex-wrap: wrap;
30 | gap: 0.5em;
31 | }
--------------------------------------------------------------------------------
/src/components/rating-criteria-title/index.tsx:
--------------------------------------------------------------------------------
1 | import {RATING_CRITERIA} from "../../constants";
2 | import Rating, {RatingScore} from "../rating";
3 | import {clsx} from "clsx";
4 | import styles from "./style.module.css";
5 |
6 | interface Props {
7 | index: 0 | 1 | 2 | 3 | 4;
8 | rating?: RatingScore
9 | }
10 |
11 | export default function RatingCriteriaTitle({index, rating}: Props) {
12 | return (
13 |
14 | {RATING_CRITERIA[index][1]}
15 |
16 |
17 | )
18 | }
--------------------------------------------------------------------------------
/src/components/m-ld/demo/code.mdx:
--------------------------------------------------------------------------------
1 | import Code from "../../code";
2 | import demoCode from "./index.tsx?raw";
3 | import CodeStep from "../../code/step";
4 |
5 |
6 |
7 | If there's an error, show it using the `ErrorMessage` component.
8 |
9 |
10 | This lays out the view that "wraps" around the peer demos, to ensure their layout on various screen sizes, and
11 | that provides a link to open the peer demo in a new window.
12 |
13 |
--------------------------------------------------------------------------------
/src/components/rdflib/6-react.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Code from "../code";
3 | import CodeLink from "../code-link";
4 | import storeHookCode from "./store-hook.ts?raw";
5 |
6 |
7 | Tips on React
8 |
9 | If you're going to use rdflib.js with React, I would encourage you to use this hook:
10 |
11 |
12 |
13 |
14 | It should allow you to easily access a global store. (It is basically the same code used in
15 | the Solid demo .)
16 |
--------------------------------------------------------------------------------
/src/components/comunica/5-rdf-sparql-builder-demo.mdx:
--------------------------------------------------------------------------------
1 | import CodeSection from "../rdf-sparql-builder-demo/code.mdx";
2 | import Content from "../content";
3 | import Install from "../install";
4 |
5 |
6 | Alternative: rdf-sparql-builder
7 |
8 | Another SPARQL builder is [rdf-sparql-builder](https://github.com/rdf-ext/rdf-sparql-builder), which sports a bit
9 | different API than @tpluscode/sparql-builder.
10 |
11 |
12 |
13 |
14 |
15 | This demo is similar to the previous demos, so I'll only point out the differences.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/inrupt/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import LocalDemo from "./3-local-demo.mdx";
4 | import SolidDemo from "./4-solid-demo.mdx";
5 | import Review from "./5-review.mdx";
6 | import Bias from "./6-bias.mdx";
7 | import {LIBRARY_INRUPT} from "../../constants";
8 | import LibraryLayout from "../library-layout";
9 |
10 | export default function Inrupt() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/ldo/7-bias.mdx:
--------------------------------------------------------------------------------
1 | import AuthorNote from "../author-note";
2 |
3 |
4 | As you have probably understood by now, I'm quite fond of LDO. Although I won't say I'm overly biased, there is the
5 | fact that I know Jackson Morgan and consider him a Solid friend (dum-dum-tsh). We're former colleagues from my time
6 | in Inrupt, and we've worked together here and there.
7 |
8 | That said, I will say that my fondness of LDO comes from its API. I'm very much in love with the expressiveness and
9 | power that it provides, and I hope to see more greatness come from the [LDO
10 | project](https://github.com/o-development/ldo/).
11 |
--------------------------------------------------------------------------------
/src/components/library-layout/index.tsx:
--------------------------------------------------------------------------------
1 | import LibraryHeader from "../library-header";
2 | import {Library} from "../../constants";
3 | import LibrarySection from "../library-section";
4 | import GuideSection from "../guide-section";
5 | import {ReactNode} from "react";
6 |
7 | interface Props {
8 | library: Library;
9 | children: ReactNode;
10 | }
11 |
12 | export default function LibraryLayout({children, library}: Props) {
13 | return (
14 | <>
15 |
16 | {children}
17 |
18 |
19 | >
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/soukai/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | [Soukai](https://soukai.js.org/) is a project by Noel De Martin where he tries to create an easy way to manage
5 | non-relational database objects in JavaScript. It uses various engines as adapters for various storages, e.g. **you
6 | can switch engines dynamically depending on whether you want to store data in memory, `localStorage`, or an online
7 | resource** (like a Solid Pod).
8 |
9 | For the last use-case Noel has developed [Soukai Solid](https://github.com/NoelDeMartin/soukai-solid), which
10 | extends the model proposed by "core" Soukai so that it's interoperable with RDF.
11 |
--------------------------------------------------------------------------------
/src/components/comunica/4-sparql-builder-demo.mdx:
--------------------------------------------------------------------------------
1 | import CodeSection from "../sparql-builder-demo/code.mdx";
2 | import Content from "../content";
3 | import Install from "../install";
4 |
5 |
6 | Alternative: @tpluscode/sparql-builder
7 |
8 | If you prefer a bit of help with building the SPARQL query,
9 | [@tpluscode/sparql-builder](https://github.com/tpluscode/sparql-builder) might be an interesting choice.
10 |
11 |
12 |
13 |
14 |
15 | This demo is also very similar to the previous code, so I'll just emphasize the differences.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/soukai/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import Models from "./3-models.mdx";
4 | import LocalDemo from "./4-local-demo.mdx";
5 | import SolidDemo from "./5-solid-demo.mdx";
6 | import Review from "./6-review.mdx";
7 | import {LIBRARY_SOUKAI} from "../../constants";
8 | import LibraryLayout from "../library-layout";
9 |
10 | export default function Soukai() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/review/index.tsx:
--------------------------------------------------------------------------------
1 | import {ReactNode} from "react";
2 | import Rating, {RatingScore} from "../rating";
3 |
4 | interface Props {
5 | children: Array<[RatingScore, ReactNode]>;
6 | }
7 |
8 | export default function Review({children}: Props) {
9 | return (
10 |
11 |
12 | {children.map(([rating, review], index) => (
13 |
14 |
15 | {review}
16 |
17 | ))}
18 |
19 |
20 | );
21 | }
--------------------------------------------------------------------------------
/src/components/frontpage/2-guides.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import GuideList from "../guide-list";
3 |
4 |
5 | "Wait, what is RDF?" or "what kinda JS is this?"
6 |
7 | Fear not, friend, I've got you covered! I've written some guides to technologies that might be of interest if you
8 | want to learn more about the demos. Also, the JavaScript examples on this website are using TypeScript and React, so
9 | I've introduced them in a couple of guides as well.
10 |
11 |
12 |
13 |
14 |
15 | Did I miss something? [Let me know](https://github.com/megoth/semtechjs-demo/issues).
16 |
--------------------------------------------------------------------------------
/src/components/ldo/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import {NavLink} from "react-router-dom";
3 |
4 |
5 | Linked Data Objects (LDO) is a set of libraries that focus around using ShEx shapes to
6 | describe data you want to interact with. It's still new and some parts are in alpha (or just simply experimental),
7 | but it shows great promises for developers who enjoy using types in their work (such as me). By transpiling the ShEx
8 | shapes into JSON-objects and TypeScript types and utilizing [JavaScript
9 | Proxy](https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Proxy) it provides some
10 | smart APIs.
11 |
--------------------------------------------------------------------------------
/src/components/frontpage/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import {BsFillHeartFill} from "react-icons/bs";
3 | import LibraryList from "../library-list";
4 |
5 |
6 |
7 | RDF + JS =
8 |
9 |
10 |
11 | Welcome to this website that documents and reviews various ways you can work with RDF using JavaScript libraries.
12 | I've chosen a few libraries to showcase how this can be done. For a more complete list, check
13 | [rdf.js.org](https://rdf.js.org/).
14 |
15 |
16 |
--------------------------------------------------------------------------------
/src/components/react-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {REACT_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import Install from "./2-install.mdx";
5 | import JSX from "./3-jsx.mdx";
6 | import StateHandling from "./4-state-handling.mdx";
7 | import Community from "./5-community.mdx";
8 | import Alternatives from "./6-alternatives.mdx";
9 |
10 | export default function ReactGuide() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/quadstore/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Quadstore is a low-level library that implements the `Sink`, `Source`, and `Store` [RDF/JS
5 | specifications](https://rdf.js.org/) in TypeScript. It supports SPARQL queries via
6 | [quadstore-comunica](https://www.npmjs.com/package/quadstore-comunica), a tailored configuration of the [Comunica
7 | querying framework](https://comunica.dev/).
8 |
9 | It works with any storage backend that implements [the AbstractLevel
10 | interface](https://github.com/level/abstract-level), of which there is an incomplete list of available backends at
11 | [level/awesome#stores](https://github.com/level/awesome#stores).
12 |
--------------------------------------------------------------------------------
/src/components/guide-section/index.tsx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import GuideList, {Props as GuideListProps} from "../guide-list";
3 |
4 | interface Props extends GuideListProps {
5 | title?: string;
6 | }
7 |
8 | export default function GuideSection({exclude, title}: Props) {
9 | return (
10 | <>
11 |
12 | {title || "Guides"}
13 |
14 | If you want to learn more about technologies that are relevant for the demos used on this
15 | website, check out these {title ? "other guides" : "guides"} as well.
16 |
17 |
18 |
19 | >
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/quadstore/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import LocalDemo from "./3-local-demo.mdx";
4 | import SparqlDemo from "./4-sparql-demo.mdx";
5 | import SolidDemo from "./5-solid-demo.mdx";
6 | import Review from "./6-review.mdx";
7 | import {LIBRARY_QUADSTORE} from "../../constants";
8 | import LibraryLayout from "../library-layout";
9 |
10 | export default function Quadstore() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/sparql-builder-demo/code.mdx:
--------------------------------------------------------------------------------
1 | import demoCode from "./index.tsx?raw";
2 | import Code from "../code";
3 | import CodeStep from "../code/step";
4 | import Content from "../content";
5 |
6 |
7 |
8 | Using the `SELECT` function we start building our query to get a name.
9 |
10 |
11 | For this query we start off with the `DELETE` function.
12 |
13 |
14 |
15 |
16 | As you can see, both approaches require a bit of experience with SPARQL.
17 |
18 |
--------------------------------------------------------------------------------
/src/components/card/style.module.css:
--------------------------------------------------------------------------------
1 | .card.card {
2 | display: flex;
3 | flex-direction: column;
4 | height: 100%;
5 |
6 | :global(.media.media) {
7 | align-items: center;
8 | flex-wrap: wrap;
9 | gap: 1rem;
10 | }
11 |
12 | :global(.media-left.media-left) {
13 | margin-right: 0;
14 | }
15 |
16 | :global(.media-content) {
17 | overflow-y: hidden;
18 | }
19 |
20 | :global(.image.image) {
21 | height: 48px;
22 |
23 | & img {
24 | height: 100%;
25 | max-width: none;
26 | width: auto;
27 | }
28 | }
29 |
30 | :global(.card-footer-item.button) {
31 | border-radius: 0 0 4px 4px;
32 | }
33 | }
--------------------------------------------------------------------------------
/src/components/rdf-ext/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import LocalDemo from "./3-local-demo.mdx";
4 | import SolidDemo from "./4-solid-demo.mdx";
5 | import TypeScriptSupport from "./5-typescript-support.mdx";
6 | import Review from "./6-review.mdx";
7 | import {LIBRARY_RDF_EXT} from "../../constants";
8 | import LibraryLayout from "../library-layout";
9 |
10 | export default function RdfExt() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/sparql-guide/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | This quote from [sparql.dev](https://sparql.dev/) explains SPARQL nicely:
5 |
6 |
7 | SPARQL is a query language for RDF data. It is used to retrieve and manipulate data stored in RDF format. SPARQL
8 | stands for "SPARQL Protocol and RDF Query Language". It was developed by the World Wide Web Consortium (W3C) and
9 | is a standard for querying RDF data.
10 |
11 |
12 | SPARQL is way to extensive to explain completely, but I'll explain enough to let you follow what's basically
13 | happening behind the hood of the libraries presented on this website.
14 |
15 |
--------------------------------------------------------------------------------
/src/components/ldo/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import Shapes from "./3-shapes.mdx";
4 | import LocalDemo from "./4-local-demo.mdx";
5 | import SolidDemo from "./5-solid-demo.mdx";
6 | import Review from "./6-review.mdx";
7 | import Bias from "./7-bias.mdx";
8 | import {LIBRARY_LDO} from "../../constants";
9 | import LibraryLayout from "../library-layout";
10 |
11 | export default function LDO() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/typings/shims.d.ts:
--------------------------------------------------------------------------------
1 | declare module '*.mdx' {
2 | import type React from 'react'
3 | const ReactComponent: React.VFC
4 | export default ReactComponent
5 | }
6 |
7 | declare module "rdf-sparql-builder" {
8 | export const deleteQuery: function;
9 | export const select: function;
10 | }
11 |
12 | declare module 'solid-namespace' {
13 | // eslint-disable-next-line @typescript-eslint/no-unused-vars
14 | export default (factory: unknown) => Record string>;
15 | }
16 |
17 | declare module '@tpluscode/sparql-builder' {
18 | export const DELETE: function;
19 | export const SELECT: function;
20 | }
21 |
22 | declare module '@zazuko/rdf-vocabularies' {
23 | export const prefixes: Record
24 | }
--------------------------------------------------------------------------------
/src/components/javascript-guide/7-web-apis.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Web APIs
5 |
6 | Now we've covered most of the basic syntax of JS. But this is only scratching the surface of what JS can do, as
7 | there a slew of APIs available to enhance your website (or server, or any other kind of JS-based program). Browser
8 | APIs offer useful way of accessing data from your browser (such as the `localStorage` property on the `window`
9 | API, which allows you to store data between sessions (i.e. visits that the user makes to the website).
10 |
11 | To see the full list of APIs, check out [Mozilla's list of Web
12 | APIs](https://developer.mozilla.org/en-US/docs/Web/API).
13 |
--------------------------------------------------------------------------------
/src/components/rdflib/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import LocalDemo from "./3-local-demo.mdx";
4 | import SolidDemo from "./4-solid-demo.mdx";
5 | import Review from "./5-review.mdx";
6 | import React from "./6-react.mdx";
7 | import Bias from "./7-bias.mdx";
8 | import {LIBRARY_RDFLIB} from "../../constants";
9 | import LibraryLayout from "../library-layout";
10 |
11 | export default function Rdflib() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/comunica/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Install from "./2-install.mdx";
3 | import SolidDemo from "./3-solid-demo.mdx";
4 | import SPARQLBuilderDemo from "./4-sparql-builder-demo.mdx";
5 | import RDFSPARQLBuilderDemo from "./5-rdf-sparql-builder-demo.mdx";
6 | import Review from "./6-review.mdx";
7 | import {LIBRARY_COMUNICA} from "../../constants";
8 | import LibraryLayout from "../library-layout";
9 |
10 | export default function Comunica() {
11 | return (
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 | )
21 | }
--------------------------------------------------------------------------------
/src/components/code/step/index.tsx:
--------------------------------------------------------------------------------
1 | import CodeLink from "../../code-link";
2 | import {HTMLAttributes, ReactNode, useContext} from "react";
3 | import Content from "../../content";
4 | import {CodeContext} from "../index.tsx";
5 |
6 | interface Props extends Omit, "title"> {
7 | lines: string[];
8 | title: ReactNode;
9 | }
10 |
11 | export default function CodeStep({children, lines, title, ...props}: Props) {
12 | const {id} = useContext(CodeContext);
13 | return (
14 |
15 |
16 | {title}
17 |
18 |
19 | {children}
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/inrupt/6-bias.mdx:
--------------------------------------------------------------------------------
1 | import AuthorNote from "../author-note";
2 |
3 |
4 | I've worked at Inrupt for four years, and have in those years worked with a lot of developers there, some of
5 | whom I recognize as friend to this day. I'm very much biased toward Inrupt as a company.
6 |
7 | I've also used these libraries as part of my work at Inrupt, and have been part of the quality assurance part of it,
8 | by testing and giving feedback to the developers. Developers who I also communicated with often.
9 |
10 | So I'm very familiar with the various APIs, and although I enjoy working with them, it's not what I'm being drawn
11 | to currently. So I think I'm able to remain impartial to Inrupt and their work.
12 |
--------------------------------------------------------------------------------
/src/components/shex-guide/2-simple-example.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import shexExample from "./shex-example.shex?raw";
3 | import Code from "../code";
4 | import {NavLink} from "react-router-dom";
5 |
6 |
7 | Let's start with an example that describes a ShEx-shape we can use for the data model used in the demos on this
8 | website:
9 |
10 |
11 |
12 |
13 |
14 | In this example we see the shape `ProfileShape` with one attribute, `foaf:name`. It's datatype, `xsd:string`, has a
15 | cardinality token, `?`, meaning that it can be zero or one occurrences of it. This is the shape needed to make our
16 | demos with LDO work.
17 |
18 |
--------------------------------------------------------------------------------
/src/components/guide-layout/index.tsx:
--------------------------------------------------------------------------------
1 | import {Guide} from "../../constants";
2 | import {ReactNode} from "react";
3 | import GuideHeader from "../guide-header";
4 | import RecommendationList from "../recommendation-list";
5 | import GuideSection from "../guide-section";
6 | import LibrarySection from "../library-section";
7 |
8 | interface Props {
9 | children: ReactNode
10 | guide: Guide
11 | minimal?: boolean;
12 | }
13 |
14 | export default function GuideLayout({children, guide, minimal}: Props) {
15 | return <>
16 |
17 | {children}
18 | {!minimal && <>
19 |
20 |
21 |
22 | >}
23 | >;
24 | }
--------------------------------------------------------------------------------
/src/components/frontpage/reviews/docs.mdx:
--------------------------------------------------------------------------------
1 | import Review from "../../review";
2 |
3 | Documentation
4 |
5 | How accessible is it to developers who need to find some fix? Does it rank high when
6 | people search for help using their library?
7 |
8 |
9 | {[
10 | [5, <>The documentation is glorious! It's setting the standard for how documentation should be written.>],
11 | [4, <>You enjoy perusing the documentation. It's leading you to make wise choices.>],
12 | [3, <>The documentation is accessible and easy to navigate. Problems are easy to figure out with the
13 | documentation at hand.>],
14 | [2, <>The documentation is useful but lacking.>],
15 | [1, <>Non-existent or "What were the devs thinking?">],
16 | ]}
17 |
--------------------------------------------------------------------------------
/src/components/rdf-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import Intro from "./1-intro.mdx";
2 | import Interoperability from "./2-interoperability.mdx";
3 | import Serializations from "./3-serializations.mdx";
4 | import Vocabularies from "./4-vocabularies.mdx";
5 | import Shapes from "./5-shapes.mdx";
6 | import Querying from "./6-querying.mdx";
7 | import BeyondRDF from "./7-beyond-rdf.mdx";
8 | import {RDF_GUIDE} from "../../constants";
9 | import GuideLayout from "../guide-layout";
10 |
11 | export default function RDFGuide() {
12 | return (
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 | )
23 | }
--------------------------------------------------------------------------------
/src/components/sparql-builder-demo/queries.ts:
--------------------------------------------------------------------------------
1 | import {literal, namedNode} from '@rdfjs/data-model'
2 | import {DELETE, SELECT} from "@tpluscode/sparql-builder";
3 | import {FOAF} from "../../namespaces.ts";
4 |
5 | export function select(webId: string): string {
6 | return SELECT`?name`
7 | .WHERE`${namedNode(webId)} ${FOAF.name} ?name .`
8 | .LIMIT(1)
9 | .build();
10 | }
11 |
12 | export function update(webId: string, oldNameValue: string, newNameValue: string) {
13 | const webIdNode = namedNode(webId);
14 | const oldName = literal(oldNameValue);
15 | const newName = literal(newNameValue);
16 | return DELETE`${webIdNode} ${FOAF.name} ${oldName}`
17 | .INSERT`${webIdNode} ${FOAF.name} ${newName}`
18 | .WHERE`${webIdNode} ${FOAF.name} ${oldName}`
19 | .build();
20 | }
--------------------------------------------------------------------------------
/src/components/react-guide/2-install.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Install from "../install";
3 |
4 |
5 | Installation
6 |
7 | To get started with React, simply install it using your favorite package manager:
8 |
9 |
10 |
11 |
12 |
13 | We add [react-dom](https://www.npmjs.com/package/react-dom) to integrate React with the webpage. You also probably
14 | want some way of managing routes in your application, in which case [React Router](https://reactrouter.com/) is
15 | probably your choice. You might switch these out depending on your needs (e.g. if you're working on a React Native
16 | app you'll switch out react-dom, and maybe you don't even need react-router-dom).
17 |
18 |
--------------------------------------------------------------------------------
/src/components/sparql-guide/3-write.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Code from "../code";
3 | import sparqlUpdateName from "./sparql-update-name.sparql?raw";
4 |
5 |
6 | Writing data with SPARQL
7 |
8 | SPARQL supports a couple of methods to manipulate RDF data, but we're most interested in [SPARQL
9 | Update](https://www.w3.org/TR/sparql11-update/).
10 |
11 |
12 |
13 |
14 |
15 | In this example we remove the triple with the object `OLD NAME` and replace it with the triple that has the object
16 | `NEW NAME`. This is very basic, but it's enough to understand how we update the names in our Solid demos, as this is
17 | basically what we do.
18 |
--------------------------------------------------------------------------------
/src/components/rdf-sparql-builder-demo/queries.ts:
--------------------------------------------------------------------------------
1 | import {literal, namedNode, variable} from '@rdfjs/data-model'
2 | import * as sparql from "rdf-sparql-builder";
3 | import {FOAF} from "../../namespaces.ts";
4 |
5 | export function select(webId: string): string {
6 | return sparql.select([variable('name')])
7 | .where([[namedNode(webId), FOAF.name, variable("name")]])
8 | .limit(1)
9 | .build();
10 | }
11 |
12 | export function update(webId: string, oldNameValue: string, newNameValue: string) {
13 | const webIdNode = namedNode(webId);
14 | const oldName = literal(oldNameValue);
15 | const newName = literal(newNameValue);
16 | return sparql.deleteQuery([[webIdNode, FOAF.name, oldName]])
17 | .insert([[webIdNode, FOAF.name, newName]])
18 | .where([[webIdNode, FOAF.name, oldName]])
19 | .build();
20 | }
--------------------------------------------------------------------------------
/src/components/m-ld/demo/index.tsx:
--------------------------------------------------------------------------------
1 | import ErrorMessage from "../../error-message";
2 | import styles from "./styles.module.css";
3 |
4 | interface Props {
5 | domainId: string
6 | error?: Error | null
7 | }
8 |
9 | export default function MLdDemo({domainId, error}: Props) {
10 | return error
11 | ?
12 | : <>
13 |
14 |
17 |
18 |
19 | You can also open a peer demo in a separate
20 | window.
21 |
22 |
23 | >
24 | }
--------------------------------------------------------------------------------
/src/components/frontpage/reviews/community.mdx:
--------------------------------------------------------------------------------
1 | import Review from "../../review";
2 |
3 | Community & Support
4 |
5 | Is there an active community that helps developers in need? Do they have community or contribution
6 | guidelines?
7 |
8 |
9 | {[
10 | [5, <>This community is the best! Why haven't you joined already?>],
11 | [4, <>The library has fostered a great community, and active users (beside the developers themselves) are
12 | helping and guiding other users.>],
13 | [3, <>The community is mostly non-existent, but the developers are active in various channels that are relevant
14 | for users of their library.>],
15 | [2, <>The community is nonexistent, and developers are slow to answer requests.>],
16 | [1, <>Stay away. Just stay away.>],
17 | ]}
18 |
--------------------------------------------------------------------------------
/src/components/inrupt/2-install.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import Install from "../install";
3 |
4 |
5 | Installation
6 |
7 | To get started with Inrupt's JavaScript client libraries, install it using your favorite package manager.
8 |
9 |
10 |
11 |
12 |
13 | Inrupt also advices to use their library
14 | [@inrupt/vocab-common-rdf](https://github.com/inrupt/solid-common-vocab-rdf) to interact with common vocabularies.
15 | I've also made use of [@rdfjs/data-model](https://github.com/rdfjs-base/data-model) to handle literals, so I suggest
16 | adding that as well.
17 |
18 |
19 |
20 |
21 |
22 | To understand how all of these can be used, check out the demos.
23 |
--------------------------------------------------------------------------------
/tsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "target": "ES2020",
4 | "useDefineForClassFields": true,
5 | "lib": [
6 | "ES2020",
7 | "DOM",
8 | "DOM.Iterable"
9 | ],
10 | "module": "ESNext",
11 | "skipLibCheck": true,
12 | /* Bundler mode */
13 | "moduleResolution": "bundler",
14 | "allowImportingTsExtensions": true,
15 | "resolveJsonModule": true,
16 | "isolatedModules": true,
17 | "noEmit": true,
18 | "jsx": "react-jsx",
19 | /* Linting */
20 | "strict": true,
21 | "noUnusedLocals": true,
22 | "noUnusedParameters": true,
23 | "noFallthroughCasesInSwitch": true,
24 | "types": [
25 | "./typings/shims.d.ts",
26 | "./typings/rdf-ext.d.ts"
27 | ]
28 | },
29 | "include": [
30 | "src",
31 | "vite.config.ts"
32 | ],
33 | "references": [
34 | {
35 | "path": "./tsconfig.node.json"
36 | }
37 | ]
38 | }
39 |
--------------------------------------------------------------------------------
/src/components/ldo/5-solid-demo.mdx:
--------------------------------------------------------------------------------
1 | import SolidReactCodeSection from "./solid-react-demo/code.mdx";
2 | import LoginGate from "../login-gate";
3 | import Content from "../content";
4 | import LDOSolidReactDemo from "./solid-react-demo";
5 | import LogoutButton from "../logout-button";
6 | import Install from "../install";
7 |
8 |
9 | @ldo/solid-react demo
10 |
11 | With the [@ldo/solid-react](https://github.com/o-development/ldo/tree/main/packages/solid-react) package you get
12 | some nifty APIs that integrates LDO with React. To get started you need to install it with:
13 |
14 |
15 |
16 |
17 |
18 | To see it in use, please check out the code below.
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
--------------------------------------------------------------------------------
/src/hooks/use-copy-to-clipboard/index.ts:
--------------------------------------------------------------------------------
1 | import {useState} from 'react'
2 |
3 | type CopiedValue = string | null
4 | type CopyFn = (text: string) => Promise // Return success
5 |
6 | export function useCopyToClipboard(): [CopiedValue, CopyFn] {
7 | const [copiedText, setCopiedText] = useState(null)
8 |
9 | const copy: CopyFn = async text => {
10 | if (!navigator?.clipboard) {
11 | console.warn('Clipboard not supported')
12 | return false
13 | }
14 |
15 | // Try to save to clipboard then save it in the state if worked
16 | try {
17 | await navigator.clipboard.writeText(text)
18 | setCopiedText(text)
19 | return true
20 | } catch (error) {
21 | console.warn('Copy failed', error)
22 | setCopiedText(null)
23 | return false
24 | }
25 | }
26 |
27 | return [copiedText, copy]
28 | }
29 |
--------------------------------------------------------------------------------
/src/components/javascript-guide/index.tsx:
--------------------------------------------------------------------------------
1 | import GuideLayout from "../guide-layout";
2 | import {JAVASCRIPT_GUIDE} from "../../constants";
3 | import Intro from "./1-intro.mdx";
4 | import Basics from "./2-basics.mdx";
5 | import Controls from "./3-controls.mdx";
6 | import Functions from "./4-functions.mdx";
7 | import Classes from "./5-classes.mdx";
8 | import Modules from "./6-modules.mdx";
9 | import WebAPIs from "./7-web-apis.mdx";
10 | import AsynchronousCode from "./8-asynchronous-code.mdx";
11 | import Outro from "./9-outro.mdx";
12 |
13 | export default function JavascriptGuide() {
14 | return (
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 | )
27 | }
--------------------------------------------------------------------------------
/src/components/library-header/index.tsx:
--------------------------------------------------------------------------------
1 | import {Library} from "../../constants";
2 | import {clsx} from "clsx";
3 | import styles from "./style.module.css";
4 |
5 | interface Props {
6 | library: Library
7 | }
8 |
9 | export default function LibraryHeader({library}: Props) {
10 | return (
11 | <>
12 |
13 |
14 |
15 |
16 | {library.name}
17 |
18 | - Project page: {library.websiteName}
19 | - Created by {library.creator}
20 |
21 |
22 | >
23 | );
24 | }
--------------------------------------------------------------------------------
/src/components/notification/index.tsx:
--------------------------------------------------------------------------------
1 | import {useEffect, useState} from "react";
2 | import {clsx} from "clsx";
3 | import useNotification from "../../hooks/use-notification";
4 | import {NotificationModel} from "../../hooks/use-notification/context.tsx";
5 |
6 | interface Props {
7 | index: number;
8 | notification: NotificationModel;
9 | }
10 |
11 | export default function Notification({index, notification}: Props) {
12 | const [hidden, setHidden] = useState(notification.hidden);
13 | const {hide} = useNotification();
14 |
15 | useEffect(() => {
16 | setTimeout(() => {
17 | setHidden(true);
18 | hide(notification.id);
19 | }, 2000);
20 | }, [hide, notification.id]);
21 |
22 | return (
23 |
25 | {notification.message}
26 |
27 | )
28 | }
--------------------------------------------------------------------------------
/src/components/frontpage/4-p2p.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import styles from "./style.module.css";
3 | import {BsHearts} from "react-icons/bs";
4 | import DemoList from "../demo-list";
5 | import {P2P_DEMOS} from "../../constants";
6 |
7 |
8 |
9 | RDF + JS + P2P =
10 |
11 |
12 |
13 | Although working on RDF locally is useful, it's even more useful when used by multiple actors in real-time.
14 | Real-time functionality can be complex and offers a lot of challenges though, so it's probably best to use some
15 | tool to handle it for us.
16 |
17 | Currently there is only one demo for this section, but I hope to expand it with more in the future as I learn of
18 | more peer-to-peer technologies offering real-time functionality with RDF.
19 |
20 |
21 |
--------------------------------------------------------------------------------
/src/components/solid-guide/3-authorization.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Authorization
5 |
6 | Authorization is another vital pillar of Solid. It is what connects the user with the control of resources.
7 | Currently there are two standards in the works describing authorization controls for Solid, [Web Access
8 | Control (WAC)](https://solidproject.org/TR/wac) and [Access Control Policy
9 | (ACP)](https://solid.github.io/authorization-panel/acp-specification/). Going into details in either is beyond the
10 | scope of this website.
11 |
12 | As a general rule you can consider WAC a more stable specification, that's implemented on more servers. ACP on the
13 | other hand provides more features that are required for larger use-cases, and is experimented on using Inrupts'
14 | [Enterprise Solid Server (ESS)](https://www.inrupt.com/products/enterprise-solid-server).
15 |
16 |
--------------------------------------------------------------------------------
/src/components/solid-guide/authentication-demo.tsx:
--------------------------------------------------------------------------------
1 | import {useSolidAuth} from "@ldo/solid-react";
2 | import Login from "../login";
3 | import {HTMLAttributes} from "react";
4 |
5 | export default function AuthenticationDemo({id, ...props}: HTMLAttributes) {
6 | const {login, logout, session: {isLoggedIn, webId}} = useSolidAuth();
7 |
8 | return isLoggedIn
9 | ?
10 |
11 | You're authenticated with
12 | {webId}
13 |
14 |
15 |
16 | :
17 |
18 | You're not authenticated
19 |
20 |
21 |
22 | }
--------------------------------------------------------------------------------
/src/components/shex-guide/shex-advanced-example.shex:
--------------------------------------------------------------------------------
1 | PREFIX foaf:
2 | PREFIX rdf:
3 | PREFIX rdfs:
4 | PREFIX ldp:
5 | PREFIX schema:
6 | PREFIX solid:
7 | PREFIX shape:
8 | PREFIX space:
9 | PREFIX vcard:
10 | PREFIX xsd:
11 | PREFIX xtypes:
12 |
13 | shape:SolidProfile EXTRA rdf:type {
14 | rdf:type [schema:Person foaf:Person] ;
15 | vcard:fn xsd:string? ;
16 | foaf:name xsd:string? ;
17 | ldp:inbox IRI? ;
18 | space:preferencesFile IRI? ;
19 | space:storage IRI* ;
20 | solid:account IRI? ;
21 | solid:oidcIssuer IRI? ;
22 | solid:privateTypeIndex IRI? ;
23 | solid:publicTypeIndex IRI? ;
24 | }
25 |
--------------------------------------------------------------------------------
/src/components/inrupt/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | [Inrupt](https://www.inrupt.com/) has created an impressive suite of tools for developers who want to work with RDF.
5 | They currently [offer tools for Java and JavaScript developers](https://www.inrupt.com/products/dev-tools), I'll be
6 | focusing on the [latter](https://docs.inrupt.com/developer-tools/javascript/client-libraries/).
7 |
8 | The API is developed using functional programming styles, e.g. you won't be working with a global store, but rather
9 | passing around objects representing datasets and things in various stages. Most of the code we'll be focusing on is
10 | from [@inrupt/solid-client](https://docs.inrupt.com/developer-tools/api/javascript/solid-client/), but note that
11 | there are some other [very useful libraries as
12 | well](https://docs.inrupt.com/developer-tools/javascript/client-libraries/api/) (especially the ones dealing with
13 | authentication).
14 |
15 |
--------------------------------------------------------------------------------
/src/components/javascript-guide/5-classes.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import classesSyntax from "./5-classes.js?raw";
3 | import Code from "../code";
4 | import CodeStep from "../code/step";
5 |
6 |
7 | Classes
8 |
9 | Although similar functionality has been achieved with alternative syntax before, `class` is a recent part of the
10 | standardized syntax that allows there to be a standardized way of encapsulating values in objects.
11 |
12 |
13 |
14 | class }>
15 | The `class` syntax is a recent entry to JS, and provides a way to describe objects with common interfaces.
16 |
17 |
18 | Classes can be extended so that you can partition your code into hierarchical structures.
19 |
20 |
--------------------------------------------------------------------------------
/src/components/author-note/style.module.css:
--------------------------------------------------------------------------------
1 | .card {
2 | margin: 2rem 0;
3 |
4 | @media screen and (min-width: 1060px) {
5 | margin-top: 3.5rem;
6 | }
7 | }
8 |
9 | .content.content.content {
10 | & h1,
11 | & h2,
12 | & h3,
13 | & h4,
14 | & h5,
15 | & h6 {
16 | margin-top: 0;
17 | margin-bottom: 0.75rem;
18 | }
19 | }
20 |
21 | .media.media.media.media {
22 | flex-wrap: nowrap;
23 | margin-bottom: 0.75rem;
24 | }
25 |
26 | .mediaContent.mediaContent {
27 | overflow-x: inherit;
28 | }
29 |
30 | .image.image.image.image {
31 | width: 48px;
32 |
33 | & img {
34 | height: auto;
35 | width: 48px;
36 | border-radius: 4px;
37 | }
38 |
39 | @media screen and (min-width: 1060px) {
40 | position: relative;
41 | width: 72px;
42 |
43 | & img {
44 | position: absolute;
45 | left: 2.75rem;
46 | top: -3.5rem;
47 | width: 72px;
48 | }
49 | }
50 | }
--------------------------------------------------------------------------------
/src/components/frontpage/reviews/devx.mdx:
--------------------------------------------------------------------------------
1 | import Review from "../../review";
2 |
3 | Developer experience
4 |
5 | Which allowances do the library offer developers to overcome their challenges? How easy is the API to get into, to
6 | get something done quickly, and then move on to other problems that need fixing? Is it prone to bugs? Does it guide
7 | developers to handle edge cases in a intuitive manner?
8 |
9 |
10 | {[
11 | [5, <>It's the best library ever! You try to find uses of it in projects that aren't even relevant.>],
12 | [4, <>It's a really nice experience. You're enjoying solving problems with this library.>],
13 | [3, <>The experience is ok - it allows you to handle RDF in an approachable manner.>],
14 | [2, <>You'll use this library if you have to, but you avoid it in most cases.>],
15 | [1, <>No. Just no. (I usually won't include libraries that I rate this low, but except for completeness.)>],
16 | ]}
17 |
18 |
--------------------------------------------------------------------------------
/src/components/frontpage/reviews/overall.mdx:
--------------------------------------------------------------------------------
1 | import Review from "../../review";
2 |
3 | Overall feeling
4 |
5 | This is where I conclude my overall rating of the library. It's based on the other ratings, but there might be
6 | certain something that will improve or decrease the overall score. I've treated myself to be able to set half scores
7 | here, as to indicate that my feeling is somewhere between those two points.
8 |
9 |
10 | {[
11 | [5, <>There's no other library like this that fills you with joy when you're using it. >],
12 | [4, <>This library is generally very good, and you enjoy interacting with it and its support system.>],
13 | [3, <>It's has its ups and downs. You use this library because it gets the work done, not because of the joy it
14 | sparks in you.>],
15 | [2, <>In general I would avoid this library for front-end projects.>],
16 | [1, <>Who spawned this creature from hell?!>],
17 | ]}
18 |
--------------------------------------------------------------------------------
/src/components/rdflib/1-intro.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 |
3 |
4 | Rdflib.js is probably _the_ longest ongoing project that allow developers to manage RDF. It's used in many projects,
5 | such as [the SolidOS project](https://github.com/SolidOS/solidos). Its API consists of low-level and high-level
6 | parts. The lower level API requires a healthy bit of understanding RDF, while the higher level API allows you to
7 | interact with RDF resources more easily. I would argue that the form of some of the functions are a bit outdated,
8 | such as `serialize` where the last parameter is a callback function. This eludes back to how callbacks were handled
9 | before promises were a thing in JavaScript.
10 |
11 | The API is extensive, and should have you covered in most situations. The low-level API does not bring me joy when
12 | working with it, so in general I would recommend _not_ using it for front-end projects, unless you're very dependent
13 | on working with a very stable API.
14 |
--------------------------------------------------------------------------------
/src/components/frontpage/reviews/maturity.mdx:
--------------------------------------------------------------------------------
1 | import Review from "../../review";
2 |
3 | Maturity
4 |
5 | How widely is the library used, and is it being actively developed? What is the track record for
6 | handling updates and hot fixes (if ever needed).
7 |
8 |
9 | {[
10 | [5, <>The processes for fixing bugs and issues are water tight, and the library has been enjoying a stable API
11 | for years.>],
12 | [4, <>The library has been in active development for years and has a reasonable amount of projects in which it
13 | is used. There are good processes for fixing bugs and various issues.>],
14 | [3, <>At this point, it's production ready. The code has been vetted reasonably well, and have earned a good
15 | degree of trust by fixing problems in reasonable manner.>],
16 | [2, <>The library is quite new, and hasn't really been vetted much.>],
17 | [1, <>It's very experimental and shouldn't be trusted.>],
18 | ]}
19 |
--------------------------------------------------------------------------------
/src/components/rdf-ext/5-typescript-support.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import rdfExtTypesShim from "../../../typings/rdf-ext.d.ts?raw";
3 | import Code from "../code";
4 |
5 |
6 | TypeScript support
7 |
8 | There is no out-of-the-box support for RDF-Ext. There's the community-managed
9 | [@types/rdf-ext](https://www.npmjs.com/package/@types/rdf-ext), but it probably won't be as updated as the main
10 | packages themselves.
11 |
12 | In the following code I've displayed the shims I've created to make my code work while I've been experimenting with
13 | the demos. It's far from complete, but should give you an idea of what to do if you want to work with RDF-Ext using
14 | TypeScript yourself. Note that I've reused types from [@rdfjs/types](https://github.com/rdfjs/types) in this shim,
15 | which is technically not correct, as RDF-Ext *extends* the RDF/JS data models, but it works for the demos.
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/src/components/inrupt/solid-demo/useSolidDataset.ts:
--------------------------------------------------------------------------------
1 | import {useEffect, useState} from "react";
2 | import {getSolidDataset, saveSolidDatasetAt, SolidDataset} from "@inrupt/solid-client";
3 | import {useSolidAuth} from "@ldo/solid-react";
4 |
5 | type SaveFunction = (updatedDataset: SolidDataset) => Promise
6 |
7 | export default function useSolidDataset(url: string | undefined, onError: (error: Error) => void): [SolidDataset | null, SaveFunction] {
8 | const {fetch} = useSolidAuth();
9 | const [dataset, setDataset] = useState(null);
10 |
11 | useEffect(() => {
12 | if (!url) return;
13 | getSolidDataset(url, {fetch})
14 | .then(setDataset)
15 | .catch(onError)
16 | }, [fetch, onError, url]);
17 |
18 | const saveDataset: SaveFunction = async (updatedDataset) => {
19 | if (!url) return;
20 | return saveSolidDatasetAt(url, updatedDataset, {fetch})
21 | .then(setDataset)
22 | .catch(onError);
23 | };
24 |
25 | return [dataset, saveDataset]
26 | }
--------------------------------------------------------------------------------
/src/components/solid-guide/5-apps.mdx:
--------------------------------------------------------------------------------
1 | import Content from "../content";
2 | import AuthorNote from "../author-note";
3 |
4 |
5 | Apps
6 |
7 | Lastly there's the term "Solid apps", which describe applications that are compatible with the Solid specification.
8 | This website is in fact a Solid app, since it allows you to authenticate with your Solid account and manipulate data
9 | in your WebID profile.
10 |
11 | Apps are arguably the most important part of the Solid ecosystem, as it is *the interface* that users will use to
12 | interact with said ecosystem. But whatever part is the most important, it is the total sum of all these parts that
13 | turns Solid into a powerful infrastructure, ripe with potential to be unleashed by social-minded developers.
14 |
15 |
16 |
17 | Ok, this is turning a bit into a fluff-piece. But just to emphasize: *Solid is really great, and you should be
18 | excited about it!* Ok, there, I'm done ^_^
19 |
--------------------------------------------------------------------------------
/src/components/navigation/index.tsx:
--------------------------------------------------------------------------------
1 | import {NavLink} from "react-router-dom";
2 | import {clsx} from "clsx";
3 | import styles from "./styles.module.css";
4 | import {GUIDES, LIBRARIES} from "../../constants";
5 | import NavigationDropdown from "./dropdown";
6 |
7 | export default function Navigation() {
8 | return (
9 |