Skip to content
Open
Show file tree
Hide file tree
Changes from 10 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ import {
processFilesForQuickAction,
loadAndInitializeCCEverywhere,
getErrorMsg,
shouldShowVideoQuickActionPickerForMobile,
} from '../../scripts/utils/frictionless-utils.js';

let replaceKey; let getConfig;
Expand Down Expand Up @@ -283,11 +284,24 @@ export default async function decorate(block) {
accept: QA_CONFIGS[quickAction].accept,
...(quickAction === 'merge-videos' && { multiple: true }),
});
inputElement.onchange = () => {
if (quickAction === 'merge-videos' && inputElement.files.length > 1) {
inputElement.onchange = async () => {
Comment thread
shairil marked this conversation as resolved.
const file = inputElement.files[0];
if (shouldShowVideoQuickActionPickerForMobile(quickAction, file)) {
if (!file) return;
const blobUrl = URL.createObjectURL(file);
inputElement.value = '';
if (typeof blobUrl !== 'string' || !blobUrl.startsWith('blob:')) {
URL.revokeObjectURL(blobUrl);
showErrorToast(block, await getErrorMsg('file-type-not-supported'));
return;
}
const { default: showVideoQuickActionPicker } = await import(
'../video-quick-action-picker/video-quick-action-picker.js'
);
showVideoQuickActionPicker(file, block, { startSDKWithUnconvertedFiles, blobUrl });
} else if (quickAction === 'merge-videos' && inputElement.files.length > 1) {
startSDKWithUnconvertedFiles(inputElement.files, quickAction, block);
} else {
const file = inputElement.files[0];
startSDKWithUnconvertedFiles([file], quickAction, block);
}
};
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
import { getLibs } from '../../scripts/utils.js';
import { QA_CONFIGS } from '../../scripts/utils/frictionless-utils.js';

const ICONS_BASE = '/express/code/icons';

export const ACTION_TYPES = {
QUICK_ACTION: 'quick-action', // launches SDK inline with the uploaded file
APP_INSTALL: 'app-install', // navigates to app install URL (same tab)
};

// Max duration in seconds per quick action (source: Adobe Express help docs)
const MAX_DURATION = {
'convert-to-gif': 60, // 1 minute
'caption-video': 300, // 5 minutes
};

let replaceKey;
let getConfig;

export async function loadPlaceholders() {
const [utils, placeholders] = await Promise.all([
import(`${getLibs()}/utils/utils.js`),
import(`${getLibs()}/features/placeholders.js`),
]);
({ getConfig } = utils);
({ replaceKey } = placeholders);
}

async function resolveKey(key, fallback) {
const resolved = await replaceKey(key, getConfig());
if (resolved === key.replaceAll('-', ' ')) return fallback;
return resolved;
}

export async function getLocalizedStrings() {
return {
editVideo: await resolveKey('edit-video', 'Edit video'),
appOnly: await resolveKey('ios-app-only', 'iOS App only'),
convertVideoToGif: await resolveKey('convert-video-to-gif', 'Convert video to GIF'),
cropVideo: await resolveKey('crop-video', 'Crop video'),
trimVideo: await resolveKey('trim-video', 'Trim video'),
resizeVideo: await resolveKey('resize-video', 'Resize video'),
convertVideoToMp4: await resolveKey('convert-video-to-mp4', 'Convert video to MP4'),
captionVideo: await resolveKey('caption-video', 'Caption video'),
openingPreview: await resolveKey('opening-preview', 'Opening preview'),
uploadedVideo: await resolveKey('uploaded-video', 'Uploaded video'),
startFromYourVideo: await resolveKey('start-from-your-video', 'Start from your video'),
closeDialog: await resolveKey('close-dialog', 'Close dialog'),
};
}

export function getVideoActions(strings, videoFile, videoDuration) {
const actions = [
{
id: 'edit-video',
label: strings.editVideo,
badge: strings.appOnly,
type: ACTION_TYPES.APP_INSTALL,
iconPath: `${ICONS_BASE}/edit-video.svg`,
},
{
id: 'convert-to-gif',
label: strings.convertVideoToGif,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/ax-convert-to-gif-22.svg`,
},
{
id: 'crop-video',
label: strings.cropVideo,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/vqa-crop-video.svg`,
},
{
id: 'trim-video',
label: strings.trimVideo,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/vqa-trim-video.svg`,
},
{
id: 'resize-video',
label: strings.resizeVideo,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/vqa-resize-video.svg`,
},
{
id: 'convert-to-mp4',
label: strings.convertVideoToMp4,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/convert-to-mp4.svg`,
},
{
id: 'caption-video',
label: strings.captionVideo,
type: ACTION_TYPES.QUICK_ACTION,
iconPath: `${ICONS_BASE}/ax-caption-video-22.svg`,
},
];

return actions.filter((action) => {
// No point offering convert-to-mp4 if the file is already an MP4
if (action.id === 'convert-to-mp4' && videoFile.type === 'video/mp4') return false;
const config = QA_CONFIGS[action.id];
if (!config) return false;
if (!config.input_check(videoFile.type)) return false;
if (videoFile.size > config.max_size) return false;
const maxDuration = MAX_DURATION[action.id];
if (maxDuration && videoDuration > maxDuration) return false;
return true;
});
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,212 @@
/* --- Fullscreen Dialog --- */
.vqap-dialog {
position: fixed;
inset: 0;
--vqap-mobile-header-bar-height: 53px;
--vqap-hero-inline-mobile-height: 282px;
background: var(--body-background-color);
display: flex;
flex-direction: column;
z-index: 9999;
overflow: hidden;
}

/* --- Close Button --- */
.vqap-close-btn {
position: absolute;
inset-block-start: calc(var(--spacing-75) + env(safe-area-inset-top, 0px));
inset-inline-end: var(--spacing-300);
width: 50px;
height: 50px;
border-radius: 100%;
border: 0;
background: transparent;
color: var(--color-white);
display: flex;
align-items: center;
justify-content: center;
cursor: pointer;
z-index: 1;
}

/* --- Hero Container --- */
.vqap-hero {
background: var(--color-gray-100);
height: var(--vqap-hero-inline-mobile-height);
width: 100%;
flex-shrink: 0;
margin-block-end: var(--spacing-400);
}

/* --- Header Bar --- */

.vqap-header-bar {
height: var(--vqap-mobile-header-bar-height);
background-color: var(--color-gray-800-variant);
flex-shrink: 0;
}

/* --- Preview Area --- */
.vqap-preview-container {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
background-color: var(--color-gray-100);
box-sizing: border-box;
height: calc(100% - var(--vqap-mobile-header-bar-height));
width: 100%;
padding: var(--spacing-300);
display: flex;
align-items: center;
justify-content: center;
}

.vqap-preview-container video {
width: 100%;
height: auto;
max-height: 100%;
max-width: 100%;
display: block;
object-fit: contain;
box-sizing: border-box;
}

/* --- Loading Spinner --- */
.vqap-loading {
display: flex;
align-items: center;
justify-content: center;
width: 100%;
height: 100%;
}

.vqap-spinner {
width: 48px;
height: 48px;
border: 4px solid var(--color-light-gray);
border-top-color: var(--color-gray-800-variant);
border-radius: 50%;
animation: vqap-spin 0.8s linear infinite;
}

@keyframes vqap-spin {
to { transform: rotate(360deg); }
}

/* --- Error State --- */
.vqap-error {
display: flex;
flex-direction: column;
align-items: center;
justify-content: center;
gap: var(--spacing-100);
width: 100%;
height: 100%;
color: var(--color-default-font);
font-size: var(--ax-body-xs-size, 14px);
}

/* --- Scrollable Body & Content Container --- */
.vqap-body {
display: flex;
flex-direction: column;
flex: 1 1 auto;
min-height: 0;
}

.vqap-content-container {
padding-inline: var(--spacing-300);
flex: 1 1 auto;
overflow-y: auto;
-webkit-overflow-scrolling: touch;
display: flex;
flex-direction: column;
gap: var(--spacing-400);
padding-block: var(--spacing-50);
padding-bottom: calc(var(--spacing-50) + env(safe-area-inset-bottom, 0px));
}

.vqap-content-container > .vqap-action-card:first-child {
margin-block-start: var(--spacing-75);
}

.vqap-content-container > .vqap-action-card:last-child {
margin-block-end: var(--spacing-300);
}

/* --- Action Card --- */
.vqap-action-card {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
display: block;
width: 100%;
border: var(--border-width-2) solid var(--color-light-gray);
border-radius: var(--border-radius-10);
padding: var(--spacing-400) var(--spacing-300);
cursor: pointer;
background: var(--body-background-color);
box-sizing: border-box;
touch-action: manipulation;
}

.vqap-action-card:hover,
.vqap-action-card:active {
border-color: var(--color-gray-250);
}

/* --- Card Inner (mirrors .action-title) --- */
.vqap-action-title {
align-items: center;
display: flex;
gap: var(--spacing-200);
padding-block: var(--spacing-75);
font-family: var(--body-font-family);
font-size: var(--ax-heading-xs-size, 16px);
line-height: var(--ax-heading-xs-lh, 20px);
}

.vqap-action-title span {
align-items: center;
display: flex;
gap: var(--spacing-100);
flex-wrap: wrap-reverse;
}

.vqap-action-title strong {
font-weight: var(--ax-heading-weight, 700);
color: var(--heading-color, var(--color-default-font));
}

.vqap-card-icon {
flex-shrink: 0;
}

.vqap-card-icon img {
width: 28px;
height: 28px;
}

.vqap-close-btn img {
width: 18px;
height: 18px;
}

/* --- Badge --- */
.vqap-badge {
display: flex;
align-items: center;
min-height: 26px;
border: 1px solid transparent;
border-radius: 4px;
background: rgb(229, 240, 254);
flex-shrink: 0;
}

.vqap-badge strong {
font-size: var(--ax-body-xs-size);
line-height: 1.3;
color: var(--color-black);
padding-block: var(--spacing-50);
padding-inline: var(--spacing-80);
}
Loading
Loading