From 43a11e983dcd03013a35919f4939e78049246275 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:12:54 +0000 Subject: [PATCH 1/6] Add spec-kit artifacts for plugin example implementations feature - Created feature specification with 5 prioritized user stories (P1-P5) - Completed clarification phase with 5 questions answered - Generated implementation plan with technical context and research - Created data model, quickstart guide, and contracts documentation - Updated GitHub Copilot context with feature information Feature: 002-plugin-examples Branch: 002-plugin-examples Co-Authored-By: onikiten@softserveinc.com --- .github/copilot-instructions.md | 29 +++ .../checklists/requirements.md | 34 +++ specs/002-plugin-examples/contracts/README.md | 55 +++++ specs/002-plugin-examples/data-model.md | 123 +++++++++++ specs/002-plugin-examples/plan.md | 84 ++++++++ specs/002-plugin-examples/quickstart.md | 200 ++++++++++++++++++ specs/002-plugin-examples/research.md | 123 +++++++++++ specs/002-plugin-examples/spec.md | 174 +++++++++++++++ 8 files changed, 822 insertions(+) create mode 100644 .github/copilot-instructions.md create mode 100644 specs/002-plugin-examples/checklists/requirements.md create mode 100644 specs/002-plugin-examples/contracts/README.md create mode 100644 specs/002-plugin-examples/data-model.md create mode 100644 specs/002-plugin-examples/plan.md create mode 100644 specs/002-plugin-examples/quickstart.md create mode 100644 specs/002-plugin-examples/research.md create mode 100644 specs/002-plugin-examples/spec.md diff --git a/.github/copilot-instructions.md b/.github/copilot-instructions.md new file mode 100644 index 0000000..97da04c --- /dev/null +++ b/.github/copilot-instructions.md @@ -0,0 +1,29 @@ +# fdo-sdk Development Guidelines + +Auto-generated from all feature plans. Last updated: 2025-10-27 + +## Active Technologies + +- TypeScript 5.7.3 (matching existing SDK codebase) + @anikitenko/fdo-sdk (the SDK itself), electron ^35.0.0, goober ^2.1.16 (CSS-in-JS), winston ^3.17.0 (logging) (002-plugin-examples) + +## Project Structure + +```text +src/ +tests/ +``` + +## Commands + +npm test && npm run lint + +## Code Style + +TypeScript 5.7.3 (matching existing SDK codebase): Follow standard conventions + +## Recent Changes + +- 002-plugin-examples: Added TypeScript 5.7.3 (matching existing SDK codebase) + @anikitenko/fdo-sdk (the SDK itself), electron ^35.0.0, goober ^2.1.16 (CSS-in-JS), winston ^3.17.0 (logging) + + + diff --git a/specs/002-plugin-examples/checklists/requirements.md b/specs/002-plugin-examples/checklists/requirements.md new file mode 100644 index 0000000..c1831ad --- /dev/null +++ b/specs/002-plugin-examples/checklists/requirements.md @@ -0,0 +1,34 @@ +# Specification Quality Checklist: Plugin Example Implementations + +**Purpose**: Validate specification completeness and quality before proceeding to planning +**Created**: 2025-10-27 +**Feature**: [spec.md](../spec.md) + +## Content Quality + +- [x] No implementation details (languages, frameworks, APIs) +- [x] Focused on user value and business needs +- [x] Written for non-technical stakeholders +- [x] All mandatory sections completed + +## Requirement Completeness + +- [x] No [NEEDS CLARIFICATION] markers remain +- [x] Requirements are testable and unambiguous +- [x] Success criteria are measurable +- [x] Success criteria are technology-agnostic (no implementation details) +- [x] All acceptance scenarios are defined +- [x] Edge cases are identified +- [x] Scope is clearly bounded +- [x] Dependencies and assumptions identified + +## Feature Readiness + +- [x] All functional requirements have clear acceptance criteria +- [x] User scenarios cover primary flows +- [x] Feature meets measurable outcomes defined in Success Criteria +- [x] No implementation details leak into specification + +## Notes + +All checklist items pass validation. The specification is complete and ready for clarification and planning phases. diff --git a/specs/002-plugin-examples/contracts/README.md b/specs/002-plugin-examples/contracts/README.md new file mode 100644 index 0000000..976c9b3 --- /dev/null +++ b/specs/002-plugin-examples/contracts/README.md @@ -0,0 +1,55 @@ +# API Contracts - Plugin Example Implementations + +**Feature**: Plugin Example Implementations +**Date**: 2025-10-27 + +## Overview + +This feature creates example plugin implementations that demonstrate existing SDK APIs. Since no new APIs are being created, there are no new API contracts to define. + +## Existing SDK APIs Used by Examples + +The examples demonstrate usage of existing FDO SDK APIs: + +### Core Plugin API +- `FDO_SDK` base class (from `src/index.ts`) +- `FDOInterface` interface (from `src/index.ts`) +- `PluginMetadata` type (from `src/types.ts`) + +### Plugin Registry API +- `PluginRegistry.registerPlugin()` - Auto-called on plugin instantiation +- `PluginRegistry.registerHandler()` - Register custom message handlers +- `PluginRegistry.useStore()` - Access storage backends + +### Storage API +- `StoreDefault` - In-memory key-value store +- `StoreJson` - File-based persistent store +- `StoreType` interface methods: `get()`, `set()`, `remove()`, `clear()`, `has()`, `keys()` + +### DOM Generation API +- `DOM` base class - Core HTML generation +- `DOMText` - Text element generation +- `DOMButton` - Button element generation +- `DOMInput` - Input element generation +- `DOMLink` - Link element generation +- `DOMNested` - Container element generation +- `DOMMisc` - Miscellaneous elements + +### Mixin API +- `QuickActionMixin` - Adds `defineQuickActions()` method +- `SidePanelMixin` - Adds `defineSidePanel()` method + +### Logging API +- `this.log()` - Info logging +- `this.error()` - Error logging + +## Contract Documentation + +All existing API contracts are documented in: +- SDK source code with JSDoc comments +- TypeScript type definitions (`.d.ts` files) +- Existing SDK documentation + +## No New Contracts + +This feature does not introduce any new APIs or contracts. It purely demonstrates usage of existing, stable SDK APIs through example implementations. diff --git a/specs/002-plugin-examples/data-model.md b/specs/002-plugin-examples/data-model.md new file mode 100644 index 0000000..7da32e3 --- /dev/null +++ b/specs/002-plugin-examples/data-model.md @@ -0,0 +1,123 @@ +# Phase 1: Data Model - Plugin Example Implementations + +**Feature**: Plugin Example Implementations +**Date**: 2025-10-27 +**Status**: Complete + +## Overview + +This feature creates example plugin implementations, which are code artifacts rather than data entities. The "data model" for this feature consists of the structure and content of the example files themselves. + +## Example File Structure + +### Entity: Plugin Example File + +Each example file is a TypeScript module that demonstrates specific SDK features. + +**Attributes**: +- **Filename**: String with format `{number}-{descriptive-name}.ts` (e.g., "01-basic-plugin.ts") +- **Header Comment Block**: Multi-line comment containing: + - Example title and description + - SDK version compatibility (e.g., "Compatible with SDK v1.x") + - Learning objectives + - Expected output description +- **Import Statements**: TypeScript imports from @anikitenko/fdo-sdk +- **Plugin Class**: TypeScript class extending FDO_SDK and implementing FDOInterface +- **Metadata Property**: PluginMetadata object with name, version, author, description, icon +- **Init Method**: Implementation of required init() lifecycle method +- **Render Method**: Implementation of required render() lifecycle method +- **Inline Documentation**: JSDoc comments and inline explanatory comments (20-30% of file) + +**Relationships**: +- Each example file is independent (no dependencies between examples) +- All examples depend on the FDO SDK package +- Examples are ordered by complexity (01 = simplest, 05 = most complex) + +**Validation Rules**: +- Must compile with TypeScript strict mode +- Must implement all required FDOInterface methods +- Must include version compatibility comment +- Must have at least 20% documentation-to-code ratio +- Filename must match pattern: `\d{2}-[a-z-]+\.ts` + +## Example Content Mapping + +### 01-basic-plugin.ts (P1) +**Demonstrates**: Plugin lifecycle, basic rendering, metadata structure +**Key Components**: +- Minimal FDO_SDK class extension +- Simple metadata object +- Basic init() with logging +- Simple render() returning HTML string +- Inline comments explaining each section + +### 02-interactive-plugin.ts (P2) +**Demonstrates**: Message handlers, UI interactions, button clicks +**Key Components**: +- Handler registration in init() +- Button creation with onClick handlers +- Message-based communication patterns +- Form input handling +- Error handling in handlers + +### 03-persistence-plugin.ts (P3) +**Demonstrates**: Data storage, state persistence, store backends +**Key Components**: +- StoreDefault usage for temporary data +- StoreJson usage for persistent data +- Key naming conventions +- Error handling for storage operations +- Data retrieval and display + +### 04-ui-extensions-plugin.ts (P4) +**Demonstrates**: QuickActionMixin, SidePanelMixin, UI extensions +**Key Components**: +- Mixin application to plugin class +- defineQuickActions() implementation +- defineSidePanel() implementation +- Message routing from UI extensions +- Icon and label configuration + +### 05-advanced-dom-plugin.ts (P5) +**Demonstrates**: DOM helper classes, CSS-in-JS, complex UI composition +**Key Components**: +- DOMText, DOMButton, DOMInput, DOMNested usage +- CSS class creation with goober +- Style object patterns +- Complex nested element structures +- Form composition with multiple input types + +## State Transitions + +Examples are static reference implementations with no runtime state transitions. The only "state" is the learning progression from example 01 to 05. + +## Data Volume + +- **Total Examples**: 5 files +- **File Size**: Approximately 100-300 lines per file (including comments) +- **Documentation Ratio**: 20-30% of total lines +- **Total LOC**: Approximately 500-1500 lines across all examples + +## Storage Considerations + +Examples are stored as TypeScript source files in the repository: +- Location: `examples/` directory in repository root +- Version Control: Tracked in git +- Distribution: Included in npm package +- No runtime data storage required (examples demonstrate storage but don't persist data themselves) + +## Dependencies + +All examples depend on: +- `@anikitenko/fdo-sdk` package (the SDK itself) +- TypeScript compiler for type checking +- No external APIs or services +- No database or persistent storage (examples demonstrate storage APIs but are self-contained) + +## Consistency Rules + +- All examples must use consistent code style (matching SDK conventions) +- All examples must use the same metadata structure +- All examples must include version compatibility comments +- All examples must compile without errors in strict mode +- All examples must be independently runnable diff --git a/specs/002-plugin-examples/plan.md b/specs/002-plugin-examples/plan.md new file mode 100644 index 0000000..2cd0ad9 --- /dev/null +++ b/specs/002-plugin-examples/plan.md @@ -0,0 +1,84 @@ +# Implementation Plan: Plugin Example Implementations + +**Branch**: `002-plugin-examples` | **Date**: 2025-10-27 | **Spec**: [spec.md](./spec.md) +**Input**: Feature specification from `/specs/002-plugin-examples/spec.md` + +**Note**: This template is filled in by the `/speckit.plan` command. See `.specify/templates/commands/plan.md` for the execution workflow. + +## Summary + +Create 5 comprehensive plugin example implementations that demonstrate core FDO SDK capabilities. Examples will be organized in a flat directory structure with numbered prefixes (01-05) and progress from basic plugin creation to advanced DOM generation. Each example will include inline documentation, version compatibility information, and text descriptions of expected output. The examples will serve as primary learning resources for plugin developers and cover plugin lifecycle, UI interactions, data persistence, UI extensions, and DOM generation. + +## Technical Context + +**Language/Version**: TypeScript 5.7.3 (matching existing SDK codebase) +**Primary Dependencies**: @anikitenko/fdo-sdk (the SDK itself), electron ^35.0.0, goober ^2.1.16 (CSS-in-JS), winston ^3.17.0 (logging) +**Storage**: StoreDefault (in-memory) and StoreJson (file-based) from SDK +**Testing**: Jest ^29.7.0 with ts-jest ^29.2.5 (matching existing test infrastructure) +**Target Platform**: Electron desktop application (cross-platform: Windows, macOS, Linux) +**Project Type**: Single project (SDK examples within existing repository) +**Performance Goals**: Examples must load and initialize in under 1 second, render UI in under 500ms +**Constraints**: Examples must be self-contained, no external API dependencies, compatible with SDK v1.x +**Scale/Scope**: 5 example files, approximately 100-300 lines each with 20%+ inline documentation + +## Constitution Check + +*GATE: Must pass before Phase 0 research. Re-check after Phase 1 design.* + +### Plugin Architecture Integrity +✅ **PASS** - Examples demonstrate the plugin architecture without modifying core SDK interfaces. All examples use existing stable APIs (FDO_SDK base class, lifecycle hooks, mixins). + +### Type Safety and Developer Experience +✅ **PASS** - Examples will be written in TypeScript with strict mode enabled. All examples will use proper typing and demonstrate type-safe patterns for plugin developers. + +### Testing and Quality Assurance +✅ **PASS** - Examples will include inline documentation and can be tested by running them in the FDO application. While examples themselves are reference implementations, they follow testable patterns that developers can adopt. + +### Automated Release Management +✅ **PASS** - Examples will be included in the npm package distribution and versioned with the SDK. No changes to release automation required. + +### Documentation and Examples +✅ **PASS** - This feature directly fulfills the constitution's requirement for "working example plugins that demonstrate core functionality." Examples will include comprehensive inline documentation. + +**Overall Status**: All constitution principles are satisfied. No violations to justify. + +## Project Structure + +### Documentation (this feature) + +```text +specs/[###-feature]/ +├── plan.md # This file (/speckit.plan command output) +├── research.md # Phase 0 output (/speckit.plan command) +├── data-model.md # Phase 1 output (/speckit.plan command) +├── quickstart.md # Phase 1 output (/speckit.plan command) +├── contracts/ # Phase 1 output (/speckit.plan command) +└── tasks.md # Phase 2 output (/speckit.tasks command - NOT created by /speckit.plan) +``` + +### Source Code (repository root) + +```text +examples/ +├── 01-basic-plugin.ts # P1: Basic plugin creation (lifecycle, rendering) +├── 02-interactive-plugin.ts # P2: Interactive UI with handlers and messaging +├── 03-persistence-plugin.ts # P3: Data persistence with storage backends +├── 04-ui-extensions-plugin.ts # P4: Quick actions and side panel integration +└── 05-advanced-dom-plugin.ts # P5: Advanced DOM generation with styling + +src/ +├── index.ts # Existing SDK exports (no changes) +├── PluginRegistry.ts # Existing registry (no changes) +├── Communicator.ts # Existing IPC (no changes) +├── DOM*.ts # Existing DOM classes (no changes) +└── ... # Other existing SDK files + +tests/ +└── ... # Existing tests (no changes for this feature) +``` + +**Structure Decision**: Single project structure. All 5 example files will be added to the existing `examples/` directory with numbered prefixes (01-05) to indicate learning progression. No changes to existing SDK source code or tests are required - this is purely additive content in the examples directory. + +## Complexity Tracking + +No constitution violations - this section is not applicable. diff --git a/specs/002-plugin-examples/quickstart.md b/specs/002-plugin-examples/quickstart.md new file mode 100644 index 0000000..fb24434 --- /dev/null +++ b/specs/002-plugin-examples/quickstart.md @@ -0,0 +1,200 @@ +# Quick Start: Using Plugin Examples + +**Feature**: Plugin Example Implementations +**Date**: 2025-10-27 +**Audience**: Plugin developers learning the FDO SDK + +## Overview + +This guide helps you get started with the FDO SDK plugin examples. The examples are organized in progressive complexity from basic to advanced, allowing you to learn at your own pace. + +## Prerequisites + +Before using these examples, ensure you have: + +1. **FDO SDK Installed**: Install via npm + ```bash + npm install @anikitenko/fdo-sdk + ``` + +2. **Development Environment**: + - Node.js 18+ installed + - TypeScript 5.7+ installed + - Code editor with TypeScript support (VS Code recommended) + +3. **FDO Desktop Application**: The FDO desktop application must be available to run and test plugins + +## Example Progression + +The examples are numbered to indicate learning progression. Start with 01 and work your way up: + +### 01-basic-plugin.ts (Start Here) +**What you'll learn**: +- How to create a minimal working plugin +- Plugin lifecycle (init and render methods) +- Basic metadata structure +- Simple HTML rendering + +**Time to complete**: 5-10 minutes + +**When to use this pattern**: When you need a simple plugin that displays static content + +### 02-interactive-plugin.ts +**What you'll learn**: +- How to handle user interactions (button clicks, form inputs) +- Message handler registration +- IPC communication between plugin and main process +- Basic error handling + +**Time to complete**: 15-20 minutes + +**When to use this pattern**: When your plugin needs to respond to user actions + +### 03-persistence-plugin.ts +**What you'll learn**: +- How to save and retrieve data +- Difference between StoreDefault (in-memory) and StoreJson (file-based) +- Proper key naming conventions +- Error handling for storage operations + +**Time to complete**: 15-20 minutes + +**When to use this pattern**: When your plugin needs to remember user preferences or state across sessions + +### 04-ui-extensions-plugin.ts +**What you'll learn**: +- How to add quick actions to the FDO application +- How to create side panel menu items +- Using mixins to extend plugin functionality +- Message routing from UI extensions + +**Time to complete**: 20-25 minutes + +**When to use this pattern**: When you want to integrate your plugin into the FDO application's UI chrome + +### 05-advanced-dom-plugin.ts +**What you'll learn**: +- How to use DOM helper classes (DOMText, DOMButton, DOMInput, etc.) +- CSS-in-JS styling with goober +- Building complex nested UI structures +- Form composition with multiple input types + +**Time to complete**: 25-30 minutes + +**When to use this pattern**: When you need rich, styled UI components with complex layouts + +## How to Use an Example + +### Step 1: Copy the Example +Copy the example file you want to learn from to your project: + +```bash +cp node_modules/@anikitenko/fdo-sdk/examples/01-basic-plugin.ts my-plugin.ts +``` + +### Step 2: Read the Documentation +Open the file and read the header comment block and inline documentation. This explains: +- What the example demonstrates +- SDK version compatibility +- Expected output when running + +### Step 3: Customize for Your Needs +Look for comments that say "CUSTOMIZE HERE" or "TODO: Replace with your...". These indicate where you should modify the code for your specific use case. + +### Step 4: Run and Test +Load your plugin in the FDO desktop application and verify it works as expected. Check the console for any errors or log messages. + +### Step 5: Experiment +Try modifying the example to add your own features. The inline comments explain what each section does, making it easier to understand how to extend the functionality. + +## Common Patterns + +### Plugin Metadata +All plugins must define metadata: +```typescript +private readonly _metadata: PluginMetadata = { + name: "Your Plugin Name", + version: "1.0.0", + author: "Your Name", + description: "What your plugin does", + icon: "icon.png" +}; +``` + +### Lifecycle Methods +All plugins must implement init() and render(): +```typescript +init(): void { + // Setup code: register handlers, initialize stores, etc. + this.log("Plugin initialized"); +} + +render(): string { + // Return HTML/UI definition + return "
Your UI here
"; +} +``` + +### Logging +Use the built-in logging methods: +```typescript +this.log("Info message"); // General information +this.error(new Error("Oops")); // Error logging +``` + +### Handler Registration +Register message handlers in init(): +```typescript +PluginRegistry.registerHandler("myHandler", (data) => { + // Handle the message + return result; +}); +``` + +## Troubleshooting + +### Example Won't Compile +- Ensure TypeScript strict mode is enabled in your tsconfig.json +- Check that all imports are correct +- Verify SDK version compatibility in the example header + +### Plugin Won't Load in FDO +- Check the console for error messages +- Verify your plugin class extends FDO_SDK +- Ensure all required methods (init, render) are implemented +- Check that metadata is properly defined + +### Storage Operations Fail +- Verify you have write permissions in the storage directory +- Check that keys are properly namespaced +- Wrap storage operations in try-catch blocks + +### UI Doesn't Render +- Check that render() returns a valid HTML string +- Verify DOM helper classes are used correctly +- Check browser console for JavaScript errors + +## Next Steps + +After working through the examples: + +1. **Read the SDK Documentation**: Dive deeper into specific APIs and classes +2. **Review the SDK Source Code**: See how the SDK itself is implemented +3. **Join the Community**: Share your plugins and get help from other developers +4. **Build Your Plugin**: Apply what you've learned to create your own plugin + +## SDK Version Compatibility + +All examples are compatible with FDO SDK v1.x. Check the header comment in each example file for specific version information. + +## Getting Help + +If you encounter issues: +1. Check the inline comments in the example files +2. Review the SDK API documentation +3. Search existing issues in the GitHub repository +4. Open a new issue with a minimal reproduction case + +## Contributing + +Found a bug in an example or have a suggestion for improvement? Contributions are welcome! Please open an issue or pull request in the SDK repository. diff --git a/specs/002-plugin-examples/research.md b/specs/002-plugin-examples/research.md new file mode 100644 index 0000000..cf69415 --- /dev/null +++ b/specs/002-plugin-examples/research.md @@ -0,0 +1,123 @@ +# Phase 0: Research - Plugin Example Implementations + +**Feature**: Plugin Example Implementations +**Date**: 2025-10-27 +**Status**: Complete + +## Research Tasks + +### 1. Example Plugin Patterns in Similar SDKs + +**Task**: Research best practices for SDK example implementations in similar plugin frameworks (Electron, VS Code extensions, browser extensions). + +**Findings**: +- **Progressive Complexity**: Most successful SDK examples follow a progressive learning path from "Hello World" to advanced features +- **Self-Contained Examples**: Each example should be independently runnable without dependencies on other examples +- **Inline Documentation**: 20-30% documentation-to-code ratio is standard for educational examples +- **Version Compatibility**: Examples typically specify compatibility using version ranges (e.g., "SDK v1.x") in header comments +- **File Naming**: Numbered prefixes (01-, 02-) are common for indicating learning progression + +**Decision**: Adopt progressive complexity pattern with numbered prefixes and comprehensive inline documentation. + +**Rationale**: This approach has proven successful in major SDK ecosystems (VS Code, Electron) and aligns with adult learning principles of scaffolding. + +**Alternatives Considered**: +- Grouping by feature area (rejected: loses learning progression) +- Single comprehensive example (rejected: too complex for beginners) +- Separate documentation files (rejected: reduces discoverability) + +### 2. TypeScript Example Best Practices + +**Task**: Identify TypeScript-specific best practices for example code. + +**Findings**: +- **Explicit Types**: Examples should use explicit type annotations even when inference would work, for educational clarity +- **Interface Usage**: Demonstrate proper interface implementation (FDOInterface) +- **Strict Mode**: All examples should compile with strict mode enabled +- **JSDoc Comments**: Include JSDoc for all public methods to demonstrate documentation practices +- **Error Handling**: Show proper try-catch patterns and error logging + +**Decision**: Use explicit typing throughout examples with comprehensive JSDoc comments. + +**Rationale**: Examples serve as reference implementations. Explicit types make the code more educational even if slightly more verbose. + +**Alternatives Considered**: +- Type inference (rejected: less educational for beginners) +- Minimal comments (rejected: doesn't meet 20% documentation requirement) + +### 3. Plugin Lifecycle Demonstration Patterns + +**Task**: Determine the best way to demonstrate plugin lifecycle (init, render) in examples. + +**Findings**: +- **Init Method**: Should demonstrate setup tasks like handler registration, store initialization, logging setup +- **Render Method**: Should show both simple HTML strings and DOM helper class usage +- **Metadata**: Should demonstrate all required metadata fields (name, version, author, description, icon) +- **Logging**: Should show proper use of this.log() and this.error() methods + +**Decision**: Each example will demonstrate appropriate lifecycle usage for its complexity level, with comments explaining when each method is called. + +**Rationale**: Understanding lifecycle is fundamental to plugin development. Examples should make the execution flow explicit. + +**Alternatives Considered**: +- Lifecycle diagram in separate file (rejected: reduces self-containment) +- Minimal lifecycle usage (rejected: doesn't demonstrate best practices) + +### 4. Storage System Demonstration + +**Task**: Research best practices for demonstrating the storage system (StoreDefault, StoreJson). + +**Findings**: +- **Store Selection**: StoreDefault for temporary data, StoreJson for persistent data +- **Key Naming**: Use namespaced keys (e.g., "pluginName:settingName") to avoid conflicts +- **Error Handling**: Storage operations can fail (permissions, disk space) and should be wrapped in try-catch +- **Data Serialization**: StoreJson handles JSON serialization automatically + +**Decision**: Example 03 will demonstrate both storage backends with proper error handling and key naming conventions. + +**Rationale**: Storage is a common plugin requirement. Demonstrating both backends helps developers choose appropriately. + +**Alternatives Considered**: +- Only demonstrate one storage type (rejected: doesn't show full capability) +- Custom storage implementation (rejected: out of scope, adds complexity) + +### 5. DOM Generation Patterns + +**Task**: Identify effective patterns for demonstrating the DOM generation system. + +**Findings**: +- **Progressive Adoption**: Start with simple HTML strings, progress to DOM helper classes +- **Styling**: Demonstrate both inline styles and CSS-in-JS via goober +- **Component Composition**: Show how to combine multiple DOM elements into complex UIs +- **Event Handling**: Demonstrate onClick handlers and form input handling + +**Decision**: Example 01 uses simple HTML strings, Example 05 demonstrates full DOM helper class usage with styling. + +**Rationale**: Progressive complexity allows developers to start simple and adopt advanced features as needed. + +**Alternatives Considered**: +- Only DOM helpers (rejected: too complex for beginners) +- Only HTML strings (rejected: doesn't demonstrate SDK capabilities) +- Separate styling example (rejected: would require 6 examples) + +## Technical Decisions Summary + +| Decision | Choice | Impact | +|----------|--------|--------| +| File Organization | Flat structure with numbered prefixes | Clear progression, easy navigation | +| Documentation Ratio | 20-30% inline comments | Meets educational goals without overwhelming | +| Type Safety | Explicit types with strict mode | Better learning experience, demonstrates best practices | +| Storage Demo | Both StoreDefault and StoreJson | Complete coverage of storage options | +| DOM Progression | HTML strings → DOM helpers | Gradual learning curve | +| Version Compatibility | Comment header with version range | Low maintenance, clear compatibility | + +## Unresolved Questions + +None - all clarifications were resolved during the clarify phase. + +## Next Steps + +Proceed to Phase 1: Design & Contracts +- Create data-model.md (minimal - examples are code artifacts) +- Create quickstart.md for developers using the examples +- No API contracts needed (examples use existing SDK APIs) diff --git a/specs/002-plugin-examples/spec.md b/specs/002-plugin-examples/spec.md new file mode 100644 index 0000000..85f336f --- /dev/null +++ b/specs/002-plugin-examples/spec.md @@ -0,0 +1,174 @@ +# Feature Specification: Plugin Example Implementations + +**Feature Branch**: `002-plugin-examples` +**Created**: 2025-10-27 +**Status**: Draft +**Input**: User description: "add plugin example implementations" + +## Clarifications + +### Session 2025-10-27 + +- Q: How many distinct example plugin files should be created? → A: 5 examples (one per user story) +- Q: How should the example files be organized within the examples directory? → A: Flat structure with numbered prefixes (e.g., 01-basic-plugin.ts, 02-interactive-plugin.ts) +- Q: How should SDK version compatibility be specified in each example? → A: Version range in comment header (e.g., "Compatible with SDK v1.x") +- Q: What types of plugin examples should be explicitly excluded from this feature? → A: Exclude production-ready and deployment examples (out of scope: production deployment, CI/CD pipelines, comprehensive testing, monitoring setup) +- Q: How should example output/screenshots be documented? → A: Inline comments with text description + +## Scope + +### In Scope +- 5 example plugin implementations demonstrating core SDK features +- Examples covering plugin lifecycle, UI interactions, data persistence, UI extensions, and DOM generation +- Inline documentation and code comments for learning purposes +- Basic error handling patterns + +### Out of Scope +- Production-ready plugin implementations with comprehensive error handling +- Deployment and CI/CD pipeline examples +- Comprehensive testing frameworks and test suites +- Production monitoring and observability setup +- Performance optimization and profiling examples +- Multi-plugin coordination and complex workflows + +## User Scenarios & Testing *(mandatory)* + +### User Story 1 - Basic Plugin Creation (Priority: P1) + +A new plugin developer wants to understand the minimal requirements to create a working FDO plugin. They need a simple, well-documented example that demonstrates the core plugin lifecycle (initialization and rendering) without additional complexity. + +**Why this priority**: This is the foundation for all plugin development. Without understanding the basic structure, developers cannot proceed to more advanced features. This represents the minimum viable knowledge needed to create any plugin. + +**Independent Test**: Can be fully tested by creating a new plugin file following the basic example, running it in the FDO application, and verifying it initializes and renders content successfully. + +**Acceptance Scenarios**: + +1. **Given** a developer has the FDO SDK installed, **When** they copy the basic plugin example and run it, **Then** the plugin initializes without errors and displays simple content +2. **Given** a developer reviews the basic example code, **When** they read the inline documentation, **Then** they understand what each required method (init, render) does and why it's needed +3. **Given** a developer wants to modify the example, **When** they change the rendered content, **Then** their changes appear in the FDO application without breaking functionality + +--- + +### User Story 2 - Interactive Plugin with UI Actions (Priority: P2) + +A plugin developer wants to create interactive functionality where users can click buttons, fill forms, and trigger custom actions. They need an example showing how to handle user interactions through the message-based communication system. + +**Why this priority**: Most useful plugins require user interaction. This builds on the basic example (P1) and demonstrates the communication layer that enables dynamic behavior, which is essential for practical plugin development. + +**Independent Test**: Can be tested independently by implementing the interactive example, clicking buttons and filling forms in the FDO application, and verifying that custom handlers execute and update the UI appropriately. + +**Acceptance Scenarios**: + +1. **Given** a developer implements the interactive example, **When** a user clicks a button in the plugin UI, **Then** the registered handler executes and the UI updates to reflect the action +2. **Given** a developer reviews the interactive example, **When** they examine the handler registration code, **Then** they understand how to register custom message handlers and process user input +3. **Given** a developer wants to add form validation, **When** they follow the example's input handling pattern, **Then** they can validate user input before processing + +--- + +### User Story 3 - Data Persistence Plugin (Priority: P3) + +A plugin developer needs to save and retrieve user data across application sessions. They need an example demonstrating how to use the storage system to persist plugin state and user preferences. + +**Why this priority**: Data persistence is important for many plugins but not essential for basic functionality. This builds on P1 and P2 by showing how to maintain state, which enhances user experience but isn't required for a minimal working plugin. + +**Independent Test**: Can be tested independently by implementing the persistence example, saving data through the plugin, restarting the FDO application, and verifying the saved data is correctly retrieved and displayed. + +**Acceptance Scenarios**: + +1. **Given** a developer implements the persistence example, **When** a user saves data through the plugin and restarts the application, **Then** the previously saved data is correctly loaded and displayed +2. **Given** a developer reviews the storage example, **When** they examine the store usage patterns, **Then** they understand how to choose between different storage backends (in-memory vs file-based) +3. **Given** a developer needs to clear stored data, **When** they follow the example's data management patterns, **Then** they can implement data clearing and updating functionality + +--- + +### User Story 4 - Quick Actions and Side Panel Integration (Priority: P4) + +A plugin developer wants to extend the FDO application's UI by adding quick action shortcuts and side panel menus. They need an example showing how to use mixins to register these UI extensions. + +**Why this priority**: UI extensions enhance plugin discoverability and user experience but are optional features. This demonstrates advanced SDK capabilities that improve polish but aren't necessary for core functionality. + +**Independent Test**: Can be tested independently by implementing the UI extension example, verifying quick actions appear in the application's quick action menu, and confirming side panel items are accessible and functional. + +**Acceptance Scenarios**: + +1. **Given** a developer implements the quick actions example, **When** they apply the QuickActionMixin, **Then** their defined quick actions appear in the FDO application's quick action interface +2. **Given** a developer implements the side panel example, **When** they apply the SidePanelMixin, **Then** their side panel configuration appears in the application's side panel with correct icons and labels +3. **Given** a developer wants to trigger specific plugin functionality from quick actions, **When** they follow the example's message routing pattern, **Then** quick action selections correctly invoke the corresponding plugin handlers + +--- + +### User Story 5 - Advanced DOM Generation (Priority: P5) + +A plugin developer wants to create rich, styled UI components using the SDK's DOM generation classes. They need an example demonstrating how to use the various DOM helper classes (DOMText, DOMButton, DOMInput, etc.) to build complex interfaces with custom styling. + +**Why this priority**: While important for creating polished UIs, developers can start with simple HTML strings (P1) and progressively adopt DOM helpers. This is an optimization and enhancement rather than a requirement. + +**Independent Test**: Can be tested independently by implementing the DOM generation example, verifying the generated UI renders correctly with proper styling, and confirming all interactive elements function as expected. + +**Acceptance Scenarios**: + +1. **Given** a developer implements the DOM generation example, **When** they use the DOM helper classes to create UI elements, **Then** the elements render with correct styling and structure +2. **Given** a developer reviews the styling examples, **When** they examine the CSS-in-JS patterns, **Then** they understand how to create custom styles using the goober integration +3. **Given** a developer wants to create a form with multiple input types, **When** they follow the example's patterns for combining DOM elements, **Then** they can build complex nested structures with proper event handling + +--- + +### Edge Cases + +- What happens when a plugin example is copied but required dependencies are missing from the developer's environment? +- How does the system handle when a developer modifies an example in a way that breaks the plugin lifecycle (e.g., missing required methods)? +- What happens when storage operations fail due to permission issues or disk space constraints? +- How does the system behave when a developer registers duplicate handlers or conflicting quick action names? +- What happens when DOM generation produces invalid HTML or CSS syntax? +- How does the system handle when a plugin example is run in an incompatible FDO SDK version? + +## Requirements *(mandatory)* + +### Functional Requirements + +- **FR-001**: Examples MUST cover all core SDK capabilities including plugin lifecycle, rendering, IPC communication, storage, and UI extensions +- **FR-002**: Each example MUST be independently runnable without requiring other examples to be present +- **FR-003**: Examples MUST include comprehensive inline documentation explaining what each code section does and why +- **FR-004**: Examples MUST demonstrate proper error handling patterns for common failure scenarios +- **FR-005**: Examples MUST follow the same code style and conventions as the SDK itself +- **FR-006**: Examples MUST include clear comments indicating where developers should customize the code for their own use cases +- **FR-007**: Each example MUST have a descriptive filename that clearly indicates its purpose and complexity level +- **FR-008**: Examples MUST demonstrate best practices for plugin development including proper initialization, cleanup, and resource management +- **FR-009**: Examples MUST be organized in a logical progression from simple to complex using a flat directory structure with numbered prefixes (01-basic-plugin.ts, 02-interactive-plugin.ts, etc.) +- **FR-010**: Examples MUST include example output documentation using inline comments with text descriptions of what the plugin displays when running +- **FR-011**: Each example MUST specify SDK version compatibility in a comment header using version range notation (e.g., "Compatible with SDK v1.x") +- **FR-012**: Examples MUST demonstrate how to use the logging system for debugging and monitoring +- **FR-013**: Examples MUST show how to properly structure plugin metadata (name, version, author, description, icon) +- **FR-014**: Examples MUST demonstrate both synchronous and asynchronous operation patterns where applicable +- **FR-015**: Examples MUST include comments explaining common pitfalls and how to avoid them + +### Key Entities + +- **Plugin Example**: A complete, runnable plugin implementation file that demonstrates specific SDK features. Contains metadata, initialization logic, rendering logic, and inline documentation. Serves as a reference implementation for developers. + +- **Example Documentation**: Inline comments and explanatory text within example files that explain the purpose, usage, and customization points. Includes code annotations, usage instructions, and expected outcomes. + +- **Example Category**: A logical grouping of examples by complexity level (basic, intermediate, advanced) or feature area (UI, storage, communication). Helps developers find relevant examples quickly. + +## Success Criteria *(mandatory)* + +### Measurable Outcomes + +- **SC-001**: Developers can create their first working plugin in under 15 minutes using the basic example as a starting point +- **SC-002**: Each example runs successfully without modification in a standard FDO SDK environment +- **SC-003**: 90% of plugin developers report that examples helped them understand SDK features without needing additional documentation +- **SC-004**: Examples cover 100% of the public SDK API surface area (all exported classes and methods are demonstrated in at least one example) +- **SC-005**: Plugin development onboarding time is reduced by 50% compared to learning from API documentation alone +- **SC-006**: Zero critical bugs or errors in example code that would prevent them from running +- **SC-007**: Each example includes at least 20% inline documentation relative to code volume (measured by comment lines vs code lines) +- **SC-008**: Examples demonstrate at least 3 different complexity levels (basic, intermediate, advanced) to support developers at different skill levels + +## Assumptions + +- Developers using these examples have basic JavaScript/TypeScript knowledge +- Developers have already installed the FDO SDK and have a working development environment +- The FDO desktop application is available for testing plugins +- Examples will be maintained alongside SDK updates to ensure compatibility +- Developers prefer learning from working code examples over written documentation +- The examples directory structure follows standard npm package conventions +- Examples will be included in the npm package distribution From 0439300f8e525b0853408d1472bf8f84bf85311c Mon Sep 17 00:00:00 2001 From: github-actions Date: Mon, 27 Oct 2025 14:14:47 +0000 Subject: [PATCH 2/6] 1.0.17 --- package-lock.json | 4 ++-- package.json | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/package-lock.json b/package-lock.json index c2d6f82..5b9eb5e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "@anikitenko/fdo-sdk", - "version": "1.0.16", + "version": "1.0.17", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "@anikitenko/fdo-sdk", - "version": "1.0.16", + "version": "1.0.17", "license": "ISC", "dependencies": { "@expo/sudo-prompt": "github:expo/sudo-prompt", diff --git a/package.json b/package.json index 962e957..dda1cef 100644 --- a/package.json +++ b/package.json @@ -4,7 +4,7 @@ "type": "git", "url": "https://github.com/anikitenko/fdo-sdk.git" }, - "version": "1.0.16", + "version": "1.0.17", "description": "SDK for FlexDevOPs (FDO) application modules", "keywords": [ "fdo", @@ -26,7 +26,7 @@ "files": [ "dist" ], - "scripts": { + "scripts": { "build": "webpack --config webpack.config.cjs", "build:types": "tsc --emitDeclarationOnly", "test": "jest", From 159269da2fd3b21f906c17ecebcc270553f4a690 Mon Sep 17 00:00:00 2001 From: "Oleksandr Nykytenko (SOFTSERVE)" Date: Mon, 27 Oct 2025 16:20:23 +0200 Subject: [PATCH 3/6] add tasks --- specs/002-plugin-examples/tasks.md | 116 +++++++++++++++++++++++++++++ 1 file changed, 116 insertions(+) create mode 100644 specs/002-plugin-examples/tasks.md diff --git a/specs/002-plugin-examples/tasks.md b/specs/002-plugin-examples/tasks.md new file mode 100644 index 0000000..0ecb74b --- /dev/null +++ b/specs/002-plugin-examples/tasks.md @@ -0,0 +1,116 @@ +# Tasks: Plugin Example Implementations + +**Feature**: Plugin Example Implementations +**Date**: 2025-10-27 +**Branch**: 002-plugin-examples + +--- + +## Phase 1: Setup + +- [ ] T001 Create examples/ directory in repository root +- [ ] T002 Initialize TypeScript strict mode in examples/ (tsconfig.json) +- [ ] T003 Install @anikitenko/fdo-sdk, electron, goober, winston dependencies +- [ ] T004 Add README to examples/ with usage instructions + +## Phase 2: Foundational Tasks + +- [ ] T005 Ensure examples/ directory is included in npm package distribution +- [ ] T006 Validate SDK version compatibility in all example headers +- [ ] T007 [P] Create PluginMetadata template in examples/metadata-template.ts + +--- + +## Phase 3: User Story 1 (P1) - Basic Plugin Creation + +- [ ] T008 [P] [US1] Create 01-basic-plugin.ts demonstrating plugin lifecycle and rendering +- [ ] T009 [US1] Add inline documentation (20%+ comment ratio) to 01-basic-plugin.ts +- [ ] T010 [US1] Add metadata block to 01-basic-plugin.ts +- [ ] T011 [US1] Implement init() and render() methods in 01-basic-plugin.ts +- [ ] T012 [US1] Add example output description in header comment of 01-basic-plugin.ts + +## Phase 4: User Story 2 (P2) - Interactive Plugin with UI Actions + +- [ ] T013 [P] [US2] Create 02-interactive-plugin.ts with button and form UI +- [ ] T014 [US2] Register message handlers in init() of 02-interactive-plugin.ts +- [ ] T015 [US2] Implement error handling in handlers in 02-interactive-plugin.ts +- [ ] T016 [US2] Add inline documentation (20%+ comment ratio) to 02-interactive-plugin.ts +- [ ] T017 [US2] Add example output description in header comment of 02-interactive-plugin.ts + +## Phase 5: User Story 3 (P3) - Data Persistence Plugin + +- [ ] T018 [P] [US3] Create 03-persistence-plugin.ts demonstrating StoreDefault and StoreJson usage +- [ ] T019 [US3] Implement key naming conventions in 03-persistence-plugin.ts +- [ ] T020 [US3] Add error handling for storage operations in 03-persistence-plugin.ts +- [ ] T021 [US3] Add inline documentation (20%+ comment ratio) to 03-persistence-plugin.ts +- [ ] T022 [US3] Add example output description in header comment of 03-persistence-plugin.ts + +## Phase 6: User Story 4 (P4) - Quick Actions and Side Panel Integration + +- [ ] T023 [P] [US4] Create 04-ui-extensions-plugin.ts demonstrating QuickActionMixin and SidePanelMixin +- [ ] T024 [US4] Implement defineQuickActions() in 04-ui-extensions-plugin.ts +- [ ] T025 [US4] Implement defineSidePanel() in 04-ui-extensions-plugin.ts +- [ ] T026 [US4] Add message routing from UI extensions in 04-ui-extensions-plugin.ts +- [ ] T027 [US4] Add inline documentation (20%+ comment ratio) to 04-ui-extensions-plugin.ts +- [ ] T028 [US4] Add example output description in header comment of 04-ui-extensions-plugin.ts + +## Phase 7: User Story 5 (P5) - Advanced DOM Generation + +- [ ] T029 [P] [US5] Create 05-advanced-dom-plugin.ts demonstrating DOM helpers and styling +- [ ] T030 [US5] Implement CSS-in-JS styling with goober in 05-advanced-dom-plugin.ts +- [ ] T031 [US5] Compose complex nested UI structures in 05-advanced-dom-plugin.ts +- [ ] T032 [US5] Add inline documentation (20%+ comment ratio) to 05-advanced-dom-plugin.ts +- [ ] T033 [US5] Add example output description in header comment of 05-advanced-dom-plugin.ts + +--- + +## Final Phase: Polish & Cross-Cutting Concerns + +- [ ] T034 Review all example files for code style and convention compliance +- [ ] T035 Validate documentation ratio in all example files +- [ ] T036 [P] Add troubleshooting section to examples/README.md +- [ ] T037 [P] Add contributing guidelines to examples/README.md +- [ ] T038 Ensure all examples compile and run independently + +--- + +## Dependencies + +- US1 → US2 → US3 → US4 → US5 (progressive learning order) +- Setup and Foundational phases must be completed before any user story phase +- Each user story phase is independently testable + +--- + +## Parallel Execution Opportunities + +- Tasks marked [P] can be executed in parallel (different files, no dependencies) +- Example: T008, T013, T018, T023, T029 (create example files) can be done in parallel after foundational setup + +--- + +## Implementation Strategy + +- MVP: Complete Phase 1, Phase 2, and User Story 1 (T001–T012) +- Incremental delivery: Add each user story phase in order, validating independent test criteria +- Each example file is independently runnable and testable + +--- + +## Format Validation + +- All tasks follow strict checklist format: `- [ ] T### [P] [US#] Description with file path` +- Each user story phase includes story label ([US1], [US2], etc.) +- All tasks specify exact file paths +- Parallelizable tasks are marked [P] +- Task IDs are sequential + +--- + +## Summary + +- **Total tasks**: 38 +- **Task count per user story**: US1: 5, US2: 5, US3: 5, US4: 6, US5: 5 +- **Parallel opportunities**: 8 (all [P] tasks) +- **Independent test criteria**: Each user story phase is independently testable +- **Suggested MVP scope**: T001–T012 (Setup, Foundational, and User Story 1) From 9575f8267762a05cd2dac92f53d087a2b11f644e Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 14:30:58 +0000 Subject: [PATCH 4/6] Address HIGH and MEDIUM severity issues from spec-kit analyze - C1 (HIGH): Added error handling tasks for all 5 examples (T013, T018, T025, T036, T044) - C2 (MEDIUM): Added customization guidance tasks with 'CUSTOMIZE HERE' markers for all examples (T014, T021, T028, T037, T045) - C3 (MEDIUM): Added logging demonstration to T011 (basic plugin init/render with this.log, this.error) - C4 (MEDIUM): Added async patterns demonstration to T016 (interactive plugin) - C5 (MEDIUM): Added common pitfalls comments tasks for all examples (T015, T022, T029, T038, T046) - I1 (MEDIUM): Clarified metadata-template.ts purpose in plan.md project structure - I2 (MEDIUM): Clarified examples/README.md vs quickstart.md relationship in T004 and plan.md - A1 (MEDIUM): Added measurement approach for SC-003 and SC-005 success criteria in spec.md Updated task numbering throughout to accommodate new tasks (54 total tasks, up from 38). Added validation tasks T049-T051 to ensure all examples include error handling, customization markers, and common pitfalls comments. Co-Authored-By: onikiten@softserveinc.com --- specs/002-plugin-examples/plan.md | 4 +- specs/002-plugin-examples/spec.md | 8 ++- specs/002-plugin-examples/tasks.md | 83 ++++++++++++++++++------------ 3 files changed, 59 insertions(+), 36 deletions(-) diff --git a/specs/002-plugin-examples/plan.md b/specs/002-plugin-examples/plan.md index 2cd0ad9..6d8622a 100644 --- a/specs/002-plugin-examples/plan.md +++ b/specs/002-plugin-examples/plan.md @@ -60,6 +60,8 @@ specs/[###-feature]/ ```text examples/ +├── README.md # Brief overview pointing to quickstart.md +├── metadata-template.ts # Reusable PluginMetadata template/helper ├── 01-basic-plugin.ts # P1: Basic plugin creation (lifecycle, rendering) ├── 02-interactive-plugin.ts # P2: Interactive UI with handlers and messaging ├── 03-persistence-plugin.ts # P3: Data persistence with storage backends @@ -77,7 +79,7 @@ tests/ └── ... # Existing tests (no changes for this feature) ``` -**Structure Decision**: Single project structure. All 5 example files will be added to the existing `examples/` directory with numbered prefixes (01-05) to indicate learning progression. No changes to existing SDK source code or tests are required - this is purely additive content in the examples directory. +**Structure Decision**: Single project structure. All 5 example files will be added to the existing `examples/` directory with numbered prefixes (01-05) to indicate learning progression. The `metadata-template.ts` file provides a reusable template that developers can copy when creating their own plugins. The `examples/README.md` serves as a brief entry point that directs developers to the comprehensive `quickstart.md` guide in the specs directory. No changes to existing SDK source code or tests are required - this is purely additive content in the examples directory. ## Complexity Tracking diff --git a/specs/002-plugin-examples/spec.md b/specs/002-plugin-examples/spec.md index 85f336f..6a15605 100644 --- a/specs/002-plugin-examples/spec.md +++ b/specs/002-plugin-examples/spec.md @@ -156,13 +156,17 @@ A plugin developer wants to create rich, styled UI components using the SDK's DO - **SC-001**: Developers can create their first working plugin in under 15 minutes using the basic example as a starting point - **SC-002**: Each example runs successfully without modification in a standard FDO SDK environment -- **SC-003**: 90% of plugin developers report that examples helped them understand SDK features without needing additional documentation +- **SC-003**: 90% of plugin developers report that examples helped them understand SDK features without needing additional documentation (measured via post-release developer survey sent to npm package users) - **SC-004**: Examples cover 100% of the public SDK API surface area (all exported classes and methods are demonstrated in at least one example) -- **SC-005**: Plugin development onboarding time is reduced by 50% compared to learning from API documentation alone +- **SC-005**: Plugin development onboarding time is reduced by 50% compared to learning from API documentation alone (measured by comparing average time-to-first-plugin before and after examples release, tracked via developer surveys and GitHub issue timestamps) - **SC-006**: Zero critical bugs or errors in example code that would prevent them from running - **SC-007**: Each example includes at least 20% inline documentation relative to code volume (measured by comment lines vs code lines) - **SC-008**: Examples demonstrate at least 3 different complexity levels (basic, intermediate, advanced) to support developers at different skill levels +### Measurement Approach + +- **SC-003 & SC-005**: Post-release developer surveys will be conducted 3 months and 6 months after examples are published to npm. Surveys will be sent to developers who have downloaded the package and will ask about their experience with the examples, time to create first plugin, and whether examples were sufficient without additional documentation. Baseline metrics for SC-005 will be established by analyzing historical GitHub issues and support requests to estimate average onboarding time before examples existed. + ## Assumptions - Developers using these examples have basic JavaScript/TypeScript knowledge diff --git a/specs/002-plugin-examples/tasks.md b/specs/002-plugin-examples/tasks.md index 0ecb74b..fa1af37 100644 --- a/specs/002-plugin-examples/tasks.md +++ b/specs/002-plugin-examples/tasks.md @@ -11,7 +11,7 @@ - [ ] T001 Create examples/ directory in repository root - [ ] T002 Initialize TypeScript strict mode in examples/ (tsconfig.json) - [ ] T003 Install @anikitenko/fdo-sdk, electron, goober, winston dependencies -- [ ] T004 Add README to examples/ with usage instructions +- [ ] T004 Add brief README to examples/ directory pointing to quickstart.md in specs/ ## Phase 2: Foundational Tasks @@ -26,51 +26,67 @@ - [ ] T008 [P] [US1] Create 01-basic-plugin.ts demonstrating plugin lifecycle and rendering - [ ] T009 [US1] Add inline documentation (20%+ comment ratio) to 01-basic-plugin.ts - [ ] T010 [US1] Add metadata block to 01-basic-plugin.ts -- [ ] T011 [US1] Implement init() and render() methods in 01-basic-plugin.ts +- [ ] T011 [US1] Implement init() and render() methods with logging (this.log, this.error) in 01-basic-plugin.ts - [ ] T012 [US1] Add example output description in header comment of 01-basic-plugin.ts +- [ ] T013 [US1] Add error handling for basic operations in 01-basic-plugin.ts +- [ ] T014 [US1] Add "CUSTOMIZE HERE" comment markers in appropriate locations in 01-basic-plugin.ts +- [ ] T015 [US1] Add common pitfalls comments to 01-basic-plugin.ts ## Phase 4: User Story 2 (P2) - Interactive Plugin with UI Actions -- [ ] T013 [P] [US2] Create 02-interactive-plugin.ts with button and form UI -- [ ] T014 [US2] Register message handlers in init() of 02-interactive-plugin.ts -- [ ] T015 [US2] Implement error handling in handlers in 02-interactive-plugin.ts -- [ ] T016 [US2] Add inline documentation (20%+ comment ratio) to 02-interactive-plugin.ts -- [ ] T017 [US2] Add example output description in header comment of 02-interactive-plugin.ts +- [ ] T016 [P] [US2] Create 02-interactive-plugin.ts with button and form UI demonstrating async patterns +- [ ] T017 [US2] Register message handlers in init() of 02-interactive-plugin.ts +- [ ] T018 [US2] Implement error handling in handlers in 02-interactive-plugin.ts +- [ ] T019 [US2] Add inline documentation (20%+ comment ratio) to 02-interactive-plugin.ts +- [ ] T020 [US2] Add example output description in header comment of 02-interactive-plugin.ts +- [ ] T021 [US2] Add "CUSTOMIZE HERE" comment markers in appropriate locations in 02-interactive-plugin.ts +- [ ] T022 [US2] Add common pitfalls comments to 02-interactive-plugin.ts ## Phase 5: User Story 3 (P3) - Data Persistence Plugin -- [ ] T018 [P] [US3] Create 03-persistence-plugin.ts demonstrating StoreDefault and StoreJson usage -- [ ] T019 [US3] Implement key naming conventions in 03-persistence-plugin.ts -- [ ] T020 [US3] Add error handling for storage operations in 03-persistence-plugin.ts -- [ ] T021 [US3] Add inline documentation (20%+ comment ratio) to 03-persistence-plugin.ts -- [ ] T022 [US3] Add example output description in header comment of 03-persistence-plugin.ts +- [ ] T023 [P] [US3] Create 03-persistence-plugin.ts demonstrating StoreDefault and StoreJson usage +- [ ] T024 [US3] Implement key naming conventions in 03-persistence-plugin.ts +- [ ] T025 [US3] Add error handling for storage operations in 03-persistence-plugin.ts +- [ ] T026 [US3] Add inline documentation (20%+ comment ratio) to 03-persistence-plugin.ts +- [ ] T027 [US3] Add example output description in header comment of 03-persistence-plugin.ts +- [ ] T028 [US3] Add "CUSTOMIZE HERE" comment markers in appropriate locations in 03-persistence-plugin.ts +- [ ] T029 [US3] Add common pitfalls comments to 03-persistence-plugin.ts ## Phase 6: User Story 4 (P4) - Quick Actions and Side Panel Integration -- [ ] T023 [P] [US4] Create 04-ui-extensions-plugin.ts demonstrating QuickActionMixin and SidePanelMixin -- [ ] T024 [US4] Implement defineQuickActions() in 04-ui-extensions-plugin.ts -- [ ] T025 [US4] Implement defineSidePanel() in 04-ui-extensions-plugin.ts -- [ ] T026 [US4] Add message routing from UI extensions in 04-ui-extensions-plugin.ts -- [ ] T027 [US4] Add inline documentation (20%+ comment ratio) to 04-ui-extensions-plugin.ts -- [ ] T028 [US4] Add example output description in header comment of 04-ui-extensions-plugin.ts +- [ ] T030 [P] [US4] Create 04-ui-extensions-plugin.ts demonstrating QuickActionMixin and SidePanelMixin +- [ ] T031 [US4] Implement defineQuickActions() in 04-ui-extensions-plugin.ts +- [ ] T032 [US4] Implement defineSidePanel() in 04-ui-extensions-plugin.ts +- [ ] T033 [US4] Add message routing from UI extensions in 04-ui-extensions-plugin.ts +- [ ] T034 [US4] Add inline documentation (20%+ comment ratio) to 04-ui-extensions-plugin.ts +- [ ] T035 [US4] Add example output description in header comment of 04-ui-extensions-plugin.ts +- [ ] T036 [US4] Add error handling for UI extension operations in 04-ui-extensions-plugin.ts +- [ ] T037 [US4] Add "CUSTOMIZE HERE" comment markers in appropriate locations in 04-ui-extensions-plugin.ts +- [ ] T038 [US4] Add common pitfalls comments to 04-ui-extensions-plugin.ts ## Phase 7: User Story 5 (P5) - Advanced DOM Generation -- [ ] T029 [P] [US5] Create 05-advanced-dom-plugin.ts demonstrating DOM helpers and styling -- [ ] T030 [US5] Implement CSS-in-JS styling with goober in 05-advanced-dom-plugin.ts -- [ ] T031 [US5] Compose complex nested UI structures in 05-advanced-dom-plugin.ts -- [ ] T032 [US5] Add inline documentation (20%+ comment ratio) to 05-advanced-dom-plugin.ts -- [ ] T033 [US5] Add example output description in header comment of 05-advanced-dom-plugin.ts +- [ ] T039 [P] [US5] Create 05-advanced-dom-plugin.ts demonstrating DOM helpers and styling +- [ ] T040 [US5] Implement CSS-in-JS styling with goober in 05-advanced-dom-plugin.ts +- [ ] T041 [US5] Compose complex nested UI structures in 05-advanced-dom-plugin.ts +- [ ] T042 [US5] Add inline documentation (20%+ comment ratio) to 05-advanced-dom-plugin.ts +- [ ] T043 [US5] Add example output description in header comment of 05-advanced-dom-plugin.ts +- [ ] T044 [US5] Add error handling for DOM generation operations in 05-advanced-dom-plugin.ts +- [ ] T045 [US5] Add "CUSTOMIZE HERE" comment markers in appropriate locations in 05-advanced-dom-plugin.ts +- [ ] T046 [US5] Add common pitfalls comments to 05-advanced-dom-plugin.ts --- ## Final Phase: Polish & Cross-Cutting Concerns -- [ ] T034 Review all example files for code style and convention compliance -- [ ] T035 Validate documentation ratio in all example files -- [ ] T036 [P] Add troubleshooting section to examples/README.md -- [ ] T037 [P] Add contributing guidelines to examples/README.md -- [ ] T038 Ensure all examples compile and run independently +- [ ] T047 Review all example files for code style and convention compliance +- [ ] T048 Validate documentation ratio in all example files (20%+ requirement) +- [ ] T049 Validate all examples include error handling +- [ ] T050 Validate all examples include customization markers +- [ ] T051 Validate all examples include common pitfalls comments +- [ ] T052 [P] Add troubleshooting section to examples/README.md +- [ ] T053 [P] Add contributing guidelines to examples/README.md +- [ ] T054 Ensure all examples compile and run independently --- @@ -85,13 +101,13 @@ ## Parallel Execution Opportunities - Tasks marked [P] can be executed in parallel (different files, no dependencies) -- Example: T008, T013, T018, T023, T029 (create example files) can be done in parallel after foundational setup +- Example: T008, T016, T023, T030, T039 (create example files) can be done in parallel after foundational setup --- ## Implementation Strategy -- MVP: Complete Phase 1, Phase 2, and User Story 1 (T001–T012) +- MVP: Complete Phase 1, Phase 2, and User Story 1 (T001–T015) - Incremental delivery: Add each user story phase in order, validating independent test criteria - Each example file is independently runnable and testable @@ -109,8 +125,9 @@ ## Summary -- **Total tasks**: 38 -- **Task count per user story**: US1: 5, US2: 5, US3: 5, US4: 6, US5: 5 +- **Total tasks**: 54 +- **Task count per user story**: US1: 8, US2: 7, US3: 7, US4: 9, US5: 8 - **Parallel opportunities**: 8 (all [P] tasks) - **Independent test criteria**: Each user story phase is independently testable -- **Suggested MVP scope**: T001–T012 (Setup, Foundational, and User Story 1) +- **Suggested MVP scope**: T001–T015 (Setup, Foundational, and User Story 1) +- **New tasks added**: Error handling (T013, T036, T044), customization markers (T014, T021, T028, T037, T045), common pitfalls (T015, T022, T029, T038, T046), logging demonstration (T011), async patterns (T016), validation tasks (T049-T051) From cffd1c95d3d64756998189c9ecefeadcd44806c0 Mon Sep 17 00:00:00 2001 From: Devin AI <158243242+devin-ai-integration[bot]@users.noreply.github.com> Date: Mon, 27 Oct 2025 15:13:35 +0000 Subject: [PATCH 5/6] Implement plugin example implementations (spec-kit) - Add 5 comprehensive plugin examples (01-05) - Create examples/README.md with troubleshooting and contributing sections - Add metadata-template.ts for reusable plugin metadata - Add examples/tsconfig.json for TypeScript strict mode - Update package.json to include examples/ in npm distribution - Mark all tasks (T001-T054) as completed in tasks.md Examples cover: - 01-basic-plugin.ts: Plugin lifecycle and rendering - 02-interactive-plugin.ts: Interactive UI with handlers - 03-persistence-plugin.ts: Data persistence with storage - 04-ui-extensions-plugin.ts: Quick actions and side panels - 05-advanced-dom-plugin.ts: Advanced DOM generation All examples include: - 20%+ inline documentation ratio - CUSTOMIZE HERE markers - COMMON PITFALL comments - Error handling - SDK v1.x compatibility headers Co-Authored-By: onikiten@softserveinc.com --- examples/01-basic-plugin.ts | 151 ++++++++ examples/02-interactive-plugin.ts | 330 ++++++++++++++++ examples/03-persistence-plugin.ts | 465 +++++++++++++++++++++++ examples/04-ui-extensions-plugin.ts | 567 ++++++++++++++++++++++++++++ examples/05-advanced-dom-plugin.ts | 562 +++++++++++++++++++++++++++ examples/README.md | 135 +++++++ examples/metadata-template.ts | 44 +++ examples/tsconfig.json | 11 + package.json | 3 +- specs/002-plugin-examples/tasks.md | 108 +++--- 10 files changed, 2321 insertions(+), 55 deletions(-) create mode 100644 examples/01-basic-plugin.ts create mode 100644 examples/02-interactive-plugin.ts create mode 100644 examples/03-persistence-plugin.ts create mode 100644 examples/04-ui-extensions-plugin.ts create mode 100644 examples/05-advanced-dom-plugin.ts create mode 100644 examples/README.md create mode 100644 examples/metadata-template.ts create mode 100644 examples/tsconfig.json diff --git a/examples/01-basic-plugin.ts b/examples/01-basic-plugin.ts new file mode 100644 index 0000000..c3fb543 --- /dev/null +++ b/examples/01-basic-plugin.ts @@ -0,0 +1,151 @@ +/** + * Example 1: Basic Plugin Creation + * + * This example demonstrates the minimal requirements to create a working FDO plugin. + * It covers the core plugin lifecycle (initialization and rendering) and basic metadata structure. + * + * Compatible with SDK v1.x + * + * Learning Objectives: + * - Understand the FDO_SDK base class and FDOInterface + * - Learn how to implement required lifecycle methods (init and render) + * - See how to structure plugin metadata + * - Use the built-in logging system + * + * Expected Output: + * When this plugin runs in the FDO application, it will: + * 1. Log "BasicPlugin initialized!" to the console during initialization + * 2. Display a simple welcome message with the plugin name and version + * 3. Show a brief description of what the plugin does + */ + +import { FDO_SDK, FDOInterface, PluginMetadata } from "@anikitenko/fdo-sdk"; + +/** + * BasicPlugin demonstrates the minimal plugin structure. + * + * All plugins must: + * 1. Extend the FDO_SDK base class + * 2. Implement the FDOInterface interface + * 3. Define metadata (name, version, author, description, icon) + * 4. Implement init() and render() methods + */ +export default class BasicPlugin extends FDO_SDK implements FDOInterface { + /** + * Plugin metadata - required by FDOInterface. + * This information is used by the FDO application to identify and describe your plugin. + * + * CUSTOMIZE HERE: Replace these values with your own plugin information + */ + private readonly _metadata: PluginMetadata = { + name: "Basic Plugin Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "A minimal example demonstrating basic plugin creation and lifecycle", + icon: "icon.png" + }; + + /** + * Getter for plugin metadata. + * Required by FDOInterface. + */ + get metadata(): PluginMetadata { + return this._metadata; + } + + /** + * Initialize the plugin. + * + * This method is called once when the plugin is loaded by the FDO application. + * Use this method to: + * - Set up initial state + * - Register message handlers (covered in example 02) + * - Initialize storage (covered in example 03) + * - Perform any setup tasks + * + * COMMON PITFALL: Do not perform long-running operations in init(). + * The init() method should complete quickly to avoid blocking the application startup. + * For async operations, consider using promises or deferring work to handlers. + */ + init(): void { + try { + this.log("BasicPlugin initialized!"); + + + } catch (error) { + this.error(error as Error); + + } + } + + /** + * Render the plugin UI. + * + * This method is called when the plugin needs to display its user interface. + * It should return an HTML string that defines the plugin's UI. + * + * The returned HTML will be rendered in the FDO application's plugin container. + * + * CUSTOMIZE HERE: Replace this simple HTML with your own UI + * + * COMMON PITFALL: The render() method should return quickly. + * For complex UIs, consider using the DOM helper classes (see example 05) + * or breaking the UI into smaller components. + * + * @returns HTML string representing the plugin's user interface + */ + render(): string { + try { + + const html = ` +
+

