@powerhousedao/academy 2.5.0-dev.4 → 2.5.0-dev.40

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.
Files changed (57) hide show
  1. package/CHANGELOG.md +237 -0
  2. package/docs/academy/01-GetStarted/00-ExploreDemoPackage.md +19 -15
  3. package/docs/academy/01-GetStarted/01-CreateNewPowerhouseProject.md +39 -40
  4. package/docs/academy/01-GetStarted/02-DefineToDoListDocumentModel.md +22 -7
  5. package/docs/academy/01-GetStarted/03-ImplementOperationReducers.md +9 -4
  6. package/docs/academy/01-GetStarted/04-BuildToDoListEditor.md +146 -422
  7. package/docs/academy/01-GetStarted/_04-BuildToDoListEditor +360 -0
  8. package/docs/academy/01-GetStarted/home.mdx +16 -24
  9. package/docs/academy/01-GetStarted/styles.module.css +31 -0
  10. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/01-Prerequisites.md +0 -18
  11. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/02-StandardDocumentModelWorkflow.md +10 -6
  12. package/docs/academy/02-MasteryTrack/01-BuilderEnvironment/03-BuilderTools.md +1 -1
  13. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/01-WhatIsADocumentModel.md +33 -16
  14. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/02-SpecifyTheStateSchema.md +73 -0
  15. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/03-SpecifyDocumentOperations.md +59 -4
  16. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/04-UseTheDocumentModelGenerator.md +32 -12
  17. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/05-ImplementDocumentReducers.md +103 -38
  18. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/06-ImplementDocumentModelTests.md +90 -228
  19. package/docs/academy/02-MasteryTrack/02-DocumentModelCreation/07-ExampleToDoListRepository.md +41 -1
  20. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/01-BuildingDocumentEditors.md +342 -67
  21. package/docs/academy/02-MasteryTrack/03-BuildingUserExperiences/02-ConfiguringDrives.md +5 -3
  22. package/docs/academy/02-MasteryTrack/05-Launch/02-PublishYourProject.md +70 -5
  23. package/docs/academy/02-MasteryTrack/05-Launch/03-SetupEnvironment.md +162 -73
  24. package/docs/academy/02-MasteryTrack/05-Launch/{03-RunOnACloudServer.md → _03-RunOnACloudServer} +8 -5
  25. package/docs/academy/03-ExampleUsecases/Chatroom/02-CreateNewPowerhouseProject.md +10 -9
  26. package/docs/academy/03-ExampleUsecases/Chatroom/03-DefineChatroomDocumentModel.md +3 -4
  27. package/docs/academy/03-ExampleUsecases/Chatroom/05-ImplementChatroomEditor.md +1 -1
  28. package/docs/academy/03-ExampleUsecases/Chatroom/_category_.json +1 -1
  29. package/docs/academy/04-APIReferences/00-PowerhouseCLI.md +13 -49
  30. package/docs/academy/05-Architecture/00-PowerhouseArchitecture.md +3 -0
  31. package/docs/academy/05-Architecture/images/PowerhouseArchitecture.png +0 -0
  32. package/docs/academy/06-ComponentLibrary/00-DocumentEngineering.md +85 -30
  33. package/docs/academy/06-ComponentLibrary/02-CreateCustomScalars.md +382 -0
  34. package/docs/academy/06-ComponentLibrary/03-IntegrateIntoAReactComponent.md +124 -0
  35. package/docs/academy/07-Cookbook.md +252 -4
  36. package/docs/academy/08-Glossary.md +20 -18
  37. package/docs/academy/09-AIResources +131 -0
  38. package/docusaurus.config.ts +4 -0
  39. package/package.json +1 -1
  40. package/sidebars.ts +3 -45
  41. package/src/css/custom.css +23 -1
  42. package/docs/academy/03-ExampleUsecases/Chatroom/01-SetupBuilderEnvironment.md +0 -216
  43. package/docs/academy/06-ComponentLibrary/02-BuildingWithScalars.md +0 -54
  44. package/docs/academy/06-ComponentLibrary/03-Scalar-Components/01-phid-field.mdx +0 -72
  45. package/docs/academy/06-ComponentLibrary/03-Scalar-Components/02-input-field.mdx +0 -0
  46. package/docs/academy/06-ComponentLibrary/04-Complex-Components/01-sidebar.mdx +0 -36
  47. package/docs/academy/06-ComponentLibrary/05-Layout-Components/01-test-toupdate.mdx +0 -61
  48. package/docs/academy/06-ComponentLibrary/06-Fragments/01-test-toupdate.mdx +0 -61
  49. /package/docs/academy/02-MasteryTrack/05-Launch/{02-IntroductionToPackages.md → 01-IntroductionToPackages.md} +0 -0
  50. /package/docs/academy/02-MasteryTrack/05-Launch/{00-IntegrateInAFront-End → _00-IntegrateInAFront-End} +0 -0
  51. /package/docs/academy/02-MasteryTrack/05-Launch/{01-IntroducingFusion → _01-IntroducingFusion} +0 -0
  52. /package/docs/academy/02-MasteryTrack/05-Launch/{04-GraphQLNamespacing → _04-GraphQLNamespacing} +0 -0
  53. /package/docs/academy/02-MasteryTrack/05-Launch/{05-LaunchYourBackend.md → _05-LaunchYourBackend} +0 -0
  54. /package/docs/academy/02-MasteryTrack/05-Launch/{06-LaunchYourFrontend.md → _06-LaunchYourFrontend} +0 -0
  55. /package/docs/academy/04-APIReferences/{01-ReactHooks.md → 01-ReactHooks} +0 -0
  56. /package/docs/academy/04-APIReferences/{02-ReactorAPI.md → 02-ReactorAPI} +0 -0
  57. /package/docs/academy/04-APIReferences/{03-Configuration.md → 03-Configuration} +0 -0
