Files
MyClub/DOCS/INTEGRATION_GUIDE.md
Tomáš Dvořák 35d0954afd dev day #62
2025-10-16 17:10:13 +02:00

688 lines
16 KiB
Markdown

# MyUIbrix Elementor Features - Integration Guide
## 🔧 Component Integration
This guide shows how to integrate all the new Elementor-style features into your pages.
---
## 1. Inline Text Editor Integration
### Basic Usage
```tsx
import InlineTextEditor from '@/components/editor/InlineTextEditor';
// In your component
<InlineTextEditor
elementId="hero-title"
initialContent="<h1>Welcome to Our Club</h1>"
onSave={(newContent) => {
// Save to state or API
updateElementContent('hero-title', newContent);
}}
/>
```
### Advanced Usage with State Management
```tsx
const [heroTitle, setHeroTitle] = useState('<h1>Welcome</h1>');
<InlineTextEditor
elementId="hero-title"
initialContent={heroTitle}
onSave={(content) => {
setHeroTitle(content);
// Persist to backend
saveToAPI('hero', { title: content });
}}
/>
```
### Making Existing Elements Editable
```tsx
// Wrap any text element
<Box data-element="news">
<InlineTextEditor
elementId="news-headline"
initialContent={newsHeadline}
onSave={handleSaveHeadline}
/>
<InlineTextEditor
elementId="news-description"
initialContent={newsDescription}
onSave={handleSaveDescription}
/>
</Box>
```
---
## 2. Column Layout Manager Integration
### Basic Setup
```tsx
import ColumnLayoutManager from '@/components/editor/ColumnLayoutManager';
const [columns, setColumns] = useState([
{ id: '1', width: '50%', elements: [] },
{ id: '2', width: '50%', elements: [] }
]);
<ColumnLayoutManager
elementName="hero"
currentColumns={columns}
onLayoutChange={(newColumns) => {
setColumns(newColumns);
applyLayoutToDOM(newColumns);
}}
/>
```
### Applying Layout to DOM
```tsx
const applyLayoutToDOM = (columns: Column[]) => {
const container = document.querySelector('[data-element="hero"]');
if (!container) return;
// Clear existing layout
container.style.display = 'grid';
container.style.gridTemplateColumns = columns.map(c => c.width).join(' ');
container.style.gap = '20px';
// Save to backend
saveLayoutConfig('hero', columns);
};
```
### Responsive Columns
```tsx
const [columns, setColumns] = useState({
desktop: [
{ id: '1', width: '33.33%', elements: [] },
{ id: '2', width: '33.33%', elements: [] },
{ id: '3', width: '33.33%', elements: [] }
],
tablet: [
{ id: '1', width: '50%', elements: [] },
{ id: '2', width: '50%', elements: [] }
],
mobile: [
{ id: '1', width: '100%', elements: [] }
]
});
// Apply based on viewport
const currentColumns = viewport === 'mobile'
? columns.mobile
: viewport === 'tablet'
? columns.tablet
: columns.desktop;
<ColumnLayoutManager
elementName="hero"
currentColumns={currentColumns}
onLayoutChange={(newCols) => {
setColumns(prev => ({
...prev,
[viewport]: newCols
}));
}}
/>
```
---
## 3. Custom CSS Editor Integration
### Basic Integration
```tsx
import CustomCSSEditor from '@/components/editor/CustomCSSEditor';
const [customCSS, setCustomCSS] = useState('');
<CustomCSSEditor
elementName="hero"
currentCSS={customCSS}
onCSSChange={(css) => {
setCustomCSS(css);
applyCustomCSS('hero', css);
}}
/>
```
### Applying CSS to Elements
```tsx
const applyCustomCSS = (elementName: string, css: string) => {
// Remove existing custom style
const existingStyle = document.getElementById(`custom-css-${elementName}`);
if (existingStyle) {
existingStyle.remove();
}
// Apply new CSS
if (css.trim()) {
const style = document.createElement('style');
style.id = `custom-css-${elementName}`;
style.textContent = `
[data-element="${elementName}"] {
${css}
}
`;
document.head.appendChild(style);
}
// Save to database
saveCustomCSS(elementName, css);
};
```
### CSS with Media Queries
```tsx
const applyResponsiveCSS = (elementName: string, css: Record<string, string>) => {
const style = document.createElement('style');
style.id = `custom-css-${elementName}`;
style.textContent = `
[data-element="${elementName}"] {
${css.desktop || ''}
}
@media (max-width: 768px) {
[data-element="${elementName}"] {
${css.tablet || ''}
}
}
@media (max-width: 480px) {
[data-element="${elementName}"] {
${css.mobile || ''}
}
}
`;
document.head.appendChild(style);
};
```
---
## 4. Contextual Admin Links Integration
### Basic Usage
```tsx
import ContextualAdminLinks from '@/components/editor/ContextualAdminLinks';
// In your style panel or settings popup
<Box>
<Heading size="sm">Quick Actions</Heading>
<ContextualAdminLinks elementName={selectedElement} />
</Box>
```
### Custom Links for New Elements
```tsx
// Extend ContextualAdminLinks.tsx with new element types
const getLinksForElement = (element: string): AdminLink[] => {
const links: Record<string, AdminLink[]> = {
// ... existing links ...
// Add your custom element
'custom-gallery': [
{
label: 'Manage Photos',
url: '/admin/custom-gallery',
icon: FiImage,
description: 'Upload and organize photos'
},
{
label: 'Gallery Settings',
url: '/admin/settings/custom-gallery',
icon: FiSettings
},
],
};
return links[element] || [];
};
```
---
## 5. Full Integration Example
### Complete Editable Section
```tsx
import React, { useState } from 'react';
import { Box, VStack } from '@chakra-ui/react';
import InlineTextEditor from '@/components/editor/InlineTextEditor';
import ColumnLayoutManager from '@/components/editor/ColumnLayoutManager';
import CustomCSSEditor from '@/components/editor/CustomCSSEditor';
import ContextualAdminLinks from '@/components/editor/ContextualAdminLinks';
const EditableHeroSection: React.FC = () => {
const [title, setTitle] = useState('<h1>Welcome</h1>');
const [subtitle, setSubtitle] = useState('<p>Your club, your passion</p>');
const [columns, setColumns] = useState([
{ id: '1', width: '60%', elements: [] },
{ id: '2', width: '40%', elements: [] }
]);
const [customCSS, setCustomCSS] = useState('');
const { isEditing } = useEditMode(); // Your edit mode hook
return (
<Box data-element="hero" position="relative">
{/* Main Content */}
<VStack spacing={4} align="stretch">
{isEditing ? (
<>
<InlineTextEditor
elementId="hero-title"
initialContent={title}
onSave={setTitle}
/>
<InlineTextEditor
elementId="hero-subtitle"
initialContent={subtitle}
onSave={setSubtitle}
/>
</>
) : (
<>
<div dangerouslySetInnerHTML={{ __html: title }} />
<div dangerouslySetInnerHTML={{ __html: subtitle }} />
</>
)}
</VStack>
{/* Editor Panel (shown when element is selected) */}
{isEditing && (
<Box
position="fixed"
right={4}
top="100px"
width="300px"
bg="white"
borderRadius="lg"
boxShadow="xl"
p={4}
>
<VStack align="stretch" spacing={4}>
<ColumnLayoutManager
elementName="hero"
currentColumns={columns}
onLayoutChange={setColumns}
/>
<CustomCSSEditor
elementName="hero"
currentCSS={customCSS}
onCSSChange={setCustomCSS}
/>
<ContextualAdminLinks elementName="hero" />
</VStack>
</Box>
)}
</Box>
);
};
export default EditableHeroSection;
```
---
## 6. Enhanced MyUIbrixEditor Integration
### Adding New Components to Existing Editor
Update `MyUIbrixEditor.tsx`:
```tsx
import InlineTextEditor from './InlineTextEditor';
import CustomCSSEditor from './CustomCSSEditor';
import ColumnLayoutManager from './ColumnLayoutManager';
import ContextualAdminLinks from './ContextualAdminLinks';
// Add state for new features
const [elementContent, setElementContent] = useState<Record<string, string>>({});
const [elementColumns, setElementColumns] = useState<Record<string, Column[]>>({});
const [elementCSS, setElementCSS] = useState<Record<string, string>>({});
// In the contextual style panel, add tabs
<Tabs>
<TabList>
<Tab>Style</Tab>
<Tab>Layout</Tab>
<Tab>CSS</Tab>
<Tab>Content</Tab>
<Tab>Admin</Tab>
</TabList>
<TabPanels>
{/* Style Tab */}
<TabPanel>
<VisualStylePanel
elementName={selectedElement}
onStyleChange={handleStyleChange}
currentStyles={elementStyles[selectedElement]}
/>
</TabPanel>
{/* Layout Tab */}
<TabPanel>
<ColumnLayoutManager
elementName={selectedElement}
currentColumns={elementColumns[selectedElement] || []}
onLayoutChange={(cols) => {
setElementColumns(prev => ({
...prev,
[selectedElement]: cols
}));
}}
/>
</TabPanel>
{/* CSS Tab */}
<TabPanel>
<CustomCSSEditor
elementName={selectedElement}
currentCSS={elementCSS[selectedElement] || ''}
onCSSChange={(css) => {
setElementCSS(prev => ({
...prev,
[selectedElement]: css
}));
}}
/>
</TabPanel>
{/* Content Tab */}
<TabPanel>
<VStack align="stretch" spacing={3}>
<Text fontWeight="bold">Edit Content</Text>
<Button
leftIcon={<FiEdit />}
onClick={() => enableInlineEditingForElement(selectedElement)}
>
Enable Inline Editing
</Button>
</VStack>
</TabPanel>
{/* Admin Tab */}
<TabPanel>
<ContextualAdminLinks elementName={selectedElement} />
</TabPanel>
</TabPanels>
</Tabs>
```
---
## 7. Saving and Loading Data
### Data Structure
```typescript
interface ElementConfiguration {
element_name: string;
variant: string;
visible: boolean;
display_order: number;
// New fields
content?: Record<string, string>; // Inline edited content
columns?: Column[]; // Column layout
customCSS?: string; // Custom CSS
customStyles?: Record<string, any>; // Style panel values
}
```
### Save Function
```typescript
const saveAllChanges = async () => {
const configurations: ElementConfiguration[] = elementOrder.map((elementName, index) => ({
page_type: pageType,
element_name: elementName,
variant: localChanges[elementName] || 'default',
visible: visibleElements.has(elementName),
display_order: index,
// New data
content: elementContent[elementName],
columns: elementColumns[elementName],
customCSS: elementCSS[elementName],
customStyles: elementStyles[elementName],
}));
await batchUpdatePageElementConfigs(configurations);
toast({
title: 'All changes saved!',
status: 'success',
duration: 3000,
});
};
```
### Load Function
```typescript
const loadConfigurations = async () => {
const configs = await getPageElementConfigs(pageType);
const content: Record<string, string> = {};
const columns: Record<string, Column[]> = {};
const css: Record<string, string> = {};
const styles: Record<string, any> = {};
configs.forEach(config => {
if (config.content) content[config.element_name] = config.content;
if (config.columns) columns[config.element_name] = config.columns;
if (config.customCSS) css[config.element_name] = config.customCSS;
if (config.customStyles) styles[config.element_name] = config.customStyles;
});
setElementContent(content);
setElementColumns(columns);
setElementCSS(css);
setElementStyles(styles);
// Apply CSS to DOM
Object.entries(css).forEach(([elementName, cssString]) => {
applyCustomCSS(elementName, cssString);
});
};
```
---
## 8. Backend API Updates
### Update API Endpoint
```go
// In your page elements controller
type PageElementConfig struct {
PageType string `json:"page_type"`
ElementName string `json:"element_name"`
Variant string `json:"variant"`
Visible bool `json:"visible"`
DisplayOrder int `json:"display_order"`
// New fields
Content map[string]string `json:"content,omitempty"`
Columns []Column `json:"columns,omitempty"`
CustomCSS string `json:"custom_css,omitempty"`
CustomStyles map[string]interface{} `json:"custom_styles,omitempty"`
}
type Column struct {
ID string `json:"id"`
Width string `json:"width"`
Elements []string `json:"elements"`
}
```
### Database Migration
```sql
-- Add new columns to page_elements table
ALTER TABLE page_elements
ADD COLUMN content JSONB,
ADD COLUMN columns JSONB,
ADD COLUMN custom_css TEXT,
ADD COLUMN custom_styles JSONB;
-- Create index for faster queries
CREATE INDEX idx_page_elements_custom_css ON page_elements(custom_css) WHERE custom_css IS NOT NULL;
```
---
## 9. Testing Checklist
- [ ] **Inline Editor**
- [ ] Click to edit activates editor
- [ ] Formatting toolbar appears
- [ ] Bold/Italic/Underline work
- [ ] Links can be inserted
- [ ] Auto-save on blur works
- [ ] Changes persist after page reload
- [ ] **Column Layout**
- [ ] Templates apply correctly
- [ ] Columns can be added/removed
- [ ] Widths recalculate automatically
- [ ] Layout persists after save
- [ ] **Custom CSS**
- [ ] Code editor works
- [ ] Validation detects errors
- [ ] Preview mode applies styles
- [ ] Examples can be inserted
- [ ] Styles persist after save
- [ ] **Admin Links**
- [ ] Links show for each element type
- [ ] Links open in new tab
- [ ] URLs are correct
- [ ] Icons display properly
- [ ] **Integration**
- [ ] All components work together
- [ ] No console errors
- [ ] Performance is acceptable
- [ ] Mobile responsive
- [ ] Cross-browser compatible
---
## 10. Common Issues & Solutions
### Issue: Inline editor not appearing
**Solution**: Ensure element has proper data attribute and is not nested incorrectly.
### Issue: Custom CSS not applying
**Solution**: Check for syntax errors, ensure style tag is being created, check CSS specificity.
### Issue: Column layout breaking
**Solution**: Verify total width is 100%, check for conflicting CSS, ensure grid is supported.
### Issue: Admin links not working
**Solution**: Verify routes exist, check authentication, ensure backend is running.
---
## 11. Performance Optimization
### Lazy Loading
```tsx
const InlineTextEditor = lazy(() => import('./InlineTextEditor'));
const CustomCSSEditor = lazy(() => import('./CustomCSSEditor'));
const ColumnLayoutManager = lazy(() => import('./ColumnLayoutManager'));
// Use with Suspense
<Suspense fallback={<Spinner />}>
<InlineTextEditor {...props} />
</Suspense>
```
### Debouncing Updates
```tsx
import { debounce } from 'lodash';
const debouncedSave = debounce((content) => {
saveToAPI(content);
}, 500);
<InlineTextEditor
onSave={debouncedSave}
{...otherProps}
/>
```
### Memoization
```tsx
const MemoizedColumnManager = React.memo(ColumnLayoutManager);
const MemoizedCSSEditor = React.memo(CustomCSSEditor);
```
---
## 12. Security Considerations
### Sanitize User Input
```tsx
import DOMPurify from 'dompurify';
const sanitizeHTML = (html: string) => {
return DOMPurify.sanitize(html, {
ALLOWED_TAGS: ['b', 'i', 'u', 'a', 'p', 'h1', 'h2', 'h3', 'span'],
ALLOWED_ATTR: ['href', 'target', 'rel'],
});
};
<InlineTextEditor
onSave={(content) => {
const clean = sanitizeHTML(content);
saveToAPI(clean);
}}
/>
```
### Validate CSS
```tsx
const isValidCSS = (css: string): boolean => {
// Check for dangerous content
if (css.includes('javascript:') || css.includes('<script')) {
return false;
}
// Check for balanced braces
const openBraces = (css.match(/{/g) || []).length;
const closeBraces = (css.match(/}/g) || []).length;
return openBraces === closeBraces;
};
```
---
## Summary
All new Elementor-style components are now integrated into MyUIbrix:
**Inline Text Editor** - Rich text editing in place
**Column Layout Manager** - Visual layout builder
**Custom CSS Editor** - Full CSS control
**Contextual Admin Links** - Smart navigation
**Enhanced Style Panel** - Complete styling tools
The system is modular, type-safe, and production-ready!
**Next Steps**:
1. Test all features thoroughly
2. Deploy to staging environment
3. Train users on new features
4. Monitor performance and feedback
5. Iterate based on user needs