Welcome to ${this._metadata.name}

+

Version: ${this._metadata.version}

+

Author: ${this._metadata.author}

+

${this._metadata.description}

+ +
+

What's Next?

+

This is a basic plugin example. To learn more advanced features:

+
    +
  • See example 02 for interactive UI with buttons and forms
  • +
  • See example 03 for data persistence
  • +
  • See example 04 for UI extensions (quick actions and side panels)
  • +
  • See example 05 for advanced DOM generation and styling
  • +
+
+
+ `; + + return html; + + } catch (error) { + this.error(error as Error); + + return ` +
+

Error rendering plugin

+

An error occurred while rendering the plugin UI. Check the console for details.

+
+ `; + } + } +} + +/** + * Key Takeaways: + * + * 1. All plugins must extend FDO_SDK and implement FDOInterface + * 2. The metadata property is required and must include name, version, author, description, and icon + * 3. The init() method is called once during plugin load - use it for setup + * 4. The render() method returns HTML that defines the plugin's UI + * 5. Use this.log() for informational messages and this.error() for error logging + * 6. Always handle errors in init() and render() to prevent plugin failures + * + * Next Steps: + * - Copy this file to your project + * - Customize the metadata with your plugin information + * - Modify the render() method to display your own UI + * - Add your initialization logic to the init() method + * - Test your plugin in the FDO application + */ diff --git a/examples/02-interactive-plugin.ts b/examples/02-interactive-plugin.ts new file mode 100644 index 0000000..fe18025 --- /dev/null +++ b/examples/02-interactive-plugin.ts @@ -0,0 +1,330 @@ +/** + * Example 2: Interactive Plugin with UI Actions + * + * This example demonstrates how to create interactive functionality where users can + * click buttons, fill forms, and trigger custom actions through the message-based + * communication system. + * + * Compatible with SDK v1.x + * + * Learning Objectives: + * - Register and handle custom message handlers + * - Create interactive UI elements (buttons, forms) + * - Process user input and update the UI + * - Handle asynchronous operations + * - Implement proper error handling for user interactions + * + * Expected Output: + * When this plugin runs in the FDO application, it will: + * 1. Display a form with a text input and submit button + * 2. Show a counter with increment/decrement buttons + * 3. Process button clicks and form submissions + * 4. Update the UI dynamically based on user actions + * 5. Log all user interactions to the console + */ + +import { FDO_SDK, FDOInterface, PluginMetadata, PluginRegistry } from "@anikitenko/fdo-sdk"; + +/** + * InteractivePlugin demonstrates user interaction handling. + * + * Key concepts: + * - Message handlers: Functions that respond to UI events + * - Handler registration: Done in init() using PluginRegistry.registerHandler() + * - Async patterns: Handlers can be async for long-running operations + */ +export default class InteractivePlugin extends FDO_SDK implements FDOInterface { + /** + * Plugin metadata. + * + * CUSTOMIZE HERE: Replace with your plugin information + */ + private readonly _metadata: PluginMetadata = { + name: "Interactive Plugin Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "Demonstrates interactive UI with buttons, forms, and message handlers", + icon: "icon.png" + }; + + /** + * Internal state for the counter example. + * In a real plugin, you might use the storage system (see example 03) for persistence. + */ + private counter: number = 0; + + get metadata(): PluginMetadata { + return this._metadata; + } + + /** + * Initialize the plugin and register message handlers. + * + * Message handlers are functions that respond to UI events. + * They are registered by name and can be triggered from UI elements. + * + * COMMON PITFALL: Always register handlers in init(), not in render(). + * Handlers registered in render() will be re-registered every time the UI updates, + * potentially causing duplicate handler registrations. + */ + init(): void { + try { + this.log("InteractivePlugin initialized!"); + + PluginRegistry.registerHandler("incrementCounter", (data: any) => { + return this.handleIncrement(data); + }); + + PluginRegistry.registerHandler("decrementCounter", (data: any) => { + return this.handleDecrement(data); + }); + + PluginRegistry.registerHandler("submitForm", async (data: any) => { + return await this.handleFormSubmit(data); + }); + + + } catch (error) { + this.error(error as Error); + } + } + + /** + * Handle increment button click. + * + * @param data - Data passed from the UI (can include button context, user info, etc.) + * @returns Result object that can be used to update the UI + */ + private handleIncrement(data: any): any { + try { + this.counter++; + this.log(`Counter incremented to ${this.counter}`); + + return { + success: true, + counter: this.counter, + message: `Counter is now ${this.counter}` + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to increment counter" + }; + } + } + + /** + * Handle decrement button click. + * + * @param data - Data passed from the UI + * @returns Result object + */ + private handleDecrement(data: any): any { + try { + this.counter--; + this.log(`Counter decremented to ${this.counter}`); + + return { + success: true, + counter: this.counter, + message: `Counter is now ${this.counter}` + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to decrement counter" + }; + } + } + + /** + * Handle form submission. + * + * This demonstrates async handler patterns for operations that might take time + * (e.g., API calls, file operations, complex computations). + * + * COMMON PITFALL: For async operations, always use async/await or promises. + * Don't block the UI with synchronous long-running operations. + * + * @param data - Form data from the UI + * @returns Promise resolving to result object + */ + private async handleFormSubmit(data: any): Promise { + try { + this.log(`Form submitted with data: ${JSON.stringify(data)}`); + + await new Promise(resolve => setTimeout(resolve, 500)); + + + const userName = data.userName || "Guest"; + + return { + success: true, + message: `Welcome, ${userName}! Your form has been processed.`, + timestamp: new Date().toISOString() + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to process form submission" + }; + } + } + + /** + * Render the interactive UI. + * + * This example shows how to create buttons and forms that trigger message handlers. + * + * CUSTOMIZE HERE: Replace with your own interactive UI + * + * @returns HTML string with interactive elements + */ + render(): string { + try { + const html = ` +
+

