Some checks failed
Build & Deploy / 🔍 Prepare (push) Successful in 7s
Build & Deploy / 🧪 QA (push) Failing after 1m6s
Build & Deploy / 🏗️ Build (push) Has been skipped
Build & Deploy / 🚀 Deploy (push) Has been skipped
Build & Deploy / 🧪 Smoke Test (push) Has been skipped
Build & Deploy / 🔔 Notify (push) Successful in 1s
584 lines
25 KiB
TypeScript
584 lines
25 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState, useEffect } from 'react';
|
|
import { useRecordMode } from './RecordModeContext';
|
|
import { Reorder, AnimatePresence } from 'framer-motion';
|
|
import {
|
|
Play,
|
|
Square,
|
|
MousePointer2,
|
|
Scroll,
|
|
Plus,
|
|
Save,
|
|
Trash2,
|
|
Eye,
|
|
Edit2,
|
|
X,
|
|
Check,
|
|
Download,
|
|
Settings2,
|
|
GripVertical,
|
|
Clock,
|
|
Maximize2,
|
|
Box,
|
|
ExternalLink,
|
|
} from 'lucide-react';
|
|
import { RecordEvent } from '@/types/record-mode';
|
|
import { PlaybackCursor } from './PlaybackCursor';
|
|
|
|
export function RecordModeOverlay() {
|
|
const {
|
|
isActive,
|
|
setIsActive,
|
|
events,
|
|
addEvent,
|
|
updateEvent,
|
|
removeEvent,
|
|
isPlaying,
|
|
playEvents,
|
|
saveSession,
|
|
clearEvents,
|
|
reorderEvents,
|
|
setHoveredEventId,
|
|
setEvents, // Added setEvents here
|
|
} = useRecordMode();
|
|
|
|
const [pickingMode, setPickingMode] = useState<'mouse' | 'scroll' | null>(null);
|
|
const [lastInteractionType, setLastInteractionType] = useState<'click' | 'hover'>('click');
|
|
const [hoveredElement, setHoveredElement] = useState<HTMLElement | null>(null);
|
|
const [editingEventId, setEditingEventId] = useState<string | null>(null);
|
|
|
|
// Edit form state
|
|
const [editForm, setEditForm] = useState<Partial<RecordEvent>>({});
|
|
const [mounted, setMounted] = useState(false);
|
|
|
|
useEffect(() => {
|
|
setMounted(true);
|
|
}, []);
|
|
|
|
useEffect(() => {
|
|
if (!mounted || !isActive) return;
|
|
|
|
const handleMessage = (e: MessageEvent) => {
|
|
if (e.data.type === 'ELEMENT_SELECTED') {
|
|
const { selector, rect, tagName } = e.data;
|
|
|
|
if (pickingMode === 'mouse') {
|
|
addEvent({
|
|
type: 'mouse',
|
|
interactionType: lastInteractionType,
|
|
selector,
|
|
duration: lastInteractionType === 'click' ? 1000 : 1500,
|
|
zoom: 1,
|
|
description: `Mouse ${lastInteractionType === 'click' ? '(Click)' : '(Hover)'} on ${tagName}`,
|
|
motionBlur: false,
|
|
realClick: false,
|
|
rect,
|
|
});
|
|
} else if (pickingMode === 'scroll') {
|
|
addEvent({
|
|
type: 'scroll',
|
|
selector,
|
|
duration: 1500,
|
|
zoom: 1,
|
|
description: `Scroll to ${tagName}`,
|
|
motionBlur: false,
|
|
rect,
|
|
});
|
|
}
|
|
setPickingMode(null);
|
|
} else if (e.data.type === 'PICKING_CANCELLED') {
|
|
setPickingMode(null);
|
|
}
|
|
};
|
|
|
|
window.addEventListener('message', handleMessage);
|
|
|
|
if (pickingMode) {
|
|
// Find the iframe and signal start picking
|
|
const iframe = document.querySelector('iframe');
|
|
if (iframe?.contentWindow) {
|
|
iframe.contentWindow.postMessage({ type: 'START_PICKING', mode: pickingMode }, '*');
|
|
}
|
|
} else {
|
|
// Signal stop picking
|
|
const iframe = document.querySelector('iframe');
|
|
if (iframe?.contentWindow) {
|
|
iframe.contentWindow.postMessage({ type: 'STOP_PICKING' }, '*');
|
|
}
|
|
}
|
|
|
|
return () => {
|
|
window.removeEventListener('message', handleMessage);
|
|
};
|
|
}, [isActive, pickingMode, addEvent, mounted]);
|
|
|
|
const saveEdit = () => {
|
|
if (editingEventId) {
|
|
updateEvent(editingEventId, editForm);
|
|
setEditingEventId(null);
|
|
}
|
|
};
|
|
|
|
const [showEvents, setShowEvents] = useState(true);
|
|
|
|
if (!mounted) return null;
|
|
|
|
if (!isActive) {
|
|
// Failsafe: Never render host toggle in embedded mode
|
|
if (
|
|
typeof window !== 'undefined' &&
|
|
(window.self !== window.top ||
|
|
window.name === 'record-mode-iframe' ||
|
|
window.location.search.includes('embedded=true'))
|
|
) {
|
|
return null;
|
|
}
|
|
|
|
return (
|
|
<button
|
|
onClick={() => setIsActive(true)}
|
|
className="fixed bottom-6 left-6 z-[9999] bg-[#82ed20]/20 hover:bg-[#82ed20]/30 text-[#82ed20] p-4 rounded-full shadow-2xl transition-all hover:scale-110 record-mode-ignore border border-[#82ed20]/30 backdrop-blur-md animate-pulse"
|
|
>
|
|
<div className="w-5 h-5 rounded-[4px] border-2 border-[#82ed20]" />
|
|
</button>
|
|
);
|
|
}
|
|
|
|
return (
|
|
<div className="fixed inset-0 z-[9998] pointer-events-none font-sans">
|
|
{/* 1. Global Toolbar - Slim Industrial Bar */}
|
|
<div className="fixed bottom-6 left-1/2 -translate-x-1/2 z-[10000] pointer-events-auto">
|
|
<div className="bg-black/80 backdrop-blur-2xl border border-white/10 p-2 rounded-[24px] shadow-[0_32px_80px_rgba(0,0,0,0.8)] flex items-center gap-2">
|
|
{/* Identity Tag */}
|
|
<div className="flex items-center gap-3 px-4 py-2 bg-white/5 rounded-[16px] border border-white/5 mx-1">
|
|
<div className="w-2 h-2 rounded-full bg-accent animate-pulse" />
|
|
<div className="flex flex-col">
|
|
<span className="text-[10px] font-bold text-white uppercase tracking-wider leading-none">
|
|
Event Builder
|
|
</span>
|
|
<span className="text-[8px] text-white/30 uppercase tracking-widest mt-1">
|
|
Manual Mode
|
|
</span>
|
|
</div>
|
|
</div>
|
|
|
|
<div className="w-px h-6 bg-white/10 mx-1" />
|
|
|
|
{/* Action Tools */}
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
onClick={() => {
|
|
setPickingMode('mouse');
|
|
setLastInteractionType('click');
|
|
}}
|
|
className={`flex items-center gap-2 px-4 py-2.5 rounded-[16px] transition-all text-xs font-bold uppercase tracking-wide ${pickingMode === 'mouse' ? 'bg-accent text-primary-dark shadow-lg shadow-accent/20' : 'text-white/40 hover:text-white hover:bg-white/5'}`}
|
|
>
|
|
<MousePointer2 size={16} />
|
|
<span>Mouse</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => setPickingMode('scroll')}
|
|
className={`flex items-center gap-2 px-4 py-2.5 rounded-[16px] transition-all text-xs font-bold uppercase tracking-wide ${pickingMode === 'scroll' ? 'bg-accent text-primary-dark shadow-lg shadow-accent/20' : 'text-white/40 hover:text-white hover:bg-white/5'}`}
|
|
>
|
|
<Scroll size={16} />
|
|
<span>Scroll</span>
|
|
</button>
|
|
|
|
<button
|
|
onClick={() =>
|
|
addEvent({
|
|
type: 'wait',
|
|
duration: 2000,
|
|
zoom: 1,
|
|
description: 'Wait for 2s',
|
|
motionBlur: false,
|
|
})
|
|
}
|
|
className="flex items-center gap-2 px-4 py-2.5 rounded-[16px] text-white/40 hover:text-white hover:bg-white/5 transition-all text-xs font-bold uppercase tracking-wide"
|
|
>
|
|
<Plus size={16} />
|
|
<span>Wait</span>
|
|
</button>
|
|
</div>
|
|
|
|
<div className="w-px h-6 bg-white/10 mx-1" />
|
|
|
|
{/* Sequence Controls */}
|
|
<div className="flex items-center gap-1 p-0.5">
|
|
<button
|
|
onClick={playEvents}
|
|
disabled={isPlaying || events.length === 0}
|
|
className="p-2.5 text-accent hover:bg-accent/10 rounded-[14px] disabled:opacity-20 transition-all"
|
|
title="Preview Sequence"
|
|
>
|
|
<Play size={18} fill="currentColor" />
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => setShowEvents(!showEvents)}
|
|
className={`p-2.5 rounded-[14px] transition-all relative ${showEvents ? 'bg-white/10 text-white' : 'text-white/40 hover:text-white hover:bg-white/5'}`}
|
|
>
|
|
<Edit2 size={18} />
|
|
{events.length > 0 && (
|
|
<span className="absolute -top-1 -right-1 w-4 h-4 bg-accent text-primary-dark text-[10px] flex items-center justify-center rounded-full font-bold border-2 border-black">
|
|
{events.length}
|
|
</span>
|
|
)}
|
|
</button>
|
|
|
|
<button
|
|
onClick={async () => {
|
|
const session = { events, name: 'Recording', createdAt: new Date().toISOString() };
|
|
try {
|
|
const res = await fetch('/api/save-session', {
|
|
method: 'POST',
|
|
headers: { 'Content-Type': 'application/json' },
|
|
body: JSON.stringify(session),
|
|
});
|
|
if (res.ok) {
|
|
// Visual feedback could be improved, but alert is fine for dev tool
|
|
alert('Session saved to remotion/session.json');
|
|
} else {
|
|
const err = await res.json();
|
|
alert(`Failed to save: ${err.error}`);
|
|
}
|
|
} catch (e) {
|
|
console.error(e);
|
|
alert('Error saving session');
|
|
}
|
|
}}
|
|
disabled={events.length === 0}
|
|
className="p-3 bg-white/5 hover:bg-green-500/20 rounded-2xl disabled:opacity-30 transition-all text-green-400"
|
|
title="Save to Project (Dev)"
|
|
>
|
|
<Save size={20} />
|
|
</button>
|
|
|
|
<button
|
|
onClick={() => {
|
|
const data = JSON.stringify(
|
|
{ events, name: 'Recording', createdAt: new Date().toISOString() },
|
|
null,
|
|
2,
|
|
);
|
|
const blob = new Blob([data], { type: 'application/json' });
|
|
const url = URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = 'remotion-session.json';
|
|
a.click();
|
|
URL.revokeObjectURL(url);
|
|
}}
|
|
disabled={events.length === 0}
|
|
className="p-3 bg-white/5 hover:bg-blue-500/20 rounded-2xl disabled:opacity-30 transition-all text-blue-400"
|
|
title="Download JSON"
|
|
>
|
|
<Download size={20} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="w-px h-6 bg-white/10 mx-1" />
|
|
|
|
<button
|
|
onClick={() => setIsActive(false)}
|
|
className="p-2.5 text-red-500 hover:bg-red-500/10 rounded-[14px] transition-all mx-1"
|
|
title="Exit Studio"
|
|
>
|
|
<X size={20} />
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* 2. Event Timeline Popover */}
|
|
{showEvents && (
|
|
<div className="fixed bottom-[100px] left-1/2 -translate-x-1/2 w-[400px] pointer-events-auto z-[9999]">
|
|
<div className="bg-black/90 backdrop-blur-3xl border border-white/10 rounded-[32px] p-6 shadow-[0_40px_100px_rgba(0,0,0,0.9)] max-h-[500px] overflow-hidden flex flex-col scale-in">
|
|
<div className="flex items-center justify-between mb-6">
|
|
<div>
|
|
<h4 className="text-white font-bold text-lg leading-none">Recording Track</h4>
|
|
<p className="text-[10px] text-white/30 uppercase tracking-widest mt-2">
|
|
{events.length} Actions Recorded
|
|
</p>
|
|
</div>
|
|
<button
|
|
onClick={clearEvents}
|
|
disabled={events.length === 0}
|
|
className="text-red-400/40 hover:text-red-400 transition-colors p-2 hover:bg-red-500/10 rounded-xl disabled:opacity-10"
|
|
>
|
|
<Trash2 size={18} />
|
|
</button>
|
|
</div>
|
|
|
|
<Reorder.Group
|
|
axis="y"
|
|
values={events}
|
|
onReorder={setEvents}
|
|
className="flex-1 overflow-y-auto space-y-2 pr-2 scrollbar-hide"
|
|
>
|
|
{events.length === 0 ? (
|
|
<div className="py-12 flex flex-col items-center justify-center text-white/10">
|
|
<Plus size={40} strokeWidth={1} />
|
|
<p className="text-xs mt-4">Timeline is empty</p>
|
|
</div>
|
|
) : (
|
|
events.map((event, index) => (
|
|
<Reorder.Item
|
|
key={event.id}
|
|
value={event}
|
|
className="group flex items-center gap-3 bg-white/[0.03] border border-white/5 p-3 rounded-[20px] transition-all hover:bg-white/[0.06] hover:border-white/10"
|
|
onMouseEnter={() => setHoveredEventId(event.id)}
|
|
onMouseLeave={() => setHoveredEventId(null)}
|
|
>
|
|
<div className="cursor-grab active:cursor-grabbing text-white/10 hover:text-white/30 transition-colors">
|
|
<GripVertical size={16} />
|
|
</div>
|
|
|
|
<div className="flex-1 min-w-0">
|
|
<div className="flex items-center gap-2">
|
|
<span className="text-white text-[10px] font-black uppercase tracking-widest">
|
|
{event.type === 'mouse' ? `Mouse (${event.interactionType})` : event.type}
|
|
</span>
|
|
{event.clickOrigin &&
|
|
event.clickOrigin !== 'center' &&
|
|
event.interactionType === 'click' && (
|
|
<span className="text-[8px] bg-accent/20 text-accent px-1.5 py-0.5 rounded uppercase font-bold">
|
|
{event.clickOrigin}
|
|
</span>
|
|
)}
|
|
<span className="text-[8px] bg-white/10 px-1.5 py-0.5 rounded text-white/40 font-mono italic">
|
|
{event.duration}ms
|
|
</span>
|
|
</div>
|
|
<p className="text-[9px] text-white/30 truncate font-mono mt-1 opacity-60">
|
|
{event.selector || 'system:wait'}
|
|
</p>
|
|
</div>
|
|
|
|
<div className="flex items-center gap-1">
|
|
<button
|
|
onClick={() => {
|
|
setEditingEventId(event.id);
|
|
setEditForm(event);
|
|
}}
|
|
className="p-2 text-white/0 group-hover:text-white/40 hover:text-white hover:bg-white/10 rounded-xl transition-all"
|
|
>
|
|
<Settings2 size={14} />
|
|
</button>
|
|
<button
|
|
onClick={() => removeEvent(event.id)}
|
|
className="p-2 text-white/0 group-hover:text-red-400/60 hover:text-red-400 hover:bg-red-500/10 rounded-xl transition-all"
|
|
>
|
|
<Trash2 size={14} />
|
|
</button>
|
|
</div>
|
|
</Reorder.Item>
|
|
))
|
|
)}
|
|
</Reorder.Group>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Industrial Selector Highlighter - handled inside iframe via PickingHelper */}
|
|
|
|
{/* Picking Tooltip */}
|
|
{pickingMode && (
|
|
<div className="fixed top-8 left-1/2 -translate-x-1/2 z-[10000] pointer-events-auto">
|
|
<div className="bg-accent text-primary-dark px-6 py-3 rounded-full flex items-center gap-4 shadow-[0_20px_40px_rgba(130,237,32,0.4)] animate-reveal border border-primary-dark/10">
|
|
<div className="flex items-center gap-2">
|
|
<div className="w-2 h-2 rounded-full bg-primary-dark animate-pulse" />
|
|
<span className="font-black uppercase tracking-widest text-xs">
|
|
Assigning {pickingMode}
|
|
</span>
|
|
</div>
|
|
<div className="w-px h-6 bg-primary-dark/20" />
|
|
<button
|
|
onClick={() => {
|
|
setPickingMode(null);
|
|
setHoveredElement(null);
|
|
}}
|
|
className="text-[10px] font-bold uppercase tracking-widest opacity-60 hover:opacity-100 transition-opacity bg-primary-dark/10 px-3 py-1.5 rounded-full"
|
|
>
|
|
ESC to Cancel
|
|
</button>
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
<PlaybackCursor />
|
|
|
|
{/* 3. Event Options Panel (Sidebar-like) */}
|
|
<AnimatePresence>
|
|
{editingEventId && (
|
|
<div className="fixed inset-y-0 right-0 w-[350px] bg-black/95 backdrop-blur-3xl border-l border-white/10 z-[11000] pointer-events-auto p-8 shadow-[-40px_0_100px_rgba(0,0,0,0.9)] flex flex-col">
|
|
<div className="flex items-center justify-between mb-8">
|
|
<h3 className="text-white font-black uppercase tracking-tighter text-xl">
|
|
Event Options
|
|
</h3>
|
|
<button
|
|
onClick={() => setEditingEventId(null)}
|
|
className="p-2 text-white/40 hover:text-white transition-colors"
|
|
>
|
|
<X size={20} />
|
|
</button>
|
|
</div>
|
|
|
|
<div className="flex-1 space-y-8 overflow-y-auto pr-2 scrollbar-hide">
|
|
{/* Type Display */}
|
|
<div className="space-y-3">
|
|
<label className="text-[10px] uppercase tracking-[0.2em] font-bold text-white/30 leading-none">
|
|
Interaction Type
|
|
</label>
|
|
<div className="flex gap-2 p-1 bg-white/5 rounded-2xl border border-white/5">
|
|
<button
|
|
onClick={() =>
|
|
setEditForm((prev) => ({ ...prev, type: 'mouse', interactionType: 'click' }))
|
|
}
|
|
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl transition-all border ${editForm.type === 'mouse' && editForm.interactionType === 'click' ? 'bg-accent text-primary-dark border-accent' : 'text-white/40 border-transparent hover:border-white/10'}`}
|
|
>
|
|
<MousePointer2 size={14} />
|
|
<span className="text-[10px] font-black uppercase">Click</span>
|
|
</button>
|
|
<button
|
|
onClick={() =>
|
|
setEditForm((prev) => ({ ...prev, type: 'mouse', interactionType: 'hover' }))
|
|
}
|
|
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl transition-all border ${editForm.type === 'mouse' && editForm.interactionType === 'hover' ? 'bg-accent text-primary-dark border-accent' : 'text-white/40 border-transparent hover:border-white/10'}`}
|
|
>
|
|
<Eye size={14} />
|
|
<span className="text-[10px] font-black uppercase">Hover</span>
|
|
</button>
|
|
<button
|
|
onClick={() => setEditForm((prev) => ({ ...prev, type: 'scroll' }))}
|
|
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl transition-all border ${editForm.type === 'scroll' ? 'bg-accent text-primary-dark border-accent' : 'text-white/40 border-transparent hover:border-white/10'}`}
|
|
>
|
|
<Scroll size={14} />
|
|
<span className="text-[10px] font-black uppercase">Scroll</span>
|
|
</button>
|
|
<button
|
|
onClick={() => setEditForm((prev) => ({ ...prev, type: 'wait' }))}
|
|
className={`flex-1 flex items-center justify-center gap-2 py-3 rounded-xl transition-all border ${editForm.type === 'wait' ? 'bg-accent text-primary-dark border-accent' : 'text-white/40 border-transparent hover:border-white/10'}`}
|
|
>
|
|
<Clock size={14} />
|
|
<span className="text-[10px] font-black uppercase">Wait</span>
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
{/* Precise Click Origin */}
|
|
{editForm.type === 'mouse' && editForm.interactionType === 'click' && (
|
|
<div className="space-y-4">
|
|
<label className="text-[10px] uppercase tracking-[0.2em] font-bold text-white/30 leading-none">
|
|
Click Origin
|
|
</label>
|
|
<div className="grid grid-cols-3 gap-2 p-2 bg-white/5 rounded-2xl border border-white/5">
|
|
{[
|
|
{ id: 'top-left', label: 'TL' },
|
|
{ id: 'top-right', label: 'TR' },
|
|
{ id: 'center', label: 'CTR' },
|
|
{ id: 'bottom-left', label: 'BL' },
|
|
{ id: 'bottom-right', label: 'BR' },
|
|
].map((origin) => (
|
|
<button
|
|
key={origin.id}
|
|
onClick={() =>
|
|
setEditForm((prev) => ({ ...prev, clickOrigin: origin.id as any }))
|
|
}
|
|
className={`py-3 rounded-xl text-[10px] font-black uppercase tracking-tighter transition-all border ${editForm.clickOrigin === origin.id ? 'bg-accent text-primary-dark border-accent' : 'bg-transparent text-white/40 border-white/5 hover:border-white/20'}`}
|
|
>
|
|
{origin.label}
|
|
</button>
|
|
))}
|
|
</div>
|
|
</div>
|
|
)}
|
|
|
|
{/* Timing */}
|
|
<div className="space-y-4">
|
|
<label className="text-[10px] uppercase tracking-[0.2em] font-bold text-white/30 leading-none flex items-center justify-between">
|
|
<span>Timeline Allocation</span>
|
|
<span className="text-accent">{editForm.duration}ms</span>
|
|
</label>
|
|
<input
|
|
type="range"
|
|
min="0"
|
|
max="5000"
|
|
step="100"
|
|
value={editForm.duration || 1000}
|
|
onChange={(e) =>
|
|
setEditForm((prev) => ({ ...prev, duration: parseInt(e.target.value) }))
|
|
}
|
|
className="w-full h-1 bg-white/10 rounded-lg appearance-none cursor-pointer accent-accent"
|
|
/>
|
|
</div>
|
|
|
|
{/* Zoom & Effects */}
|
|
<div className="space-y-6">
|
|
<div className="flex items-center justify-between p-4 bg-white/5 rounded-2xl border border-white/5 group hover:border-white/20 transition-all">
|
|
<div className="flex items-center gap-3">
|
|
<Maximize2 size={18} className="text-white/40" />
|
|
<span className="text-xs font-bold text-white uppercase tracking-wider">
|
|
Zoom Shift
|
|
</span>
|
|
</div>
|
|
<input
|
|
type="number"
|
|
step="0.1"
|
|
min="1"
|
|
max="3"
|
|
value={editForm.zoom || 1}
|
|
onChange={(e) =>
|
|
setEditForm((prev) => ({ ...prev, zoom: parseFloat(e.target.value) }))
|
|
}
|
|
className="w-16 bg-white/10 border border-white/10 rounded-lg px-2 py-1 text-xs text-white text-center font-mono"
|
|
/>
|
|
</div>
|
|
|
|
<button
|
|
onClick={() => setEditForm((prev) => ({ ...prev, motionBlur: !prev.motionBlur }))}
|
|
className={`flex items-center justify-between w-full p-4 rounded-2xl border transition-all ${editForm.motionBlur ? 'bg-accent/10 border-accent/30 text-accent' : 'bg-white/5 border-white/5 text-white/40'}`}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<Box size={18} />
|
|
<span className="text-xs font-bold uppercase tracking-wider">Motion Blur</span>
|
|
</div>
|
|
{editForm.motionBlur ? <Check size={18} /> : <div className="w-[18px]" />}
|
|
</button>
|
|
|
|
{editForm.type === 'mouse' && editForm.interactionType === 'click' && (
|
|
<button
|
|
onClick={() => setEditForm((prev) => ({ ...prev, realClick: !prev.realClick }))}
|
|
className={`flex items-center justify-between w-full p-4 rounded-2xl border transition-all ${editForm.realClick ? 'bg-orange-500/10 border-orange-500/30 text-orange-400' : 'bg-white/5 border-white/5 text-white/40'}`}
|
|
>
|
|
<div className="flex items-center gap-3">
|
|
<ExternalLink size={18} />
|
|
<div className="flex flex-col items-start">
|
|
<span className="text-xs font-bold uppercase tracking-wider">
|
|
Trigger Navigation
|
|
</span>
|
|
<span className="text-[8px] opacity-60">
|
|
Allows URL transitions in Studio
|
|
</span>
|
|
</div>
|
|
</div>
|
|
{editForm.realClick ? <Check size={18} /> : <div className="w-[18px]" />}
|
|
</button>
|
|
)}
|
|
</div>
|
|
</div>
|
|
|
|
<button
|
|
onClick={saveEdit}
|
|
className="mt-8 py-5 bg-accent text-primary-dark text-xs font-black uppercase tracking-[0.2em] rounded-2xl shadow-2xl shadow-accent/20 hover:scale-[1.02] transition-all"
|
|
>
|
|
Commit Changes
|
|
</button>
|
|
</div>
|
|
)}
|
|
</AnimatePresence>
|
|
</div>
|
|
);
|
|
}
|