@@ -257,7 +257,7 @@ export function ConfigSidebar() {
257257
258258 return (
259259 < KTabs
260- value = { state . selectedTab }
260+ value = { editorState . timeline . selection ? undefined : state . selectedTab }
261261 class = "flex flex-col min-h-0 shrink-0 flex-1 max-w-[26rem] overflow-hidden rounded-xl z-10 bg-gray-1 dark:bg-gray-2 border border-gray-3"
262262 >
263263 < KTabs . List class = "flex overflow-hidden sticky top-0 z-[60] flex-row items-center h-16 text-lg border-b border-gray-3 shrink-0 bg-gray-1 dark:bg-gray-2" >
@@ -877,6 +877,236 @@ export function ConfigSidebar() {
877877 ) }
878878 </ Show >
879879 </ div >
880+ < Show when = { editorState . timeline . selection } >
881+ { ( selection ) => (
882+ < div
883+ style = { {
884+ "--margin-top-scroll" : "5px" ,
885+ } }
886+ class = "absolute custom-scroll p-5 top-16 left-0 right-0 bottom-0 text-[0.875rem] space-y-4 bg-gray-1 dark:bg-gray-2 z-50 animate-in slide-in-from-bottom-2 fade-in"
887+ >
888+ < Suspense >
889+ < Show
890+ when = { ( ( ) => {
891+ const zoomSelection = selection ( ) ;
892+ if ( zoomSelection . type !== "zoom" ) return ;
893+
894+ const segments = zoomSelection . indices
895+ . map ( ( index ) => ( {
896+ index,
897+ segment : project . timeline ?. zoomSegments ?. [ index ] ,
898+ } ) )
899+ . filter (
900+ ( item ) : item is { index : number ; segment : ZoomSegment } =>
901+ item . segment !== undefined ,
902+ ) ;
903+
904+ if ( segments . length === 0 ) {
905+ setEditorState ( "timeline" , "selection" , null ) ;
906+ return ;
907+ }
908+ return { selection : zoomSelection , segments } ;
909+ } ) ( ) }
910+ >
911+ { ( value ) => (
912+ < div class = "space-y-4" >
913+ < div class = "flex flex-row justify-between items-center" >
914+ < div class = "flex gap-2 items-center" >
915+ < EditorButton
916+ onClick = { ( ) =>
917+ setEditorState ( "timeline" , "selection" , null )
918+ }
919+ leftIcon = { < IconLucideCheck /> }
920+ >
921+ Done
922+ </ EditorButton >
923+ < span class = "text-sm text-gray-10" >
924+ { value ( ) . segments . length } zoom{ " " }
925+ { value ( ) . segments . length === 1
926+ ? "segment"
927+ : "segments" } { " " }
928+ selected
929+ </ span >
930+ </ div >
931+ < EditorButton
932+ variant = "danger"
933+ onClick = { ( ) => {
934+ projectActions . deleteZoomSegments (
935+ value ( ) . segments . map ( ( s ) => s . index ) ,
936+ ) ;
937+ } }
938+ leftIcon = { < IconCapTrash /> }
939+ >
940+ Delete
941+ </ EditorButton >
942+ </ div >
943+ < Show
944+ when = { value ( ) . segments . length === 1 }
945+ fallback = {
946+ < div class = "grid grid-cols-3 gap-4" >
947+ < Index each = { value ( ) . segments } >
948+ { ( item , index ) => (
949+ < div class = "p-2.5 rounded-lg border border-gray-4 bg-gray-3" >
950+ < ZoomSegmentPreview
951+ segment = { item ( ) . segment }
952+ segmentIndex = { index }
953+ />
954+ </ div >
955+ ) }
956+ </ Index >
957+ </ div >
958+ }
959+ >
960+ < For each = { value ( ) . segments } >
961+ { ( item ) => (
962+ < div class = "p-4 rounded-lg border border-gray-200" >
963+ < ZoomSegmentConfig
964+ segment = { item . segment }
965+ segmentIndex = { item . index }
966+ />
967+ </ div >
968+ ) }
969+ </ For >
970+ </ Show >
971+ </ div >
972+ ) }
973+ </ Show >
974+ < Show
975+ when = { ( ( ) => {
976+ const sceneSelection = selection ( ) ;
977+ if ( sceneSelection . type !== "scene" ) return ;
978+
979+ const segments = sceneSelection . indices
980+ . map ( ( idx ) => ( {
981+ segment : project . timeline ?. sceneSegments ?. [ idx ] ,
982+ index : idx ,
983+ } ) )
984+ . filter ( ( s ) => s . segment !== undefined ) ;
985+
986+ if ( segments . length === 0 ) return ;
987+ return { selection : sceneSelection , segments } ;
988+ } ) ( ) }
989+ >
990+ { ( value ) => (
991+ < Show
992+ when = { value ( ) . segments . length > 1 }
993+ fallback = {
994+ < SceneSegmentConfig
995+ segment = { value ( ) . segments [ 0 ] . segment ! }
996+ segmentIndex = { value ( ) . segments [ 0 ] . index }
997+ />
998+ }
999+ >
1000+ < div class = "space-y-4" >
1001+ < div class = "flex flex-row justify-between items-center" >
1002+ < div class = "flex gap-2 items-center" >
1003+ < EditorButton
1004+ onClick = { ( ) =>
1005+ setEditorState ( "timeline" , "selection" , null )
1006+ }
1007+ leftIcon = { < IconLucideCheck /> }
1008+ >
1009+ Done
1010+ </ EditorButton >
1011+ < span class = "text-sm text-gray-10" >
1012+ { value ( ) . segments . length } scene{ " " }
1013+ { value ( ) . segments . length === 1
1014+ ? "segment"
1015+ : "segments" } { " " }
1016+ selected
1017+ </ span >
1018+ </ div >
1019+ < EditorButton
1020+ variant = "danger"
1021+ onClick = { ( ) => {
1022+ const indices = value ( ) . selection . indices ;
1023+
1024+ // Delete segments in reverse order to maintain indices
1025+ [ ...indices ]
1026+ . sort ( ( a , b ) => b - a )
1027+ . forEach ( ( idx ) => {
1028+ projectActions . deleteSceneSegment ( idx ) ;
1029+ } ) ;
1030+ } }
1031+ leftIcon = { < IconCapTrash /> }
1032+ >
1033+ Delete
1034+ </ EditorButton >
1035+ </ div >
1036+ </ div >
1037+ </ Show >
1038+ ) }
1039+ </ Show >
1040+ < Show
1041+ when = { ( ( ) => {
1042+ const clipSelection = selection ( ) ;
1043+ if ( clipSelection . type !== "clip" ) return ;
1044+
1045+ const segments = clipSelection . indices
1046+ . map ( ( idx ) => ( {
1047+ segment : project . timeline ?. segments ?. [ idx ] ,
1048+ index : idx ,
1049+ } ) )
1050+ . filter ( ( s ) => s . segment !== undefined ) ;
1051+
1052+ if ( segments . length === 0 ) return ;
1053+ return { selection : clipSelection , segments } ;
1054+ } ) ( ) }
1055+ >
1056+ { ( value ) => (
1057+ < Show
1058+ when = { value ( ) . segments . length > 1 }
1059+ fallback = {
1060+ < ClipSegmentConfig
1061+ segment = { value ( ) . segments [ 0 ] . segment ! }
1062+ segmentIndex = { value ( ) . segments [ 0 ] . index }
1063+ />
1064+ }
1065+ >
1066+ < div class = "space-y-4" >
1067+ < div class = "flex flex-row justify-between items-center" >
1068+ < div class = "flex gap-2 items-center" >
1069+ < EditorButton
1070+ onClick = { ( ) =>
1071+ setEditorState ( "timeline" , "selection" , null )
1072+ }
1073+ leftIcon = { < IconLucideCheck /> }
1074+ >
1075+ Done
1076+ </ EditorButton >
1077+ < span class = "text-sm text-gray-10" >
1078+ { value ( ) . segments . length } clip{ " " }
1079+ { value ( ) . segments . length === 1
1080+ ? "segment"
1081+ : "segments" } { " " }
1082+ selected
1083+ </ span >
1084+ </ div >
1085+ < EditorButton
1086+ variant = "danger"
1087+ onClick = { ( ) => {
1088+ const indices = value ( ) . selection . indices ;
1089+
1090+ // Delete segments in reverse order to maintain indices
1091+ [ ...indices ]
1092+ . sort ( ( a , b ) => b - a )
1093+ . forEach ( ( idx ) => {
1094+ projectActions . deleteClipSegment ( idx ) ;
1095+ } ) ;
1096+ } }
1097+ leftIcon = { < IconCapTrash /> }
1098+ >
1099+ Delete
1100+ </ EditorButton >
1101+ </ div >
1102+ </ div >
1103+ </ Show >
1104+ ) }
1105+ </ Show >
1106+ </ Suspense >
1107+ </ div >
1108+ ) }
1109+ </ Show >
8801110 </ KTabs >
8811111 ) ;
8821112}
0 commit comments