${this._metadata.name}

+

${this._metadata.description}

+ + +
+

Counter Example

+

Current count: ${this.counter}

+ + + + + +

+ Click the buttons to increment or decrement the counter. + The counter value is maintained in plugin state. +

+
+ + +
+

Form Example

+
+ + + +
+ + +
+ +
+ +

+ Enter your name and submit the form to see async handler processing. +

+
+ + + + +
+

Key Concepts

+
    +
  • Message Handlers: Functions registered in init() that respond to UI events
  • +
  • Handler Registration: Use PluginRegistry.registerHandler(name, function)
  • +
  • Async Patterns: Handlers can be async for long-running operations
  • +
  • Error Handling: Always wrap handler logic in try-catch blocks
  • +
  • State Management: Use class properties for temporary state, storage for persistence
  • +
+
+
+ `; + + return html; + + } catch (error) { + this.error(error as Error); + return ` +
+

Error rendering plugin

+

An error occurred while rendering the plugin UI. Check the console for details.

+
+ `; + } + } +} + +/** + * Key Takeaways: + * + * 1. Register message handlers in init() using PluginRegistry.registerHandler() + * 2. Handlers can be synchronous or asynchronous (use async/await for long operations) + * 3. Always handle errors in handlers to prevent UI failures + * 4. Use class properties for temporary state, storage system for persistence + * 5. Validate user input before processing to prevent security issues + * 6. Return structured data from handlers to enable UI updates + * + * Common Pitfalls to Avoid: + * - Don't register handlers in render() - do it in init() + * - Don't forget error handling in handlers + * - Don't block the UI with synchronous long-running operations + * - Don't trust user input - always validate + * + * Next Steps: + * - See example 03 for data persistence with the storage system + * - See example 04 for UI extensions (quick actions and side panels) + * - See example 05 for advanced DOM generation with styling + */ diff --git a/examples/03-persistence-plugin.ts b/examples/03-persistence-plugin.ts new file mode 100644 index 0000000..28b87c6 --- /dev/null +++ b/examples/03-persistence-plugin.ts @@ -0,0 +1,465 @@ +/** + * Example 3: Data Persistence Plugin + * + * This example demonstrates how to save and retrieve user data across application sessions + * using the FDO SDK storage system. It covers both in-memory (StoreDefault) and file-based + * (StoreJson) storage backends. + * + * Compatible with SDK v1.x + * + * Learning Objectives: + * - Use StoreDefault for temporary data (in-memory) + * - Use StoreJson for persistent data (file-based) + * - Implement proper key naming conventions + * - Handle storage errors gracefully + * - Save and retrieve different data types + * + * Expected Output: + * When this plugin runs in the FDO application, it will: + * 1. Display saved user preferences (name, theme, notifications) + * 2. Provide forms to update preferences + * 3. Show temporary session data (visit count, last action) + * 4. Persist preference changes across application restarts + * 5. Clear temporary data on each session + */ + +import { FDO_SDK, FDOInterface, PluginMetadata, PluginRegistry } from "@anikitenko/fdo-sdk"; + +/** + * PersistencePlugin demonstrates data storage and retrieval. + * + * Key concepts: + * - StoreDefault: In-memory storage (data lost on restart) + * - StoreJson: File-based storage (data persists across restarts) + * - Key naming: Use namespaced keys to avoid conflicts + * - Error handling: Storage operations can fail + */ +export default class PersistencePlugin extends FDO_SDK implements FDOInterface { + /** + * Plugin metadata. + * + * CUSTOMIZE HERE: Replace with your plugin information + */ + private readonly _metadata: PluginMetadata = { + name: "Persistence Plugin Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "Demonstrates data persistence with StoreDefault and StoreJson", + icon: "icon.png" + }; + + /** + * Storage instances. + * StoreDefault is automatically available without registration. + * StoreJson must be registered before use. + */ + private tempStore: any; // StoreDefault for temporary data + private persistentStore: any; // StoreJson for persistent data + + /** + * Key naming convention. + * Use namespaced keys to avoid conflicts with other plugins. + * Format: "pluginName:category:keyName" + * + * COMMON PITFALL: Always namespace your keys to prevent conflicts. + * Without namespacing, multiple plugins might overwrite each other's data. + */ + private readonly KEYS = { + USER_NAME: "persistencePlugin:prefs:userName", + USER_THEME: "persistencePlugin:prefs:theme", + NOTIFICATIONS_ENABLED: "persistencePlugin:prefs:notifications", + + VISIT_COUNT: "persistencePlugin:session:visitCount", + LAST_ACTION: "persistencePlugin:session:lastAction", + SESSION_START: "persistencePlugin:session:startTime" + }; + + get metadata(): PluginMetadata { + return this._metadata; + } + + /** + * Initialize the plugin and set up storage. + * + * COMMON PITFALL: Always initialize storage in init(), not in render(). + * Storage operations in render() can cause performance issues and data inconsistencies. + */ + init(): void { + try { + this.log("PersistencePlugin initialized!"); + + this.tempStore = PluginRegistry.useStore("default"); + + try { + this.persistentStore = PluginRegistry.useStore("json"); + } catch (error) { + this.log("StoreJson not available, using StoreDefault for all storage"); + this.persistentStore = this.tempStore; + } + + this.initializeSessionData(); + + PluginRegistry.registerHandler("savePreferences", (data: any) => { + return this.handleSavePreferences(data); + }); + + PluginRegistry.registerHandler("clearPreferences", (data: any) => { + return this.handleClearPreferences(data); + }); + + PluginRegistry.registerHandler("recordAction", (data: any) => { + return this.handleRecordAction(data); + }); + + + } catch (error) { + this.error(error as Error); + } + } + + /** + * Initialize session data in temporary storage. + * This data is cleared on each application restart. + */ + private initializeSessionData(): void { + try { + const visitCount = this.tempStore.get(this.KEYS.VISIT_COUNT) || 0; + this.tempStore.set(this.KEYS.VISIT_COUNT, visitCount + 1); + + this.tempStore.set(this.KEYS.SESSION_START, new Date().toISOString()); + + this.log(`Session initialized. Visit count: ${visitCount + 1}`); + + } catch (error) { + this.error(error as Error); + } + } + + /** + * Handle saving user preferences to persistent storage. + * + * @param data - Preference data from the UI + * @returns Result object + */ + private handleSavePreferences(data: any): any { + try { + if (!data) { + return { + success: false, + error: "No data provided" + }; + } + + if (data.userName !== undefined) { + this.persistentStore.set(this.KEYS.USER_NAME, data.userName); + } + + if (data.theme !== undefined) { + this.persistentStore.set(this.KEYS.USER_THEME, data.theme); + } + + if (data.notificationsEnabled !== undefined) { + this.persistentStore.set(this.KEYS.NOTIFICATIONS_ENABLED, data.notificationsEnabled); + } + + this.log("Preferences saved successfully"); + + return { + success: true, + message: "Preferences saved successfully", + savedData: data + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to save preferences" + }; + } + } + + /** + * Handle clearing all preferences. + * + * @param data - Optional data + * @returns Result object + */ + private handleClearPreferences(data: any): any { + try { + this.persistentStore.remove(this.KEYS.USER_NAME); + this.persistentStore.remove(this.KEYS.USER_THEME); + this.persistentStore.remove(this.KEYS.NOTIFICATIONS_ENABLED); + + this.log("Preferences cleared"); + + return { + success: true, + message: "All preferences have been cleared" + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to clear preferences" + }; + } + } + + /** + * Handle recording a user action to temporary storage. + * + * @param data - Action data + * @returns Result object + */ + private handleRecordAction(data: any): any { + try { + const action = data.action || "unknown"; + const timestamp = new Date().toISOString(); + + this.tempStore.set(this.KEYS.LAST_ACTION, { + action, + timestamp + }); + + this.log(`Action recorded: ${action}`); + + return { + success: true, + action, + timestamp + }; + + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to record action" + }; + } + } + + /** + * Render the persistence UI. + * + * CUSTOMIZE HERE: Replace with your own storage UI + * + * @returns HTML string + */ + render(): string { + try { + const userName = this.persistentStore.get(this.KEYS.USER_NAME) || "Not set"; + const theme = this.persistentStore.get(this.KEYS.USER_THEME) || "light"; + const notificationsEnabled = this.persistentStore.get(this.KEYS.NOTIFICATIONS_ENABLED) ?? true; + + const visitCount = this.tempStore.get(this.KEYS.VISIT_COUNT) || 0; + const lastAction = this.tempStore.get(this.KEYS.LAST_ACTION); + const sessionStart = this.tempStore.get(this.KEYS.SESSION_START); + + const html = ` +
+

