PageSourceSearch

https://omniclip.app/components/omni-anim/component.js

js omniclip.app collected 2026-09-25 22:13:13 UTC 6,516 bytes, 169 lines download raw bytes

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.