Skip to content

Commit

Permalink
Refactor to new context pattern
Browse files Browse the repository at this point in the history
  • Loading branch information
guillemcordoba committed Nov 18, 2024
1 parent 8a26089 commit ebe9335
Show file tree
Hide file tree
Showing 5 changed files with 97 additions and 145 deletions.
107 changes: 13 additions & 94 deletions docs/setup.md
Original file line number Diff line number Diff line change
@@ -1,118 +1,37 @@
# Setup

> [!WARNING]
> This guide assumes that you have scaffolded a hApp with the [TNESH stack template](https://darksoil.studio/tnesh-stack).
> This guide assumes that you have scaffolded a hApp with the [TNESH stack template](https://darksoil.studio/tnesh-stack/scaffolding-a-happ).
1. Run this to scaffold this zome in your hApp:
Run this to scaffold this zome in your hApp:

```bash
nix run github:darksoil-studio/file-storage/main-0.3#scaffold
nix run github:darksoil-studio/file-storage#scaffold
```

This will do the following:
- Add the flake input for that repository in your `flake.nix`.
- Add the appropriate zome packages to the `dna.nix` that you select.
- Add the UI package for that zome in the local NPM package that you select.

Now you only need to integrate the zome's frontend in your web-app.

2. Connect to Holochain with the `AppClient`, and create the `FileStorageClient` with it:

```js
import { FileStorageClient } from "@darksoil-studio/file-storage-zome";
import { AppWebsocket } from "@holochain/client";

async function setupFileStorageClient() {
// TODO: change "MY_APP_NAME" for the roleId that you can find in your "happ.yaml"
const client = await AppWebsocket.connect();

// TODO: change "MY_CELL_ROLE" for the roleId that you can find in your "happ.yaml"
return new FileStorageClient(client, '<MY_CELL_ROLE>');
}
```

3. Import the `<file-storage-context>` element and add it to your html **wrapping the whole section of your page in which you are going to be placing** the other elements from `@darksoil-studio/file-storage-zome`:

```js
// This can be placed in the index.js, at the top level of your web-app.
import "@darksoil-studio/file-storage-zome/elements/file-storage-context.js";
```

And then add the `<file-storage-context>` element in your html:

```html
<file-storage-context>
<!-- Add here other elements from @darksoil-studio/file-storage-zome -->
</file-storage-context>
```

4. Attach the `fileStorageClient` to the `<file-storage-context>` element:

- Go to [this page](https://darksoil.studio/tnesh-stack/integrating-with-frameworks/), select the framework you are using, and follow its example.

You need to set the `client` property of it to your already instantiated `FileStorageClient` object:

- If you **are using some JS framework**:

::: code-group
```html [React]
<file-storage-context client={fileStorageClient}><!-- ... --></file-storage-context>
```

```html [Angular]
<file-storage-context [client]="fileStorageClient"><!-- ... --></file-storage-context>
```

```html [Vue]
<file-storage-context :client="fileStorageClient"><!-- ... --></file-storage-context>
```

```html [Svelte]
<file-storage-context client={fileStorageClient}><!-- ... --></file-storage-context>
```

```html [Lit]
<file-storage-context .client=${fileStorageClient}><!-- ... --></file-storage-context>
```
:::

OR

- If you **are not using any framework**:

```js
const contextElement = document.querySelector("file-storage-context");
contextElement.client = client;
```
- Add the UI package for @darksoil-studio/file-storage-zome as a dependency of your UI package.
- Add the `<file-storage-context>` element at the top level of your application.

> [!NOTE]
> You can read more about the context pattern [here](https://darksoil.studio/tnesh-stack/guides/custom-elements#context).
5. [Choose which elements you need](?path=/docs/frontend-elements) and import them like this:

```js
import "@darksoil-studio/file-storage-zome/dist/elements/file-storage-context.js";
```

And then they are ready be used inside the `<file-storage-context>` just like any other HTML tag.

This will define all the elements from this module in the global `CustomElementsRegistry`. You can read more about Custom Elements [here](https://developers.google.com/web/fundamentals/web-components/customelements).
That's it! You have now integrated the `file-storage` coordinator and integrity zomes and their UI into your app!

6. Add your preferred shoelace theme in your `<head>` tag:
Now, [choose which elements you need](/elements/upload-files.md) and import them like this:

```html
<head>
<link rel="stylesheet" href="path/to/shoelace/dist/themes/light.css" />
</head>
```js
import "@darksoil-studio/file-storage-zome/dist/elements/upload-files.js";
```

You can read more about how to initialize the shoelace theme [here](https://shoelace.style/getting-started/themes?id=activating-themes).
And then they are ready be used inside the `<file-storage-context>` just like any other HTML tag.

---

That's it! You have now integrated both the backend and the frontend for the profiles module.
> [!NOTE]
> Importing the elements from the UI package will define them in the global `CustomElementsRegistry`, which makes them available to be used like any normal HTML tag. You can read more about custom elements [here](https://darksoil.studio/tnesh-stack/guides/custom-elements).
# Example

You can see a full working example of the UI working in [here](https://github.com/darksoil-studio/file-storage-zome/blob/main/ui/demo/index.html).
You can see a full working example of the UI working in [here](https://github.com/darksoil-studio/file-storage/blob/main/ui/demo/index.html).

11 changes: 6 additions & 5 deletions pnpm-lock.yaml

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

88 changes: 44 additions & 44 deletions ui/demo/index.html
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,15 @@

<script type="module">
import "@shoelace-style/shoelace/dist/themes/light.css";
import { FileStorageClient, fileStorageClientContext } from "../src";
import { FileStorageClient } from "../src";
import "../src/elements/upload-files.ts";
import "../src/elements/file-storage-context.ts";
import "../src/elements/show-image.ts";
import { css, html, LitElement } from "lit";
import { ContextProvider } from "@lit/context";
import { AppWebsocket } from "@holochain/client";
import { onSubmit } from "@tnesh-stack/elements";
import "@tnesh-stack/elements/dist/elements/app-client-context.js";

customElements.define(
"file-storage-demo",
Expand All @@ -40,58 +42,56 @@
};

async firstUpdated() {
const hcclient = await AppWebsocket.connect();
this.appClient = await AppWebsocket.connect();

const client = new FileStorageClient(
hcclient,
"file_storage_provider"
);

new ContextProvider(this, fileStorageClientContext, client);
this.loaded = true;
this.requestUpdate();
}

render() {
if (!this.loaded) return html`Loading...`;
return html`
<form ${onSubmit((data) => {
console.log(data);
this.shadowRoot.querySelector("form").reset();
})} style="display: flex; flex-direction: column; flex: 1">
<upload-files
id="uf"
.oneFile=${true}
required
name="file_hash"
style="max-width: 20px; max-height:20px"
@file-uploaded=${(e) => {
this.hash = e.detail.file.hash;
}}
></upload-files>
${
this.hash
? html`
<div
style="display: flex; flex-direction: row; flex: 1"
>
<show-image
.imageHash=${this.hash}
style="width: 500px; height: 500px; border-radius: 12px"
></show-image>
<app-client-context .client=${this.appClient}>
<file-storage-context role="file_storage_provider">
<form ${onSubmit((data) => {
console.log(data);
this.shadowRoot.querySelector("form").reset();
})} style="display: flex; flex-direction: column; flex: 1">
<upload-files
id="uf"
.oneFile=${true}
required
name="file_hash"
style="max-width: 20px; max-height:20px"
@file-uploaded=${(e) => {
this.hash = e.detail.file.hash;
}}
></upload-files>
${
this.hash
? html`
<div
style="display: flex; flex-direction: row; flex: 1"
>
<show-image
.imageHash=${this.hash}
style="width: 500px; height: 500px; border-radius: 12px"
></show-image>
<upload-files
.defaultValue=${this.hash}
style="flex: 1"
.oneFile=${true}
name="file_hash"
></upload-files>
</div>
`
: html``
}
<input type="submit"></input>
</form>
<upload-files
.defaultValue=${this.hash}
style="flex: 1"
.oneFile=${true}
name="file_hash"
></upload-files>
</div>
`
: html``
}
<input type="submit"></input>
</form>
</file-storage-context>
</app-client-context>
`;
}
}
Expand Down
2 changes: 1 addition & 1 deletion ui/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@
"@lit/localize": "^0.12.0",
"@scoped-elements/dropzone": "^0.2.1",
"@shoelace-style/shoelace": "^2.11.0",
"@tnesh-stack/elements": "^0.300.0",
"@tnesh-stack/elements": "^0.300.5",
"@tnesh-stack/utils": "^0.300.0",
"idb-keyval": "^6.2.1",
"js-base64": "^3.7.7",
Expand Down
34 changes: 33 additions & 1 deletion ui/src/elements/file-storage-context.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
import { css, html, LitElement } from "lit";
import { provide } from "@lit/context";
import { consume, provide } from "@lit/context";
import { property, customElement } from "lit/decorators.js";
import { AppClient } from "@holochain/client";
import { appClientContext } from "@tnesh-stack/elements";

import { fileStorageClientContext } from "../context.js";
import { FileStorageClient } from "../file-storage-client.js";
Expand All @@ -11,6 +13,36 @@ export class FileStorageContext extends LitElement {
@property({ type: Object })
client!: FileStorageClient;

@consume({ context: appClientContext, subscribe: true })
appClient!: AppClient;

@property()
role!: string;

@property()
zome = "file_storage";

connectedCallback() {
super.connectedCallback();
if (this.client) return;
if (!this.role) {
throw new Error(
`<file-storage-context> must have a role="YOUR_DNA_ROLE" property, eg: <file-storage-context role="role1">`
);
}
if (!this.appClient) {
throw new Error(
`<file-storage-context> must either:
a) be placed inside <app-client-context>
or
b) receive an AppClient property (eg. <file-storage-context .client=\${client}>)
or
c) receive a store property (eg. <file-storage-context .store=\${store}>)`
);
}
this.client = new FileStorageClient(this.appClient, this.role, this.zome);
}

render() {
return html`<slot></slot>`;
}
Expand Down

0 comments on commit ebe9335

Please sign in to comment.