${this._metadata.name}

+

${this._metadata.description}

+ + +
+

Persistent Preferences (StoreJson)

+

+ These preferences are saved to a file and persist across application restarts. +

+ +
+ User Name: ${userName} +
+
+ Theme: ${theme} +
+
+ Notifications: ${notificationsEnabled ? "Enabled" : "Disabled"} +
+ +
+
+ + +
+ +
+ + +
+ +
+ +
+ + + + +
+ +
+
+ + +
+

Session Data (StoreDefault)

+

+ This data is stored in memory and cleared when the application restarts. +

+ +
+ Visit Count: ${visitCount} +
+
+ Session Started: ${sessionStart ? new Date(sessionStart).toLocaleString() : 'N/A'} +
+
+ Last Action: + ${lastAction ? `${lastAction.action} at ${new Date(lastAction.timestamp).toLocaleTimeString()}` : 'None'} +
+ + +
+ + +
+

Storage Concepts

+
    +
  • StoreDefault: In-memory storage, data cleared on restart
  • +
  • StoreJson: File-based storage, data persists across restarts
  • +
  • Key Naming: Use namespaced keys (pluginName:category:key)
  • +
  • Error Handling: Always wrap storage operations in try-catch
  • +
  • Data Types: Stores support strings, numbers, booleans, objects, arrays
  • +
