Overlay Example
/**
* Test Overlay - Background Module Example
* This demonstrates a background overlay that runs outside of project context
*/
module.exports = ({ useState, useEffect, useRef, useGlobalState, api, usePlaceholders }) => {
const [isVisible, setIsVisible] = useGlobalState('overlayVisible', true);
const [position, setPosition] = useGlobalState('overlayPosition', { x: 100, y: 100 });
const [isDragging, setIsDragging] = useState(false);
const [dragOffset, setDragOffset] = useState({ x: 0, y: 0 });
const [stats, setStats] = useGlobalState('overlayStats', {
clicks: 0,
toggles: 0,
lastInteraction: null
});
const overlayRef = useRef(null);
const placeholders = usePlaceholders();
// Listen for global keyboard shortcuts
useEffect(() => {
const handleKeyPress = (e) => {
// Ctrl+Shift+O to toggle overlay
if (e.ctrlKey && e.shiftKey && e.key === 'O') {
e.preventDefault();
setIsVisible(prev => {
const newState = !prev;
setStats(prev => ({
...prev,
toggles: prev.toggles + 1,
lastInteraction: new Date().toISOString()
}));
api.nexomaker.background.notify({
type: newState ? 'success' : 'info',
title: 'Test Overlay',
message: `Overlay ${newState ? 'shown' : 'hidden'} via keyboard shortcut`,
duration: 2000
});
return newState;
});
}
// Ctrl+Shift+R to reset overlay position
if (e.ctrlKey && e.shiftKey && e.key === 'R') {
e.preventDefault();
setPosition({ x: 100, y: 100 });
api.nexomaker.background.notify({
type: 'info',
title: 'Test Overlay',
message: 'Position reset to default',
duration: 2000
});
}
};
window.addEventListener('keydown', handleKeyPress);
return () => window.removeEventListener('keydown', handleKeyPress);
}, []);
// Handle dragging
const handleMouseDown = (e) => {
setIsDragging(true);
const rect = overlayRef.current.getBoundingClientRect();
setDragOffset({
x: e.clientX - rect.left,
y: e.clientY - rect.top
});
};
useEffect(() => {
const handleMouseMove = (e) => {
if (isDragging) {
setPosition({
x: e.clientX - dragOffset.x,
y: e.clientY - dragOffset.y
});
}
};
const handleMouseUp = () => {
setIsDragging(false);
};
if (isDragging) {
window.addEventListener('mousemove', handleMouseMove);
window.addEventListener('mouseup', handleMouseUp);
}
return () => {
window.removeEventListener('mousemove', handleMouseMove);
window.removeEventListener('mouseup', handleMouseUp);
};
}, [isDragging, dragOffset]);
const handleClick = () => {
setStats(prev => ({
...prev,
clicks: prev.clicks + 1,
lastInteraction: new Date().toISOString()
}));
};
const showStatsOverlay = () => {
api.nexomaker.background.showOverlay('stats-overlay', `
<div style="
background: linear-gradient(135deg, #4f46e5 0%, #7c3aed 100%);
color: white;
padding: 24px;
border-radius: 12px;
box-shadow: 0 8px 32px rgba(0,0,0,0.3);
max-width: 400px;
font-family: -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, sans-serif;
">
<h3 style="margin: 0 0 20px 0; font-size: 18px; font-weight: 600;">
📊 Test Overlay Statistics
</h3>
<div style="margin: 12px 0; padding: 16px; background: rgba(255,255,255,0.1); border-radius: 8px;">
<p style="margin: 8px 0;"><strong>Total Clicks:</strong> ${stats.clicks}</p>
<p style="margin: 8px 0;"><strong>Total Toggles:</strong> ${stats.toggles}</p>
<p style="margin: 8px 0;"><strong>Current Position:</strong> (${Math.round(position.x)}, ${Math.round(position.y)})</p>
<p style="margin: 8px 0;"><strong>Last Interaction:</strong> ${stats.lastInteraction ? new Date(stats.lastInteraction).toLocaleString() : 'Never'}</p>
<p style="margin: 8px 0;"><strong>Overlay Visible:</strong> ${isVisible ? '✅ Yes' : '❌ No'}</p>
<p style="margin: 8px 0;"><strong>Context:</strong> ${placeholders.context}</p>
<p style="margin: 8px 0;"><strong>Project ID:</strong> ${placeholders.projectId}</p>
</div>
<div style="margin-top: 20px; font-size: 12px; opacity: 0.8;">
<p style="margin: 4px 0;">🔥 <strong>Shortcuts:</strong></p>
<p style="margin: 4px 0;">• Ctrl+Shift+O: Toggle overlay</p>
<p style="margin: 4px 0;">• Ctrl+Shift+R: Reset position</p>
<p style="margin: 4px 0;">• Drag to move overlay</p>
</div>
<button
onclick="window.dispatchEvent(new CustomEvent('modular-hide-overlay', {detail: {overlayId: 'stats-overlay'}}))"
style="
background: rgba(255,255,255,0.2);
color: white;
border: 1px solid rgba(255,255,255,0.3);
padding: 12px 24px;
border-radius: 8px;
cursor: pointer;
font-size: 14px;
width: 100%;
margin-top: 16px;
"
>
Close Statistics
</button>
</div>
`);
};
const resetStats = () => {
setStats({
clicks: 0,
toggles: 0,
lastInteraction: null
});
api.nexomaker.background.notify({
type: 'success',
title: 'Test Overlay',
message: 'Statistics reset successfully',
duration: 2000
});
};
const testBackgroundApis = () => {
api.console.log('🧪 Testing background APIs...');
api.console.log('Context:', placeholders.context);
api.console.log('Project ID:', placeholders.projectId);
// Test global data storage
api.nexomaker.background.setGlobalData('testData', {
timestamp: new Date().toISOString(),
clicks: stats.clicks,
context: placeholders.context
});
const retrievedData = api.nexomaker.background.getGlobalData('testData');
api.console.log('Global data test:', retrievedData);
api.nexomaker.background.notify({
type: 'success',
title: 'API Test Complete',
message: 'All background APIs working correctly!',
duration: 3000
});
};
if (!isVisible) {
return null;
}
return (
<div
ref={overlayRef}
className="interactive"
style={{
position: 'fixed',
left: `${position.x}px`,
top: `${position.y}px`,
background: 'linear-gradient(135deg, #667eea 0%, #764ba2 100%)',
color: 'white',
padding: '16px',
borderRadius: '12px',
boxShadow: '0 8px 32px rgba(0,0,0,0.3)',
cursor: isDragging ? 'grabbing' : 'grab',
userSelect: 'none',
zIndex: 2000,
minWidth: '280px',
border: '1px solid rgba(255,255,255,0.2)',
backdropFilter: 'blur(10px)'
}}
onMouseDown={handleMouseDown}
onClick={handleClick}
>
<div style={{ marginBottom: '12px', display: 'flex', alignItems: 'center', justifyContent: 'space-between' }}>
<h4 style={{ margin: 0, fontSize: '16px', fontWeight: '600' }}>
🧪 Test Overlay ({placeholders.context})
</h4>
<button
onClick={(e) => {
e.stopPropagation();
setIsVisible(false);
}}
style={{
background: 'rgba(255,255,255,0.2)',
border: 'none',
color: 'white',
width: '24px',
height: '24px',
borderRadius: '50%',
cursor: 'pointer',
fontSize: '14px',
display: 'flex',
alignItems: 'center',
justifyContent: 'center'
}}
>
×
</button>
</div>
<div style={{ fontSize: '14px', marginBottom: '12px', opacity: 0.9 }}>
Background overlay running in {placeholders.context} context
</div>
<div style={{
background: 'rgba(255,255,255,0.1)',
padding: '12px',
borderRadius: '8px',
marginBottom: '12px',
fontSize: '12px'
}}>
<div>📊 Clicks: {stats.clicks}</div>
<div>🔄 Toggles: {stats.toggles}</div>
<div>📍 Position: ({Math.round(position.x)}, {Math.round(position.y)})</div>
<div>🎯 Project: {placeholders.projectId}</div>
</div>
<div style={{ display: 'flex', gap: '8px', flexDirection: 'column' }}>
<button
onClick={(e) => {
e.stopPropagation();
showStatsOverlay();
}}
style={{
background: 'rgba(255,255,255,0.2)',
border: '1px solid rgba(255,255,255,0.3)',
color: 'white',
padding: '8px 12px',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '12px'
}}
>
📊 Show Statistics
</button>
<button
onClick={(e) => {
e.stopPropagation();
testBackgroundApis();
}}
style={{
background: 'rgba(16, 185, 129, 0.3)',
border: '1px solid rgba(16, 185, 129, 0.5)',
color: 'white',
padding: '8px 12px',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '12px'
}}
>
🧪 Test Background APIs
</button>
<button
onClick={(e) => {
e.stopPropagation();
resetStats();
}}
style={{
background: 'rgba(239, 68, 68, 0.3)',
border: '1px solid rgba(239, 68, 68, 0.5)',
color: 'white',
padding: '8px 12px',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '12px'
}}
>
🔄 Reset Stats
</button>
<button
onClick={(e) => {
e.stopPropagation();
api.nexomaker.background.notify({
type: 'info',
title: 'Test Notification',
message: `Overlay clicked ${stats.clicks} times! Running in ${placeholders.context} context`,
duration: 4000
});
}}
style={{
background: 'rgba(59, 130, 246, 0.3)',
border: '1px solid rgba(59, 130, 246, 0.5)',
color: 'white',
padding: '8px 12px',
borderRadius: '6px',
cursor: 'pointer',
fontSize: '12px'
}}
>
🔔 Test Notification
</button>
</div>
<div style={{
marginTop: '12px',
fontSize: '10px',
opacity: 0.7,
textAlign: 'center',
borderTop: '1px solid rgba(255,255,255,0.2)',
paddingTop: '8px'
}}>
Ctrl+Shift+O to toggle • Drag to move • Ctrl+Shift+R to reset
</div>
</div>
);
};Last updated