Skip to content

Commit 7ff70bf

Browse files
committed
Merge branch 'v0.2.0' - Theme system, refactoring, and documentation
Major features and improvements: - Theme system with onThemeEnable/onThemeDisable lifecycle hooks - Style context for type-safe theme variables - Context-driven layout slots (no more prop drilling) - Refactored app structure into components and pages - Full CSS variable support in all plugins - Dark theme plugin implementation - Comprehensive theme system documentation - GitHub Pages documentation setup Breaking changes: - Layout slots now use context hooks instead of props - RouterService.getRoutes() method added Commits included: - Theme persistence and style context - Plugin updates for theme support - Documentation updates - App refactoring - Context-based layout slots - GitHub Pages setup
2 parents 2921084 + 8ee5d40 commit 7ff70bf

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

42 files changed

+2887
-467
lines changed

.github/workflows/pages.yml

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
name: Deploy Documentation to GitHub Pages
2+
3+
on:
4+
# Runs on pushes targeting the default branch
5+
push:
6+
branches: ["main"]
7+
paths:
8+
- 'docs/**'
9+
- 'README.md'
10+
- '.github/workflows/pages.yml'
11+
12+
# Allows you to run this workflow manually from the Actions tab
13+
workflow_dispatch:
14+
15+
# Sets permissions of the GITHUB_TOKEN to allow deployment to GitHub Pages
16+
permissions:
17+
contents: read
18+
pages: write
19+
id-token: write
20+
21+
# Allow only one concurrent deployment, skipping runs queued between the run in-progress and latest queued.
22+
# However, do NOT cancel in-progress runs as we want to allow these production deployments to complete.
23+
concurrency:
24+
group: "pages"
25+
cancel-in-progress: false
26+
27+
jobs:
28+
# Build job
29+
build:
30+
runs-on: ubuntu-latest
31+
steps:
32+
- name: Checkout
33+
uses: actions/checkout@v4
34+
35+
- name: Setup Pages
36+
uses: actions/configure-pages@v4
37+
38+
- name: Build with Jekyll
39+
uses: actions/jekyll-build-pages@v1
40+
with:
41+
source: ./docs
42+
destination: ./_site
43+
44+
- name: Upload artifact
45+
uses: actions/upload-pages-artifact@v3
46+
47+
# Deployment job
48+
deploy:
49+
environment:
50+
name: github-pages
51+
url: ${{ steps.deployment.outputs.page_url }}
52+
runs-on: ubuntu-latest
53+
needs: build
54+
steps:
55+
- name: Deploy to GitHub Pages
56+
id: deployment
57+
uses: actions/deploy-pages@v4

README.md

Lines changed: 144 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
# React PKL
22

3-
A **typesafe plugin system for React applications** written in TypeScript. React PKL allows you to extend React applications from external sources through a robust, type-safe plugin architecture.
3+
A **typesafe plugin system for React applications** written in TypeScript. React PKL allows you to extend React applications from external sources through a robust, type-safe plugin architecture with advanced theming support.
44