+
+ + + +
+ `; + + return html; + + } catch (error) { + this.error(error as Error); + return ` +
+

Error rendering plugin

+

An error occurred while rendering the plugin UI. Check the console for details.

+
+ `; + } + } +} + +/** + * Key Takeaways: + * + * 1. Use StoreDefault for temporary data (in-memory, cleared on restart) + * 2. Use StoreJson for persistent data (file-based, survives restarts) + * 3. Always namespace your keys to avoid conflicts (pluginName:category:key) + * 4. Wrap all storage operations in try-catch blocks + * 5. Initialize storage in init(), not in render() + * 6. Storage supports all JSON-serializable types (strings, numbers, objects, arrays) + * + * Common Pitfalls to Avoid: + * - Don't use generic key names - always namespace them + * - Don't forget error handling for storage operations + * - Don't perform storage operations in render() - do it in handlers + * - Don't assume StoreJson is always available - have a fallback + * + * Next Steps: + * - See example 04 for UI extensions (quick actions and side panels) + * - See example 05 for advanced DOM generation with styling + */ diff --git a/examples/04-ui-extensions-plugin.ts b/examples/04-ui-extensions-plugin.ts new file mode 100644 index 0000000..2b741a6 --- /dev/null +++ b/examples/04-ui-extensions-plugin.ts @@ -0,0 +1,567 @@ +/** + * Example 4: Quick Actions and Side Panel Integration + * + * This example demonstrates how to extend the FDO application's UI by adding quick action + * shortcuts and side panel menu items using mixins. These UI extensions make your plugin + * more discoverable and accessible to users. + * + * Compatible with SDK v1.x + * + * Learning Objectives: + * - Use QuickActionMixin to add quick action shortcuts + * - Use SidePanelMixin to add side panel menu items + * - Route messages from UI extensions to plugin handlers + * - Configure icons and labels for UI extensions + * - Handle errors in UI extension operations + * + * Expected Output: + * When this plugin runs in the FDO application, it will: + * 1. Add quick actions to the application's quick action menu + * 2. Add a side panel with multiple menu items + * 3. Route quick action and side panel selections to appropriate handlers + * 4. Display different content based on which UI extension was triggered + * 5. Log all UI extension interactions + */ + +import { + FDO_SDK, + FDOInterface, + PluginMetadata, + PluginRegistry, + QuickActionMixin, + SidePanelMixin, + QuickAction, + SidePanelConfig +} from "@anikitenko/fdo-sdk"; + +/** + * UIExtensionsPlugin demonstrates UI extension capabilities. + * + * Key concepts: + * - Mixins: Add functionality to plugin classes + * - QuickActionMixin: Adds defineQuickActions() method + * - SidePanelMixin: Adds defineSidePanel() method + * - Message routing: UI extensions trigger message handlers + * + * COMMON PITFALL: Mixins must be applied using the mixin pattern. + * This example shows the correct way to apply multiple mixins. + */ + +const UIExtensionsPluginBase = SidePanelMixin(QuickActionMixin(FDO_SDK)); + +export default class UIExtensionsPlugin extends UIExtensionsPluginBase implements FDOInterface { + /** + * Plugin metadata. + * + * CUSTOMIZE HERE: Replace with your plugin information + */ + private readonly _metadata: PluginMetadata = { + name: "UI Extensions Plugin Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "Demonstrates quick actions and side panel integration using mixins", + icon: "icon.png" + }; + + /** + * Current view state. + * Used to track which UI extension was triggered. + */ + private currentView: string = "default"; + + get metadata(): PluginMetadata { + return this._metadata; + } + + /** + * Initialize the plugin and register message handlers. + * + * COMMON PITFALL: Register handlers for all message types used in UI extensions. + * If a handler is missing, clicking the UI extension will result in an error. + */ + init(): void { + try { + this.log("UIExtensionsPlugin initialized!"); + + PluginRegistry.registerHandler("quickSearch", (data: any) => { + return this.handleQuickSearch(data); + }); + + PluginRegistry.registerHandler("quickCreate", (data: any) => { + return this.handleQuickCreate(data); + }); + + PluginRegistry.registerHandler("quickSettings", (data: any) => { + return this.handleQuickSettings(data); + }); + + PluginRegistry.registerHandler("showDashboard", (data: any) => { + return this.handleShowDashboard(data); + }); + + PluginRegistry.registerHandler("showReports", (data: any) => { + return this.handleShowReports(data); + }); + + PluginRegistry.registerHandler("showSettings", (data: any) => { + return this.handleShowSettings(data); + }); + + + } catch (error) { + this.error(error as Error); + } + } + + /** + * Define quick actions for the plugin. + * + * Quick actions appear in the FDO application's quick action menu and provide + * shortcuts to common plugin functionality. + * + * CUSTOMIZE HERE: Define your own quick actions + * + * @returns Array of QuickAction objects + */ + defineQuickActions(): QuickAction[] { + try { + return [ + { + name: "Search Plugin Data", + message_type: "quickSearch", + subtitle: "Search through plugin data", + icon: "search.png" + }, + { + name: "Create New Item", + message_type: "quickCreate", + subtitle: "Create a new item in the plugin", + icon: "create.png" + }, + { + name: "Plugin Settings", + message_type: "quickSettings", + icon: "settings.png" + } + ]; + } catch (error) { + this.error(error as Error); + return []; + } + } + + /** + * Define side panel configuration for the plugin. + * + * The side panel provides a persistent menu in the FDO application's UI + * for accessing plugin features. + * + * CUSTOMIZE HERE: Define your own side panel structure + * + * @returns SidePanelConfig object + */ + defineSidePanel(): SidePanelConfig { + try { + return { + icon: "panel.png", + label: "UI Extensions", + submenu_list: [ + { + id: "dashboard", + name: "Dashboard", + message_type: "showDashboard" + }, + { + id: "reports", + name: "Reports", + message_type: "showReports" + }, + { + id: "settings", + name: "Settings", + message_type: "showSettings" + } + ] + }; + } catch (error) { + this.error(error as Error); + return { + icon: "panel.png", + label: "UI Extensions", + submenu_list: [] + }; + } + } + + /** + * Handle quick search action. + * + * @param data - Data from the quick action + * @returns Result object + */ + private handleQuickSearch(data: any): any { + try { + this.currentView = "search"; + this.log("Quick search triggered"); + + return { + success: true, + view: "search", + message: "Search view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to activate search" + }; + } + } + + /** + * Handle quick create action. + * + * @param data - Data from the quick action + * @returns Result object + */ + private handleQuickCreate(data: any): any { + try { + this.currentView = "create"; + this.log("Quick create triggered"); + + return { + success: true, + view: "create", + message: "Create view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to activate create" + }; + } + } + + /** + * Handle quick settings action. + * + * @param data - Data from the quick action + * @returns Result object + */ + private handleQuickSettings(data: any): any { + try { + this.currentView = "settings"; + this.log("Quick settings triggered"); + + return { + success: true, + view: "settings", + message: "Settings view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to activate settings" + }; + } + } + + /** + * Handle show dashboard from side panel. + * + * @param data - Data from the side panel + * @returns Result object + */ + private handleShowDashboard(data: any): any { + try { + this.currentView = "dashboard"; + this.log("Dashboard view triggered from side panel"); + + return { + success: true, + view: "dashboard", + message: "Dashboard view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to show dashboard" + }; + } + } + + /** + * Handle show reports from side panel. + * + * @param data - Data from the side panel + * @returns Result object + */ + private handleShowReports(data: any): any { + try { + this.currentView = "reports"; + this.log("Reports view triggered from side panel"); + + return { + success: true, + view: "reports", + message: "Reports view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to show reports" + }; + } + } + + /** + * Handle show settings from side panel. + * + * @param data - Data from the side panel + * @returns Result object + */ + private handleShowSettings(data: any): any { + try { + this.currentView = "settings"; + this.log("Settings view triggered from side panel"); + + return { + success: true, + view: "settings", + message: "Settings view activated" + }; + } catch (error) { + this.error(error as Error); + return { + success: false, + error: "Failed to show settings" + }; + } + } + + /** + * Render the UI based on current view. + * + * CUSTOMIZE HERE: Replace with your own view rendering logic + * + * @returns HTML string + */ + render(): string { + try { + let contentHtml = ""; + + switch (this.currentView) { + case "search": + contentHtml = this.renderSearchView(); + break; + case "create": + contentHtml = this.renderCreateView(); + break; + case "dashboard": + contentHtml = this.renderDashboardView(); + break; + case "reports": + contentHtml = this.renderReportsView(); + break; + case "settings": + contentHtml = this.renderSettingsView(); + break; + default: + contentHtml = this.renderDefaultView(); + } + + const html = ` +
+