@@ -6,7 +6,8 @@ At Powerhouse, frontend development for document editors follows a simple and fa
6
6
 
7
7
  ### Development Environment
8
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).
9
+ Connect Studio is your primary tool for development.
10
+ 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
 
11
12
  Key aspects of the Powerhouse development environment:
12
13
  - **React Foundation**: Build your editor UIs using React components, just as you would in any standard React project.
@@ -20,7 +21,8 @@ Powerhouse aims to keep your developer experience clean, familiar, and focused:
20
21
 
21
22
  ### Generating Your Editor Template
22
23
 
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
+ To kickstart your editor development, Powerhouse provides a command to generate a basic editor template. This command reads your document model specifications and creates the initial `editor.tsx` file.
25
+ If you want a refresher on how to define your document model specification please read the chapter on [specifying the State Schema](/academy/MasteryTrack/DocumentModelCreation/SpecifyTheStateSchema)
24
26
 
25
27
  For example, to generate an editor for a `ToDoList` document model with a document type `powerhouse/todolist`:
26
28
  ```bash
@@ -72,40 +74,6 @@ You have several options for styling your editor components:
72
74
 
73
75
  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
76
 
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
77
  ### State Management in Editors
110
78
 
111
79
  When you build an editor in Powerhouse, your main editor component receives `EditorProps`. These props are crucial for interacting with the document:
@@ -176,26 +144,69 @@ Storybook allows you to:
176
144
  </Form>
177
145
  ```
