-
diff --git a/Readme.md b/Readme.md index 84c4085..d084623 100644 --- a/Readme.md +++ b/Readme.md @@ -5,9 +5,6 @@ This is a monorepo that contains all libraries associated with Linked Data Objec ## Documentation Full documentation can be found at [ldo.js.org](https://ldo.js.org). -## Tutorial -[A tutorial for how to use LDO](./documentation/solid-react-tutorial.md) is available here. - ## Libraries The LDO monorepo contains the following - [@ldo/cli](./packages/cli/) diff --git a/documentation/images/Step2.png b/documentation/images/Step2.png deleted file mode 100644 index 5efcc6a..0000000 Binary files a/documentation/images/Step2.png and /dev/null differ diff --git a/documentation/images/Step4Login.png b/documentation/images/Step4Login.png deleted file mode 100644 index 18750d2..0000000 Binary files a/documentation/images/Step4Login.png and /dev/null differ diff --git a/documentation/images/Step4Logout.png b/documentation/images/Step4Logout.png deleted file mode 100644 index 5c91904..0000000 Binary files a/documentation/images/Step4Logout.png and /dev/null differ diff --git a/documentation/images/Step8.png b/documentation/images/Step8.png deleted file mode 100644 index 33f19b3..0000000 Binary files a/documentation/images/Step8.png and /dev/null differ diff --git a/documentation/solid-react-tutorial.md b/documentation/solid-react-tutorial.md deleted file mode 100644 index aef4f58..0000000 --- a/documentation/solid-react-tutorial.md +++ /dev/null @@ -1,787 +0,0 @@ -# Using LDO to build a Solid Application for React - -Solid separates the application from the storage, allowing users to put their data wherever they choose. Core to achieving this is application interoparability, the ability to use multiple apps on the same dataset. In order to make applications interoperable, Solid is standardized around RDF (Resource Description Framework), a standard for representing data. While RDF is extremely flexible, it is sometimes cumbersome to work with, that's where LDO (Linked Data Objects) comes in. - -In this tutorial, we'll build a web application for Solid using React and LDO. LDO's react library, "@ldo/solid-react" is designed to make it easy to manipulate data on a Solid Pod. - -We'll be making a simple micro-blogging website that allows you to write notes and upload photos. - -// TODO insert image - -This tutorial assumes that you are already familiar with React and the overall concepts associated with Solid. - -## 1. Getting Started - -First, we'll initialize the project. LDO is designed to work with TypeScript, so we want to initialize a typescript react project. - -```bash -npx create-react-app my-solid-app --template typescript -cd my-solid-app -``` - -## 2. Setting up a basic app infrastructure - -Before we can use LDO and connect to a Solid Pod, let's get the boilerplace React infrastructure out of the way. We'll set up a single page that renders your blog timeline and lets you make new posts, and we'll do this with 5 components: - -**App.tsx**: Base of the application. -```tsx -import React, { FunctionComponent } from 'react'; -import { Header } from './Header'; -import { Blog } from './Blog'; - -export const App: FunctionComponent = () => { - return ( -
Header
-Post
-- You are logged in with the webId {session.webId}.{" "} - -
- ) : ( - // If the session is not logged in -- You are not Logged In{" "} - -
- )} -No blog available. Log in first.
; - - return ( -- You are logged as {loggedInName}.{" "} - -
- ) : ( -// ... -``` - -The `useResource(uri: string)` will load a provided URI into your application. You can use methods like `.isReading()` to get the current status of the resource. When anything updates with the resource, a rerender will be triggered on your component. - -RDF data is automatically loaded into a central dataset inside your application. To access that dataset, we can use `useSubject(uri: string)`. `useSubject` takes in a ShapeType and an uri. It returns a JSON representation of that URI given the ShapeType. In the above example, we've provided the autogenerated `SolidProfileShapeShapeType` as well as the webId. This essentially says to LDO, "The URI I've provided is a Solid Profile. Please give me JSON representing this as a Solid Profile." - -Once we have the subject, all we have to do is treat it like JSON. To get the "formalName" for a profile, just call `profile.fn`. - -## 7. Getting the main container - -Let's move on to building the blog section of our site. One of the biggest questions when building Solid applications is "Where should I save new data?" While that question may have an different answer in the future, today apps traditionally create a new folder to save new data to. - -But, to create a new folder, we want to know what the root folder of the application is. At the time of login, the only URL we know is the WebId, so we want to find the root folder for that WebId. It's not always to root domain. For example, on some pod servers a WebId follows this format `https://example.pod/myusername/profile/card#me` and the root file is `https://example.pod/myusername/`. So, how do we know which container is the real root container? Well, we can use the `getRootContainer` method. - -Let's add the following hook to **Blog.tsx** - -```tsx -// ... -import { useLdo, useResource, useSolidAuth } from "@ldo/solid-react"; -import { ConatinerUri } from "@ldo/solid"; - -export const Blog: FunctionComponent = () => { - const { session } = useSolidAuth(); - - const { getResource } = useLdo(); - const [mainContainerUri, setMainContainerUri] = useState< - ContainerUri | undefined - >(); - - useEffect(() => { - if (session.webId) { - // Get the WebId resource - const webIdResource = getResource(session.webId); - // Get the root container associated with that WebId - webIdResource.getRootContainer().then((rootContainerResult) => { - // Check if there is an error - if (rootContainerResult.isError) return; - // Get a child of the root resource called "my-solid-app/" - const mainContainer = rootContainerResult.child("my-solid-app/"); - setMainContainerUri(mainContainer.uri); - // Create the main container if it doesn't exist yet - mainContainer.createIfAbsent(); - }); - } - }, [getResource, session.webId]); - - //... -``` - -Let's walk through what's happening here. First, we can use the `useLdo` hook to get a number of useful functions for interacting with data (and we'll use more in the future). In this case, we're getting the `getResource` function. This serves roughly the same purpose as the `useResource` hook, but in function form rather than hook form. Keep in mind that resources retrieved from the `getResource` function won't trigger rerenders on update, so it's best used when you need a resource for purposes other than the render. - -Using the `getResource` function, we get a resource representing the webId. Every resource has the `getRootContainer` method which returns a promise with either the root container, or an error. Everything returned by LDO methods has the `isError` parameter, so you can easily check if it's an error. - -We'll then save the URI of the main application container so we can use it in step 8. - -Any container resource has the `child` method which gets a representation of the any child, and with that representation we can call the `createIfAbsent` method to create the create out application's main container. - -## 8. Rendering Container Children - -Before we continue, let's talk a bit about the folder structure for this application. We just got our "main folder", the folder we'll save everything to. Inside that folder, we'll put our individual blog posts. These will be folders themselves with potentially two files: a post data file (index.ttl) and some image file. Overall, our folder layout will look like this: - -``` -rootContainer/ -├─ my-solid-app/ -│ ├─ post1/ -│ │ ├─ index.ttl -│ │ ├─ some_image.png/ -│ ├─ post2/ -│ │ ├─ index.ttl -│ │ ├─ another_image.jpg/ -``` - -We've already created the `my-solid-app/` container, so let's add a bit of functionality to create the post folders. Let's modify **MakePost.tsx**. - -```tsx -export const MakePost: FunctionComponent<{ mainContainer: Container }> = ({ - mainContainer, -}) => { - const [message, setMessage] = useState(""); - const [selectedFile, setSelectedFile] = useStateContainerURI is: {postUri}
-postResource.status.message
; - } - - return ( -{post.articleBody}
- {blobUrl && ( -{post.articleBody}
`. - -Notice that we can get the URL for the image with `post.image["@id"]`, but we're not using that directly in the img tag (eg `