55
[![TypeScript](https://img.shields.io/badge/TypeScript-5.5-blue.svg)](https://www.typescriptlang.org/)
66
[![React](https://img.shields.io/badge/React-18.0+-61dafb.svg)](https://reactjs.org/)
@@ -9,10 +9,13 @@ A **typesafe plugin system for React applications** written in TypeScript. React
99

1010
React PKL is designed for **SDK developers** who want to create extensible React applications. It provides the foundation for building plugin systems where:
1111

12-
- Plugins can extend the UI through defined **slots**
12+
- Plugins can extend the UI through defined **slots** and **layout overrides**
1313
- Plugins receive a **typesafe context** from the host application
14+
- **Theme plugins** can override entire layout components with custom styling
15+
- **Static plugins** work without lifecycle management (perfect for themes)
1416
- Resources are **automatically cleaned up** when plugins are disabled
1517
- Plugins can be managed **locally** or fetched from a **remote source**
18+
- **Style context** provides type-safe access to theme variables
1619

1720
## 📦 Packages
1821

@@ -292,6 +295,131 @@ Get all components registered for a slot:
292295
const toolbarComponents = useSlotComponents('toolbar');
293296
```
294297

298+
## 🎨 Theme System
299+
300+
### Creating Theme Plugins
301+
302+
Theme plugins use `onThemeEnable()` and `onThemeDisable()` to manage theme lifecycle:
303+
304+
```typescript
305+
import { definePlugin, AppHeader, AppSidebar, StyleProvider } from 'my-sdk';
306+
307+
const darkThemePlugin = definePlugin({
308+
meta: {
309+
id: 'com.example.dark-theme',
310+
name: 'Dark Theme',
311+
version: '1.0.0',
312+
},
313+
314+
// Theme plugins don't need activate/deactivate (static plugins)
315+
// They only activate when set as the active theme
316+
317+
onThemeEnable(slots) {
318+
// Apply CSS variables
319+
document.documentElement.style.setProperty('--bg-primary', '#1a1a1a');
320+
document.documentElement.style.setProperty('--text-primary', '#e4e4e7');
321+
322+
// Override layout slots with themed components
323+
slots.set(AppHeader, DarkHeader);
324+
slots.set(AppSidebar, DarkSidebar);
325+
326+
// Return cleanup function
327+
return () => {
328+
document.documentElement.style.removeProperty('--bg-primary');
329+
document.documentElement.style.removeProperty('--text-primary');
330+
};
331+
},
332+
333+
onThemeDisable() {
334+
console.log('Theme disabled - additional cleanup');
335+
},
336+
});
337+
338+
function DarkHeader({ toolbar }) {
339+
return (
340+
<StyleProvider variables={{
341+
bgPrimary: '#1a1a1a',
342+
textPrimary: '#e4e4e7',
343+
accentColor: '#60a5fa',
344+
}}>
345+
<header style={{ background: 'linear-gradient(135deg, #18181b 0%, #27272a 100%)' }}>
346+
{toolbar}
347+
</header>
348+
</StyleProvider>
349+
);
350+
}
351+
```
352+
353+
### Using StyleProvider
354+
355+
Provide type-safe style variables to components:
356+
357+
```tsx
358+
import { StyleProvider, useStyles } from 'my-sdk';
359+
360+
function MyComponent() {
361+
const styles = useStyles();
362+
363+
return (
364+
<div style={{
365+
background: styles.bgPrimary,
366+
color: styles.textPrimary,
367+
borderColor: styles.borderColor,
368+
}}>
369+
Themed content
370+
</div>
371+
);
372+
}
373+
```
374+
375+
### Setting Active Theme
376+
377+
```typescript
378+
import { isThemePlugin } from '@react-pkl/core';
379+
380+
// Check if a plugin is a theme plugin
381+
if (isThemePlugin(plugin)) {
382+
pluginHost.setThemePlugin(plugin);
383+
}
384+
385+
// Get current theme
386+
const currentTheme = pluginHost.getThemePlugin();
387+
388+
// Remove theme (back to default)
389+
pluginHost.setThemePlugin(null);
390+
391+
// Persist theme in localStorage
392+
localStorage.setItem('active-theme', plugin.meta.id);
393+
```
394+
395+
### Static vs Dynamic Plugins
396+
397+
React PKL supports two plugin types:
398+
399+
```typescript
400+
import { isStaticPlugin, isThemePlugin } from '@react-pkl/core';
401+
402+
// Static plugins - no activate/deactivate lifecycle
403+
// Perfect for theme plugins that only need theme lifecycle
404+
const themePlugin = {
405+
meta: { id: 'theme', name: 'Theme', version: '1.0.0' },
406+
onThemeEnable(slots) { /* ... */ },
407+
onThemeDisable() { /* ... */ },
408+
};
409+
410+
isStaticPlugin(themePlugin); // true
411+
isThemePlugin(themePlugin); // true
412+
413+
// Dynamic plugins - full lifecycle management
414+
const dataPlugin = {
415+
meta: { id: 'data', name: 'Data', version: '1.0.0' },
416+
async activate(context) { /* ... */ },
417+
async deactivate() { /* ... */ },
418+
};
419+
420+
isStaticPlugin(dataPlugin); // false
421+
```
422+
295423
## 🧩 Components
296424

297425
### `<PluginProvider>`
@@ -383,12 +511,22 @@ interface PluginModule<TContext> {
383511
// Optional lifecycle hooks
384512
activate?(context: TContext): void | Promise<void>;
385513
deactivate?(): void | Promise<void>;
514+
515+
// Optional React entrypoint
516+
entrypoint?(): ReactNode;
386517

387-
// Optional React components by slot name
388-
components?: Record<string, ComponentType<any>>;
518+
// Optional theme lifecycle hooks
519+
onThemeEnable?(slots: Map<Function, Function>): void | (() => void);
520+
onThemeDisable?(): void;
389521
}
390522
```
391523

524+
**Plugin Types:**
525+
- **Dynamic Plugins**: Have `activate`/`deactivate` - Full lifecycle management
526+
- **Static Plugins**: No `activate`/`deactivate` - Always available, perfect for themes
527+
- **Theme Plugins**: Have `onThemeEnable`/`onThemeDisable` - Can be set as active theme
528+
```
529+
392530
### TypeScript Plugin Helper
393531
394532
Create a helper for better type inference:
@@ -469,8 +607,9 @@ The repository includes complete examples:
469607
- **`examples/plugins`** - Sample plugins demonstrating various features:
470608
- `hello-plugin` - Basic plugin with notification
471609
- `user-greeting-plugin` - Accesses app context
472-
- `theme-toggle-plugin` - State management
610+
- `theme-toggle-plugin` - State management with toolbar button
473611
- `custom-page-plugin` - Route registration with cleanup
612+
- `dark-theme-plugin` - Complete theme with layout overrides and style context
474613

475614
## 🏛️ Design Philosophy
476615

docs/README.md

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
# React PKL Documentation
2+
3+
This directory contains the comprehensive documentation for React PKL.
4+
5+
## 📖 View Documentation
6+
7+
**Online:** Visit [https://xpodev.github.io/react-pkl/](https://xpodev.github.io/react-pkl/)
8+
9+
**Locally:** Browse the markdown files in this directory.
10+
11+
## 📚 Available Documentation
12+
13+
- **[index.md](./index.md)** - Documentation index and navigation
14+
- **[GETTING_STARTED.md](./GETTING_STARTED.md)** - Step-by-step guide for beginners
15+
- **[API.md](./API.md)** - Complete API reference
16+
- **[EXAMPLES.md](./EXAMPLES.md)** - Example walkthrough
17+
- **[QUICK_REFERENCE.md](./QUICK_REFERENCE.md)** - Quick reference guide
18+
- **[ADVANCED.md](./ADVANCED.md)** - Advanced usage patterns
19+
- **[THEME_SYSTEM.md](./THEME_SYSTEM.md)** - Theme system guide
20+
- **[ARCHITECTURE.md](./ARCHITECTURE.md)** - Architecture overview
21+
- **[CONTRIBUTING.md](./CONTRIBUTING.md)** - Contribution guidelines
22+
23+
## 🚀 Quick Start
24+
25+
If you're new to React PKL:
26+
27+
1. Read the [main README](../README.md) for project overview
28+
2. Follow the [Getting Started Guide](./GETTING_STARTED.md)
29+
3. Explore the [Examples](./EXAMPLES.md)
30+
31+
## 🔧 GitHub Pages Setup
32+
33+
This documentation is configured for GitHub Pages using Jekyll:
34+
35+
- **Theme:** Cayman (defined in `_config.yml`)
36+
- **Configuration:** See `_config.yml` for settings
37+
- **Base URL:** `/react-pkl`
38+
39+
### Local Preview
40+
41+
To preview the documentation locally with Jekyll:
42+
43+
```bash
44+
# Install Jekyll (if not already installed)
45+
gem install bundler jekyll
46+
47+
# Serve the documentation
48+
cd docs
49+
jekyll serve
50+
```
51+
52+
Then visit `http://localhost:4000/react-pkl/`
53+
54+
## 📝 Contributing to Documentation
55+
56+
When updating documentation:
57+
58+
1. Follow markdown best practices
59+
2. Keep examples up-to-date with code
60+
3. Cross-reference related topics
61+
4. Test links work correctly
62+
5. Use clear, concise language
63+
64+
See [CONTRIBUTING.md](./CONTRIBUTING.md) for more details.
65+
66+
## 📄 License
67+
68+
Same as the main project - see [../LICENSE](../LICENSE) if available.

0 commit comments

Comments
 (0)