${this._metadata.name}

+

${this._metadata.description}

+ + ${contentHtml} + + +
+

UI Extensions

+

Quick Actions: Access quick actions from the FDO application's quick action menu

+
    +
  • Search Plugin Data
  • +
  • Create New Item
  • +
  • Plugin Settings
  • +
+ +

Side Panel: Access features from the side panel menu

+
    +
  • Dashboard
  • +
  • Reports
  • +
  • Settings
  • +
+
+
+ `; + + return html; + + } catch (error) { + this.error(error as Error); + return ` +
+

Error rendering plugin

+

An error occurred while rendering the plugin UI. Check the console for details.

+
+ `; + } + } + + /** + * Render the default view. + */ + private renderDefaultView(): string { + return ` +
+

Welcome to UI Extensions Example

+

This plugin demonstrates quick actions and side panel integration.

+

Try the following:

+
    +
  • Use the quick action menu to trigger quick actions
  • +
  • Use the side panel to navigate between views
  • +
  • See how different views are rendered based on UI extension triggers
  • +
+
+ `; + } + + /** + * Render the search view. + */ + private renderSearchView(): string { + return ` +
+

Search View

+

This view was triggered by the "Search Plugin Data" quick action.

+ + +
+ `; + } + + /** + * Render the create view. + */ + private renderCreateView(): string { + return ` +
+

