Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Video data object data type #842

Merged
merged 16 commits into from
Jan 10, 2025
Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions assets/js/src/core/app/config/services/index.ts
Original file line number Diff line number Diff line change
Expand Up @@ -107,6 +107,7 @@ import { DynamicTypeObjectDataDateRange } from '@Pimcore/modules/element/dynamic
import { DynamicTypeObjectDataTime } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-time'
import { DynamicTypeObjectDataExternalImage } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-external-image'
import { DynamicTypeObjectDataImage } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-image'
import { DynamicTypeObjectDataVideo } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-video'
import { DynamicTypeObjectDataImageGallery } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-image-gallery'
import { DynamicTypeObjectDataGeoPoint } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-geopoint'
import { DynamicTypeObjectDataGeoBounds } from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/types/dynamic-type-object-data-geobounds'
Expand Down Expand Up @@ -255,6 +256,7 @@ container.bind(serviceIds['DynamicTypes/ObjectData/DateRange']).to(DynamicTypeOb
container.bind(serviceIds['DynamicTypes/ObjectData/Time']).to(DynamicTypeObjectDataTime).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ExternalImage']).to(DynamicTypeObjectDataExternalImage).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/Image']).to(DynamicTypeObjectDataImage).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/Video']).to(DynamicTypeObjectDataVideo).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/ImageGallery']).to(DynamicTypeObjectDataImageGallery).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/GeoPoint']).to(DynamicTypeObjectDataGeoPoint).inSingletonScope()
container.bind(serviceIds['DynamicTypes/ObjectData/GeoBounds']).to(DynamicTypeObjectDataGeoBounds).inSingletonScope()
Expand Down
1 change: 1 addition & 0 deletions assets/js/src/core/app/config/services/service-ids.ts
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,7 @@ export const serviceIds = {
'DynamicTypes/ObjectData/Time': 'DynamicTypes/ObjectData/Time',
'DynamicTypes/ObjectData/ExternalImage': 'DynamicTypes/ObjectData/ExternalImage',
'DynamicTypes/ObjectData/Image': 'DynamicTypes/ObjectData/Image',
'DynamicTypes/ObjectData/Video': 'DynamicTypes/ObjectData/Video',
'DynamicTypes/ObjectData/ImageGallery': 'DynamicTypes/ObjectData/ImageGallery',
'DynamicTypes/ObjectData/GeoPoint': 'DynamicTypes/ObjectData/GeoPoint',
'DynamicTypes/ObjectData/GeoBounds': 'DynamicTypes/ObjectData/GeoBounds',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,11 +12,11 @@
*/

import { type Meta } from '@storybook/react'
import { ImageTarget } from './image-target'
import { AssetTarget } from './asset-target'

const config: Meta = {
title: 'Components/Data Display/ImageTarget',
component: ImageTarget,
title: 'Components/Data Display/AssetTarget',
component: AssetTarget,
tags: ['autodocs']
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@ import { createStyles } from 'antd-style'

export const useStyle = createStyles(({ token, css }) => {
return {
imageTargetContainer: css`
assetTargetContainer: css`
border-radius: ${token.borderRadiusLG}px;
outline: 1px dashed ${token.colorBorder};
background: ${token.controlItemBgHover};
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@

import React, { forwardRef, type MutableRefObject } from 'react'
import { Flex } from '@Pimcore/components/flex/flex'
import { useStyle } from './image-target.styles'
import { useStyle } from './asset-target.styles'
import cn from 'classnames'
import { toCssDimension } from '@Pimcore/utils/css'
import { Icon } from '@Pimcore/components/icon/icon'
Expand All @@ -22,7 +22,7 @@ import { IconButton } from '@Pimcore/components/icon-button/icon-button'
import { Tooltip } from 'antd'
import { useTranslation } from 'react-i18next'

interface ImageTargetProps {
interface AssetTargetProps {
onRemove?: (event: React.MouseEvent<HTMLButtonElement>) => void
title: string
className?: string
Expand All @@ -32,14 +32,14 @@ interface ImageTargetProps {
uploadIcon?: boolean
}

export const ImageTarget = forwardRef(function ImageTarget ({ title, className, width = 200, height = 200, dndIcon, uploadIcon, onRemove }: ImageTargetProps, ref: MutableRefObject<HTMLDivElement>): React.JSX.Element {
export const AssetTarget = forwardRef(function AssetTarget ({ title, className, width = 200, height = 200, dndIcon, uploadIcon, onRemove }: AssetTargetProps, ref: MutableRefObject<HTMLDivElement>): React.JSX.Element {
const { getStateClasses } = useDroppable()
const { styles } = useStyle()
const { t } = useTranslation()

return (
<div
className={ cn(className, styles.imageTargetContainer, ...getStateClasses()) }
className={ cn(className, styles.assetTargetContainer, ...getStateClasses()) }
ref={ ref }
style={ {
height: toCssDimension(height),
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -97,7 +97,7 @@ export const DragAndDropContextProvider = ({ children }: { children: ReactNode }
<DragOverlay
className='dnd-overlay'
dropAnimation={ null }
style={ { width: 'max-content' } }
style={ { width: 'max-content', zIndex: 1001 } }
>
<StyledDragOverlay info={ info } />
</DragOverlay>
Expand Down
70 changes: 50 additions & 20 deletions assets/js/src/core/components/image-preview/image-preview.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -26,6 +26,7 @@ import { ImagePreviewDropdown } from '@Pimcore/components/image-preview/componen
interface ImagePreviewProps {
src?: string
assetId?: number
assetType?: 'image' | 'video'
className?: string
width: number | string
height: number | string
Expand All @@ -34,12 +35,37 @@ interface ImagePreviewProps {
dropdownItems?: DropdownProps['menu']['items']
}

export const ImagePreview = forwardRef(function ImagePreview ({ src, assetId, width, height, className, style, dropdownItems, bordered = false }: ImagePreviewProps, ref: MutableRefObject<HTMLDivElement>): React.JSX.Element {
export const ImagePreview = forwardRef(function ImagePreview ({ src, assetId, assetType, width, height, className, style, dropdownItems, bordered = false }: ImagePreviewProps, ref: MutableRefObject<HTMLDivElement>): React.JSX.Element {
const [key, setKey] = React.useState(0)
const [thumbnailDimensions, setThumbnailDimensions] = React.useState({ width: 0, height: 0 })
const { getStateClasses } = useDroppable()
const { styles } = useStyle()
const wrapperRef = React.useRef<HTMLDivElement>(null)

const imageSrc = assetId !== undefined ? `${getPrefix()}/assets/${assetId}/image/stream/preview` : src
const getAssetPreviewUrl = (): string | undefined => {
const { width, height } = thumbnailDimensions

if (width === 0 || height === 0) {
return undefined
}

if (assetType === 'video') {
return `${getPrefix()}/assets/${assetId}/video/stream/image-thumbnail?width=${width}&height=${height}&frame=true&aspectRatio=true`
}

return `${getPrefix()}/assets/${assetId}/image/stream/custom?width=${width}&height=${height}&mimeType=JPEG&resizeMode=none&frame=true`
}

const imageSrc = assetId !== undefined ? getAssetPreviewUrl() : src

useEffect(() => {
if (wrapperRef?.current !== null && wrapperRef?.current !== undefined) {
setThumbnailDimensions({
width: wrapperRef.current.offsetWidth,
height: wrapperRef.current.offsetHeight
})
}
}, [wrapperRef, width, height])

useEffect(() => {
setKey(key + 1)
Expand All @@ -56,25 +82,29 @@ export const ImagePreview = forwardRef(function ImagePreview ({ src, assetId, wi
)

return (
<div
className={ cn(className, styles.imagePreviewContainer, bordered ? 'image-preview-bordered' : undefined, ...getStateClasses()) }
ref={ ref }
style={ {
...style,
height: toCssDimension(height),
width: toCssDimension(width)
} }
>
<Image
className="w-full"
fallback="/bundles/pimcorestudioui/img/fallback-image.svg"
key={ key }
placeholder={ loadingSpinner }
preview={ false }
src={ imageSrc }
/>
<div ref={ ref }>
<div
className={ cn(className, styles.imagePreviewContainer, bordered ? 'image-preview-bordered' : undefined, ...getStateClasses()) }
ref={ wrapperRef }
style={ {
...style,
height: toCssDimension(height),
width: toCssDimension(width)
} }
>
{ imageSrc !== undefined && (
<Image
className="w-full"
fallback="/bundles/pimcorestudioui/img/fallback-image.svg"
key={ key }
placeholder={ loadingSpinner }
preview={ false }
src={ imageSrc }
/>
) }

<ImagePreviewDropdown dropdownItems={ dropdownItems } />
<ImagePreviewDropdown dropdownItems={ dropdownItems } />
</div>
</div>
)
})
3 changes: 0 additions & 3 deletions assets/js/src/core/components/modal/modal.styles.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,9 +16,6 @@ import { createStyles } from 'antd-style'
export const useStyle = createStyles(({ token, css }) => {
return {
modal: css`
&.ant-modal .ant-modal-footer > .ant-btn + .ant-btn {
margin-inline-start: 0;
}

.ant-modal-content {
width: 100%;
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import { createStyles } from 'antd-style'

export const useStyle = createStyles(({ token, css }) => {
return {
modal: css`
.ant-modal-content {
outline: 1px solid ${token.colorBorderContainer};
box-shadow: ${token.boxShadowSecondary} !important;
}
`
}
}, { hashPriority: 'low' })
91 changes: 91 additions & 0 deletions assets/js/src/core/components/modal/window-modal/window-modal.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,91 @@
/**
* Pimcore
*
* This source file is available under two different licenses:
* - Pimcore Open Core License (POCL)
* - Pimcore Commercial License (PCL)
* Full copyright and license information is available in
* LICENSE.md which is distributed with this source code.
*
* @copyright Copyright (c) Pimcore GmbH (http://www.pimcore.org)
* @license https://github.com/pimcore/studio-ui-bundle/blob/1.x/LICENSE.md POCL and PCL
*/

import React, { useState, useRef } from 'react'
import { type IModalProps, Modal } from '@Pimcore/components/modal/modal'
import type { DraggableData, DraggableEvent } from 'react-draggable'
import Draggable from 'react-draggable'
import { useStyle } from './window-modal.styles'
import cn from 'classnames'
import { Icon } from '@Pimcore/components/icon/icon'
import { Flex } from '@Pimcore/components/flex/flex'

export interface IWindowModalProps extends Omit<IModalProps, 'mask' | 'maskClosable' | 'maskStyle' | 'maskTransitionName' | 'wrapStyle' | 'modalRender'> {

}

export const WindowModal = (props: IWindowModalProps): React.JSX.Element => {
const { styles } = useStyle()

const [disabled, setDisabled] = useState(true)
const [bounds, setBounds] = useState({ left: 0, top: 0, bottom: 0, right: 0 })
const draggleRef = useRef<HTMLDivElement>(null!)

const onStart = (_event: DraggableEvent, uiData: DraggableData): void => {
const { clientWidth, clientHeight } = window.document.documentElement
const targetRect = draggleRef.current?.getBoundingClientRect()
if (targetRect === undefined) {
return
}
setBounds({
left: -targetRect.left + uiData.x,
right: clientWidth - (targetRect.right - uiData.x),
top: -targetRect.top + uiData.y,
bottom: clientHeight - (targetRect.bottom - uiData.y)
})
}

return (
<Modal
{ ...props }
className={ cn(styles.modal, props.className) }
mask={ false }
maskClosable={ false }
modalRender={ (modal) => (
<Draggable
bounds={ bounds }
disabled={ disabled }
nodeRef={ draggleRef }
onStart={ (event, uiData) => { onStart(event, uiData) } }
>
<div ref={ draggleRef }>{modal}</div>
</Draggable>
) }
title={
<div
onBlur={ () => {} }
onFocus={ () => {} }
onMouseOut={ () => {
setDisabled(true)
} }
onMouseOver={ () => {
if (disabled) {
setDisabled(false)
}
} }
// fix eslintjsx-a11y/mouse-events-have-key-events
// https://github.com/jsx-eslint/eslint-plugin-jsx-a11y/blob/master/docs/rules/mouse-events-have-key-events.md
style={ { width: '100%', cursor: 'move', flex: 1 } }
// end
>
<Flex gap="small">
{props.title ?? <Icon value={ 'drag-option' } />}
</Flex>
</div>
}
wrapStyle={ { pointerEvents: 'none' } }
>
{props.children}
</Modal>
)
}
Original file line number Diff line number Diff line change
Expand Up @@ -16,7 +16,7 @@ import { Card } from '@Pimcore/components/card/card'
import {
ExternalImageFooter
} from '@Pimcore/modules/element/dynamic-types/defintinitions/objects/data-related/components/external-image/footer'
import { ImageTarget } from '@Pimcore/components/image-target/image-target'
import { AssetTarget } from '@Pimcore/components/asset-target/asset-target'
import { useTranslation } from 'react-i18next'
import { ImagePreview } from '@Pimcore/components/image-preview/image-preview'

Expand Down Expand Up @@ -71,7 +71,7 @@ export const ExternalImage = (props: ExternalImageProps): React.JSX.Element => {
/>
)
: (
<ImageTarget
<AssetTarget
height={ previewHeight }
title={ t('external-image.preview-placeholder') }
width={ previewWidth }
Expand Down
Loading
Loading