formatting
This commit is contained in:
parent
e4dd94f478
commit
6581fd70c2
@ -73,7 +73,11 @@ class Project_transition_settingsDBApi extends GenericDBApi {
|
|||||||
* @param {object} options - Query options
|
* @param {object} options - Query options
|
||||||
* @returns {object|null} Settings record or null
|
* @returns {object|null} Settings record or null
|
||||||
*/
|
*/
|
||||||
static async findByProjectAndEnvironment(projectId, environment, options = {}) {
|
static async findByProjectAndEnvironment(
|
||||||
|
projectId,
|
||||||
|
environment,
|
||||||
|
options = {},
|
||||||
|
) {
|
||||||
const transaction = options.transaction;
|
const transaction = options.transaction;
|
||||||
|
|
||||||
const record = await this.MODEL.findOne({
|
const record = await this.MODEL.findOne({
|
||||||
|
|||||||
@ -52,12 +52,13 @@ class ProjectsDBApi extends GenericDBApi {
|
|||||||
// Note: transition_settings moved to project_transition_settings table
|
// Note: transition_settings moved to project_transition_settings table
|
||||||
return {
|
return {
|
||||||
id: data.id || undefined,
|
id: data.id || undefined,
|
||||||
name: 'name' in data ? (data.name || null) : undefined,
|
name: 'name' in data ? data.name || null : undefined,
|
||||||
slug: 'slug' in data ? (data.slug || null) : undefined,
|
slug: 'slug' in data ? data.slug || null : undefined,
|
||||||
description: 'description' in data ? (data.description || null) : undefined,
|
description: 'description' in data ? data.description || null : undefined,
|
||||||
logo_url: 'logo_url' in data ? (data.logo_url || null) : undefined,
|
logo_url: 'logo_url' in data ? data.logo_url || null : undefined,
|
||||||
favicon_url: 'favicon_url' in data ? (data.favicon_url || null) : undefined,
|
favicon_url: 'favicon_url' in data ? data.favicon_url || null : undefined,
|
||||||
og_image_url: 'og_image_url' in data ? (data.og_image_url || null) : undefined,
|
og_image_url:
|
||||||
|
'og_image_url' in data ? data.og_image_url || null : undefined,
|
||||||
design_width: 'design_width' in data ? data.design_width : undefined,
|
design_width: 'design_width' in data ? data.design_width : undefined,
|
||||||
design_height: 'design_height' in data ? data.design_height : undefined,
|
design_height: 'design_height' in data ? data.design_height : undefined,
|
||||||
};
|
};
|
||||||
|
|||||||
@ -130,13 +130,20 @@ module.exports = {
|
|||||||
try {
|
try {
|
||||||
settings = JSON.parse(settings);
|
settings = JSON.parse(settings);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.warn(`Failed to parse transition_settings for project ${project.id}:`, e);
|
console.warn(
|
||||||
|
`Failed to parse transition_settings for project ${project.id}:`,
|
||||||
|
e,
|
||||||
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Skip if settings is null, empty object, or has no actual values
|
// Skip if settings is null, empty object, or has no actual values
|
||||||
if (!settings || typeof settings !== 'object' || Object.keys(settings).length === 0) {
|
if (
|
||||||
|
!settings ||
|
||||||
|
typeof settings !== 'object' ||
|
||||||
|
Object.keys(settings).length === 0
|
||||||
|
) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -160,7 +167,9 @@ module.exports = {
|
|||||||
|
|
||||||
if (records.length > 0) {
|
if (records.length > 0) {
|
||||||
await queryInterface.bulkInsert('project_transition_settings', records);
|
await queryInterface.bulkInsert('project_transition_settings', records);
|
||||||
console.log(`Migrated ${records.length} project transition settings to 'dev' environment`);
|
console.log(
|
||||||
|
`Migrated ${records.length} project transition settings to 'dev' environment`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Drop the transition_settings column from projects table
|
// Step 3: Drop the transition_settings column from projects table
|
||||||
@ -192,16 +201,19 @@ module.exports = {
|
|||||||
overlayColor: setting.overlay_color,
|
overlayColor: setting.overlay_color,
|
||||||
});
|
});
|
||||||
|
|
||||||
await queryInterface.sequelize.query(`
|
await queryInterface.sequelize.query(
|
||||||
|
`
|
||||||
UPDATE projects
|
UPDATE projects
|
||||||
SET transition_settings = :settings::jsonb
|
SET transition_settings = :settings::jsonb
|
||||||
WHERE id = :projectId
|
WHERE id = :projectId
|
||||||
`, {
|
`,
|
||||||
replacements: {
|
{
|
||||||
settings: jsonValue,
|
replacements: {
|
||||||
projectId: setting.projectId,
|
settings: jsonValue,
|
||||||
|
projectId: setting.projectId,
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Step 3: Drop indexes and table
|
// Step 3: Drop indexes and table
|
||||||
@ -212,6 +224,8 @@ module.exports = {
|
|||||||
await queryInterface.dropTable('project_transition_settings');
|
await queryInterface.dropTable('project_transition_settings');
|
||||||
|
|
||||||
// Drop the ENUM type
|
// Drop the ENUM type
|
||||||
await queryInterface.sequelize.query('DROP TYPE IF EXISTS "enum_project_transition_settings_environment";');
|
await queryInterface.sequelize.query(
|
||||||
|
'DROP TYPE IF EXISTS "enum_project_transition_settings_environment";',
|
||||||
|
);
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|||||||
@ -114,7 +114,11 @@ const sanitizePublicRuntimeListResponse = (entityName) => {
|
|||||||
pattern instanceof RegExp ? pattern.test(req.path) : req.path === pattern,
|
pattern instanceof RegExp ? pattern.test(req.path) : req.path === pattern,
|
||||||
);
|
);
|
||||||
|
|
||||||
if (!isPublicRuntimeReadRequest(req) || !pathMatches || fields.length === 0) {
|
if (
|
||||||
|
!isPublicRuntimeReadRequest(req) ||
|
||||||
|
!pathMatches ||
|
||||||
|
fields.length === 0
|
||||||
|
) {
|
||||||
return next();
|
return next();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -433,10 +433,7 @@ const downloadFile = async (req, res) => {
|
|||||||
res.setHeader('Content-Length', result.contentLength);
|
res.setHeader('Content-Length', result.contentLength);
|
||||||
|
|
||||||
// Add caching headers for browser
|
// Add caching headers for browser
|
||||||
res.setHeader(
|
res.setHeader('Cache-Control', `public, max-age=${config.s3CacheMaxAge}`);
|
||||||
'Cache-Control',
|
|
||||||
`public, max-age=${config.s3CacheMaxAge}`,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (useCache && typeof result.body.pipe === 'function') {
|
if (useCache && typeof result.body.pipe === 'function') {
|
||||||
// Stream to both response and cache file
|
// Stream to both response and cache file
|
||||||
@ -839,13 +836,11 @@ const finalizeUploadSession = async (req, res) => {
|
|||||||
// Verify all chunks exist
|
// Verify all chunks exist
|
||||||
for (let i = 0; i < session.totalChunks; i++) {
|
for (let i = 0; i < session.totalChunks; i++) {
|
||||||
if (!sessionManager.chunkExists(sessionId, i)) {
|
if (!sessionManager.chunkExists(sessionId, i)) {
|
||||||
return res
|
return res.status(400).send(
|
||||||
.status(400)
|
createErrorResponse(`Missing chunk ${i}`, 'MISSING_CHUNK', {
|
||||||
.send(
|
missingChunk: i,
|
||||||
createErrorResponse(`Missing chunk ${i}`, 'MISSING_CHUNK', {
|
}),
|
||||||
missingChunk: i,
|
);
|
||||||
}),
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -956,12 +951,16 @@ const getMimeTypeFromExtension = (filepath) => {
|
|||||||
*/
|
*/
|
||||||
const copyFile = async (sourceKey, destKey, options = {}) => {
|
const copyFile = async (sourceKey, destKey, options = {}) => {
|
||||||
const provider = getFileStorageProvider();
|
const provider = getFileStorageProvider();
|
||||||
const contentType = options.contentType || getMimeTypeFromExtension(sourceKey);
|
const contentType =
|
||||||
|
options.contentType || getMimeTypeFromExtension(sourceKey);
|
||||||
|
|
||||||
if (provider === 's3') {
|
if (provider === 's3') {
|
||||||
const s3 = getS3Provider();
|
const s3 = getS3Provider();
|
||||||
const result = await s3.copy(sourceKey, destKey, { contentType });
|
const result = await s3.copy(sourceKey, destKey, { contentType });
|
||||||
logger.debug({ sourceKey, destKey, provider: 's3' }, 'File copied (server-side)');
|
logger.debug(
|
||||||
|
{ sourceKey, destKey, provider: 's3' },
|
||||||
|
'File copied (server-side)',
|
||||||
|
);
|
||||||
return { url: result.url };
|
return { url: result.url };
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -969,7 +968,9 @@ const copyFile = async (sourceKey, destKey, options = {}) => {
|
|||||||
const local = getLocalProvider();
|
const local = getLocalProvider();
|
||||||
await local.copy(sourceKey, destKey);
|
await local.copy(sourceKey, destKey);
|
||||||
logger.debug({ sourceKey, destKey, provider: 'local' }, 'File copied');
|
logger.debug({ sourceKey, destKey, provider: 'local' }, 'File copied');
|
||||||
return { url: `/api/file/download?privateUrl=${encodeURIComponent(destKey)}` };
|
return {
|
||||||
|
url: `/api/file/download?privateUrl=${encodeURIComponent(destKey)}`,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
// GCloud fallback: download + upload (no native copy implemented)
|
// GCloud fallback: download + upload (no native copy implemented)
|
||||||
@ -1029,13 +1030,20 @@ const copyFilesParallel = async (copies, options = {}) => {
|
|||||||
throw new Error(`Copy failed for ${copy.sourceKey}: ${errorMsg}`);
|
throw new Error(`Copy failed for ${copy.sourceKey}: ${errorMsg}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.warn({ sourceKey: copy.sourceKey, error: errorMsg }, 'File copy failed');
|
logger.warn(
|
||||||
|
{ sourceKey: copy.sourceKey, error: errorMsg },
|
||||||
|
'File copy failed',
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
logger.info(
|
logger.info(
|
||||||
{ succeeded: succeeded.length, failed: failed.length, total: copies.length },
|
{
|
||||||
|
succeeded: succeeded.length,
|
||||||
|
failed: failed.length,
|
||||||
|
total: copies.length,
|
||||||
|
},
|
||||||
'Batch file copy completed',
|
'Batch file copy completed',
|
||||||
);
|
);
|
||||||
|
|
||||||
|
|||||||
@ -124,7 +124,11 @@ module.exports = class Project_transition_settingsService {
|
|||||||
/**
|
/**
|
||||||
* Find settings by project ID and environment
|
* Find settings by project ID and environment
|
||||||
*/
|
*/
|
||||||
static async findByProjectAndEnvironment(projectId, environment, currentUser) {
|
static async findByProjectAndEnvironment(
|
||||||
|
projectId,
|
||||||
|
environment,
|
||||||
|
currentUser,
|
||||||
|
) {
|
||||||
return Project_transition_settingsDBApi.findByProjectAndEnvironment(
|
return Project_transition_settingsDBApi.findByProjectAndEnvironment(
|
||||||
projectId,
|
projectId,
|
||||||
environment,
|
environment,
|
||||||
|
|||||||
@ -293,10 +293,13 @@ class ProjectsService extends BaseProjectsService {
|
|||||||
'Starting parallel file copy for project clone',
|
'Starting parallel file copy for project clone',
|
||||||
);
|
);
|
||||||
|
|
||||||
const { succeeded, failed } = await FileService.copyFilesParallel(copyOperations, {
|
const { succeeded, failed } = await FileService.copyFilesParallel(
|
||||||
concurrency: 10,
|
copyOperations,
|
||||||
continueOnError: true,
|
{
|
||||||
});
|
concurrency: 10,
|
||||||
|
continueOnError: true,
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// ============================================
|
// ============================================
|
||||||
// Phase D: Build assetPathMap from results
|
// Phase D: Build assetPathMap from results
|
||||||
@ -322,7 +325,9 @@ class ProjectsService extends BaseProjectsService {
|
|||||||
asset_type: sourceAsset.asset_type,
|
asset_type: sourceAsset.asset_type,
|
||||||
type: sourceAsset.type || 'general',
|
type: sourceAsset.type || 'general',
|
||||||
cdn_url: '', // Will be populated on first presigned URL request
|
cdn_url: '', // Will be populated on first presigned URL request
|
||||||
storage_key: assetPathMap.get(sourceAsset.storage_key) || sourceAsset.storage_key,
|
storage_key:
|
||||||
|
assetPathMap.get(sourceAsset.storage_key) ||
|
||||||
|
sourceAsset.storage_key,
|
||||||
mime_type: sourceAsset.mime_type,
|
mime_type: sourceAsset.mime_type,
|
||||||
size_mb: sourceAsset.size_mb,
|
size_mb: sourceAsset.size_mb,
|
||||||
width_px: sourceAsset.width_px,
|
width_px: sourceAsset.width_px,
|
||||||
@ -345,7 +350,8 @@ class ProjectsService extends BaseProjectsService {
|
|||||||
if (sourceVariant.variant_type === 'reversed') continue; // Handled in Phase F
|
if (sourceVariant.variant_type === 'reversed') continue; // Handled in Phase F
|
||||||
|
|
||||||
const variantStorageKey =
|
const variantStorageKey =
|
||||||
assetPathMap.get(sourceVariant.storage_key) || sourceVariant.storage_key;
|
assetPathMap.get(sourceVariant.storage_key) ||
|
||||||
|
sourceVariant.storage_key;
|
||||||
|
|
||||||
await db.asset_variants.create(
|
await db.asset_variants.create(
|
||||||
{
|
{
|
||||||
@ -385,10 +391,13 @@ class ProjectsService extends BaseProjectsService {
|
|||||||
'Copying reversed videos for cloned assets',
|
'Copying reversed videos for cloned assets',
|
||||||
);
|
);
|
||||||
|
|
||||||
const reversedResults = await FileService.copyFilesParallel(reversedCopyOps, {
|
const reversedResults = await FileService.copyFilesParallel(
|
||||||
concurrency: 10,
|
reversedCopyOps,
|
||||||
continueOnError: true, // Many assets won't have reversed videos - that's OK
|
{
|
||||||
});
|
concurrency: 10,
|
||||||
|
continueOnError: true, // Many assets won't have reversed videos - that's OK
|
||||||
|
},
|
||||||
|
);
|
||||||
|
|
||||||
// Add successful reversed video copies to assetPathMap
|
// Add successful reversed video copies to assetPathMap
|
||||||
for (const { sourceKey, destKey } of reversedResults.succeeded) {
|
for (const { sourceKey, destKey } of reversedResults.succeeded) {
|
||||||
@ -431,15 +440,18 @@ class ProjectsService extends BaseProjectsService {
|
|||||||
// Transform background URLs to new storage keys
|
// Transform background URLs to new storage keys
|
||||||
if (pageData.background_image_url) {
|
if (pageData.background_image_url) {
|
||||||
pageData.background_image_url =
|
pageData.background_image_url =
|
||||||
assetPathMap.get(pageData.background_image_url) || pageData.background_image_url;
|
assetPathMap.get(pageData.background_image_url) ||
|
||||||
|
pageData.background_image_url;
|
||||||
}
|
}
|
||||||
if (pageData.background_video_url) {
|
if (pageData.background_video_url) {
|
||||||
pageData.background_video_url =
|
pageData.background_video_url =
|
||||||
assetPathMap.get(pageData.background_video_url) || pageData.background_video_url;
|
assetPathMap.get(pageData.background_video_url) ||
|
||||||
|
pageData.background_video_url;
|
||||||
}
|
}
|
||||||
if (pageData.background_audio_url) {
|
if (pageData.background_audio_url) {
|
||||||
pageData.background_audio_url =
|
pageData.background_audio_url =
|
||||||
assetPathMap.get(pageData.background_audio_url) || pageData.background_audio_url;
|
assetPathMap.get(pageData.background_audio_url) ||
|
||||||
|
pageData.background_audio_url;
|
||||||
}
|
}
|
||||||
|
|
||||||
await db.tour_pages.create(
|
await db.tour_pages.create(
|
||||||
|
|||||||
@ -257,20 +257,21 @@ module.exports = class PublishService {
|
|||||||
transaction,
|
transaction,
|
||||||
) {
|
) {
|
||||||
// Get source content
|
// Get source content
|
||||||
const [sourcePages, sourceAudioTracks, sourceTransitionSettings] = await Promise.all([
|
const [sourcePages, sourceAudioTracks, sourceTransitionSettings] =
|
||||||
db.tour_pages.findAll({
|
await Promise.all([
|
||||||
where: { projectId, environment: fromEnv },
|
db.tour_pages.findAll({
|
||||||
transaction,
|
where: { projectId, environment: fromEnv },
|
||||||
}),
|
transaction,
|
||||||
db.project_audio_tracks.findAll({
|
}),
|
||||||
where: { projectId, environment: fromEnv },
|
db.project_audio_tracks.findAll({
|
||||||
transaction,
|
where: { projectId, environment: fromEnv },
|
||||||
}),
|
transaction,
|
||||||
db.project_transition_settings.findOne({
|
}),
|
||||||
where: { projectId, environment: fromEnv },
|
db.project_transition_settings.findOne({
|
||||||
transaction,
|
where: { projectId, environment: fromEnv },
|
||||||
}),
|
transaction,
|
||||||
]);
|
}),
|
||||||
|
]);
|
||||||
|
|
||||||
// Clean up target environment (hard delete - paranoid models need force: true)
|
// Clean up target environment (hard delete - paranoid models need force: true)
|
||||||
await Promise.all([
|
await Promise.all([
|
||||||
|
|||||||
@ -773,19 +773,20 @@ export function ElementEditorPanel({
|
|||||||
selectedElement.type === 'gallery'
|
selectedElement.type === 'gallery'
|
||||||
? selectedElement.gallerySlideTransitionDurationMs !==
|
? selectedElement.gallerySlideTransitionDurationMs !==
|
||||||
undefined &&
|
undefined &&
|
||||||
selectedElement.gallerySlideTransitionDurationMs !== ''
|
selectedElement.gallerySlideTransitionDurationMs !==
|
||||||
|
''
|
||||||
? String(
|
? String(
|
||||||
selectedElement.gallerySlideTransitionDurationMs,
|
selectedElement.gallerySlideTransitionDurationMs,
|
||||||
)
|
)
|
||||||
: ''
|
: ''
|
||||||
: selectedElement.carouselSlideTransitionDurationMs !==
|
: selectedElement.carouselSlideTransitionDurationMs !==
|
||||||
undefined &&
|
undefined &&
|
||||||
selectedElement.carouselSlideTransitionDurationMs !==
|
selectedElement.carouselSlideTransitionDurationMs !==
|
||||||
''
|
''
|
||||||
? String(
|
? String(
|
||||||
selectedElement.carouselSlideTransitionDurationMs,
|
selectedElement.carouselSlideTransitionDurationMs,
|
||||||
)
|
)
|
||||||
: '',
|
: '',
|
||||||
slideTransitionEasing:
|
slideTransitionEasing:
|
||||||
selectedElement.type === 'gallery'
|
selectedElement.type === 'gallery'
|
||||||
? selectedElement.gallerySlideTransitionEasing || ''
|
? selectedElement.gallerySlideTransitionEasing || ''
|
||||||
@ -848,7 +849,8 @@ export function ElementEditorPanel({
|
|||||||
} else if (prop === 'slideTransitionOverlayColor') {
|
} else if (prop === 'slideTransitionOverlayColor') {
|
||||||
if (selectedElement.type === 'gallery') {
|
if (selectedElement.type === 'gallery') {
|
||||||
updateSelectedElement({
|
updateSelectedElement({
|
||||||
gallerySlideTransitionOverlayColor: value || undefined,
|
gallerySlideTransitionOverlayColor:
|
||||||
|
value || undefined,
|
||||||
});
|
});
|
||||||
} else if (selectedElement.type === 'carousel') {
|
} else if (selectedElement.type === 'carousel') {
|
||||||
updateSelectedElement({
|
updateSelectedElement({
|
||||||
|
|||||||
@ -270,7 +270,9 @@ const EffectsSettingsSectionCompact: React.FC<
|
|||||||
<select
|
<select
|
||||||
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
className='w-full rounded border border-gray-300 px-2 py-1 text-xs'
|
||||||
value={values.slideTransitionType || ''}
|
value={values.slideTransitionType || ''}
|
||||||
onChange={(e) => onChange('slideTransitionType', e.target.value)}
|
onChange={(e) =>
|
||||||
|
onChange('slideTransitionType', e.target.value)
|
||||||
|
}
|
||||||
>
|
>
|
||||||
<option value=''>Use Default</option>
|
<option value=''>Use Default</option>
|
||||||
<option value='fade'>Fade</option>
|
<option value='fade'>Fade</option>
|
||||||
|
|||||||
@ -14,7 +14,13 @@
|
|||||||
* - Navigation-style rendering when custom icons with dimensions are set
|
* - Navigation-style rendering when custom icons with dimensions are set
|
||||||
*/
|
*/
|
||||||
|
|
||||||
import React, { useMemo, useCallback, useEffect, useRef, useState } from 'react';
|
import React, {
|
||||||
|
useMemo,
|
||||||
|
useCallback,
|
||||||
|
useEffect,
|
||||||
|
useRef,
|
||||||
|
useState,
|
||||||
|
} from 'react';
|
||||||
import { createPortal } from 'react-dom';
|
import { createPortal } from 'react-dom';
|
||||||
import type { CSSProperties } from 'react';
|
import type { CSSProperties } from 'react';
|
||||||
import Icon from '@mdi/react';
|
import Icon from '@mdi/react';
|
||||||
|
|||||||
@ -110,12 +110,15 @@ export function resolveSlideTransition(
|
|||||||
* Extract slide transition override from carousel element
|
* Extract slide transition override from carousel element
|
||||||
*/
|
*/
|
||||||
export function extractCarouselSlideOverride(
|
export function extractCarouselSlideOverride(
|
||||||
element: {
|
element:
|
||||||
carouselSlideTransitionType?: SlideTransitionType | '';
|
| {
|
||||||
carouselSlideTransitionDurationMs?: number | '';
|
carouselSlideTransitionType?: SlideTransitionType | '';
|
||||||
carouselSlideTransitionEasing?: EasingFunction | '';
|
carouselSlideTransitionDurationMs?: number | '';
|
||||||
carouselSlideTransitionOverlayColor?: string;
|
carouselSlideTransitionEasing?: EasingFunction | '';
|
||||||
} | null | undefined,
|
carouselSlideTransitionOverlayColor?: string;
|
||||||
|
}
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
): SlideTransitionOverride | null {
|
): SlideTransitionOverride | null {
|
||||||
if (!element) return null;
|
if (!element) return null;
|
||||||
return {
|
return {
|
||||||
@ -130,12 +133,15 @@ export function extractCarouselSlideOverride(
|
|||||||
* Extract slide transition override from gallery element
|
* Extract slide transition override from gallery element
|
||||||
*/
|
*/
|
||||||
export function extractGallerySlideOverride(
|
export function extractGallerySlideOverride(
|
||||||
element: {
|
element:
|
||||||
gallerySlideTransitionType?: SlideTransitionType | '';
|
| {
|
||||||
gallerySlideTransitionDurationMs?: number | '';
|
gallerySlideTransitionType?: SlideTransitionType | '';
|
||||||
gallerySlideTransitionEasing?: EasingFunction | '';
|
gallerySlideTransitionDurationMs?: number | '';
|
||||||
gallerySlideTransitionOverlayColor?: string;
|
gallerySlideTransitionEasing?: EasingFunction | '';
|
||||||
} | null | undefined,
|
gallerySlideTransitionOverlayColor?: string;
|
||||||
|
}
|
||||||
|
| null
|
||||||
|
| undefined,
|
||||||
): SlideTransitionOverride | null {
|
): SlideTransitionOverride | null {
|
||||||
if (!element) return null;
|
if (!element) return null;
|
||||||
return {
|
return {
|
||||||
|
|||||||
@ -347,7 +347,9 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
// Look up current element for gallery carousel (so it receives updates from element editor)
|
// Look up current element for gallery carousel (so it receives updates from element editor)
|
||||||
const activeGalleryCarouselElement = useMemo(() => {
|
const activeGalleryCarouselElement = useMemo(() => {
|
||||||
if (!activeGalleryCarousel) return null;
|
if (!activeGalleryCarousel) return null;
|
||||||
return elements.find((el) => el.id === activeGalleryCarousel.elementId) || null;
|
return (
|
||||||
|
elements.find((el) => el.id === activeGalleryCarousel.elementId) || null
|
||||||
|
);
|
||||||
}, [activeGalleryCarousel, elements]);
|
}, [activeGalleryCarousel, elements]);
|
||||||
|
|
||||||
// Draggable panels using useDraggable hook
|
// Draggable panels using useDraggable hook
|
||||||
@ -1303,7 +1305,10 @@ const ConstructorPage = ({ mode = 'constructor' }: ConstructorPageProps) => {
|
|||||||
const handleGalleryCardClick = useCallback(
|
const handleGalleryCardClick = useCallback(
|
||||||
(element: CanvasElement, cardIndex: number) => {
|
(element: CanvasElement, cardIndex: number) => {
|
||||||
if (element.galleryCards && element.galleryCards.length > 0) {
|
if (element.galleryCards && element.galleryCards.length > 0) {
|
||||||
setActiveGalleryCarousel({ elementId: element.id, initialIndex: cardIndex });
|
setActiveGalleryCarousel({
|
||||||
|
elementId: element.id,
|
||||||
|
initialIndex: cardIndex,
|
||||||
|
});
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
[],
|
[],
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user