Create View

+

This view was triggered by the "Create New Item" quick action.

+
+ + + +
+
+ `; + } + + /** + * Render the dashboard view. + */ + private renderDashboardView(): string { + return ` +
+

Dashboard View

+

This view was triggered from the side panel "Dashboard" menu item.

+
+
+

Metric 1

+

42

+
+
+

Metric 2

+

87%

+
+
+
+ `; + } + + /** + * Render the reports view. + */ + private renderReportsView(): string { + return ` +
+

Reports View

+

This view was triggered from the side panel "Reports" menu item.

+
    +
  • Monthly Report - View
  • +
  • Quarterly Report - View
  • +
  • Annual Report - View
  • +
+
+ `; + } + + /** + * Render the settings view. + */ + private renderSettingsView(): string { + return ` +
+

Settings View

+

This view can be triggered from either the quick action or side panel.

+
+ + + + +
+
+ `; + } +} + +/** + * Key Takeaways: + * + * 1. Use QuickActionMixin to add quick action shortcuts to the FDO application + * 2. Use SidePanelMixin to add side panel menu items + * 3. Apply mixins using the mixin pattern: SidePanelMixin(QuickActionMixin(FDO_SDK)) + * 4. Define quick actions in defineQuickActions() method + * 5. Define side panel structure in defineSidePanel() method + * 6. Register handlers for all message types used in UI extensions + * 7. Always handle errors in defineQuickActions() and defineSidePanel() + * + * Common Pitfalls to Avoid: + * - Don't forget to register handlers for all UI extension message types + * - Don't throw errors in defineQuickActions() or defineSidePanel() + * - Don't forget to apply mixins to the base class + * - Don't use the same message_type for different actions without proper routing + * + * Next Steps: + * - See example 05 for advanced DOM generation with styling + * - Combine UI extensions with storage (example 03) for stateful plugins + * - Use interactive handlers (example 02) with UI extensions for dynamic behavior + */ diff --git a/examples/05-advanced-dom-plugin.ts b/examples/05-advanced-dom-plugin.ts new file mode 100644 index 0000000..8acb924 --- /dev/null +++ b/examples/05-advanced-dom-plugin.ts @@ -0,0 +1,562 @@ +/** + * Example 5: Advanced DOM Generation + * + * This example demonstrates how to create rich, styled UI components using the SDK's + * DOM generation classes. It covers the various DOM helper classes (DOMText, DOMButton, + * DOMInput, etc.) and shows how to build complex interfaces with custom styling using + * CSS-in-JS via goober. + * + * Compatible with SDK v1.x + * + * Learning Objectives: + * - Use DOM helper classes for programmatic HTML generation + * - Apply CSS-in-JS styling with goober integration + * - Build complex nested UI structures + * - Create forms with multiple input types + * - Compose reusable UI components + * + * Expected Output: + * When this plugin runs in the FDO application, it will: + * 1. Display a styled card layout with custom CSS + * 2. Show a complex form with multiple input types + * 3. Demonstrate nested UI structures + * 4. Apply custom styles using CSS-in-JS + * 5. Render all elements using DOM helper classes + */ + +import { + FDO_SDK, + FDOInterface, + PluginMetadata, + DOM, + DOMText, + DOMButton, + DOMInput, + DOMLink, + DOMNested, + DOMMisc +} from "@anikitenko/fdo-sdk"; + +/** + * AdvancedDOMPlugin demonstrates advanced DOM generation capabilities. + * + * Key concepts: + * - DOM helper classes: Programmatic HTML generation + * - CSS-in-JS: Style objects converted to CSS classes + * - Component composition: Building complex UIs from simple elements + * - Nested structures: Using DOMNested for containers + */ +export default class AdvancedDOMPlugin extends FDO_SDK implements FDOInterface { + /** + * Plugin metadata. + * + * CUSTOMIZE HERE: Replace with your plugin information + */ + private readonly _metadata: PluginMetadata = { + name: "Advanced DOM Plugin Example", + version: "1.0.0", + author: "FDO SDK Team", + description: "Demonstrates advanced DOM generation with helper classes and CSS-in-JS styling", + icon: "icon.png" + }; + + /** + * DOM helper instances. + * These provide methods for creating HTML elements programmatically. + */ + private dom: DOM; + private domText: DOMText; + private domButton: DOMButton; + private domInput: DOMInput; + private domLink: DOMLink; + private domNested: DOMNested; + private domMisc: DOMMisc; + + constructor() { + super(); + + this.dom = new DOM(); + this.domText = new DOMText(); + this.domButton = new DOMButton(); + this.domInput = new DOMInput(); + this.domLink = new DOMLink(); + this.domNested = new DOMNested(); + this.domMisc = new DOMMisc(); + } + + get metadata(): PluginMetadata { + return this._metadata; + } + + /** + * Initialize the plugin. + * + * COMMON PITFALL: DOM helper classes should be instantiated in the constructor, + * not in init() or render(), to avoid unnecessary object creation. + */ + init(): void { + try { + this.log("AdvancedDOMPlugin initialized!"); + + + } catch (error) { + this.error(error as Error); + } + } + + /** + * Render the plugin UI using DOM helper classes. + * + * This example demonstrates: + * - Creating styled elements with CSS-in-JS + * - Building complex nested structures + * - Composing reusable UI components + * - Using all major DOM helper classes + * + * CUSTOMIZE HERE: Replace with your own DOM generation logic + * + * @returns HTML string with embedded CSS + */ + render(): string { + try { + const containerStyle = { + padding: "20px", + fontFamily: "Arial, sans-serif", + maxWidth: "800px", + margin: "0 auto" + }; + + const header = this.createHeader(); + const infoCard = this.createInfoCard(); + const formSection = this.createFormSection(); + const buttonSection = this.createButtonSection(); + const conceptsSection = this.createConceptsSection(); + + const content = this.domNested.createBlockDiv( + { style: containerStyle }, + undefined, + header, + infoCard, + formSection, + buttonSection, + conceptsSection + ); + + return this.dom.renderHTML(content); + + } catch (error) { + this.error(error as Error); + + return ` +
+

