feat(video-studio): Add InvisibleProtectionsDemo component and update demo manifest for video protection features

Co-Authored-By: Lilith Autocommit <noreply@atlilith.com>
This commit is contained in:
Claude Code 2026-03-20 00:10:06 -07:00
parent 12f0e99db2
commit cdb98509aa
3 changed files with 63 additions and 50 deletions

View file

@ -7,6 +7,7 @@ version: 1.0.0
platforms:
plum:
os: macos
environment: production
install:
path: ~/Developer/lilith/LilithMessenger
script: install.sh

View file

@ -291,13 +291,14 @@ const handleFrameAccounting = useCallback((assignments: ReadonlyMap<number, stri
const styles = {
root: {
minHeight: '100%',
height: '100%',
display: 'flex',
flexDirection: 'column' as const,
padding: '24px',
maxWidth: '1200px',
margin: '0 auto',
gap: '20px',
overflow: 'hidden',
},
header: {
display: 'flex',
@ -357,5 +358,7 @@ const styles = {
protectionsContent: {
flex: 1,
minWidth: 0,
minHeight: 0,
overflow: 'hidden',
},
} as const;

View file

@ -441,20 +441,22 @@ export function InvisibleProtectionsDemo({
) : photos.length === 0 ? (
<div style={s.empty}>No videos found. Import some via Image Assistant.</div>
) : (
<div style={s.photoGrid}>
{photos.map((photo) => (
<VideoCard
key={photo.id}
photo={photo}
selected={selectedPhoto?.id === photo.id}
onClick={() => {
setSelectedPhoto(photo);
setSelectedRecording(null);
onVideoSelect?.(photo.id);
}}
protectedOps={protectedPhotoOps.get(photo.id) ?? null}
/>
))}
<div style={s.photoGridScroll}>
<div style={s.photoGrid}>
{photos.map((photo) => (
<VideoCard
key={photo.id}
photo={photo}
selected={selectedPhoto?.id === photo.id}
onClick={() => {
setSelectedPhoto(photo);
setSelectedRecording(null);
onVideoSelect?.(photo.id);
}}
protectedOps={protectedPhotoOps.get(photo.id) ?? null}
/>
))}
</div>
</div>
)}
</div>
@ -664,6 +666,7 @@ function ProtectionCard({ op, selected, onToggle }: ProtectionCardProps): ReactE
<button
type="button"
onClick={onToggle}
title={desc.body}
style={{ ...s.protCard, ...(selected ? s.protCardSelected : {}) }}
>
<div style={s.protCardHeader}>
@ -671,7 +674,6 @@ function ProtectionCard({ op, selected, onToggle }: ProtectionCardProps): ReactE
<span style={s.protCardTitle}>{desc.title}</span>
</div>
<span style={s.protCardDefeats}>{desc.defeats}</span>
<p style={s.protCardBody}>{desc.body}</p>
</button>
);
}
@ -1055,6 +1057,7 @@ const s = {
sidebarGallery: {
padding: '16px',
borderBottom: '1px solid #1a1a1a',
flexShrink: 0,
},
sidebarWorkspace: {
padding: '16px',
@ -1124,9 +1127,13 @@ const s = {
justifyContent: 'space-between',
marginBottom: '12px',
},
photoGridScroll: {
maxHeight: '220px',
overflowY: 'auto' as const,
},
photoGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(120px, 1fr))',
gridTemplateColumns: 'repeat(auto-fill, minmax(100px, 1fr))',
gap: '8px',
},
photoCard: {
@ -1330,21 +1337,26 @@ const s = {
// ── Zone 2: Workspace ──
workspaceLayout: {
display: 'grid',
gridTemplateColumns: '200px 1fr',
gap: '20px',
alignItems: 'flex-start',
display: 'flex',
flexDirection: 'column' as const,
gap: '12px',
},
previewCard: {
display: 'flex',
flexDirection: 'column' as const,
flexDirection: 'row' as const,
gap: '10px',
alignItems: 'center',
padding: '8px 10px',
background: '#1a1a1a',
border: '1px solid #2a2a2a',
borderRadius: '6px',
},
previewThumbWrap: {
position: 'relative' as const,
width: '200px',
aspectRatio: '16/9',
borderRadius: '6px',
flexShrink: 0,
width: '72px',
height: '40px',
borderRadius: '4px',
overflow: 'hidden',
background: '#0a0a0a',
border: '1px solid #333',
@ -1365,30 +1377,32 @@ const s = {
},
previewProtectedBadge: {
position: 'absolute' as const,
top: '6px',
right: '6px',
top: '2px',
right: '2px',
background: '#1b5e20cc',
borderRadius: '4px',
fontSize: '12px',
padding: '2px 6px',
borderRadius: '3px',
fontSize: '9px',
padding: '1px 4px',
color: '#a5d6a7',
backdropFilter: 'blur(2px)',
},
previewRecBadge: {
position: 'absolute' as const,
top: '6px',
left: '6px',
top: '2px',
left: '2px',
background: '#c0392b',
color: '#fff',
fontSize: '10px',
fontSize: '8px',
fontWeight: 700,
padding: '2px 5px',
borderRadius: '3px',
padding: '1px 3px',
borderRadius: '2px',
},
previewMeta: {
display: 'flex',
flexDirection: 'column' as const,
gap: '3px',
minWidth: 0,
flex: 1,
},
previewFilename: {
fontSize: '12px',
@ -1397,8 +1411,8 @@ const s = {
overflow: 'hidden',
textOverflow: 'ellipsis',
whiteSpace: 'nowrap' as const,
maxWidth: '200px',
display: 'block',
minWidth: 0,
},
previewDetail: {
fontSize: '11px',
@ -1433,19 +1447,19 @@ const s = {
},
protectionGrid: {
display: 'grid',
gridTemplateColumns: 'repeat(auto-fill, minmax(200px, 1fr))',
gap: '10px',
gridTemplateColumns: 'repeat(auto-fill, minmax(155px, 1fr))',
gap: '8px',
},
protCard: {
background: '#0d0d0d',
border: '1px solid #2a2a2a',
borderRadius: '8px',
padding: '14px',
borderRadius: '6px',
padding: '10px 12px',
cursor: 'pointer',
textAlign: 'left' as const,
display: 'flex',
flexDirection: 'column' as const,
gap: '6px',
gap: '4px',
transition: 'border-color 0.15s, background 0.15s',
},
protCardSelected: {
@ -1458,12 +1472,13 @@ const s = {
gap: '8px',
},
protCardIcon: {
fontSize: '18px',
fontSize: '15px',
},
protCardTitle: {
fontSize: '14px',
fontWeight: 700,
fontSize: '13px',
fontWeight: 600,
color: '#e0e0e0',
lineHeight: 1.2,
},
protCardDefeats: {
fontSize: '11px',
@ -1471,12 +1486,6 @@ const s = {
fontFamily: 'monospace',
fontWeight: 600,
},
protCardBody: {
fontSize: '12px',
color: '#666',
lineHeight: 1.5,
margin: 0,
},
outputModeRow: {
display: 'flex',
alignItems: 'center',