178
146
 
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.
147
+ <details>
148
+ <summary>Tutorial: Implementing the `ToDoList` Editor</summary>
149
+
150
+ ## Build a ToDoList Editor
151
+
152
+ In this final part of our tutorial we will continue with the interface or editor implementation of the **ToDoList** document model. This means you will create a simple user interface for the **ToDoList** document model which will be used inside the Connect app to create, update and delete your ToDoList items, but also dispaly the statistics we've implemented in our reducers.
153
+
154
+ ## Generate the editor template
155
+
156
+ Run the command below to generate the editor template for the **ToDoList** document model.
157
+ This command reads the **ToDoList** document model definition from the `document-models` folder and generates the editor template in the `editors/to-do-list` folder as `editor.tsx`.
158
+
159
+ Notice the `--editor` flag which specifies the **ToDoList** document model, and the `--document-types` flag defines the document type `powerhouse/todolist`.
160
+
161
+ ```bash
162
+ ph generate --editor ToDoList --document-types powerhouse/todolist
163
+ ```
164
+
165
+ Once complete, navigate to the `editors/to-do-list/editor.tsx` file and open it in your editor.
166
+
167
+
168
+ ### Editor Implementation Options
169
+
170
+ When building your editor component within the Powerhouse ecosystem, you have several options for styling, allowing you to leverage your preferred methods:
171
+
172
+ 1. **Default HTML Styling:** Standard HTML tags (`<h1>`, `<p>`, `<button>`, etc.) will render with default styles offered through the boilerplate.
173
+ 2. **Tailwind CSS:** Connect Studio comes with Tailwind CSS integrated. You can directly use Tailwind utility classes for rapid, consistent styling without writing separate CSS files.
174
+ 3. **Custom CSS Files:** You can import traditional CSS files (`.css`) to apply custom styles or integrate existing style libraries.
175
+
176
+ Connect Studio provides a dynamic local environment (`ph connect`) to visualize your components instantly as you build them, regardless of the styling method you choose. Manual build steps are typically only needed when publishing packages.
177
+
178
+ ---
179
+
180
+ ## ToDoList Editor
181
+
182
+ :::tip
183
+ ### Implementing Components
184
+ The editor we are about to implement makes use of some components from **Powerhouse Document Engineering**.
185
+ When you add the editor code, you'll see it makes use of two components, the `Checkbox` and `InputField`.
186
+ These are imported from the Powerhouse Document Engineering design system (`@powerhousedao/document-engineering/scalars`).
187
+
188
+ This system provides a library of reusable components to ensure consistency and speed up development.
189
+ You can explore available components, see usage examples, and understand their properties (props) using our Storybook instance. For a detailed guide on how to leverage the Document Engineering design system and Storybook, see [Using the Powerhouse Document Engineering](/academy/ComponentLibrary/DocumentEngineering) page.
181
190
 
182
- **Example: Local `Checkbox` Wrapper (conceptual)**
191
+ For this tutorial, create a `components` folder inside `editors/to-do-list`. Then, within this new `components` folder, create the files for the `Checkbox` and `InputField` components (e.g., `checkbox.tsx` and `inputfield.tsx`) with the following code:
192
+ :::
193
+
194
+ <details>
195
+ <summary>Checkbox</summary>
183
196
  ```typescript
184
- // editors/to-do-list/components/checkbox.tsx
185
197
  import { Form, BooleanField } from "@powerhousedao/document-engineering/scalars";
186
198
 
187
- interface CustomCheckboxProps {
199
+ interface CheckboxProps {
188
200
  value: boolean;
189
201
  onChange: (value: boolean) => void;
190
- label?: string; // Added custom prop or passed through
191
202
  }
192
203
 
193
- export const Checkbox = ({ value, onChange, label }: CustomCheckboxProps) => {
204
+ export const Checkbox = ({ value, onChange }: CheckboxProps) => {
194
205
  return (
195
- <Form onSubmit={() => { /* May not be needed for simple checkbox */ }}>
206
+ <Form onSubmit={() => {}}>
196
207
  <BooleanField
197
- name="customChecked" // Internal name for the form field
198
- description={label || "Toggle state"} // Use label for description
208
+ name="checked"
209
+ description="Check this box to mark the todo as completed"
199
210
  value={value}
200
211
  onChange={onChange}
201
212
  />
@@ -203,31 +214,295 @@ export const Checkbox = ({ value, onChange, label }: CustomCheckboxProps) => {
203
214
  );
204
215
  };
205
216
  ```