Error rendering plugin

+

An error occurred while rendering the plugin UI. Check the console for details.

+
+ `; + } + } + + /** + * Create the header section. + * Demonstrates text element creation with styling. + */ + private createHeader(): string { + const titleStyle = { + color: "#333", + marginBottom: "10px" + }; + + const subtitleStyle = { + color: "#666", + fontSize: "14px", + marginBottom: "20px" + }; + + const title = this.domText.createHText( + 1, + this._metadata.name, + { style: titleStyle } + ); + + const subtitle = this.domText.createPText( + this._metadata.description, + { style: subtitleStyle } + ); + + return title + subtitle; + } + + /** + * Create an info card with styled content. + * Demonstrates nested structures and CSS-in-JS styling. + */ + private createInfoCard(): string { + const cardStyle = { + backgroundColor: "#f8f9fa", + padding: "20px", + borderRadius: "8px", + marginBottom: "20px", + boxShadow: "0 2px 4px rgba(0,0,0,0.1)" + }; + + const cardTitleStyle = { + color: "#007bff", + marginTop: "0", + marginBottom: "15px" + }; + + const listStyle = { + lineHeight: "1.8", + color: "#495057" + }; + + const cardTitle = this.domText.createHText( + 3, + "DOM Helper Classes", + { style: cardTitleStyle } + ); + + const description = this.domText.createPText( + "This example uses the following DOM helper classes to generate HTML programmatically:", + { style: { marginBottom: "10px" } } + ); + + const listItems = [ + this.domText.createLiText("DOMText - Text elements (h1-h6, p, span, strong, etc.)"), + this.domText.createLiText("DOMButton - Button elements with click handlers"), + this.domText.createLiText("DOMInput - Form input elements (text, checkbox, radio, etc.)"), + this.domText.createLiText("DOMLink - Anchor elements for navigation"), + this.domText.createLiText("DOMNested - Container elements (div, ul, form, etc.)"), + this.domText.createLiText("DOMMisc - Miscellaneous elements (hr, etc.)") + ]; + + const list = this.domNested.createList( + listItems, + { style: listStyle } + ); + + return this.domNested.createBlockDiv( + { style: cardStyle }, + undefined, + cardTitle, + description, + list + ); + } + + /** + * Create a complex form section. + * Demonstrates form composition with multiple input types. + */ + private createFormSection(): string { + const formStyle = { + backgroundColor: "#e8f4f8", + padding: "20px", + borderRadius: "8px", + marginBottom: "20px" + }; + + const formTitle = this.domText.createHText( + 3, + "Form Example", + { style: { marginTop: "0", marginBottom: "15px" } } + ); + + const labelStyle = { + display: "block", + marginBottom: "5px", + fontWeight: "bold", + color: "#333" + }; + + const inputStyle = { + padding: "8px", + width: "100%", + marginBottom: "15px", + border: "1px solid #ced4da", + borderRadius: "4px", + boxSizing: "border-box" + }; + + const nameLabel = this.domText.createLabelText( + "Name:", + { style: labelStyle } + ); + + const nameInput = this.domInput.createInput( + "text", + { + style: inputStyle, + placeholder: "Enter your name", + id: "name-input" + } + ); + + const emailLabel = this.domText.createLabelText( + "Email:", + { style: labelStyle } + ); + + const emailInput = this.domInput.createInput( + "email", + { + style: inputStyle, + placeholder: "Enter your email", + id: "email-input" + } + ); + + const messageLabel = this.domText.createLabelText( + "Message:", + { style: labelStyle } + ); + + const messageInput = this.domInput.createTextarea( + { + style: { ...inputStyle, height: "100px", resize: "vertical" }, + placeholder: "Enter your message", + id: "message-input" + } + ); + + const notifyCheckbox = this.domInput.createInput( + "checkbox", + { id: "notify-checkbox", style: { marginRight: "8px" } } + ); + + const notifyLabel = this.domText.createLabelText( + "Send me notifications", + { style: { display: "inline", fontWeight: "normal" } } + ); + + const checkboxContainer = this.domNested.createBlockDiv( + { style: { marginBottom: "15px" } }, + undefined, + notifyCheckbox + notifyLabel + ); + + const submitButton = this.domButton.createButton( + "Submit Form", + () => { /* Handler would be registered separately */ }, + { + style: { + padding: "10px 20px", + backgroundColor: "#007bff", + color: "white", + border: "none", + borderRadius: "4px", + cursor: "pointer", + fontSize: "14px" + } + } + ); + + const formContent = this.domNested.createForm( + { style: { marginTop: "15px" } }, + undefined, + nameLabel, + nameInput, + emailLabel, + emailInput, + messageLabel, + messageInput, + checkboxContainer, + submitButton + ); + + return this.domNested.createBlockDiv( + { style: formStyle }, + undefined, + formTitle, + formContent + ); + } + + /** + * Create a button section. + * Demonstrates button styling and composition. + */ + private createButtonSection(): string { + const sectionStyle = { + backgroundColor: "#d4edda", + padding: "20px", + borderRadius: "8px", + marginBottom: "20px" + }; + + const sectionTitle = this.domText.createHText( + 3, + "Button Examples", + { style: { marginTop: "0", marginBottom: "15px" } } + ); + + const primaryButton = this.domButton.createButton( + "Primary Action", + () => {}, + { + style: { + padding: "10px 20px", + backgroundColor: "#007bff", + color: "white", + border: "none", + borderRadius: "4px", + cursor: "pointer", + marginRight: "10px", + marginBottom: "10px" + } + } + ); + + const secondaryButton = this.domButton.createButton( + "Secondary Action", + () => {}, + { + style: { + padding: "10px 20px", + backgroundColor: "#6c757d", + color: "white", + border: "none", + borderRadius: "4px", + cursor: "pointer", + marginRight: "10px", + marginBottom: "10px" + } + } + ); + + const dangerButton = this.domButton.createButton( + "Danger Action", + () => {}, + { + style: { + padding: "10px 20px", + backgroundColor: "#dc3545", + color: "white", + border: "none", + borderRadius: "4px", + cursor: "pointer", + marginBottom: "10px" + } + } + ); + + const buttonContainer = this.domNested.createBlockDiv( + { style: { marginTop: "10px" } }, + undefined, + primaryButton, + secondaryButton, + dangerButton + ); + + return this.domNested.createBlockDiv( + { style: sectionStyle }, + undefined, + sectionTitle, + buttonContainer + ); + } + + /** + * Create a concepts section. + * Demonstrates links and dividers. + */ + private createConceptsSection(): string { + const sectionStyle = { + backgroundColor: "#fff3cd", + padding: "20px", + borderRadius: "8px" + }; + + const sectionTitle = this.domText.createHText( + 3, + "Key Concepts", + { style: { marginTop: "0", marginBottom: "15px" } } + ); + + const concepts = [ + this.domText.createPText( + this.domText.createStrongText("CSS-in-JS: ") + + "Style objects are converted to CSS classes using goober. This provides scoped styling and prevents conflicts." + ), + this.domText.createPText( + this.domText.createStrongText("Component Composition: ") + + "Complex UIs are built by composing simple elements. Each DOM helper returns an HTML string that can be combined." + ), + this.domText.createPText( + this.domText.createStrongText("Nested Structures: ") + + "Use DOMNested.createBlockDiv() to create containers that hold multiple child elements." + ), + this.domText.createPText( + this.domText.createStrongText("renderHTML(): ") + + "This method wraps your content with a