@powerhousedao/academy 0.1.0-dev.5 → 2.5.0-dev.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +54 -0
- package/Dockerfile +1 -1
- package/docs/academy/01-GetStarted/00-ExploreDemoPackage.md +7 -1
- package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +2 -2
- package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +4 -5
- package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +4 -16
- package/docs/academy/01-GetStarted/home.mdx +1 -1
- package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +1 -0
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/01-WhatIsADocumentModel.md +1 -1
- package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/_category_.json +2 -2
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +233 -0
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/_category_.json +6 -7
- package/docs/academy/02-MasteryTrack/05-Launch/03-SetupEnvironment.md +28 -53
- package/docs/academy/04-APIReferences/01-ReactHooks.md +82 -0
- package/package.json +5 -1
- package/sidebars.ts +33 -4
- package/src/components/HomepageFeatures/index.tsx +1 -1
- package/src/css/custom.css +5 -0
- package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingBeautifulDocumentEditors.md +0 -109
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,57 @@
|
|
|
1
|
+
## 2.5.0-dev.0 (2025-06-04)
|
|
2
|
+
|
|
3
|
+
### 🚀 Features
|
|
4
|
+
|
|
5
|
+
- **academy:** centralize husky & auto-update cli docs ([8c92e0bb1](https://github.com/powerhouse-inc/powerhouse/commit/8c92e0bb1))
|
|
6
|
+
- **ph-cli:** added setup-service command ([dfa082aa6](https://github.com/powerhouse-inc/powerhouse/commit/dfa082aa6))
|
|
7
|
+
- **scripts:** updated setup scripts ([9f7fa7644](https://github.com/powerhouse-inc/powerhouse/commit/9f7fa7644))
|
|
8
|
+
- enforce conventional commits ([faa49da40](https://github.com/powerhouse-inc/powerhouse/commit/faa49da40))
|
|
9
|
+
- removed scalars package ([d6f7059a7](https://github.com/powerhouse-inc/powerhouse/commit/d6f7059a7))
|
|
10
|
+
- enabled switchboard command ([5a9c467bf](https://github.com/powerhouse-inc/powerhouse/commit/5a9c467bf))
|
|
11
|
+
- removed scalars dependencies ([596aedbd5](https://github.com/powerhouse-inc/powerhouse/commit/596aedbd5))
|
|
12
|
+
- **builder-tools:** handle recursive objects in initial state generator ([c9eedcc43](https://github.com/powerhouse-inc/powerhouse/commit/c9eedcc43))
|
|
13
|
+
- **monorepo:** bump graphql lib ([ba9d5d338](https://github.com/powerhouse-inc/powerhouse/commit/ba9d5d338))
|
|
14
|
+
- **monorepo:** handle updating monorepo build deps ([db2ac2316](https://github.com/powerhouse-inc/powerhouse/commit/db2ac2316))
|
|
15
|
+
- **monorepo:** regenerate lockfile ([a6c390b4e](https://github.com/powerhouse-inc/powerhouse/commit/a6c390b4e))
|
|
16
|
+
- **builder-tools:** fix wrong value used for field id ([a6c6142e0](https://github.com/powerhouse-inc/powerhouse/commit/a6c6142e0))
|
|
17
|
+
- **reactor-api,reactor-local:** updated analytics dependencies ([cbeace573](https://github.com/powerhouse-inc/powerhouse/commit/cbeace573))
|
|
18
|
+
|
|
19
|
+
### 🩹 Fixes
|
|
20
|
+
|
|
21
|
+
- **academy:** docker build ([58e83be09](https://github.com/powerhouse-inc/powerhouse/commit/58e83be09))
|
|
22
|
+
- **academy:** lockfile issue second time' ([6208fe614](https://github.com/powerhouse-inc/powerhouse/commit/6208fe614))
|
|
23
|
+
- **academy:** fix frozen lockfile issue' ([80f18ec73](https://github.com/powerhouse-inc/powerhouse/commit/80f18ec73))
|
|
24
|
+
- **academy:** fix frozen lockfile issue ([bfc3dcd21](https://github.com/powerhouse-inc/powerhouse/commit/bfc3dcd21))
|
|
25
|
+
- **pre-commit:** use bash syntax and shebang ([da00ff581](https://github.com/powerhouse-inc/powerhouse/commit/da00ff581))
|
|
26
|
+
- added missing dep to academy ([4ec6c8278](https://github.com/powerhouse-inc/powerhouse/commit/4ec6c8278))
|
|
27
|
+
- **academy:** clean up husky script ([e18e26cd8](https://github.com/powerhouse-inc/powerhouse/commit/e18e26cd8))
|
|
28
|
+
- **academy:** deployment ([36e5f194d](https://github.com/powerhouse-inc/powerhouse/commit/36e5f194d))
|
|
29
|
+
- **switchboard:** docker build ([7052e39e1](https://github.com/powerhouse-inc/powerhouse/commit/7052e39e1))
|
|
30
|
+
- docker build with PH_PACKAGES ([856ac1187](https://github.com/powerhouse-inc/powerhouse/commit/856ac1187))
|
|
31
|
+
- **document-drive:** fix type issue on browser storage ([240a78b41](https://github.com/powerhouse-inc/powerhouse/commit/240a78b41))
|
|
32
|
+
- **ph-cli:** ph add does not remove installed packages ([aedfbf56e](https://github.com/powerhouse-inc/powerhouse/commit/aedfbf56e))
|
|
33
|
+
- remove .env and add to .gitignore ([0d2d48684](https://github.com/powerhouse-inc/powerhouse/commit/0d2d48684))
|
|
34
|
+
- **switchboard,reactor-local:** latest version of sky atlas was not being installed ([72bf72fd4](https://github.com/powerhouse-inc/powerhouse/commit/72bf72fd4))
|
|
35
|
+
|
|
36
|
+
### ❤️ Thank You
|
|
37
|
+
|
|
38
|
+
- acaldas @acaldas
|
|
39
|
+
- Benjamin Jordan
|
|
40
|
+
- Callme-T
|
|
41
|
+
- Frank
|
|
42
|
+
- Guillermo Puente @gpuente
|
|
43
|
+
- ryanwolhuter @ryanwolhuter
|
|
44
|
+
|
|
45
|
+
## 0.1.0-dev.6 (2025-06-04)
|
|
46
|
+
|
|
47
|
+
### 🩹 Fixes
|
|
48
|
+
|
|
49
|
+
- **academy:** docker build ([58e83be09](https://github.com/powerhouse-inc/powerhouse/commit/58e83be09))
|
|
50
|
+
|
|
51
|
+
### ❤️ Thank You
|
|
52
|
+
|
|
53
|
+
- Frank
|
|
54
|
+
|
|
1
55
|
## 0.1.0-dev.5 (2025-06-03)
|
|
2
56
|
|
|
3
57
|
### 🩹 Fixes
|
package/Dockerfile
CHANGED
|
@@ -33,6 +33,13 @@ This command downloads and sets up the Contributor Billing package, making its f
|
|
|
33
33
|
|
|
34
34
|
You have now successfully installed `ph-cmd` and added your first package!
|
|
35
35
|
|
|
36
|
+
:::info
|
|
37
|
+
WORK IN PROGRESS @callmet
|
|
38
|
+
Let's explore what exactly you can do with this package
|
|
39
|
+
- Document model
|
|
40
|
+
- Drive App
|
|
41
|
+
:::
|
|
42
|
+
|
|
36
43
|
## Step 3: Run the Connect App in Studio mode
|
|
37
44
|
To run the package locally in Connect Studio (our collaboration and contributor app), run the `ph connect` command.
|
|
38
45
|
|
|
@@ -40,7 +47,6 @@ To run the package locally in Connect Studio (our collaboration and contributor
|
|
|
40
47
|
|
|
41
48
|
Renown is Powerhouse's decentralized identity and reputation system designed to address the challenge of trust within DAOs, where contributors often operate under pseudonyms. In traditional organizations, personal identity and reputation are key to establishing trust and accountability. Renown replicates this dynamic in the digital space, allowing contributors to earn experience and build reputation without revealing their real-world identities.
|
|
42
49
|
|
|
43
|
-
|
|
44
50
|
:::tip
|
|
45
51
|
When signing in with Renown, use an Ethereum or blockchain address that can function as your \'identity\', as this address will accrue more experience and history over time.
|
|
46
52
|
:::
|
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
# Create a
|
|
1
|
+
# Create a ToDoList Document
|
|
2
2
|
|
|
3
3
|
## Overview
|
|
4
|
-
This tutorial guides you through creating a 'Powerhouse project' for a ToDoList
|
|
4
|
+
This tutorial guides you through creating a 'Powerhouse project' for a **ToDoList**. A Powerhouse project primarily consists of a document model and its editor. You'll be using Connect locally, known as 'Studio mode'.
|
|
5
5
|
|
|
6
6
|
## Prerequisites
|
|
7
7
|
- Powerhouse CLI installed: `pnpm install -g ph-cmd`
|
|
@@ -1,22 +1,21 @@
|
|
|
1
1
|
# Define the ToDoList document specification
|
|
2
2
|
|
|
3
|
-
In this tutorial, you will learn how to define the specifications for a
|
|
3
|
+
In this tutorial, you will learn how to define the specifications for a **ToDoList** document model within the Connect application using its GraphQL schema, and then export the resulting document model specification document for your Powerhouse project.
|
|
4
4
|
If you don't have a document specification file created yet, have a look at the previous step of this tutorial to create a new document specification.
|
|
5
5
|
|
|
6
6
|
Before you start, make sure you have the Connect application running locally with the command `ph connect`
|
|
7
7
|
|
|
8
8
|
## ToDoList Document Specification
|
|
9
9
|
|
|
10
|
-
Likely you have called your project 'ToDoList'. If you've used a different name, please create a new document specification named 'ToDoList'. Pay close attention to capitalization, as it influences our code
|
|
10
|
+
Likely you have called your project 'ToDoList'. If you've used a different name, please create a new document specification named 'ToDoList'. **Pay close attention to capitalization, as it influences our code.**
|
|
11
|
+
|
|
11
12
|
We'll continue with this project to teach you how to create a document model specification and later an editor for your document model. We use the **GraphQL Schema Definition Language** (SDL) to define the schema for the document model. Below, you can see the SDL for the `ToDoList` document model.
|
|
12
13
|
|
|
13
14
|
:::info
|
|
14
15
|
This schema defines the **data structure** of the document model and the types involved in its operations, which are detailed further as input types.
|
|
15
|
-
Documents in Powerhouse leverage **event sourcing principles**, where every state transition is represented by an operation. GraphQL input types describe operations, ensuring that user intents are captured effectively. These operations detail the parameters needed for state transitions. The use of GraphQL aligns these transitions with explicit, validated, and reproducible commands
|
|
16
|
+
Documents in Powerhouse leverage **event sourcing principles**, where every state transition is represented by an operation. GraphQL input types describe operations, ensuring that user intents are captured effectively. These operations detail the parameters needed for state transitions. The use of GraphQL aligns these transitions with explicit, validated, and reproducible commands.
|
|
16
17
|
:::
|
|
17
18
|
|
|
18
|
-
|
|
19
|
-
|
|
20
19
|
<details>
|
|
21
20
|
<summary>State Schema of our ToDoList</summary>
|
|
22
21
|
|
|
@@ -6,24 +6,12 @@ To export the document model specification, follow the steps in the [Define ToDo
|
|
|
6
6
|
|
|
7
7
|
## Understanding Reducers in Document Models
|
|
8
8
|
|
|
9
|
-
Reducers are a core concept in Powerhouse document models. They implement the state transition logic for each operation defined in your schema
|
|
9
|
+
Reducers are a core concept in Powerhouse document models. They implement the state transition logic for each operation defined in your schema.
|
|
10
10
|
|
|
11
|
-
|
|
11
|
+
**Connection to Schema Definition Language (SDL)**: The reducers directly implement the operations you defined in your SDL. Remember how we defined `AddTodoItemInput`, `UpdateTodoItemInput`, and `DeleteTodoItemInput` in our schema?
|
|
12
|
+
The reducers provide the actual implementation of what happens when those operations are performed.
|
|
12
13
|
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
3. **Immutable Updates**: While the reducer code appears to modify the state directly, Powerhouse handles immutability behind the scenes. Each operation produces a new document state without modifying the previous one.
|
|
16
|
-
|
|
17
|
-
4. **Type Safety**: Powerhouse generates TypeScript types from your SDL, ensuring that your reducers and operations are type-safe.
|
|
18
|
-
|
|
19
|
-
5. **Pure Functions**: Reducers should be pure functions that depend only on the current state and the operation input, making them predictable and testable.
|
|
20
|
-
|
|
21
|
-
Let's see how these concepts are implemented in our **ToDoList** document model.
|
|
22
|
-
|
|
23
|
-
## Importing the Document Model Specification and Generating Code
|
|
24
|
-
|
|
25
|
-
To import the document model specification into your Powerhouse project, you can either:
|
|
26
|
-
|
|
14
|
+
To import the document model specification into your Powerhouse project, you can either:
|
|
27
15
|
- Copy and paste the file directly into the root of your Powerhouse project.
|
|
28
16
|
- Or drag and drop the file into the Powerhouse project directory in the VSCode editor as seen in the image below:
|
|
29
17
|
|
|
@@ -71,7 +71,7 @@ import BrowserOnly from '@docusaurus/BrowserOnly';
|
|
|
71
71
|
</div>
|
|
72
72
|
<div className={styles.cardContent}>
|
|
73
73
|
<a href="/docs/academy/GetStarted/BuildToDoListEditor" className="path-button">Building a Todo-list Editor</a>
|
|
74
|
-
<a href="/docs/academy/BuildingUserExperiences/
|
|
74
|
+
<a href="/docs/academy/BuildingUserExperiences/BuildingDocumentEditors" className="path-button">Building Document Editors</a>
|
|
75
75
|
<a href="/docs/academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer" className="path-button">Building Custom Drive Explorers</a>
|
|
76
76
|
<a href="/docs/academy/ComponentLibrary/DocumentEngineering" className="path-button">Component Library</a>
|
|
77
77
|
</div>
|
|
@@ -181,7 +181,7 @@ Document Models offer a range of features that can be leveraged to create sophis
|
|
|
181
181
|
|
|
182
182
|
- **API Integration**: Document Models can be integrated with Switchboard API or external APIs, allowing for the exchange of data between Connect and other systems or services.
|
|
183
183
|
|
|
184
|
-
- **Data
|
|
184
|
+
- **Data Analysis**: The structured nature of Document Models makes them ideal for data analysis and reporting. Users can extract insights and generate reports based on the data captured within the models which is accessible through read models. (Operational data + Analytics data which takes into account time series of the data).
|
|
185
185
|
|
|
186
186
|
- **Version Control**: Similar to how Git manages changes to source code, Document Models in Connect will support version control, enabling users to track changes, compare different versions, and ensure data integrity over time.
|
|
187
187
|
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"label": "Document Model Creation",
|
|
3
3
|
"link": {
|
|
4
|
-
"type": "
|
|
5
|
-
"
|
|
4
|
+
"type": "doc",
|
|
5
|
+
"id": "academy/MasteryTrack/DocumentModelCreation/WhatIsADocumentModel"
|
|
6
6
|
}
|
|
7
7
|
}
|
|
@@ -0,0 +1,233 @@
|
|
|
1
|
+
# Build Document Editors
|
|
2
|
+
|
|
3
|
+
## Build with React on Powerhouse
|
|
4
|
+
|
|
5
|
+
At Powerhouse, frontend development for document editors follows a simple and familiar flow, leveraging the power and flexibility of React.
|
|
6
|
+
|
|
7
|
+
### Development Environment
|
|
8
|
+
|
|
9
|
+
Connect Studio is your primary tool for development. When you run `ph connect`, it provides a dynamic, local environment where you can define and preview your document models and their editors live. This replaces the need for tools like Storybook for editor development, though Storybook remains invaluable for exploring the [Powerhouse Component Library](#powerhouse-component-library).
|
|
10
|
+
|
|
11
|
+
Key aspects of the Powerhouse development environment:
|
|
12
|
+
- **React Foundation**: Build your editor UIs using React components, just as you would in any standard React project.
|
|
13
|
+
- **Automatic Build Processes**: Tailwind CSS is installed by default and fully managed by Connect Studio. There's no need to manually configure or run Tailwind or other build processes during development. Connect Studio handles CSS generation and other necessary build steps automatically, especially when you publish a package.
|
|
14
|
+
- **Styling Flexibility**: You are not limited to Tailwind. Regular CSS (`.css` files), inline styles, and any React-compatible styling method work exactly as you would expect.
|
|
15
|
+
|
|
16
|
+
Powerhouse aims to keep your developer experience clean, familiar, and focused:
|
|
17
|
+
- Build React components as you normally would.
|
|
18
|
+
- Use styling approaches you're comfortable with.
|
|
19
|
+
- Trust Connect Studio to handle the setup and build processes for you.
|
|
20
|
+
|
|
21
|
+
### Generating Your Editor Template
|
|
22
|
+
|
|
23
|
+
To kickstart your editor development, Powerhouse provides a command to generate a basic editor template. This command reads your document model definition and creates the initial `editor.tsx` file.
|
|
24
|
+
|
|
25
|
+
For example, to generate an editor for a `ToDoList` document model with a document type `powerhouse/todolist`:
|
|
26
|
+
```bash
|
|
27
|
+
ph generate --editor ToDoList --document-types powerhouse/todolist
|
|
28
|
+
```
|
|
29
|
+
This will create the template in the `editors/to-do-list/editor.tsx` folder.
|
|
30
|
+
|
|
31
|
+
### Styling Your Editor
|
|
32
|
+
|
|
33
|
+
You have several options for styling your editor components:
|
|
34
|
+
|
|
35
|
+
1. **Default HTML Styling**: Standard HTML tags (`<h1>`, `<p>`, `<button>`, etc.) will render with default browser styles or any base styling provided by the Connect environment. This is suitable for basic structure and quick prototyping.
|
|
36
|
+
|
|
37
|
+
2. **Tailwind CSS**: Connect Studio comes with Tailwind CSS integrated. You can directly use Tailwind utility classes in your JSX for rapid and consistent styling without writing separate CSS files.
|
|
38
|
+
*Example (from the ToDoList Editor):*
|
|
39
|
+
```typescript
|
|
40
|
+
<div className="container mx-auto p-4 max-w-md">
|
|
41
|
+
<h1 className="text-2xl font-bold mb-4">To-do List</h1>
|
|
42
|
+
{/* ... more Tailwind styled elements */}
|
|
43
|
+
</div>
|
|
44
|
+
```
|
|
45
|
+
|
|
46
|
+
3. **Custom CSS Files**: You can import traditional CSS files (`.css`) to apply custom styles or integrate existing style libraries.
|
|
47
|
+
*Create an `editor.css` file in your editor's directory:*
|
|
48
|
+
```css
|
|
49
|
+
/* editors/your-editor/editor.css */
|
|
50
|
+
.editor-container {
|
|
51
|
+
padding: 1rem;
|
|
52
|
+
border: 1px solid #ccc;
|
|
53
|
+
}
|
|
54
|
+
.editor-title {
|
|
55
|
+
color: navy;
|
|
56
|
+
font-size: 1.8rem;
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
*Import and use it in your `editor.tsx`:*
|
|
60
|
+
```typescript
|
|
61
|
+
import './editor.css'; // Import the CSS file
|
|
62
|
+
|
|
63
|
+
export default function Editor(props: IProps) {
|
|
64
|
+
return (
|
|
65
|
+
<div className="editor-container">
|
|
66
|
+
<h1 className="editor-title">My Document Title</h1>
|
|
67
|
+
{/* ... */}
|
|
68
|
+
</div>
|
|
69
|
+
);
|
|
70
|
+
}
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
Choose the method or combination of methods that best suits your project needs and team preferences. Connect Studio (`ph connect`) will allow you to see your styles applied in real-time.
|
|
74
|
+
|
|
75
|
+
<details>
|
|
76
|
+
<summary>Refresher on React Hooks</summary>
|
|
77
|
+
|
|
78
|
+
All of the Powerhouse React Hooks can be found here: [Powerhouse React Hooks API Reference](docs/academy/APIReferences/ReactHooks)
|
|
79
|
+
|
|
80
|
+
React Hooks allow you to use various React features directly within your functional components. You can use built-in Hooks or combine them to create your own custom Hooks.
|
|
81
|
+
|
|
82
|
+
**What are Custom Hooks?**
|
|
83
|
+
A custom hook is a JavaScript function whose name starts with "use" and that calls other Hooks. They are used to:
|
|
84
|
+
- Reuse stateful logic between components.
|
|
85
|
+
- Abstract complex logic into a simpler interface.
|
|
86
|
+
- Isolate side effects, particularly those managed by `useEffect`.
|
|
87
|
+
|
|
88
|
+
**Key Built-in Hooks Examples:**
|
|
89
|
+
- `useState`: Lets a component "remember" information (state).
|
|
90
|
+
- `useEffect`: Lets a component perform side effects (e.g., data fetching, subscriptions, manually changing the DOM).
|
|
91
|
+
- `useContext`: Lets a component receive information from distant parent components without explicitly passing props through every level of the component tree.
|
|
92
|
+
|
|
93
|
+
**Naming Convention:**
|
|
94
|
+
Hook names must always start with `use` followed by a capital letter (e.g., `useState`, `useOnlineStatus`).
|
|
95
|
+
|
|
96
|
+
**Rules of Hooks:**
|
|
97
|
+
1. **Only Call Hooks at the Top Level**: Don't call Hooks inside loops, conditions, or nested functions.
|
|
98
|
+
2. **Only Call Hooks from React Functions**: Call Hooks from React functional components or from custom Hooks.
|
|
99
|
+
|
|
100
|
+
It's important to note that a function should only be named and treated as a hook if it actually utilizes one or more built-in React hooks. If a function (even if named `useSomething`) doesn't call any built-in hooks, it behaves like a regular JavaScript function, and making it a "hook" offers no specific React advantages.
|
|
101
|
+
|
|
102
|
+
For more details, see the official documentation and our API reference:
|
|
103
|
+
- [Reusing Logic with Custom Hooks (react.dev)](https://react.dev/learn/reusing-logic-with-custom-hooks)
|
|
104
|
+
- [Rules of Hooks (react.dev)](https://react.dev/reference/rules/rules-of-hooks)
|
|
105
|
+
- [Powerhouse React Hooks API Reference](docs/academy/APIReferences/ReactHooks)
|
|
106
|
+
|
|
107
|
+
</details>
|
|
108
|
+
|
|
109
|
+
### State Management in Editors
|
|
110
|
+
|
|
111
|
+
When you build an editor in Powerhouse, your main editor component receives `EditorProps`. These props are crucial for interacting with the document:
|
|
112
|
+
|
|
113
|
+
* **`document`**: This object contains the entire document structure, including its current state. You'll typically access the global document state via `document.state.global`.
|
|
114
|
+
* **`dispatch`**: This function is your gateway to modifying the document's state. You call `dispatch` with an action object (usually created by action creators from your document model's generated code) to signal an intended change.
|
|
115
|
+
|
|
116
|
+
**Local vs. Global State:**
|
|
117
|
+
* **Local Component State**: For UI-specific state that doesn't need to be part of the persisted document model (e.g., the current text in an input field before submission, visibility of a dropdown), use React's `useState` hook.
|
|
118
|
+
```typescript
|
|
119
|
+
const [inputValue, setInputValue] = useState('');
|
|
120
|
+
// ...
|
|
121
|
+
<input value={inputValue} onChange={(e) => setInputValue(e.target.value)} />
|
|
122
|
+
```
|
|
123
|
+
* **Global Document State**: For data that is part of the document itself and should be saved (e.g., the items in a to-do list), you modify it by dispatching actions. The `document.state.global` object provides read-only access to this state within your editor.
|
|
124
|
+
|
|
125
|
+
**Dispatching Actions:**
|
|
126
|
+
Your document model's generated code (e.g., in `document-models/your-model/index.js` or `document-models/your-model/gen/operations.js`) will provide action creators.
|
|
127
|
+
```typescript
|
|
128
|
+
// Assuming 'actions' are imported from your document model
|
|
129
|
+
// import { actions } from '../../document-models/to-do-list/index.js';
|
|
130
|
+
|
|
131
|
+
// Inside your editor component:
|
|
132
|
+
// function Editor({ document, dispatch }: IProps) {
|
|
133
|
+
// ...
|
|
134
|
+
// const handleAddItem = () => {
|
|
135
|
+
// if (todoItem.trim()) {
|
|
136
|
+
// dispatch(actions.addTodoItem({ // Dispatch action to add item.
|
|
137
|
+
// id: Math.random().toString(), // Generate a simple unique ID
|
|
138
|
+
// text: todoItem,
|
|
139
|
+
// }));
|
|
140
|
+
// setTodoItem(''); // Clear local input state
|
|
141
|
+
// }
|
|
142
|
+
// };
|
|
143
|
+
// }
|
|
144
|
+
```
|
|
145
|
+
The actual state modification logic resides in your document model's reducers, ensuring that all changes are consistent and follow the defined operations.
|
|
146
|
+
|
|
147
|
+
## Powerhouse Component Library
|
|
148
|
+
|
|
149
|
+
Powerhouse provides a rich set of reusable UI components through the **`@powerhousedao/document-engineering/scalars`** package. These components are designed for consistency, efficiency, and seamless integration with the Powerhouse ecosystem, with many based on GraphQL scalar types.
|
|
150
|
+
|
|
151
|
+
### Exploring Components
|
|
152
|
+
You can explore available components, see usage examples, and understand their properties (props) using our Storybook instance:
|
|
153
|
+
[https://storybook.powerhouse.academy](https://storybook.powerhouse.academy)
|
|
154
|
+
|
|
155
|
+
Storybook allows you to:
|
|
156
|
+
* Visually inspect each component.
|
|
157
|
+
* Interact with different states and variations.
|
|
158
|
+
* View code snippets for basic implementation.
|
|
159
|
+
* Consult the props table for detailed configuration options.
|
|
160
|
+
|
|
161
|
+
### Using Components
|
|
162
|
+
1. **Import**: Add an import statement at the top of your editor file:
|
|
163
|
+
```typescript
|
|
164
|
+
import { Checkbox, StringField, Form } from '@powerhousedao/document-engineering/scalars';
|
|
165
|
+
```
|
|
166
|
+
2. **Implement**: Use the component in your JSX, configuring it with props:
|
|
167
|
+
```typescript
|
|
168
|
+
// Example using StringField for an input
|
|
169
|
+
<Form onSubmit={() => { /* Handle submission */ }}>
|
|
170
|
+
<StringField
|
|
171
|
+
name="taskName"
|
|
172
|
+
label="New Task"
|
|
173
|
+
value={taskText} // From local state
|
|
174
|
+
onChange={(e) => setTaskText(e.target.value)}
|
|
175
|
+
/>
|
|
176
|
+
</Form>
|
|
177
|
+
```
|
|
178
|
+
|
|
179
|
+
### Creating Local Wrapper Components
|
|
180
|
+
Sometimes, you might want to create local wrapper components in your editor's project to encapsulate specific configurations or behaviors for library components. This was demonstrated in the "Build a ToDoList Editor" tutorial with `Checkbox.tsx` and `InputField.tsx` components, which internally used `BooleanField` and `StringField` from the `@powerhousedao/document-engineering/scalars` library.
|
|
181
|
+
|
|
182
|
+
**Example: Local `Checkbox` Wrapper (conceptual)**
|
|
183
|
+
```typescript
|
|
184
|
+
// editors/to-do-list/components/checkbox.tsx
|
|
185
|
+
import { Form, BooleanField } from "@powerhousedao/document-engineering/scalars";
|
|
186
|
+
|
|
187
|
+
interface CustomCheckboxProps {
|
|
188
|
+
value: boolean;
|
|
189
|
+
onChange: (value: boolean) => void;
|
|
190
|
+
label?: string; // Added custom prop or passed through
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
export const Checkbox = ({ value, onChange, label }: CustomCheckboxProps) => {
|
|
194
|
+
return (
|
|
195
|
+
<Form onSubmit={() => { /* May not be needed for simple checkbox */ }}>
|
|
196
|
+
<BooleanField
|
|
197
|
+
name="customChecked" // Internal name for the form field
|
|
198
|
+
description={label || "Toggle state"} // Use label for description
|
|
199
|
+
value={value}
|
|
200
|
+
onChange={onChange}
|
|
201
|
+
/>
|
|
202
|
+
</Form>
|
|
203
|
+
);
|
|
204
|
+
};
|
|
205
|
+
```
|
|
206
|
+
This pattern helps keep your main editor file cleaner and allows for more complex compositions.
|
|
207
|
+
|
|
208
|
+
## Conceptual Example: Building a ToDoList Editor
|
|
209
|
+
|
|
210
|
+
Let's consider key aspects of building an editor like the `ToDoList` example:
|
|
211
|
+
|
|
212
|
+
1. **Input for New Items**:
|
|
213
|
+
* Use a local `useState` to manage the text of the new to-do item.
|
|
214
|
+
* Use an `InputField` (or a `StringField` from the library) for text entry.
|
|
215
|
+
* On "Add" button click or "Enter" key press, `dispatch` an `addTodoItem` action with the current input value.
|
|
216
|
+
|
|
217
|
+
2. **Displaying List Items**:
|
|
218
|
+
* Map over `document.state.global.items`.
|
|
219
|
+
* For each item, display its `text` and a `Checkbox`.
|
|
220
|
+
* The `Checkbox` `value` should be bound to `item.checked`.
|
|
221
|
+
* Its `onChange` handler should `dispatch` an `updateTodoItem` action to toggle the `checked` status.
|
|
222
|
+
|
|
223
|
+
3. **Editing Items**:
|
|
224
|
+
* Implement local state (`editingItemId`, `editedText`) to manage which item is being edited and its current text.
|
|
225
|
+
* Conditionally render either the item text (display mode) or an input field (edit mode).
|
|
226
|
+
* When entering edit mode, populate `editedText` with the item's current text.
|
|
227
|
+
* On saving the edit (e.g., "Enter" key in the input), `dispatch` an `updateTodoItem` action with the new text.
|
|
228
|
+
|
|
229
|
+
4. **Deleting Items**:
|
|
230
|
+
* Provide a delete button/icon next to each item.
|
|
231
|
+
* Its `onClick` handler should `dispatch` a `deleteTodoItem` action with the item's `id`.
|
|
232
|
+
|
|
233
|
+
By combining local React state for UI control with dispatched actions for document state mutations, and leveraging the Powerhouse Component Library, you can build powerful and interactive document editors. Always refer to your document model's defined operations and state schema as the source of truth for how data should be structured and modified.
|
|
@@ -1,8 +1,7 @@
|
|
|
1
1
|
{
|
|
2
|
-
|
|
3
|
-
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
}
|
|
2
|
+
"label": "Building User Experiences",
|
|
3
|
+
"link": {
|
|
4
|
+
"type": "doc",
|
|
5
|
+
"id": "academy/MasteryTrack/BuildingUserExperiences/BuildingDocumentEditors"
|
|
6
|
+
}
|
|
7
|
+
}
|
|
@@ -6,67 +6,36 @@ Powerhouse is a powerful platform that helps you manage and deploy your applicat
|
|
|
6
6
|
## Prerequisites
|
|
7
7
|
Before you begin, ensure you have a Linux-based system (Ubuntu or Debian recommended), sudo privileges, and a stable internet connection. These are essential for the installation and configuration process. The system should have at least 1GB of RAM and 10GB of free disk space for optimal performance. While these are minimum requirements, more resources will provide better performance, especially when running multiple services.
|
|
8
8
|
|
|
9
|
-
## 1.
|
|
9
|
+
## 1. Setting up a new cloud environment
|
|
10
10
|
|
|
11
|
-
The `install
|
|
11
|
+
The `install` script provides a streamlined way to install the Powerhouse CLI tool and all its necessary dependencies. This script handles the installation of node.js 22, pnpm, Powerhouse CLI itself and the services. It's designed to work across different Linux distributions, though it's optimized for Ubuntu and Debian-based systems. It also prepares your machine for running Powerhouse services. It handles everything from package installation to service configuration, making the setup process straightforward and automated. This script is particularly useful for setting up new servers or reconfiguring existing ones.
|
|
12
12
|
|
|
13
|
-
### Installation Steps:
|
|
14
|
-
1. Download the setup script:
|
|
15
|
-
```bash
|
|
16
|
-
curl -O https://raw.githubusercontent.com/powerhouse-inc/powerhouse/refs/heads/main/scripts/install-tools.sh
|
|
17
|
-
```
|
|
18
|
-
|
|
19
|
-
2. Make the script executable:
|
|
20
|
-
```bash
|
|
21
|
-
chmod +x install-tools.sh
|
|
22
|
-
```
|
|
23
13
|
|
|
24
|
-
|
|
14
|
+
### Installation Steps:
|
|
15
|
+
1. Run the setup script:
|
|
25
16
|
```bash
|
|
26
|
-
|
|
17
|
+
curl -fsSL https://apps.powerhouse.io/install | bash # for macOS, Linux, and WSL
|
|
27
18
|
```
|
|
28
19
|
|
|
29
|
-
|
|
30
|
-
- `dev`: Development version - Use this for testing new features or development work
|
|
31
|
-
- `staging`: Staging version - Use this for pre-production testing
|
|
32
|
-
- RECOMMENDED: `latest`: Latest stable version - Recommended for production environments
|
|
33
|
-
- Press Enter to go ahead with the latest version
|
|
34
|
-
|
|
35
|
-
5. After installation, source your shell configuration:
|
|
20
|
+
2. After installation, source your shell configuration:
|
|
36
21
|
```bash
|
|
37
22
|
source ~/.bashrc # or source ~/.zshrc if using zsh
|
|
38
23
|
```
|
|
39
24
|
|
|
40
|
-
|
|
25
|
+
3. Verify the installation:
|
|
41
26
|
```bash
|
|
42
27
|
ph --version
|
|
43
28
|
```
|
|
44
29
|
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
curl -O https://raw.githubusercontent.com/powerhouse-inc/powerhouse/refs/heads/main/scripts/setup-environment.sh
|
|
50
|
-
```
|
|
51
|
-
|
|
52
|
-
The `setup-environment.sh` script is a comprehensive tool that prepares your machine for running Powerhouse services. It handles everything from package installation to service configuration, making the setup process straightforward and automated. This script is particularly useful for setting up new servers or reconfiguring existing ones.
|
|
30
|
+
4. You will see ph-cli is not yet installed. But it will get installed automatically in the next step.
|
|
31
|
+
If you are a builder that wants to make use of the dev releases use `ph use dev` before going to the next step.
|
|
32
|
+
- `ph use dev`: Development version - Use this for testing new features or development work
|
|
33
|
+
- `ph use staging`: Staging version - Use this for pre-production testing
|
|
53
34
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
1. Make the script executable:
|
|
57
|
-
```bash
|
|
58
|
-
chmod +x setup-environment.sh
|
|
59
|
-
```
|
|
60
|
-
|
|
61
|
-
2. Run the script:
|
|
62
|
-
```bash
|
|
63
|
-
./setup-environment.sh
|
|
64
|
-
```
|
|
65
|
-
|
|
66
|
-
3. Follow the interactive prompts:
|
|
35
|
+
5. Follow the interactive prompts:
|
|
67
36
|
|
|
68
37
|
### Step 1: Package Installation
|
|
69
|
-
During the package installation phase, you'll be prompted to enter package names that you want to install. For example, you might want to install `@
|
|
38
|
+
During the package installation phase, you'll be prompted to enter package names that you want to install. For example, you might want to install `@powerhousedao/todo-demo-package` or other Powerhouse packages. This step is crucial for adding the specific functionality you need to your Powerhouse installation. You can press Enter to skip this step if you don't need to install any packages immediately, but you can always install packages later using the `ph install` command.
|
|
70
39
|
|
|
71
40
|
### Step 2: Database Configuration
|
|
72
41
|
The script offers two options for database configuration.
|
|
@@ -138,7 +107,7 @@ It will take a minute or two for your Droplet to be provisioned. Once it's ready
|
|
|
138
107
|
|
|
139
108
|
To log in via SSH:
|
|
140
109
|
|
|
141
|
-
1. Open a terminal (on macOS/Linux) or an SSH client like PuTTY (on Windows).
|
|
110
|
+
1. Open a terminal (on macOS/Linux) or an SSH client like PuTTY (on Windows). You can also use Digital Ocean's web 'Console'.
|
|
142
111
|
2. Use one of these commands:
|
|
143
112
|
```bash
|
|
144
113
|
# If using password authentication
|
|
@@ -154,7 +123,7 @@ To log in via SSH:
|
|
|
154
123
|
3. If you used a password, you'll be prompted to enter it.
|
|
155
124
|
4. If it's your first time logging in, you might be asked to change the root password.
|
|
156
125
|
|
|
157
|
-
Now your Droplet is running!
|
|
126
|
+
Now your Droplet is running! Now you can continue with the Powerhouse tutorial or any next steps.
|
|
158
127
|
|
|
159
128
|
### DNS Configuration
|
|
160
129
|
|
|
@@ -165,7 +134,7 @@ Now your Droplet is running! You'll likely want to install and configure a web s
|
|
|
165
134
|
- Enter your domain name (e.g., `yourdomain.com`)
|
|
166
135
|
- Click "Add Domain"
|
|
167
136
|
|
|
168
|
-
2. **
|
|
137
|
+
2. **Start with Updating Nameservers at Your Domain Registrar:**
|
|
169
138
|
- Log in to your domain registrar
|
|
170
139
|
- Update nameservers to:
|
|
171
140
|
```
|
|
@@ -187,9 +156,9 @@ Now your Droplet is running! You'll likely want to install and configure a web s
|
|
|
187
156
|
- **WILL DIRECT TO:** Your Droplet's IP
|
|
188
157
|
- **TTL:** 3600
|
|
189
158
|
|
|
190
|
-
#### Option B: Using Your Existing Nameservers
|
|
159
|
+
#### Option B: Using Your Existing Nameservers (NS locked)
|
|
191
160
|
|
|
192
|
-
1. **Create DNS Records at Your Registrar:**
|
|
161
|
+
1. **Just Create DNS Records at Your Registrar:**
|
|
193
162
|
- **Root Domain (A Record):**
|
|
194
163
|
- **TYPE:** A
|
|
195
164
|
- **HOSTNAME:** @
|
|
@@ -324,10 +293,16 @@ Security is a top priority in the setup process. The script implements automatic
|
|
|
324
293
|
|
|
325
294
|
After the installation is complete, it's important to verify that everything is working correctly. You can check the status of your services using PM2, verify the Nginx configuration, and ensure your SSL certificates are properly installed. This step is crucial for identifying any potential issues before they affect your users.
|
|
326
295
|
|
|
327
|
-
1. Check service status:
|
|
296
|
+
1. Check service status of switchboard & connect:
|
|
297
|
+
```bash
|
|
298
|
+
ph service status
|
|
299
|
+
```
|
|
300
|
+
You can also use
|
|
301
|
+
|
|
328
302
|
```bash
|
|
329
|
-
|
|
303
|
+
ph service start | stop | restart
|
|
330
304
|
```
|
|
305
|
+
- to start | stop | restart switchboard and connect
|
|
331
306
|
|
|
332
307
|
2. View Nginx configuration:
|
|
333
308
|
```bash
|
|
@@ -390,12 +365,12 @@ ph update <package-name>
|
|
|
390
365
|
|
|
391
366
|
### Restarting Services:
|
|
392
367
|
```bash
|
|
393
|
-
|
|
368
|
+
ph service restart
|
|
394
369
|
```
|
|
395
370
|
|
|
396
371
|
### Viewing Logs:
|
|
397
372
|
```bash
|
|
398
|
-
|
|
373
|
+
ph service status
|
|
399
374
|
```
|
|
400
375
|
|
|
401
376
|
## 7. Security Notes
|
|
@@ -1,5 +1,87 @@
|
|
|
1
1
|
# React Hooks (WIP)
|
|
2
2
|
|
|
3
|
+
The idea is to make this feel as simple and familiar as using useState.
|
|
4
|
+
Happy Path would look something like this:
|
|
5
|
+
|
|
6
|
+
```js
|
|
7
|
+
// in a component that only needs to read a value, you can use
|
|
8
|
+
const invoiceName = useReadDocumentField('myInvoiceDocumentId', 'name') // returns a string which is the `name`
|
|
9
|
+
// and for documents that need to update data as well, you would have
|
|
10
|
+
const updateInvoiceName = useUpdateDocumentField('myInvoiceDocumentId', 'name') // returns a function that takes a new string for the new name and dispatches the update
|
|
11
|
+
// finally, we can combine these into a single hook which works like react's useState hook returning both the value and updater function
|
|
12
|
+
const [invoiceName, updateInvoiceName] = useDocumentField('myInvoiceDocumentId', 'name')
|
|
13
|
+
|
|
14
|
+
|
|
15
|
+
// Read-only value
|
|
16
|
+
const invoiceName = useReadDocumentField('docId', 'name')
|
|
17
|
+
|
|
18
|
+
// Write-only updater
|
|
19
|
+
const updateInvoiceName = useUpdateDocumentField('docId', 'name')
|
|
20
|
+
|
|
21
|
+
// Combined read + write (like useState)
|
|
22
|
+
const [invoiceName, updateInvoiceName] = useDocumentField('docId', 'name')
|
|
23
|
+
```
|
|
24
|
+
|
|
25
|
+
Request Translation
|
|
26
|
+
Global access to drive state: A top-level, possibly context-based, way to introspect and interact with any document and its state tree without manually passing things around.
|
|
27
|
+
Global dispatcher access: A utility or API (probably a hook or service function) where they give a document ID and get back all the relevant dispatch functions — kind of like a command palette for document ops.
|
|
28
|
+
Time spent wiring > time spent building Frustration with current DX (developer experience) — they want abstractions and helpers to just do the thing.
|
|
29
|
+
|
|
30
|
+
Core Hooks & Patterns
|
|
31
|
+
- useDocumentField
|
|
32
|
+
- useReadDocumentField
|
|
33
|
+
- useUpdateDocumentField
|
|
34
|
+
- useDocumentDispatch(docId): updateX, delete, ...
|
|
35
|
+
|
|
36
|
+
Global Drive Access
|
|
37
|
+
- How to access and manipulate the global document tree
|
|
38
|
+
- How to inspect children from parent context
|
|
39
|
+
- Tree traversal utilities (if any)
|
|
40
|
+
|
|
41
|
+
Convenience APIs
|
|
42
|
+
- Utility functions like getDispatchFunctions(docId)
|
|
43
|
+
- “Quick Start” to manipulate any document like a pro
|
|
44
|
+
|
|
45
|
+
Working with Context
|
|
46
|
+
- DriveContext: what lives there, how to use it
|
|
47
|
+
- Example: using context to get current doc, sibling docs
|
|
48
|
+
|
|
49
|
+
Best Practices & Patterns
|
|
50
|
+
- When to use useDocumentField vs getDispatch
|
|
51
|
+
- Composing document fields into custom logic
|
|
52
|
+
|
|
53
|
+
<details>
|
|
54
|
+
<summary>Refresher on React Hooks</summary>
|
|
55
|
+
|
|
56
|
+
React Hooks allow you to use various React features directly within your functional components. You can use built-in Hooks or combine them to create your own custom Hooks.
|
|
57
|
+
|
|
58
|
+
**What are Custom Hooks?**
|
|
59
|
+
A custom hook is a JavaScript function whose name starts with "use" and that calls other Hooks. They are used to:
|
|
60
|
+
- Reuse stateful logic between components.
|
|
61
|
+
- Abstract complex logic into a simpler interface.
|
|
62
|
+
- Isolate side effects, particularly those managed by `useEffect`.
|
|
63
|
+
|
|
64
|
+
**Key Built-in Hooks Examples:**
|
|
65
|
+
- `useState`: Lets a component "remember" information (state).
|
|
66
|
+
- `useEffect`: Lets a component perform side effects (e.g., data fetching, subscriptions, manually changing the DOM).
|
|
67
|
+
- `useContext`: Lets a component receive information from distant parent components without explicitly passing props through every level of the component tree.
|
|
68
|
+
|
|
69
|
+
**Naming Convention:**
|
|
70
|
+
Hook names must always start with `use` followed by a capital letter (e.g., `useState`, `useOnlineStatus`).
|
|
71
|
+
|
|
72
|
+
**Rules of Hooks:**
|
|
73
|
+
1. **Only Call Hooks at the Top Level**: Don't call Hooks inside loops, conditions, or nested functions.
|
|
74
|
+
2. **Only Call Hooks from React Functions**: Call Hooks from React functional components or from custom Hooks.
|
|
75
|
+
|
|
76
|
+
It's important to note that a function should only be named and treated as a hook if it actually utilizes one or more built-in React hooks. If a function (even if named `useSomething`) doesn't call any built-in hooks, it behaves like a regular JavaScript function, and making it a "hook" offers no specific React advantages.
|
|
77
|
+
|
|
78
|
+
For more details, see the official documentation and our API reference:
|
|
79
|
+
- [Reusing Logic with Custom Hooks (react.dev)](https://react.dev/learn/reusing-logic-with-custom-hooks)
|
|
80
|
+
- [Rules of Hooks (react.dev)](https://react.dev/reference/rules/rules-of-hooks)
|
|
81
|
+
- [Powerhouse React Hooks API Reference](docs/academy/APIReferences/ReactHooks)
|
|
82
|
+
|
|
83
|
+
</details>
|
|
84
|
+
|
|
3
85
|
### Hook Name and Signature
|
|
4
86
|
The name of the hook and its TypeScript (or JavaScript) signature.
|
|
5
87
|
### Description
|
package/package.json
CHANGED
|
@@ -1,7 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@powerhousedao/academy",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "2.5.0-dev.0",
|
|
4
4
|
"homepage": "https://powerhouse.academy",
|
|
5
|
+
"repository": {
|
|
6
|
+
"type": "git",
|
|
7
|
+
"url": "https://github.com/powerhouse-inc/powerhouse"
|
|
8
|
+
},
|
|
5
9
|
"dependencies": {
|
|
6
10
|
"@codesandbox/sandpack-react": "^2.14.4",
|
|
7
11
|
"@docusaurus/core": "^3.8.0",
|
package/sidebars.ts
CHANGED
|
@@ -10,7 +10,7 @@ import type { SidebarsConfig } from '@docusaurus/plugin-content-docs';
|
|
|
10
10
|
|
|
11
11
|
Create as many sidebars as you want.
|
|
12
12
|
*/
|
|
13
|
-
const sidebars
|
|
13
|
+
const sidebars = {
|
|
14
14
|
// By default, Docusaurus generates a sidebar from the docs folder structure
|
|
15
15
|
academySidebar: [
|
|
16
16
|
{
|
|
@@ -49,9 +49,18 @@ const sidebars: SidebarsConfig = {
|
|
|
49
49
|
type: 'category',
|
|
50
50
|
label: 'Document Model Creation',
|
|
51
51
|
link: {
|
|
52
|
-
type: '
|
|
52
|
+
type: 'doc',
|
|
53
|
+
id: "academy/MasteryTrack/DocumentModelCreation/WhatIsADocumentModel"
|
|
53
54
|
},
|
|
54
|
-
items: [
|
|
55
|
+
items: [
|
|
56
|
+
'academy/MasteryTrack/DocumentModelCreation/WhatIsADocumentModel',
|
|
57
|
+
'academy/MasteryTrack/DocumentModelCreation/SpecifyTheStateSchema',
|
|
58
|
+
'academy/MasteryTrack/DocumentModelCreation/SpecifyDocumentOperations',
|
|
59
|
+
'academy/MasteryTrack/DocumentModelCreation/UseTheDocumentModelGenerator',
|
|
60
|
+
'academy/MasteryTrack/DocumentModelCreation/ImplementDocumentReducers',
|
|
61
|
+
'academy/MasteryTrack/DocumentModelCreation/ImplementDocumentModelTests',
|
|
62
|
+
'academy/MasteryTrack/DocumentModelCreation/ExampleToDoListRepository',
|
|
63
|
+
]
|
|
55
64
|
},
|
|
56
65
|
{
|
|
57
66
|
type: 'category',
|
|
@@ -59,7 +68,27 @@ const sidebars: SidebarsConfig = {
|
|
|
59
68
|
link: {
|
|
60
69
|
type: 'generated-index',
|
|
61
70
|
},
|
|
62
|
-
items: [
|
|
71
|
+
items: [
|
|
72
|
+
'academy/MasteryTrack/BuildingUserExperiences/BuildingDocumentEditors',
|
|
73
|
+
'academy/MasteryTrack/BuildingUserExperiences/ConfiguringDrives',
|
|
74
|
+
'academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer',
|
|
75
|
+
]
|
|
76
|
+
},
|
|
77
|
+
{
|
|
78
|
+
type: 'category',
|
|
79
|
+
label: 'Document Tools',
|
|
80
|
+
link: {
|
|
81
|
+
type: 'generated-index',
|
|
82
|
+
},
|
|
83
|
+
items: [{ type: 'autogenerated', dirName: 'academy/02-MasteryTrack/03-BuildingUserExperiences/07-DocumentTools' }]
|
|
84
|
+
},
|
|
85
|
+
{
|
|
86
|
+
type: 'category',
|
|
87
|
+
label: 'Authorization',
|
|
88
|
+
link: {
|
|
89
|
+
type: 'generated-index',
|
|
90
|
+
},
|
|
91
|
+
items: [{ type: 'autogenerated', dirName: 'academy/02-MasteryTrack/03-BuildingUserExperiences/08-Authorization' }]
|
|
63
92
|
},
|
|
64
93
|
{
|
|
65
94
|
type: 'category',
|
|
@@ -164,7 +164,7 @@ export default function HomepageFeatures() {
|
|
|
164
164
|
</div>
|
|
165
165
|
<div className={styles.cardContent}>
|
|
166
166
|
<a href="/docs/academy/GetStarted/BuildToDoListEditor" className={styles.pathButton}>Building a Todo-list Editor</a>
|
|
167
|
-
<a href="/docs/academy/BuildingUserExperiences/
|
|
167
|
+
<a href="/docs/academy/BuildingUserExperiences/BuildingDocumentEditors" className={styles.pathButton}>Building Beautiful Document Editors</a>
|
|
168
168
|
<a href="/docs/academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer" className={styles.pathButton}>Building Custom Drive Explorers</a>
|
|
169
169
|
</div>
|
|
170
170
|
</div>
|
package/src/css/custom.css
CHANGED
|
@@ -459,3 +459,8 @@ html[data-theme='dark'] .DocSearch-Hits > *:empty {
|
|
|
459
459
|
.doc-card-list-item {
|
|
460
460
|
width: 100%; /* Ensure items take full width */
|
|
461
461
|
}
|
|
462
|
+
|
|
463
|
+
/* Attempt to hide icons in DocCard titles */
|
|
464
|
+
.doc-card-list .card h2 svg {
|
|
465
|
+
display: none !important;
|
|
466
|
+
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
# Build Document Editors
|
|
2
|
-
|
|
3
|
-
*Placeholder for a tutorial about building beautiful document editors.*
|
|
4
|
-
|
|
5
|
-
## Build with React on Powerhouse
|
|
6
|
-
|
|
7
|
-
At Powerhouse, frontend development follows a simple and familiar flow. Tailwind CSS is installed by default and fully managed by Connect Studio — you can use Tailwind classes freely, but you’re not required to. Regular CSS, inline styles, and any React-compatible styling method work exactly as you would expect in a standard React project. There is no need to manually configure or run Tailwind or build processes; **Connect Studio automatically handles everything during development.**
|
|
8
|
-
|
|
9
|
-
For component visualization and testing, **Connect Studio replaces the need for Storybook**. Please do not use Storybook by default — Connect Studio provides a dynamic, local environment where you can define and preview your document models and editors live. If you still wish to set up Storybook on your own, you may, but it is unsupported and discouraged.
|
|
10
|
-
|
|
11
|
-
During normal development, simply run Connect Studio with `ph connect`. Manual build commands are only needed when you publish a package, at which point the necessary build steps (including CSS generation) are handled automatically.
|
|
12
|
-
|
|
13
|
-
Powerhouse aims to keep your developer experience clean, familiar, and focused.
|
|
14
|
-
- Build React components as you would in any project.
|
|
15
|
-
- Use styling approaches you're comfortable with.
|
|
16
|
-
- Trust Connect Studio to handle the setup for you.
|
|
17
|
-
|
|
18
|
-
### Building with react hooks
|
|
19
|
-
|
|
20
|
-
What are React Hooks?
|
|
21
|
-
|
|
22
|
-
From the React docs:
|
|
23
|
-
|
|
24
|
-
"Hooks let you use different React features from your components. You can either use the built-in Hooks or combine them to build your own."
|
|
25
|
-
https://react.dev/reference/react/hooks
|
|
26
|
-
|
|
27
|
-
The "combine them to build your own" part is key here. A so-called "custom hook" is just a function that uses these built-in hooks.
|
|
28
|
-
|
|
29
|
-
There are several types of built-in hooks which are used to solve different problems.
|
|
30
|
-
|
|
31
|
-
For example:
|
|
32
|
-
|
|
33
|
-
State lets a component “remember” information like user input.
|
|
34
|
-
|
|
35
|
-
Effects let a component connect to and synchronize with external systems.
|
|
36
|
-
|
|
37
|
-
Context lets a component receive information from distant parents without passing it as props.
|
|
38
|
-
|
|
39
|
-
Details about custom hooks are provided here: https://react.dev/learn/reusing-logic-with-custom-hooks
|
|
40
|
-
|
|
41
|
-
In summary, there are three reasons to use custom hooks:
|
|
42
|
-
|
|
43
|
-
To re-use logic that calls multiple hooks.
|
|
44
|
-
To abstract away the complexity of multiple hooks.
|
|
45
|
-
To isolate the side effects of the useEffect hook.
|
|
46
|
-
|
|
47
|
-
Hook names must start with use followed by a capital letter, like useState (built-in) or useOnlineStatus (custom, like earlier on the page). Hooks may return arbitrary values.
|
|
48
|
-
|
|
49
|
-
https://react.dev/learn/reusing-logic-with-custom-hooks#hook-names-always-start-with-use
|
|
50
|
-
|
|
51
|
-
When you use any function that starts with "use", react will treat it as a hook and expect it to follow the rules of hooks.
|
|
52
|
-
|
|
53
|
-
Rules of Hooks
|
|
54
|
-
https://react.dev/reference/rules/rules-of-hooks
|
|
55
|
-
|
|
56
|
-
Hooks are defined using JavaScript functions, but they represent a special type of reusable UI logic with restrictions on where they can be called.
|
|
57
|
-
|
|
58
|
-
Only call Hooks at the top level
|
|
59
|
-
Only call Hooks from React functions
|
|
60
|
-
|
|
61
|
-
React needs these rules to ensure that the state is properly managed and that the component behaves as expected.
|
|
62
|
-
|
|
63
|
-
So it is indeed possible to create a "hook" like so:
|
|
64
|
-
|
|
65
|
-
```
|
|
66
|
-
function useCurrentTime() {
|
|
67
|
-
const currentTime = new Date().toLocaleTimeString();
|
|
68
|
-
|
|
69
|
-
return currentTime;
|
|
70
|
-
}
|
|
71
|
-
```
|
|
72
|
-
|
|
73
|
-
And this is technically a hook, but making it a hook is pointless because it doesn't use any of the built-in hooks.
|
|
74
|
-
|
|
75
|
-
There is no reason that this could not just be:
|
|
76
|
-
|
|
77
|
-
```
|
|
78
|
-
function getCurrentTime() {
|
|
79
|
-
return new Date().toLocaleTimeString();
|
|
80
|
-
}
|
|
81
|
-
```
|
|
82
|
-
|
|
83
|
-
Because in a component, both hooks and normal functions are called on every render.
|
|
84
|
-
|
|
85
|
-
So if your component looks like this:
|
|
86
|
-
|
|
87
|
-
```
|
|
88
|
-
function MyComponent() {
|
|
89
|
-
const currentTimeFromFunc = getCurrentTime();
|
|
90
|
-
}
|
|
91
|
-
```
|
|
92
|
-
|
|
93
|
-
or this:
|
|
94
|
-
|
|
95
|
-
```
|
|
96
|
-
function MyComponent() {
|
|
97
|
-
const currentTimeFromHook = useCurrentTime();
|
|
98
|
-
}
|
|
99
|
-
```
|
|
100
|
-
|
|
101
|
-
The end result would be the same. The function would be called on every render.
|
|
102
|
-
|
|
103
|
-
So in summary, the only reason a function should be a hook is if it uses one or more built-in hooks.
|
|
104
|
-
|
|
105
|
-
In general, you will not want to take a normal function and turn it into a hook, because your normal function should not have been trying to use react hooks in the first place.
|
|
106
|
-
|
|
107
|
-
## Powerhouse Component Library
|
|
108
|
-
|
|
109
|
-
TBD
|