206
- This pattern helps keep your main editor file cleaner and allows for more complex compositions.
217
+ </details>
218
+
219
+ <details>
220
+ <summary>Inputfield</summary>
221
+ ```typescript
222
+ import { Form, StringField } from "@powerhousedao/document-engineering/scalars";
223
+
224
+ interface InputFieldProps {
225
+ input: string;
226
+ value: string;
227
+ label?: string;
228
+ onKeyDown: (e: React.KeyboardEvent<HTMLTextAreaElement>) => void;
229
+ handleInputChange: (e: React.ChangeEvent<HTMLTextAreaElement>) => void;
230
+ }
231
+
232
+ export const InputField = (props: InputFieldProps) => {
233
+ const { input, value, label, onKeyDown, handleInputChange } = props;
234
+
235
+ return (
236
+ <Form
237
+ defaultValues={{
238
+ input: input,
239
+ }}
240
+ onSubmit={() => {}}
241
+ resetOnSuccessfulSubmit
242
+ >
243
+ <StringField
244
+ style={{
245
+ color: "black",
246
+ }}
247
+ label={label}
248
+ name="input"
249
+ value={value}
250
+ onKeyDown={onKeyDown}
251
+ onChange={(e: React.ChangeEvent<HTMLTextAreaElement>) => {
252
+ handleInputChange(e);
253
+ }}
254
+ />
255
+ </Form>
256
+ );
257
+ };
258
+ ```
259
+ </details>
260
+
261
+
262
+ Below is the complete code for the To-Do List editor. It primarily uses Tailwind CSS for styling and imports the local `Checkbox` and `InputField` components you created in the previous step. These local components, in turn, utilize elements from the Powerhouse Document Engineering design system.
263
+
264
+ <details>
265
+ <summary>Complete ToDoList Editor Example (using Tailwind CSS)</summary>
266
+
267
+ ```typescript
268
+ import { EditorProps } from 'document-model'; // Core type for editor components.
269
+ import {
270
+ ToDoListState, // Type for the global state of the ToDoList.
271
+ ToDoListAction, // Type for actions that can modify the ToDoList state.
272
+ ToDoListLocalState, // Type for local (non-shared) editor state (if needed).
273
+ ToDoItem, // Type for a single item in the list.
274
+ actions, // Object containing action creators for dispatching changes.
275
+ ToDoListDocument // The complete document structure including state and metadata.
276
+ } from '../document-models/to-do-list/index.js'; // Path to your document model definition.
277
+ import { useState } from 'react'; // React hook for managing component-local state.
278
+ import { Checkbox } from './components/checkbox.js'; // Custom Checkbox component.
279
+ import { InputField } from './components/inputfield.js'; // Custom InputField component.
280
+
281
+ // Define the props expected by this Editor component. It extends EditorProps with our specific document type.
282
+ export type IProps = EditorProps<ToDoListDocument>;
283
+
284
+ // Define the main Editor component function.
285
+ export default function Editor(props: IProps) {
286
+ // Destructure props for easier access.
287
+ const { document, dispatch } = props;
288
+ // Access the global state from the document object.
289
+ const { state: { global: state } } = document;
290
+
291
+ // --- Component State ---
292
+ // State for the text input field where new tasks are typed.
293
+ const [todoItem, setTodoItem] = useState('');
294
+ // State to track which item is currently being edited (null if none). Stores the item's ID.
295
+ const [editingItemId, setEditingItemId] = useState<string | null>(null);
296
+ // State to hold the text of the item currently being edited.
297
+ const [editedText, setEditedText] = useState('');
298
+
299
+ // Sort items to show unchecked items first
300
+ const sortedItems: ToDoItem[] = [...state.items].sort((a, b) => {
301
+ return (a.checked ? 1 : 0) - (b.checked ? 1 : 0);
302
+ });
303
+
304
+ // --- JSX Structure (What gets rendered) ---
305
+ return (
306
+ // Main container div.
307
+ // `container`: Sets max-width based on viewport breakpoints.
308
+ // `mx-auto`: Centers the container horizontally.
309
+ // `p-4`: Adds padding on all sides (4 units, typically 1rem).
310
+ // `max-w-sm`: Sets a maximum width (small size).
311
+ <div className="container mx-auto p-4 max-w-xs">
312
+ {/* Heading for the editor */}
313
+ {/* `text-2xl`: Sets font size to extra-large. */}
314
+ {/* `font-bold`: Makes the text bold. */}
315
+ {/* `mb-4`: Adds margin to the bottom. */}
316
+ <h1 className="text-2xl font-bold mb-4">To-do List</h1>
317
+
318
+ {/* Stats Section */}
319
+ {state.items.length >= 2 && (
320
+ <div className="mb-4 bg-white rounded-lg px-3 py-2 shadow-md">
321
+ <div className="grid grid-cols-3 gap-3">
322
+ <div>
323
+ <div className="text-xs text-slate-500 mb-0.5">Total</div>
324
+ <div className="text-lg font-semibold text-slate-800">{state.stats.total}</div>
325
+ </div>
326
+ <div>
327
+ <div className="text-xs text-slate-500 mb-0.5">Completed</div>
328
+ <div className="text-lg font-semibold text-green-600">{state.stats.checked}</div>
329
+ </div>
330
+ <div>
331
+ <div className="text-xs text-slate-500 mb-0.5">Remaining</div>
332
+ <div className="text-lg font-semibold text-orange-600">{state.stats.unchecked}</div>
333
+ </div>
334
+ </div>
335
+ </div>
336
+ )}
337
+
338
+ {/* Container for the input field and "Add" button */}
339
+ {/* `flex items-end`: Enables flexbox layout for children with bottom alignment. */}
340
+ {/* `gap-2`: Adds a small gap between flex items. */}
341
+ {/* `mb-4`: Adds margin to the bottom. */}
342
+ <div className="flex items-end gap-2 mb-4">
343
+ {/* Custom InputField component */}
344
+ <div className="flex-grow">
345
+ <InputField
346
+ label="New Task" // Prop for accessibility/placeholder.
347
+ input={todoItem} // Current value from state.
348
+ value={todoItem} // Controlled component value.
349
+ handleInputChange={(e) => setTodoItem(e.target.value)} // Update state on change.
350
+ onKeyDown={(e) => { // Handle "Enter" key press to add item.
351
+ if (e.key === 'Enter' && todoItem.trim()) { // Check if key is Enter and input is not empty
352
+ dispatch(actions.addTodoItem({ // Dispatch action to add item.
353
+ id: Math.random().toString(), // Generate a simple unique ID (use a better method in production!).
354
+ text: todoItem,
355
+ }));
356
+ setTodoItem(''); // Clear the input field.
357
+ }
358
+ }}
359
+ />
360
+ </div>
361
+ {/* "Add" button */}
362
+ {/* `bg-blue-500`: Sets background color to blue. */}
363
+ {/* `hover:bg-blue-600`: Changes background color on hover. */}
364
+ {/* `text-white`: Sets text color to white. */}
365
+ {/* `px-4`: Adds horizontal padding (4 units). */}
366
+ {/* `py-1.5`: Adds vertical padding (1.5 units). */}
367
+ {/* `rounded`: Applies rounded corners. */}
368
+ {/* `transition-colors`: Smoothly animates color changes. */}
369
+ <button
370
+ className="bg-blue-500 hover:bg-blue-600 text-white px-4 py-1.5 rounded transition-colors"
371
+ onClick={() => { // Handle button click to add item.
372
+ if (todoItem.trim()) { // Check if input is not empty
373
+ dispatch(actions.addTodoItem({ // Dispatch action to add item.
374
+ id: Math.random().toString(), // Simple unique ID.
375
+ text: todoItem,
376
+ }));
377
+ setTodoItem(''); // Clear the input field.
378
+ }
379
+ }}
380
+ >
381
+ Add
382
+ </button>
383
+ </div>
384
+
385
+ {/* Unordered list to display the to-do items */}
386
+ {/* `list-none`: Removes default list bullet points. */}
387
+ {/* `p-0`: Removes default padding. */}
388
+ <ul className="list-none p-0">
389
+ {/* Map over the items array in the global state to render each item */}
390
+ {sortedItems.map((item: ToDoItem) => (
391
+ // List item element for each to-do.
392
+ // `key={item.id}`: React requires a unique key for list items for efficient updates.
393
+ // `flex`: Enables flexbox layout (checkbox, text, delete icon in a row).
394
+ // `items-center`: Aligns items vertically in the center.
395
+ // `p-2`: Adds padding.
396
+ // `relative`: Needed for positioning the delete icon absolutely (if we were doing that).
397
+ // `border-b`: Adds a bottom border.
398
+ // `border-gray-100`: Sets border color to light gray.
399
+ <li
400
+ key={item.id}
401
+ className="flex items-center p-2 relative border-b border-gray-100"
402
+ >
403
+ {/* Custom Checkbox component */}
404
+ <Checkbox
405
+ value={item.checked} // Bind checked state to item's checked property.
406
+ onChange={() => { // Handle checkbox click.
407
+ dispatch(actions.updateTodoItem({ // Dispatch action to update item.
408
+ id: item.id,
409
+ checked: !item.checked, // Toggle the checked state.
410
+ }));
411
+ }}
412
+ />
413
+
414
+ {/* Conditional Rendering: Show input field or text based on editing state */}
415
+ {editingItemId === item.id ? (
416
+ // --- Editing State ---
417
+ // Input field shown when this item is being edited.
418
+ // `ml-2`: Adds left margin.
419
+ // `flex-grow`: Allows input to take available horizontal space.
420
+ // `p-1`: Adds small padding.
421
+ // `border`: Adds a default border.
422
+ // `rounded`: Applies rounded corners.
423
+ // `focus:outline-none`: Removes the default browser focus outline.
424
+ // `focus:ring-1 focus:ring-blue-500`: Adds a custom blue ring when focused.
425
+ <input
426
+ className="ml-2 flex-grow p-1 border rounded focus:outline-none focus:ring-1 focus:ring-blue-500"
427
+ value={editedText} // Controlled input value from editedText state.
428
+ onChange={(e) => setEditedText(e.target.value)} // Update editedText state.
429
+ onKeyDown={(e) => { // Handle "Enter" key to save changes.
430
+ if (e.key === 'Enter') {
431
+ dispatch(actions.updateTodoItem({ // Dispatch update action.
432
+ id: item.id,
433
+ text: editedText, // Save the edited text.
434
+ }));
435
+ setEditingItemId(null); // Exit editing mode.
436
+ }
437
+ }}
438
+ autoFocus // Automatically focus the input when it appears.
439
+ />
440
+ ) : (
441
+ // --- Display State ---
442
+ // Container for the item text and delete icon when not editing.
443
+ // `ml-2`: Adds left margin.
444
+ // `flex items-center`: Aligns text and icon vertically.
445
+ // `flex-grow`: Allows this container to take available space.
446
+ // `gap-1`: Adds a small gap between text and icon.
447
+ <div className="ml-2 flex items-center flex-grow gap-1">
448
+ {/* The actual to-do item text */}
449
+ {/* `cursor-pointer`: Shows a pointer cursor on hover, indicating clickability. */}
450
+ {/* Conditional class: Apply line-through and gray text if item is checked. */}
451
+ {/* `line-through`: Strikes through the text. */}
452
+ {/* `text-gray-500`: Sets text color to gray. */}
453
+ <span
454
+ className={`cursor-pointer ${item.checked ? 'line-through text-gray-500' : ''}`}
455
+ onClick={() => { // Handle click to enter editing mode.
456
+ setEditingItemId(item.id); // Set the ID of the item being edited.
457
+ setEditedText(item.text); // Initialize the input with current text.
458
+ }}
459
+ >
460
+ {item.text} {/* Display the item's text */}
461
+ </span>
462
+ {/* Delete "button" (using a span styled as a button) */}
463
+ {/* `text-gray-400`: Sets default text color to light gray. */}
464
+ {/* `cursor-pointer`: Shows pointer cursor. */}
465
+ {/* `opacity-40`: Makes it semi-transparent by default. */}
466
+ {/* `transition-all duration-200`: Smoothly animates all changes (opacity, color). */}
467
+ {/* `text-base font-bold`: Sets text size and weight. */}
468
+ {/* `inline-flex items-center`: Needed for proper alignment if using an icon font/SVG. */}
469
+ {/* `pl-1`: Adds small left padding. */}
470
+ {/* `hover:opacity-100`: Makes it fully opaque on hover. */}
471
+ {/* `hover:text-red-500`: Changes text color to red on hover. */}
472
+ <span
473
+ className="text-gray-400 cursor-pointer opacity-40 transition-all duration-200 text-base font-bold inline-flex items-center pl-1 hover:opacity-100 hover:text-red-500"
474
+ onClick={() => dispatch(actions.deleteTodoItem({ id: item.id }))} // Dispatch delete action on click.
475
+ >
476
+ × {/* Simple multiplication sign used as delete icon */}
477
+ </span>
478
+ </div>
479
+ )}
480
+ </li>
481
+ ))}
482
+ </ul>
483
+ </div>
484
+ );
485
+ }
486
+ ```
487
+ </details>
207
488
 
