init commit

This commit is contained in:
Carlos
2026-02-21 10:33:18 +01:00
parent c863a943ed
commit 9d955bf338
9512 changed files with 2015317 additions and 1305 deletions

View File

@@ -0,0 +1,2 @@
import React from 'react';
export declare const AlgoliaCredit: React.FC;

File diff suppressed because one or more lines are too long

View File

@@ -0,0 +1,6 @@
import React from 'react';
export type QuickSwitcherMode = 'commands' | 'compositions' | 'docs';
export declare const QuickSwitcherNoResults: React.FC<{
readonly query: string;
readonly mode: QuickSwitcherMode;
}>;

View File

@@ -0,0 +1,20 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuickSwitcherNoResults = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const colors_1 = require("../../helpers/colors");
const container = {
padding: 80,
color: colors_1.LIGHT_TEXT,
textAlign: 'center',
fontSize: 14,
};
const MODE_TO_STRING = {
commands: 'commands',
compositions: 'compositions',
docs: 'documentation',
};
const QuickSwitcherNoResults = ({ query, mode }) => {
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: ["No ", MODE_TO_STRING[mode], " matching ", '"', query, '"'] }));
};
exports.QuickSwitcherNoResults = QuickSwitcherNoResults;

View File

@@ -0,0 +1,8 @@
import React from 'react';
import type { QuickSwitcherMode } from './NoResults';
declare const QuickSwitcher: React.FC<{
readonly initialMode: QuickSwitcherMode;
readonly invocationTimestamp: number;
readonly readOnlyStudio: boolean;
}>;
export default QuickSwitcher;

View File

@@ -0,0 +1,9 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
const jsx_runtime_1 = require("react/jsx-runtime");
const DismissableModal_1 = require("../NewComposition/DismissableModal");
const QuickSwitcherContent_1 = require("./QuickSwitcherContent");
const QuickSwitcher = ({ initialMode, invocationTimestamp, readOnlyStudio }) => {
return ((0, jsx_runtime_1.jsx)(DismissableModal_1.DismissableModal, { children: (0, jsx_runtime_1.jsx)(QuickSwitcherContent_1.QuickSwitcherContent, { readOnlyStudio: readOnlyStudio, invocationTimestamp: invocationTimestamp, initialMode: initialMode }) }));
};
exports.default = QuickSwitcher;

View File

@@ -0,0 +1,7 @@
import React from 'react';
import type { QuickSwitcherMode } from './NoResults';
export declare const QuickSwitcherContent: React.FC<{
readonly initialMode: QuickSwitcherMode;
readonly invocationTimestamp: number;
readonly readOnlyStudio: boolean;
}>;

View File

