1import { Op, html, css } from "@benev/slate"; 2import { styles } from "./styles.js"; 3import { Tooltip } from "../../views/tooltip/view.js"; 4import { shadow_component } from "../../context/context.js"; 5import { tooltipStyles } from "../../views/tooltip/styles.js"; 6import { StateHandler } from "../../views/state-handler/view.js"; 7import circleInfoSvg from "../../icons/gravity-ui/circle-info.svg.js"; 8import animationSvg from "../../icons/material-design-icons/animation.svg.js"; 9import { animationIn, animationNone, animationOut } from "../../context/controllers/compositor/parts/animation-manager.js"; 10export const OmniAnim = shadow_component(use => { 11 use.styles([styles, tooltipStyles, css ` 12 #icon-container { 13 position: relative; 14 top: -25px; 15 } 16 `]); 17 use.watch(() => use.context.state); 18 const controllers = use.context.controllers; 19 const [kind, setKind] = use.state("in"); 20 const manager = use.context.controllers.compositor.managers.animationManager; 21 const selectedImageOrVideoEffect = use.context.state.selected_effect?.kind === "video" || use.context.state.selected_effect?.kind === "image" 22 ? use.context.state.effects.find(effect => effect.id === use.context.state.selected_effect.id) 23 : null; 24 use.mount(() => { 25 const dispose = manager.onChange(() => use.rerender()); 26 return () => dispose(); 27 }); 28 const getAnimationDuration = () => { 29 if (selectedImageOrVideoEffect) { 30 const effect = use.context.state.animations.find(a => a.targetEffect.id === selectedImageOrVideoEffect.id && a.type === kind && a.for === "Animation"); 31 const duration = effect?.duration; 32 if (duration) { 33 return duration; 34 } 35 else 36 return 520; 37 } 38 else 39 return 520; 40 }; 41 const imageAndVideoEffects = () => use.context.state.effects.filter(effect => effect.kind === "image" || effect.kind === "video"); 42 const duration = getAnimationDuration(); 43 const renderAnimationsIn = () => { 44 return animationIn.map(animation => { 45 const [name, type] = animation.split("-"); 46 const anim = { 47 type: "in", 48 name: animation, 49 targetEffect: selectedImageOrVideoEffect, 50 duration, 51 for: "Animation" 52 }; 53 return html ` 54 <div 55 ?data-selected=${manager.selectedAnimationForEffect(selectedImageOrVideoEffect, anim)} 56 ?disabled=${!selectedImageOrVideoEffect} 57 @click=${() => manager.selectAnimation(selectedImageOrVideoEffect, anim, use.context.state)} 58 class="animation" 59 > 60 <span class="text"> 61 ${name} ${type} 62 </span> 63 </div> 64 `; 65 }); 66 }; 67 const renderAnimationsOut = () => { 68 return animationOut.map(animation => { 69 const [name, type] = animation.split("-"); 70 const anim = { 71 type: "out", 72 name: animation, 73 targetEffect: selectedImageOrVideoEffect, 74 duration, 75 for: "Animation" 76 }; 77 return html ` 78 <div 79 ?data-selected=${manager.selectedAnimationForEffect(selectedImageOrVideoEffect, anim)} 80 ?disabled=${!selectedImageOrVideoEffect} 81 @click=${() => manager.selectAnimation(selectedImageOrVideoEffect, anim, use.context.state)} 82 class="animation" 83 > 84 <span class="text"> 85 ${name} ${type} 86 </span> 87 </div> 88 `; 89 }); 90 }; 91 const renderAnimationNone = (type) => { 92 return html ` 93 <div 94 ?data-selected=${type === "in" 95 ? !manager.isAnyAnimationInSelected(selectedImageOrVideoEffect) 96 : !manager.isAnyAnimationOutSelected(selectedImageOrVideoEffect)} 97 ?disabled=${!selectedImageOrVideoEffect} 98 @click=${() => manager.removeAnimation(use.context.state, selectedImageOrVideoEffect, type)} 99 class="animation" 100 > 101 <span class="text"> 102 ${animationNone} 103 </span> 104 </div> 105 `; 106 }; 107 const renderEffectSelectionDropdown = () => { 108 return html ` 109 <div class=flex> 110 <select 111 @change=${(event) => { 112 const target = event.target; 113 const effectId = target.value; 114 const effect = use.context.state.effects.find(effect => effect.id === effectId); 115 controllers.timeline.set_selected_effect(effect, use.context.state); 116 }} 117 id="clip" 118 name="clip" 119 > 120 <option .selected=${!selectedImageOrVideoEffect} value=none>none</option> 121 ${imageAndVideoEffects().map(effect => html `<option .selected=${selectedImageOrVideoEffect?.id === effect.id} value=${effect.id}>${effect.name}</option>`)} 122 </select> 123 ${renderDropdownInfo()} 124 </div> 125 `; 126 }; 127 const renderDurationSlider = () => {
128 const frameDuration = 1000 / use.context.state.timebase; 129 const maxAnimationDuration = selectedImageOrVideoEffect ? (selectedImageOrVideoEffect.end - selectedImageOrVideoEffect.start) : 10000; 130 const normalizeMaxAnimationDuration = Math.round(maxAnimationDuration / frameDuration) * frameDuration; 131 return html ` 132 <div class=duration-slider> 133 <label for="duration">Duration:</label> 134 <input 135 @change=${(e) => manager.updateAnimation({ duration: +e.target.value, kind, effect: selectedImageOrVideoEffect })} 136 type="range" 137 min="520" 138 max=${normalizeMaxAnimationDuration} 139 step=${frameDuration} 140 .value=${duration} 141 name="duration" 142 id="duration" 143 > 144 <span>${duration / 1000}s</span> 145 </div> 146 `; 147 }; 148 const renderDropdownInfo = () => { 149 return Tooltip(circleInfoSvg, html `<p>Select video or image either from dropdown menu here, timeline or scene</p>`); 150 }; 151 return StateHandler(Op.all(use.context.helpers.ffmpeg.is_loading.value, use.context.is_webcodecs_supported.value), () => html ` 152 <div class="animations"> 153 <h2>${animationSvg} Animations</h2> 154 <div class="btn-cnt"> 155 <button ?data-selected=${kind === "in"} @click=${() => setKind("in")}>In</button> 156 <button ?data-selected=${kind === "out"} @click=${() => setKind("out")}>Out</button> 157 </div> 158 ${renderEffectSelectionDropdown()} 159 ${renderDurationSlider()} 160 <div class="anim-cnt" ?disabled=${!selectedImageOrVideoEffect}> 161 ${renderAnimationNone(kind)} 162 ${kind === "in" 163 ? renderAnimationsIn() 164 : renderAnimationsOut()} 165 </div> 166 </div> 167 `); 168}); 169//# sourceMappingURL=component.js.map
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.