208
- ## Conceptual Example: Building a ToDoList Editor
489
+ Now you can run the Connect app and see the **ToDoList** editor in action.
209
490
 
210
- Let's consider key aspects of building an editor like the `ToDoList` example:
491
+ ```bash
492
+ ph connect
493
+ ```
211
494
 
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.
495
+ In Connect, in the bottom right corner you'll find a new Document Model that you can create: **ToDoList**.
496
+ Click on it to create a new ToDoList document.
216
497
 
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.
498
+ :::info
499
+ The editor will update dynamically, so you can play around with your editor styling while seeing your results appear in Connect Studio.
500
+ :::
222
501
 
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.
502
+ </details>
228
503
 
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`.
504
+ Congratulations!
505
+ If you managed to follow this tutorial until this point, you have successfully implemented the **ToDoList** document model with its reducer operations and editor.
232
506
 
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.
507
+ Now you can move on to creating a [custom drive explorer](/academy/MasteryTrack/BuildingUserExperiences/BuildingADriveExplorer) for your ToDoList document.
508
+ Imagine you have many ToDoLists sitting in a drive. A custom drive explorer will allow you to organize and track them at a glance, opening up a new world of possibilities to increase the functionality of your documents!
@@ -2,12 +2,13 @@
2
2
 
3
3
  A drive in Powerhouse is a container or a wrapper for documents and data. It's a place where you can organize and store your documents and share them with others. This guide will walk you through the process of configuring and managing drives in your Powerhouse environment.
4
4
 
5
- ## Prerequisites
5
+ :::info **Prerequisites**
6
6
 
7
7
  Before configuring a drive, ensure you have:
8
8
  - Powerhouse [CLI installed](/academy/MasteryTrack/BuilderEnvironment/BuilderTools)
9
9
  - Access to a Powerhouse instance
10
10
  - Appropriate permissions to create and manage drives
11
+ :::
11
12
 
12
13
  ## Understanding Drives
13
14
 
@@ -23,7 +24,7 @@ Remote drives in Powerhouse allow you to connect to and work with data stored in
23
24
  - **Cloud Storage**: For centralized, scalable data management.
24
25
  - **Decentralized Storage**: Such as Ceramic or IPFS, enabling distributed and blockchain-based storage options.
25
26
 
26
- :::tip
27
+ :::tip **Explainer**
27
28
  **Powerhouse Reactors** are the nodes in the network that store and synchronise documents & drives , resolve conflicts and rerun operations to verify document event histories.
28
29
  Reactors can be configured for local storage, centralized cloud storage or on a decentralized storage network.
29
30
 
@@ -57,10 +58,11 @@ To create a new drive in Powerhouse, follow these steps:
57
58
 
58
59
  You can also add a new remote drive to your Connect environment programmatically using GraphQL mutations. This is especially useful for automation, scripting, or integrating with external systems.
59
60
 
60
- ### Prerequisites
61
+ :::info **Prerequisites**
61
62
  - Access to the Switchboard or remote reactor (server node) of your Connect instance.
62
63
  - The GraphQL endpoint for your instance. For example, for the staging environment, use: `https://staging.switchboard.phd/graphql/system` (this is a supergraph gateway).