@@ -0,0 +1,302 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuickSwitcherContent = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const remotion_1 = require("remotion");
const colors_1 = require("../../helpers/colors");
const is_composition_still_1 = require("../../helpers/is-composition-still");
const use_keybinding_1 = require("../../helpers/use-keybinding");
const use_menu_structure_1 = require("../../helpers/use-menu-structure");
const modals_1 = require("../../state/modals");
const InitialCompositionLoader_1 = require("../InitialCompositionLoader");
const KeyboardShortcutsExplainer_1 = require("../KeyboardShortcutsExplainer");
const is_menu_item_1 = require("../Menu/is-menu-item");
const RemInput_1 = require("../NewComposition/RemInput");
const layout_1 = require("../layout");
const AlgoliaCredit_1 = require("./AlgoliaCredit");
const NoResults_1 = require("./NoResults");
const QuickSwitcherResult_1 = require("./QuickSwitcherResult");
const algolia_search_1 = require("./algolia-search");
const fuzzy_search_1 = require("./fuzzy-search");
const input = {
width: '100%',
};
const modeSelector = {
paddingLeft: 16,
paddingRight: 16,
display: 'flex',
flexDirection: 'row',
paddingTop: 8,
paddingBottom: 5,
};
const modeItem = {
appearance: 'none',
border: 'none',
fontFamily: 'inherit',
padding: 0,
fontSize: 13,
cursor: 'pointer',
};
const modeInactive = {
...modeItem,
color: colors_1.LIGHT_TEXT,
};
const modeActive = {
...modeItem,
color: 'white',
fontWeight: 'bold',
};
const content = {
paddingLeft: 16,
paddingRight: 16,
paddingTop: 4,
paddingBottom: 10,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
};
const loopIndex = (index, length) => {
if (index < 0) {
index += length;
}
return index % length;
};
const stripQuery = (query) => {
if (query.startsWith('>') || query.startsWith('?')) {
return query.substring(1).trim();
}
return query.trim();
};
const mapQueryToMode = (query) => {
return query.startsWith('>')
? 'commands'
: query.startsWith('?')
? 'docs'
: 'compositions';
};
const mapModeToQuery = (mode) => {
if (mode === 'commands') {
return '> ';
}
if (mode === 'compositions') {
return '';
}
if (mode === 'docs') {
return '? ';
}
throw new Error('no mode' + mode);
};
const QuickSwitcherContent = ({ initialMode, invocationTimestamp, readOnlyStudio }) => {
const { compositions } = (0, react_1.useContext)(remotion_1.Internals.CompositionManager);
const [state, setState] = (0, react_1.useState)(() => {
return {
query: mapModeToQuery(initialMode),
selectedIndex: 0,
};
});
(0, react_1.useEffect)(() => {
setState({
query: mapModeToQuery(initialMode),
selectedIndex: 0,
});
}, [initialMode, invocationTimestamp]);
const inputRef = (0, react_1.useRef)(null);
const selectComposition = (0, InitialCompositionLoader_1.useSelectComposition)();
const closeMenu = (0, react_1.useCallback)(() => undefined, []);
const actions = (0, use_menu_structure_1.useMenuStructure)(closeMenu, readOnlyStudio);
const [docResults, setDocResults] = (0, react_1.useState)({ type: 'initial' });
const { setSelectedModal } = (0, react_1.useContext)(modals_1.ModalsContext);
const keybindings = (0, use_keybinding_1.useKeybinding)();
const mode = mapQueryToMode(state.query);
const actualQuery = (0, react_1.useMemo)(() => {
return stripQuery(state.query);
}, [state.query]);
const menuActions = (0, react_1.useMemo)(() => {
if (mode !== 'commands') {
return [];
}
return (0, use_menu_structure_1.makeSearchResults)(actions, setSelectedModal);
}, [actions, mode, setSelectedModal]);
const resultsArray = (0, react_1.useMemo)(() => {
if (mode === 'commands') {
return (0, fuzzy_search_1.fuzzySearch)(actualQuery, menuActions);
}
if (mode === 'docs' && docResults.type === 'results') {
return docResults.results;
}
return (0, fuzzy_search_1.fuzzySearch)(actualQuery, compositions.map((c) => {
return {
id: 'composition-' + c.id,
title: c.id,
type: 'composition',
onSelected: () => {
var _a;
selectComposition(c, true);
setSelectedModal(null);
const selector = `.__remotion-composition[data-compname="${c.id}"]`;
(_a = remotion_1.Internals.compositionSelectorRef.current) === null || _a === void 0 ? void 0 : _a.expandComposition(c.id);
waitForElm(selector).then(() => {
var _a;
(_a = document
.querySelector(selector)) === null || _a === void 0 ? void 0 : _a.scrollIntoView({ block: 'center' });
});
},
compositionType: (0, is_composition_still_1.isCompositionStill)(c) ? 'still' : 'composition',
};
}));
}, [
mode,
actualQuery,
compositions,
menuActions,
docResults,
selectComposition,
setSelectedModal,
]);
const onArrowDown = (0, react_1.useCallback)(() => {
setState((s) => {
return {
...s,
selectedIndex: s.selectedIndex + 1,
};
});
}, []);
const onArrowUp = (0, react_1.useCallback)(() => {
setState((s) => {
return {
...s,
selectedIndex: s.selectedIndex - 1,
};
});
}, []);
// Arrow up
(0, react_1.useEffect)(() => {
const binding = keybindings.registerKeybinding({
key: 'ArrowUp',
callback: onArrowUp,
commandCtrlKey: false,
event: 'keydown',
preventDefault: true,
// Will be using the input field while selecting
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
binding.unregister();
};
}, [keybindings, onArrowDown, onArrowUp]);
(0, react_1.useEffect)(() => {
if (mode !== 'docs') {
return;
}
if (actualQuery.trim() === '') {
setDocResults({ type: 'initial' });
return;
}
let cancelled = false;
setDocResults({ type: 'loading' });
(0, algolia_search_1.algoliaSearch)(actualQuery)
.then((agoliaResults) => {
if (cancelled) {
return;
}
setDocResults({ type: 'results', results: agoliaResults });
})
.catch((err) => {
if (cancelled) {
return;
}
setDocResults({ type: 'error', error: err });
});
return () => {
cancelled = true;
};
}, [actualQuery, mode]);
// Arrow down
(0, react_1.useEffect)(() => {
const binding = keybindings.registerKeybinding({
key: 'ArrowDown',
callback: onArrowDown,
commandCtrlKey: false,
event: 'keydown',
preventDefault: true,
// Will be using the input field while selecting
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
binding.unregister();
};
}, [keybindings, onArrowDown]);
const onTextChange = (0, react_1.useCallback)((e) => {
setState({ query: e.target.value, selectedIndex: 0 });
}, []);
const selectedIndexRounded = loopIndex(state.selectedIndex, resultsArray.length);
const onActionsSelected = (0, react_1.useCallback)(() => {
var _a;
setState((s) => ({
query: `> ${stripQuery(s.query)}`,
selectedIndex: 0,
}));
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, []);
const onCompositionsSelected = (0, react_1.useCallback)(() => {
var _a;
setState((s) => ({
query: stripQuery(s.query),
selectedIndex: 0,
}));
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, []);
const onDocSearchSelected = (0, react_1.useCallback)(() => {
var _a;
setState((s) => ({
query: `? ${stripQuery(s.query)}`,
selectedIndex: 0,
}));
setDocResults({ type: 'initial' });
(_a = inputRef.current) === null || _a === void 0 ? void 0 : _a.focus();
}, []);
const showKeyboardShortcuts = mode === 'docs' && actualQuery.trim() === '';
const showSearchLoadingState = mode === 'docs' && docResults.type === 'loading';
const container = (0, react_1.useMemo)(() => {
return {
width: showKeyboardShortcuts ? 800 : 500,
};
}, [showKeyboardShortcuts]);
const results = (0, react_1.useMemo)(() => {
if (showKeyboardShortcuts) {
return {
maxHeight: 600,
overflowY: 'auto',
};
}
return {
overflowY: 'auto',
height: 300,
};
}, [showKeyboardShortcuts]);
return ((0, jsx_runtime_1.jsxs)("div", { style: container, children: [(0, jsx_runtime_1.jsxs)("div", { style: modeSelector, children: [(0, jsx_runtime_1.jsx)("button", { onClick: onCompositionsSelected, style: mode === 'compositions' ? modeActive : modeInactive, type: "button", children: "Compositions" }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("button", { onClick: onActionsSelected, style: mode === 'commands' ? modeActive : modeInactive, type: "button", children: "Actions" }), (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("button", { onClick: onDocSearchSelected, style: mode === 'docs' ? modeActive : modeInactive, type: "button", children: "Documentation" })] }), (0, jsx_runtime_1.jsxs)("div", { style: content, children: [(0, jsx_runtime_1.jsx)(RemInput_1.RemotionInput, { ref: inputRef, type: "text", style: input, autoFocus: true, status: "ok", value: state.query, onChange: onTextChange, placeholder: "Search compositions...", rightAlign: false }), showKeyboardShortcuts ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 2 }), " ", (0, jsx_runtime_1.jsx)(AlgoliaCredit_1.AlgoliaCredit, {})] })) : null] }), (0, jsx_runtime_1.jsx)("div", { style: results, className: is_menu_item_1.VERTICAL_SCROLLBAR_CLASSNAME, children: showKeyboardShortcuts ? ((0, jsx_runtime_1.jsx)(KeyboardShortcutsExplainer_1.KeyboardShortcutsExplainer, {})) : showSearchLoadingState ? null : resultsArray.length === 0 ? ((0, jsx_runtime_1.jsx)(NoResults_1.QuickSwitcherNoResults, { mode: mode, query: actualQuery })) : (resultsArray.map((result, i) => {
return ((0, jsx_runtime_1.jsx)(QuickSwitcherResult_1.QuickSwitcherResult, { selected: selectedIndexRounded === i, result: result }, result.id));
})) })] }));
};
exports.QuickSwitcherContent = QuickSwitcherContent;
function waitForElm(selector) {
return new Promise((resolve) => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
return;
}
const observer = new MutationObserver(() => {
if (document.querySelector(selector)) {
resolve(document.querySelector(selector));
observer.disconnect();
}
});
observer.observe(document.body, {
childList: true,
subtree: true,
});
});
}

