Final Updated README for release, Added CDNjs imports

This commit is contained in:
Elias 2025-02-01 21:20:23 +00:00
parent 0cb1867ac7
commit deab1a970c
6 changed files with 987 additions and 366 deletions

6
.env
View file

@ -1,6 +0,0 @@
// .env file (Do NOT commit this file)
ALPHA_VANTAGE_PRIMARY_KEY=7NMNWUG3QGNSK9J2
ALPHA_VANTAGE_SECONDARY_KEY=9H7UI9KW24V8UXCW
MARKET_DATA_CACHE_DURATION=86400000
TIMEZONE=US/Eastern

BIN
.gitignore vendored

Binary file not shown.

337
Contributing.md Normal file
View file

@ -0,0 +1,337 @@
# Contributing to ReactiveNotes
> ⚡️ Help us advance the Obsidian powerhouse
First off, thank you for considering contributing to ReactiveNotes! It's people like you who make ReactiveNotes an amazing tool for the Obsidian community.
## 🗺️ Development Roadmap
Before diving in, check our current focus areas:
- 📱 Mobile support optimization
- 🎨 Enhanced visualization capabilities
- 🔄 State management improvements
- 🧪 Testing infrastructure
- 📚 Documentation enhancements
## 🔧 Development Setup
### Prerequisites
- Node.js (v16.0.0 or higher)
- npm or yarn
- Git
- Obsidian (v1.4.0 or higher)
### Local Development Environment
1. Fork and clone the repository:
```bash
git clone https://github.com/YOUR_USERNAME/ReactiveNotes.git
cd ReactiveNotes
```
2. Install dependencies:
```bash
npm install
# or
yarn install
```
3. Create a development vault:
```bash
mkdir TestVault
cd TestVault
mkdir .obsidian/plugins/reactive-notes
```
4. Link your development build:
```bash
# From project root
npm run dev
# This will watch for changes and rebuild
```
5. Enable the plugin in Obsidian:
- Open Obsidian settings
- Go to Community Plugins
- Enable ReactiveNotes
## 🏗️ Project Structure
```
ReactiveNotes/
├── src/
│ ├── config/ # Configuration and registry
│ │ └── componentRegistry.ts
│ ├── components/ # React components
│ │ ├── core/
│ │ └── ui/
│ ├── services/ # Core services
│ │ ├── storage.ts
│ │ └── marketData.ts
│ ├── hooks/ # Custom React hooks
│ ├── utils/ # Utility functions
│ └── main.tsx # Plugin entry point
├── styles/ # CSS and Tailwind configs
├── tests/ # Test files
└── types/ # TypeScript definitions
```
## 🧪 Testing Guidelines
### Unit Tests
```bash
npm run test
```
Tests should be placed in the `tests` directory, mirroring the source structure:
```typescript
// tests/components/MyComponent.test.ts
describe('MyComponent', () => {
it('should render correctly', () => {
// Test code
});
});
```
### Integration Tests
```bash
npm run test:integration
```
Integration tests should focus on:
- Component interactions
- Plugin initialization
- File system operations
- State persistence
### Manual Testing Checklist
- [ ] Test in both light and dark themes
- [ ] Verify mobile responsiveness
- [ ] Check memory usage
- [ ] Validate error handling
- [ ] Test with different vault configurations
## 📝 Code Style Guidelines
### TypeScript Standards
```typescript
// Use explicit typing
interface ComponentProps {
data: DataType[];
onUpdate: (newData: DataType) => void;
}
// Prefer functional components
const MyComponent: React.FC<ComponentProps> = ({ data, onUpdate }) => {
// Implementation
};
// Use proper type guards
function isValidData(data: unknown): data is DataType {
return (
typeof data === 'object' &&
data !== null &&
'id' in data
);
}
```
### React Best Practices
1. **Hooks Organization**
```typescript
const MyComponent: React.FC = () => {
// 1. State hooks
const [data, setData] = useState<DataType[]>([]);
// 2. Ref hooks
const containerRef = useRef<HTMLDivElement>(null);
// 3. Memoization
const processedData = useMemo(() =>
data.map(processItem),
[data]
);
// 4. Effects
useEffect(() => {
// Effect logic
return () => {
// Cleanup
};
}, [dependencies]);
// 5. Event handlers
const handleUpdate = useCallback(() => {
// Handler logic
}, [dependencies]);
// 6. Render
return <div />;
};
```
2. **Component Structure**
- One component per file
- Clear prop interfaces
- Proper error boundaries
- Effective memo usage
### Documentation Requirements
1. **Component Documentation**
```typescript
/**
* Visualizes data using an interactive chart.
*
* @component
* @example
* ```jsx
* <DataVisualizer
* data={[1, 2, 3]}
* title="My Chart"
* />
* ```
*
* @param {Object} props
* @param {number[]} props.data - Data points to visualize
* @param {string} props.title - Chart title
*/
```
2. **README Updates**
- Document new features
- Update API references
- Add usage examples
- Note breaking changes
## 🔄 Pull Request Process
### 1. Branch Naming
```bash
feature/description-of-feature
bugfix/issue-being-fixed
docs/documentation-updates
test/testing-improvements
```
### 2. Commit Messages
```bash
# Format
<type>(<scope>): <description>
# Examples
feat(components): add new visualization component
fix(storage): resolve persistence issue
docs(readme): update installation instructions
test(core): add unit tests for storage service
```
### 3. PR Template
```markdown
## Description
Brief description of changes
## Type of Change
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation update
## Testing
Describe testing performed
## Screenshots
If applicable
## Checklist
- [ ] Tests added/updated
- [ ] Documentation updated
- [ ] Code follows style guide
- [ ] All tests passing
```
## 📋 Review Process
### Code Review Checklist
1. **Functionality**
- [ ] Meets requirements
- [ ] Handles edge cases
- [ ] Error handling implemented
- [ ] Performance considered
2. **Code Quality**
- [ ] Follows style guide
- [ ] Properly typed
- [ ] No unnecessary complexity
- [ ] Clean architecture
3. **Testing**
- [ ] Unit tests added
- [ ] Integration tests updated
- [ ] Edge cases covered
- [ ] Performance tested
4. **Documentation**
- [ ] API docs updated
- [ ] Examples provided
- [ ] Breaking changes noted
- [ ] Migration guide if needed
## 🚀 Release Process
### Version Numbering
We follow [Semantic Versioning](https://semver.org/):
- MAJOR.MINOR.PATCH
- Breaking.Feature.Fix
### Release Checklist
1. **Pre-release**
- [ ] All tests passing
- [ ] Documentation updated
- [ ] CHANGELOG.md updated
- [ ] Version bumped
- [ ] Build artifacts verified
2. **Release**
- [ ] GitHub release created
- [ ] Tags pushed
- [ ] NPM package published
- [ ] Release notes completed
3. **Post-release**
- [ ] Documentation deployed
- [ ] Community notified
- [ ] Version bumped to next dev version
## 🤝 Community Guidelines
### Communication
- Be respectful and inclusive
- Keep discussions technical
- Provide context with questions
- Use appropriate channels
### Support
- Check existing issues first
- Provide minimal reproduction
- Include environment details
- Follow issue templates
### Recognition
Contributors are recognized in:
- CONTRIBUTORS.md
- Release notes
- Community spotlights
## 📜 License
By contributing, you agree that your contributions will be licensed under the MIT License.

695
README.md
View file

@ -1,29 +1,165 @@
# ReactiveNotes - Dynamic React Components in Obsidian
[![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
![Obsidian Downloads](https://img.shields.io/badge/dynamic/json?logo=obsidian&color=%23483699&label=downloads&query=%24%5B%22reactive-notes%22%5D.downloads&url=https%3A%2F%2Fraw.githubusercontent.com%2Fobsidianmd%2Fobsidian-releases%2Fmaster%2Fcommunity-plugin-stats.json)
[![Buy Me A Coffee](https://img.shields.io/badge/Buy%20Me%20A%20Coffee-support-%23FFDD00?style=flat&logo=buy-me-a-coffee)](https://www.buymeacoffee.com/prodigist)
ReactiveNotes transforms your Obsidian notes into interactive documents by enabling full React component capabilities directly within your markdown files.
Transform your Obsidian vault into a reactive computational environment. ReactiveNotes seamlessly integrates React's component ecosystem with Obsidian's powerful note-taking capabilities, enabling dynamic, interactive documents that evolve with your thoughts.
> ⚠️ **Mobile Support**: Currently optimized for desktop use. Mobile support is under development.
## Core Capabilities
## Why ReactiveNotes?
### 1. Interactive Components
- Write and use React components directly in markdown
- Full React 18 feature support including Hooks
- Real-time component updates
- TypeScript support
- **Native Integration**: Built from the ground up for Obsidian
- **Powerful Yet Simple**: Write React components directly in your notes
- **Dynamic & Interactive**: Turn static notes into living documents
- **Extensible Foundation**: Build your own tools and visualizations
## Compatibility
- Obsidian v1.4.0 or higher
- React v18.2.0
- Libraries:
- Recharts v2.10.0
- Lightweight Charts v4.1.0
- d3-force v3.0.0
- lucide-react v0.263.1
- shadcn/ui (latest components)
## 🚀 Quick Start
### Installation
1. Open Obsidian Settings → Community Plugins
2. Disable Safe Mode if necessary
3. Search for "ReactiveNotes"
4. Click Install and Enable
For manual installation:
1. Download release from GitHub
2. Extract to your vault's `.obsidian/plugins` folder
3. Enable in Community Plugins settings
### Basic Usage
Create a React component in any note:
````markdown
```react
const Greeting = () => {
const [name, setName] = useState("World");
return <h1>Hello, {name}!</h1>;
};
export default Greeting;
```
````
**Component Requirements:**
- Must include a default export
- Must be self-contained in one code block
- Component name should match default export
### Component Structure
A typical component structure follows this basic structure:
````
```react
// Optional: CDN imports at the top
import ExternalLib from 'https://cdnjs.cloudflare.com/...';
// Component definition
const MyComponent = () => {
// 1. Hooks
const [state, setState] = useState(null);
const componentRef = useRef(null);
// 2. Effects & Lifecycle
useEffect(() => {
// Setup code
return () => {
// Cleanup code
};
}, []);
// 3. Helper functions
const handleEvent = () => {
// Event handling logic
};
// 4. Render
return (
<div>
{/* Your JSX here */}
</div>
);
};
// Required: Default export
export default MyComponent;
```
````
**Key Structure Points**:
1. Imports always at the top
2. Component name matches default export
3. Hooks before effects
4. Helper functions before render
5. Single default export at bottom
## 📚 Built-in Libraries & Components
### React Core & Hooks
```javascript
import React, { useState, useEffect, useRef, useMemo } from react';
```
### UI Components from shadcn/ui
```javascript
import {
Card, CardHeader, CardTitle, CardContent,
Tabs, TabsList, TabsTrigger,
Button, Dialog, Form
} from '@/components/ui';
```
### Visualization Libraries
```javascript
//Include Responsive containers
// Recharts for data visualization
import {
LineChart, BarChart, PieChart,
Line, Bar, Pie,
Tooltip, Legend
} from 'recharts';
// Lightweight Charts for financial charts
import { createChart } from 'lightweight-charts';
// D3-force for network graphs
import {
forceSimulation,
forceLink
} from 'd3-force';
```
### Icons
```javascript
import {
Upload, Activity, AlertCircle,
TrendingUp, TrendingDown
} from 'lucide-react';
```
## 💻 Core Features
### 1. Component Systems
- Write React components directly in notes
- Full TypeScript and React 18 support
- Hot reloading during development
### 2. Data Visualization
Built-in libraries:
- **Recharts**: Full suite of chart components
- Line, Bar, Area, Pie charts
- Custom tooltips and legends
- Responsive containers
- **Lightweight Charts**: Professional-grade financial charts
- Candlestick charts
- Technical indicators
- Custom overlays
- Error Boundaries and Suspense
- Resource cleanup and lifecycle management
- Custom component registration
- Real-time component updates
- Error reporting
### 3. Canvas Manipulation
- Direct canvas access for custom drawing
@ -32,217 +168,424 @@ Built-in libraries:
- Custom overlays and annotations
- Interactive drawing tools
### 4. Data Processing
- Real-time data manipulation
- CSV/Excel file processing
- Data transformation utilities
- Pattern recognition
- Statistical analysis
### 5. State Management
### 5. Performance
- Efficient re-rendering
- Memory leak prevention
- Lazy loading support
### 2. State Management
```javascript
// Local state with React
const [local, setLocal] = useState(0);
// Persistent state in note frontmatter
const [stored, setStored] = useStorage('key', defaultValue);
```
- Persistent storage between sessions
- State synchronization across components
- Frontmatter integration
- Cross-note state management
### 6. UI Components
Ready-to-use components from shadcn/ui:
- Cards
- Tabs
- Dialogs
- Forms
- Buttons
- Alerts
### Note-Specific Data Persistence
- Each note maintains independent state through frontmatter
- Component states persist across sessions
- Data automatically travels with notes when shared
- Multiple instances of same component can have different states
- Perfect for creating reusable interactive templates
## Integration Features
Example:
### 1. File System Integration
```javascript
// Access and manipulate files
const fileContent = await window.fs.readFile('example.csv');
const jsonData = await window.fs.readFile('data.json', { encoding: 'utf8' });
// In Note1.md - counter starts at 0
const Counter = () => {
const [count1, setCount1] = useStorage('counter', 0);
return <button onClick={() => setCount1(count1 + 1)}>Count: {count1}</button>;
};
// In Note2.md - same component, independent state
const Counter = () => {
const [count2, setCount2] = useStorage('counter', 0);
return <button onClick={() => setCount2(count2 + 1)}>Count: {count2}</button>;
};
```
### 2. Theme Integration
### 3. File System Integration
```javascript
// Automatic theme detection
const theme = getTheme(); // 'dark' or 'light'
// Read files with encoding
const text = await window.fs.readFile('data.txt', {
encoding: 'utf8'
});
// Read binary files
const binary = await window.fs.readFile('data.xlsx');
```
### 4. CDN Library Support
Import additional libraries from cdnjs:
```javascript
import Chart from 'https://cdnjs.cloudflare.com/ajax/libs/Chart.js/4.4.0/chart.umd.min.js';
```
Requirements:
- HTTPS URLs from cdnjs.cloudflare.com only
- Imports at component top
- Browser-compatible libraries only
### 5. Theme Integration
```javascript
const theme = getTheme(); // Returns 'dark' or 'light'
// Theme-aware styling
const styles = {
background: theme === 'dark' ? '#1a1b1e' : '#ffffff',
color: theme === 'dark' ? '#ffffff' : '#000000'
background: theme === 'dark' ? 'var(--background-primary)' : 'white',
color: theme === 'dark' ? 'var(--text-normal)' : 'black'
};
```
### 3. Data Persistence
### File System Access
```javascript
// Persistent storage hook
const [value, setValue] = useStorage('key', defaultValue);
// Automatic state persistence
const [count, setCount] = useStorage('counter', 0);
// Read files
const csv = await window.fs.readFile('data.csv', { encoding: 'utf8' });
const binary = await window.fs.readFile('data.xlsx');
```
## Component Types
## 🎨 Component Examples
### 1. Visualization Components
### Interactive Data Visualization
````
```react
// Interactive data visualization
const DataVisualization = () => {
return (
<ResponsiveContainer>
<LineChart data={data}>
<Line type="monotone" dataKey="value" />
<Tooltip />
<Legend />
</LineChart>
</ResponsiveContainer>
);
const DataChart = () => {
const data = [
{ month: 'Jan', value: 100 },
{ month: 'Feb', value: 150 },
{ month: 'Mar', value: 120 }
];
return (
<ResponsiveContainer width="100%" height={300}>
<LineChart data={data}>
<XAxis dataKey="month" />
<YAxis />
<Line type="monotone" dataKey="value" />
<Tooltip />
</LineChart>
</ResponsiveContainer>
);
};
```
````
### Canvas Manipulation
````
const DrawingCanvas = () => {
const canvasRef = useRef(null);
useEffect(() => {
const ctx = canvasRef.current.getContext('2d');
ctx.fillStyle = getTheme() === 'dark' ? '#fff' : '#000';
// Your drawing code
return () => {
// Cleanup
};
}, []);
### 2. Canvas Components
return <canvas ref={canvasRef} className="w-full h-64" />;
};
````
### Persistent State Component
````
```react
// Interactive canvas usage
const CanvasComponent = () => {
const canvasRef = useRef(null);
useEffect(() => {
const ctx = canvasRef.current.getContext('2d');
// Custom drawing and animations
}, []);
return <canvas ref={canvasRef} />;
const NoteTracker = () => {
const [notes, setNotes] = useStorage('notes', []);
const addNote = (text) => {
setNotes(prev => [...prev, {
id: Date.now(),
text,
created: new Date()
}]);
};
return (
<Card>
<CardHeader>
<CardTitle>My Notes</CardTitle>
</CardHeader>
<CardContent>
{notes.map(note => (
<div key={note.id}>{note.text}</div>
))}
<Button onClick={() => addNote("New Note")}>
Add Note
</Button>
</CardContent>
</Card>
);
};
```
````
### 3. Network Visualizations
### Network Visualization
````
```react
// Force-directed graphs
const NetworkGraph = () => {
return (
<ForceGraph
nodes={nodes}
links={links}
onNodeClick={handleClick}
/>
);
const [nodes] = useState([
{ id: 1, label: 'Node 1' },
{ id: 2, label: 'Node 2' }
]);
const [links] = useState([
{ source: 1, target: 2 }
]);
return (
<ForceGraph
graphData={{ nodes, links }}
nodeAutoColorBy="label"
nodeLabel="label"
/>
);
};
```
````
## Technical Features
### 1. React Integration
- Full React 18 support
- Hooks support
- Error Boundaries
- Suspense support
- TypeScript enabled
### 2. Performance
- Efficient re-rendering
- Automatic cleanup
- Memory leak prevention
- Resource management
- Lazy loading support
### 3. Development Tools
- Hot reloading
- Error reporting
- Debug mode
- Performance monitoring
## API Access
### 1. Available Libraries
- React + Hooks
- Recharts
- Lightweight Charts
- d3-force
- Lucide icons
- shadcn/ui components
### 2. Utility Functions
- File system operations
- Data processing
- Theme detection
- State persistence
- Math operations
### 3. Component Registry
- Custom component registration
- Component sharing
- Dynamic loading
- Type safety
## Best Practices
### 1. Component Design
## 🛠Development Guide
### Component Structure
```react
const ResponsiveComponent = () => {
// Use relative units
return (
<div className="w-full">
<ResponsiveContainer width="100%" height={400}>
{/* Component content */}
</ResponsiveContainer>
</div>
);
// Basic component template
const MyComponent = () => {
// 1. Hooks and state
const [data, setData] = useState(null);
const componentRef = useRef(null);
// 2. Effects and lifecycle
useEffect(() => {
// Setup code
return () => {
// Cleanup code
};
}, []);
// 3. Event handlers
const handleUpdate = useCallback(() => {
// Handler code
}, []);
// 4. Render
return (
<div>
{/* Component JSX */}
</div>
);
};
export default MyComponent;
```
### 2. State Management
```react
const StatefulComponent = () => {
// Use persistent storage for important state
const [data, setData] = useStorage('data-key', initialData);
// Use local state for UI-only state
const [isOpen, setIsOpen] = useState(false);
};
```
### Best Practices
1. **Component Design**
```react
const ResponsiveComponent = () => {
return (
<div className="w-full">
<ResponsiveContainer width="100%" height={400}>
{/* Content adapts to container */}
</ResponsiveContainer>
</div>
);
};
```
2. **State Management**
```react
const DataComponent = () => {
// Persistent data
const [savedData, setSavedData] = useStorage('data-key', []);
// Temporary UI state
const [isLoading, setIsLoading] = useState(false);
// Computed values
const processedData = useMemo(() => {
return savedData.map(item => /* process */);
}, [savedData]);
};
```
3. **Error Handling**
```react
const SafeComponent = () => {
return (
<ErrorBoundary
fallback={({ error }) => (
<div className="text-red-500">
Error: {error.message}
</div>
)}
>
{/* Protected content */}
</ErrorBoundary>
);
};
```
1. **Error Checking**:
- Check browser console for errors
- Verify imports are working
- Ensure all required exports are present
2. **Performance**:
- Keep components focused and minimal
- Use CDN imports sparingly
- Clean up resources in useEffect
3. **Testing**:
- Test in both light and dark themes
- Verify mobile responsiveness (Hasn't been tested for mobile yet)
- Check CDN imports load correctly
## 🔧 Troubleshooting
### Common Issues
1. **Component not rendering**
- Verify default export is present
- Check console for React errors
- Ensure all imports are available and supported
- Validate JSX syntax
2. **CDN imports not working**
- Verify HTTPS URL
- Check library compatibility
- Confirm import syntax
3. **State persistence issues**
- Check frontmatter permissions
- Verify storage key uniqueness
- Validate data serialization
- Monitor storage size limits
4. **Performance Problems**
- Use React DevTools for profiling
- Implement proper cleanup in useEffect
- Optimize re-renders with useMemo/useCallback
- Monitor memory usage with large datasets
## ⚠️ Important Notes
### Mobile Compatibility
- Currently optimized for desktop use
- Mobile support is under development
- Test thoroughly on mobile devices
### Performance and Resource Management
Best practices for optimal performance:
- Clean up subscriptions and intervals
- Dispose of chart instances
- Release canvas resources
- Free up WebGL contexts
- Use persistent storage thoughtfully
### Security Considerations
- CDN imports are restricted to cdnjs.cloudflare.com
- File system access is limited to vault
- Component code runs in sandbox
- No external network requests
## 📋 Technical Reference
### Available APIs
1. **File System**
```javascript
// File operations
await window.fs.readFile(path, options);
const text = await window.fs.readFile(path, { encoding: 'utf8' });
```
2. **Theme Management**
```javascript
// Theme utilities
const theme = getTheme();
const isDark = theme === 'dark';
```
3. **Storage**
```javascript
// Storage hooks
const [value, setValue] = useStorage(key, defaultValue);
const stored = useStorage(key, null, storage);
```
### 3. Error Handling
```react
const SafeComponent = () => {
return (
<ErrorBoundary fallback={<ErrorDisplay />}>
{/* Component content */}
</ErrorBoundary>
);
};
```
## Limitations
- No external package imports (use provided libraries)
- Limited to frontend functionality
- Storage is note-specific through frontmatter
- Component code must be self-contained
1. **Environment Constraints**
- CDN imports limited to cdnjs.cloudflare.com
- Components must be self-contained in one code block
- Network requests follow Obsidian's security policies
## Future Plans
2. **Performance Considerations**
- Large datasets may impact performance
- Heavy animations should be optimized
- Memory usage needs monitoring
- Mobile performance varies
- Additional visualization libraries
- Enhanced state management
- Component sharing mechanism
- Template system
- Enhanced debugging tools
3. **Work in Progress**
- Mobile support still under development
- Some touch interactions need optimization
- Advanced debugging tools coming soon
## Contributing
## 🔮 Future Plans
Contributions welcome! Please read our [Contributing Guide](CONTRIBUTING.md).
### Upcoming Features
1. Advanced Visualization
- More chart types
- Enhanced animations
- 3D visualization support
- Custom chart templates
## Support
2. Developer Experience
- Component templates
- Debug tools
- Performance monitoring
- Testing utilities
- Report bugs through [GitHub Issues](https://github.com/YourUsername/ReactiveNotes/issues)
- Request features in [Discussions](https://github.com/YourUsername/ReactiveNotes/discussions)
- Join our [Discord community](your-discord-link)
3. Mobile Support
- Touch optimization
- Responsive layouts
- Performance improvements
- Mobile-specific components
## 🤝 Contributing
We welcome contributions! Here's how to get started:
1. Fork the repository
2. Create your feature branch
3. Make your changes
4. Submit a pull request
Please read our [Contributing Guide](CONTRIBUTING.md) for details.
## 💬 Support
- Report bugs through [GitHub Issues](https://github.com/Prodigist/ReactiveNotes/issues)
- Request features in [Discussions](https://github.com/Prodigist/ReactiveNotes/discussions)
- Join our [Discord community](# "Discord link to be added")
## License
MIT License - see [LICENSE](LICENSE) for details
MIT License - see [LICENSE](# "LICENSE") for details
---
<p align="center">Built with ❤️ for the Obsidian community</p>
<p align="center">Built to advance the Obsidian powerhouse</p>
[!["Buy Me A Coffee"](https://www.buymeacoffee.com/assets/img/custom_images/orange_img.png)](https://www.buymeacoffee.com/prodigist)

View file

@ -7,35 +7,14 @@ import tailwindcss from 'tailwindcss';
import autoprefixer from 'autoprefixer';
import { StorageManager } from 'src/core/storage';
import { useStorage } from 'src/hooks/useStorage';
import { createChart } from 'lightweight-charts';
import { Card, CardHeader, CardTitle, CardContent } from 'src/components/ui/card';
import { Tabs, TabsContent, TabsList, TabsTrigger } from 'src/components/ui/tabs';
import { ComponentRegistry } from 'src/components/componentRegistry';
import { ErrorBoundary } from 'src/components/ErrorBoundary';
//Optional niche market analysis tools
import { useMarketData } from 'src/core/useMarketData';
import { createMarketDataHook } from 'src/core/useMarketData';
import { MarketDataService } from 'src/services/marketDataService';
import { Switch } from 'src/components/ui/switch';
import { OrderBlockAnalysisService } from 'src/services/OrderBlockAnalysis';
import { Upload, Activity,AlertCircle, TrendingUp, TrendingDown, } from 'lucide-react';
import { forceSimulation, forceLink, forceManyBody, forceCenter } from 'd3-force';
// Add all React components you want to make available
import {
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend,
ComposedChart,
BarChart,
XAxis,
YAxis,
Bar,
Line,
Area,
ReferenceLine,
LineChart,
} from 'recharts';
import { MarketDataStorage } from 'src/services/marketDataStorage';
class ReactComponentChild extends MarkdownRenderChild {
@ -120,6 +99,14 @@ class ReactComponentChild extends MarkdownRenderChild {
);
};
private preprocessCode(code: string): string {
// Replace CDN imports with script loading
code = code.replace(
/import\s+(\w+)\s+from\s+['"]https:\/\/cdnjs\.cloudflare\.com\/([^'"]+)['"]/g,
(match, importName, cdnPath) => `
const script = document.createElement('script');
script.src = 'https://cdnjs.cloudflare.com/${cdnPath}';
document.body.appendChild(script);`);
// Remove imports more carefully
code = code.replace(/import\s+.*?['"]\s*;?\s*$/gm, '');
code = code.replace(/import\s*{[^}]*}\s*from\s*['"][^'"]*['"];?\s*$/gm, '');
@ -251,49 +238,12 @@ class ReactComponentChild extends MarkdownRenderChild {
const useMarketData = createMarketDataHook(this.storage, this.noteFile);
// Create scope with all required dependencies
const scope = {
React,
useState: React.useState,
useEffect: React.useEffect,
useRef: React.useRef,
useMemo: React.useMemo,
...ComponentRegistry,
useStorage: boundUseStorage,
useMarketData,
useCallback:React.useCallback,
MarketDataStorage,
OrderBlockAnalysisService,
MarketDataService,
// Chart library
createChart,
// UI Components
Card,
CardHeader,
CardTitle,
CardContent,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
Switch,
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend,
ComposedChart, // Add these chart components
BarChart,
XAxis,
YAxis,
Bar,
Upload,
Area,
Line,
ReferenceLine,
LineChart,
Activity,
AlertCircle,
TrendingUp, TrendingDown,
forceSimulation, forceLink, forceManyBody, forceCenter,
getTheme: () => document.body.hasClass('theme-dark') ? 'dark' : 'light',
// Add note context
noteContext: {
@ -354,7 +304,7 @@ class ReactComponentChild extends MarkdownRenderChild {
}
}
export default class ReactTestPlugin extends Plugin {
export default class ReactNotesPlugin extends Plugin {
async onload() {
// Listen for theme changes
this.registerEvent(

View file

@ -1,133 +1,130 @@
// src/components/ComponentRenderer.tsx
import React, { useState, useEffect } from 'react';
import { transform } from '@babel/standalone';
import { ErrorBoundary } from './ErrorBoundary';
import { App } from 'obsidian';
import { useStorage } from '../hooks/useStorage';
import { ComponentRegistry } from '../core/registry';
import { StorageManager } from '../core/storage';
// src/config/componentRegistry.ts
import React from 'react';
import {
PieChart, Pie, Cell, ResponsiveContainer, Tooltip, Legend,
ComposedChart, BarChart, XAxis, YAxis, Bar, Line, Area,
ReferenceLine, LineChart
} from 'recharts';
import { createChart } from 'lightweight-charts';
import { forceSimulation, forceLink, forceManyBody, forceCenter } from 'd3-force';
import {
Upload, Activity, AlertCircle, TrendingUp, TrendingDown,
// Add other icons as needed
} from 'lucide-react';
import {
Card, CardHeader, CardTitle, CardContent,
Tabs, TabsContent, TabsList, TabsTrigger,
Switch,
} from 'src/components/ui/';
interface ComponentRendererProps {
code: string;
scopeId: string;
inline?: boolean;
storage: StorageManager; // Add storage prop
children?: React.ReactNode;
}
// Core React hooks wrapper
// Type for React utilities (non-component exports)
export const ReactUtils = {
React,
useState: React.useState,
useEffect: React.useEffect,
useRef: React.useRef,
useMemo: React.useMemo,
useCallback: React.useCallback,
} as const;
interface TransformError {
message: string;
line?: number;
column?: number;
}
// Only actual components
export const Components = {
// Chart Components
PieChart,
Pie,
Cell,
ResponsiveContainer,
Tooltip,
Legend,
ComposedChart,
BarChart,
XAxis,
YAxis,
Bar,
Line,
Area,
ReferenceLine,
LineChart,
// UI Components
Card,
CardHeader,
CardTitle,
CardContent,
Tabs,
TabsContent,
TabsList,
TabsTrigger,
Switch,
const ErrorDisplay: React.FC<{ error: TransformError }> = ({ error }) => {
return (
<div className="react-component-error">
<p>Error in component:</p>
<pre className="error-message">
{error.message}
{error.line && error.column &&
`\nAt line ${error.line}, column ${error.column}`
}
</pre>
</div>
);
// Icons
Upload,
Activity,
AlertCircle,
TrendingUp,
TrendingDown,
} as const;
// Utilities that aren't React components
export const Utilities = {
createChart,
forceSimulation,
forceLink,
forceManyBody,
forceCenter,
} as const;
// All exports combined
export const ComponentRegistry = {
...ReactUtils,
...Components,
...Utilities,
} as const;
// Optional: Type guard for checking if a component exists
export const hasComponent = (name: string): name is keyof typeof ComponentRegistry => {
return name in ComponentRegistry;
};
export const ComponentRenderer: React.FC<ComponentRendererProps> = ({
code,
scopeId,
storage, // Get storage from props
inline = false
}) => {
const [Component, setComponent] = useState<React.ComponentType | null>(null);
const [error, setError] = useState<TransformError | null>(null);
// main.tsx can now be simplified to:
// import { ComponentRegistry } from './config/componentRegistry';
// const scope = ComponentRegistry;
useEffect(() => {
const createComponent = async () => {
try {
const transformedCode = transform(code, {
presets: ['env','react'],
plugins: [
'@babel/plugin-syntax-jsx', // Add JSX syntax plugin explicitly
'@babel/plugin-transform-react-jsx', // Transforms JSX into JS
'@babel/plugin-proposal-class-properties', // Handles class properties
'@babel/plugin-proposal-object-rest-spread', // Handles object spread syntax
],
filename: `component-${scopeId}`,
sourceType: 'module',
configFile: false,
babelrc: false
}).code;
console.log('Transformed Code:', transformedCode);
// Create storage hook bound to this storage instance
const boundUseStorage = <T,>(key: string, defaultValue: T) =>
useStorage(key, defaultValue, storage);
// Enhanced scope with registry and storage
const scope = {
React,
useState: React.useState,
useEffect: React.useEffect,
useRef: React.useRef,
useStorage: boundUseStorage, // Add bound storage hook
...ComponentRegistry,
};
/* Optionol stuff
// Type for actual components only
type ComponentsOnly = {
[K in keyof typeof Components]: typeof Components[K];
};
const componentFn = new Function(
...Object.keys(scope),
`try {
${transformedCode}
return Component;
} catch (err) {
console.error('Error in component execution:', err);
throw err;
}`
);
// Type for props of actual components
export type ComponentProps = {
[K in keyof ComponentsOnly]: ComponentsOnly[K] extends ComponentType<infer P> ? P : never;
};
const ComponentType = componentFn(...Object.values(scope));
setComponent(() => ComponentType);
setError(null);
} catch (err) {
console.error('Component transformation failed:', err);
setError({
message: err instanceof Error ? err.message : 'Unknown error',
line: (err as any).loc?.line,
column: (err as any).loc?.column
});
setComponent(null);
}
};
// Type guard for checking if something is a component
export const isComponent = (name: keyof typeof ComponentRegistry): name is keyof ComponentsOnly => {
return name in Components;
};
createComponent();
}, [code, scopeId, storage]); // Add storage to dependencies
// Type guard for checking if something is a utility
export const isUtility = (name: keyof typeof ComponentRegistry): name is keyof typeof Utilities => {
return name in Utilities;
};
const Wrapper: React.FC<{ children: React.ReactNode }> =
inline ? ({ children }) => (
<span className="inline-component">{children}</span>
) : ({ children }) => (
<div className="block-component">{children}</div>
);
// Helper to get component safely
export function getComponent<K extends keyof ComponentsOnly>(name: K): ComponentsOnly[K] {
return Components[name];
}
if (error) {
return <ErrorDisplay error={error} />;
}
if (!Component) {
return null;
}
return (
<Wrapper>
<div
className="component-sandbox"
onClick={e => e.stopPropagation()}
>
<ErrorBoundary>
<Component />
</ErrorBoundary>
</div>
</Wrapper>
);
};
// Optional: Type-safe hook usage
type Hook<T> = (...args: any[]) => T;
export const getHook = <T>(name: keyof typeof ReactUtils): Hook<T> | undefined => {
const hook = ReactUtils[name];
return typeof hook === 'function' ? hook as Hook<T> : undefined;
};*/