63
64
  - Appropriate permissions to perform mutations.
65
+ :::
64
66
 
65
67
  ### Steps
66
68
  1. **Navigate to the GraphQL Playground or use a GraphQL client**
@@ -145,9 +145,10 @@ This command will **build** the project and create a build directory with the ou
145
145
 
146
146
  This command will **start a local server** and serve the build output.
147
147
  Inspect the build output and verify that the document models are working correctly.
148
+ Instead of `pnpm serve`, we'll be using:
148
149
 
149
150
  ```bash
150
- pnpm serve (Not working yet)
151
+ ph connect
151
152
  ```
152
153
 
153
154
  ### 1.4 Storing your project in a git repository
@@ -202,15 +203,79 @@ If you're publishing a package under a scope (like @your-org/my-package), you mi
202
203
  }
203
204
  ```
204
205
 
205
- For the actual publishing step, run the following command to publish your project to the npm registry:
206
+ ### 2.1 Versioning, Tagging, and Publishing Your Package
207
+
208
+ Before publishing, it's crucial to version your package correctly and tag the release in your Git repository. This helps track changes and allows users to depend on specific versions.
209
+
210
+ **1. Versioning with PNPM**
211
+
212
+ Use the `pnpm version` command to update your package version according to semantic versioning rules (`patch` for bugfixes, `minor` for new features, `major` for breaking changes). This command will:
213
+ - Update the `version` in your `package.json`.
214
+ - Create a Git commit for the version change.
215
+ - Create a Git tag for the new version (e.g., `v1.0.1`).
216
+
217
+ ```bash
218
+ # For a patch release (e.g., from 1.0.0 to 1.0.1)
219
+ pnpm version patch
220
+
221
+ # For a minor release (e.g., from 1.0.1 to 1.1.0)
222
+ pnpm version minor
223
+
224
+ # For a major release (e.g., from 1.1.0 to 2.0.0)
225
+ pnpm version major
226
+ ```
227
+ Take note of the new version tag created (e.g., `v1.0.1`), as you'll need it in the next step.
228
+
229
+ **2. Pushing Changes to Git**
230
+
231
+ Next, push your commits and the new version tag to your remote Git repository:
232
+
233
+ ```bash
234
+ # Push your current branch (e.g., main or master)
235
+ # Replace 'main' with your default branch name if different
236
+ git push origin main
237
+
238
+ # Push the specific tag created by pnpm version
239
+ # Replace vX.Y.Z with the actual tag name (e.g., v1.0.1)
240
+ git push origin vX.Y.Z
241
+ ```
242
+ The specific tag name (e.g., `v1.0.1`) is usually output by the `pnpm version` command. Pushing the specific tag is recommended to avoid unintentionally pushing other local tags.
243
+
244
+ Alternatively, to push all new local tags (use with caution):
245
+ ```bash
246
+ # git push --tags
247
+ ```
248
+
249
+ **3. Understanding Git Tags vs. NPM Distributor Tags**
250
+
251
+ It's important to distinguish between Git tags and NPM distributor tags (dist-tags):
252
+
253
+ - **Git Tags**: These are markers in your Git repository's history. They are primarily for developers to pinpoint specific release versions in the codebase (e.g., `v1.0.0`, `v1.0.1`). The `pnpm version` command creates these.
254
+ - **NPM Distributor Tags (dist-tags)**: These are labels used by the NPM registry to point to specific published versions of your package. Common NPM tags include:
255
+ - `latest`: This is the default tag. When someone runs `pnpm install my-package`, NPM installs the version tagged as `latest`.
256
+ - `beta`, `next`, `alpha`: Often used for pre-release versions.
257
+ When you publish a package without specifying an NPM tag, it usually gets the `latest` tag by default.
258
+
259
+ **4. Publishing to NPM**
260
+
261
+ Now you are ready to publish your package to the NPM registry. Ensure you are logged into NPM (the `npm login` command shown in previous steps should be used, or `pnpm login` which is an alias).
262
+
263
+ ```bash
264
+ pnpm publish
265
+ ```
266
+ This command will publish the version of your package that is currently specified in your `package.json`. By default, this will also set the `latest` NPM dist-tag for this version.
267
+
268
+ If your package is scoped (e.g., `@your-org/my-package`) and intended to be public, ensure your `package.json` includes the `publishConfig` shown earlier. If this is not set in `package.json` (and your package is scoped), you might need to use:
206
269
  ```bash
207
- npm publish
270
+ pnpm publish --access public
208
271
  ```
209
272
 
210
- Optionally, if you are publishing a scoped package and you want it public, run:
273
+ You can also publish a version to a specific NPM dist-tag. For example, to publish a beta version:
211
274
  ```bash
212
- npm publish --access public
275
+ # Ensure your package.json version reflects the beta (e.g., 1.1.0-beta.0)
276
+ pnpm publish --tag beta
213
277
  ```
278
+ This is useful for testing releases before making them `latest`.
214
279
 
215
280
  Now let's verify that the package(s) get published in the package repository, next to pre-existing packages that you might have been publishing before.
216
281