View File

@@ -0,0 +1,21 @@
import React from 'react';
type QuickSwitcherResultDetail = {
type: 'composition';
compositionType: 'composition' | 'still';
} | {
type: 'menu-item';
} | {
type: 'search-result';
titleLine: string;
subtitleLine: string;
};
export type TQuickSwitcherResult = {
title: string;
id: string;
onSelected: () => void;
} & QuickSwitcherResultDetail;
export declare const QuickSwitcherResult: React.FC<{
readonly result: TQuickSwitcherResult;
readonly selected: boolean;
}>;
export {};

View File

@@ -0,0 +1,112 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.QuickSwitcherResult = void 0;
const jsx_runtime_1 = require("react/jsx-runtime");
const react_1 = require("react");
const colors_1 = require("../../helpers/colors");
const use_keybinding_1 = require("../../helpers/use-keybinding");
const still_1 = require("../../icons/still");
const video_1 = require("../../icons/video");
const layout_1 = require("../layout");
const container = {
paddingLeft: 16,
paddingRight: 16,
display: 'flex',
flexDirection: 'row',
alignItems: 'center',
cursor: 'pointer',
};
const label = {
whiteSpace: 'nowrap',
textOverflow: 'ellipsis',
};
const searchLabel = {
...label,
lineHeight: 1.25,
};
const iconStyle = {
width: 14,
height: 14,
};
const labelContainer = {
overflow: 'hidden',
flex: 1,
paddingTop: 5,
paddingBottom: 5,
};
const QuickSwitcherResult = ({ result, selected }) => {
const [hovered, setIsHovered] = (0, react_1.useState)(false);
const ref = (0, react_1.useRef)(null);
const keybindings = (0, use_keybinding_1.useKeybinding)();
(0, react_1.useEffect)(() => {
const { current } = ref;
if (!current) {
return;
}
const onMouseEnter = () => setIsHovered(true);
const onMouseLeave = () => setIsHovered(false);
current.addEventListener('mouseenter', onMouseEnter);
current.addEventListener('mouseleave', onMouseLeave);
return () => {
current.removeEventListener('mouseenter', onMouseEnter);
current.removeEventListener('mouseleave', onMouseLeave);
};
}, []);
(0, react_1.useEffect)(() => {
if (!selected) {
return;
}
const binding = keybindings.registerKeybinding({
key: 'Enter',
callback: result.onSelected,
commandCtrlKey: false,
event: 'keydown',
preventDefault: true,
// Input will be focused while selection
triggerIfInputFieldFocused: true,
keepRegisteredWhenNotHighestContext: false,
});
return () => {
binding.unregister();
};
}, [keybindings, result.onSelected, selected]);
(0, react_1.useEffect)(() => {
var _a;
if (selected) {
(_a = ref.current) === null || _a === void 0 ? void 0 : _a.scrollIntoView({
block: 'nearest',
inline: 'center',
});
}
}, [selected]);
const style = (0, react_1.useMemo)(() => {
return {
...container,
backgroundColor: (0, colors_1.getBackgroundFromHoverState)({
hovered,
selected,
}),
};
}, [hovered, selected]);
const labelStyle = (0, react_1.useMemo)(() => {
return {
...(result.type === 'search-result' ? searchLabel : label),
color: result.type === 'search-result'
? colors_1.LIGHT_TEXT
: selected || hovered
? 'white'
: colors_1.LIGHT_TEXT,
fontSize: 15,
};
}, [hovered, result.type, selected]);
return ((0, jsx_runtime_1.jsxs)("div", { ref: ref, style: style, onClick: result.onSelected, children: [result.type === 'composition' ? (result.compositionType === 'still' ? ((0, jsx_runtime_1.jsx)(still_1.StillIcon, { color: selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle })) : ((0, jsx_runtime_1.jsx)(video_1.FilmIcon, { color: selected ? 'white' : colors_1.LIGHT_TEXT, style: iconStyle }))) : null, (0, jsx_runtime_1.jsx)(layout_1.Spacing, { x: 1 }), (0, jsx_runtime_1.jsx)("div", { style: labelContainer, children: result.type === 'search-result' ? ((0, jsx_runtime_1.jsxs)(jsx_runtime_1.Fragment, { children: [(0, jsx_runtime_1.jsx)("div", {
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML: {
__html: result.titleLine,
}, style: labelStyle }), (0, jsx_runtime_1.jsx)("div", {
// eslint-disable-next-line react/no-danger
dangerouslySetInnerHTML: {
__html: result.subtitleLine,
}, style: labelStyle })] })) : ((0, jsx_runtime_1.jsx)("div", { style: labelStyle, children: result.title })) })] }, result.id));
};
exports.QuickSwitcherResult = QuickSwitcherResult;

View File

@@ -0,0 +1,2 @@
import type { TQuickSwitcherResult } from './QuickSwitcherResult';
export declare const algoliaSearch: (query: string) => Promise<TQuickSwitcherResult[]>;

View File

@@ -0,0 +1,62 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.algoliaSearch = void 0;
const no_react_1 = require("remotion/no-react");
const ALGOLIA_API_KEY = '3e42dbd4f895fe93ff5cf40d860c4a85';
const ALGOLIA_APPLICATION_ID = 'PLSDUOL1CA';
const AGOLIA_SEARCH_URL = 'https://plsduol1ca-dsn.algolia.net/1/indexes/*/queries';
const algoliaSearch = async (query) => {
const url = new URL(AGOLIA_SEARCH_URL);
url.searchParams.set('x-algolia-agen', encodeURIComponent('Remotion Studio DocSearch'));
url.searchParams.set('x-algolia-api-key', ALGOLIA_API_KEY);
url.searchParams.set('x-algolia-application-id', ALGOLIA_APPLICATION_ID);
const { results } = await fetch(url.toString(), {
headers: {
'content-type': 'application/x-www-form-urlencoded',
},
body: JSON.stringify({
requests: [
{
query,
indexName: 'remotion',
params: 'attributesToRetrieve=["hierarchy.lvl0","hierarchy.lvl1","hierarchy.lvl2","hierarchy.lvl3","hierarchy.lvl4","hierarchy.lvl5","hierarchy.lvl6","content","type","url"]&attributesToSnippet=["hierarchy.lvl1:10","hierarchy.lvl2:10","hierarchy.lvl3:10","hierarchy.lvl4:10","hierarchy.lvl5:10","hierarchy.lvl6:10","content:10"]&hitsPerPage=20',
},
],
}),
method: 'POST',
}).then((res) => res.json());
const { hits } = results[0];
return hits
.map((hit) => {
var _a;
const entries = Object.values(hit._highlightResult.hierarchy);
const result = (_a = entries.find((value) => value.matchLevel === 'full')) !== null && _a !== void 0 ? _a : entries.find((value) => value.matchLevel === 'partial');
const { subtitle, title } = splitMatchIntoTitleAndSubtitle(hit);
if (!result) {
return null;
}
return {
type: 'search-result',
id: hit.objectID,
title: 'Should not display',
titleLine: title,
subtitleLine: subtitle,
onSelected: () => {
window.open(hit.url);
},
};
})
.filter(no_react_1.NoReactInternals.truthy);
};
exports.algoliaSearch = algoliaSearch;
const splitMatchIntoTitleAndSubtitle = (match) => {
const main = match.type === 'content'
? match._highlightResult.content
: match._highlightResult.hierarchy[match.type];
const title = main.value;
const subtitle = Object.entries(match._highlightResult.hierarchy)
.filter(([level]) => level !== match.type)
.map((value) => value[1].value)
.join(' • ');
return { title, subtitle };
};

View File

@@ -0,0 +1,2 @@
import type { TQuickSwitcherResult } from './QuickSwitcherResult';
export declare function fuzzySearch(query: string, dataset: TQuickSwitcherResult[]): TQuickSwitcherResult[];

View File

@@ -0,0 +1,24 @@
"use strict";
Object.defineProperty(exports, "__esModule", { value: true });
exports.fuzzySearch = fuzzySearch;
function fuzzySearch(query, dataset) {
const q = query ? query.trim().toLowerCase() : '';
const matchingIndices = [];
if (q.length === 0) {
for (let i = 0; i < dataset.length; i++) {
matchingIndices.push(i);
}
return dataset.filter((_, i) => matchingIndices.includes(i));
}
dataset.forEach((d, index) => {
const s = d.title.trim().toLowerCase();
let i = 0;
let n = -1;
let l;
for (; (l = q[i++]);)
if (!~(n = s.indexOf(l, n + 1)))
return;
matchingIndices.push(index);
});
return dataset.filter((_, i) => matchingIndices.includes(i));
}