Skip to content

Commit

Permalink
video preview and duration
Browse files Browse the repository at this point in the history
  • Loading branch information
nikigan committed Jul 7, 2024
1 parent b3719b6 commit 22c65cb
Show file tree
Hide file tree
Showing 4 changed files with 213 additions and 35 deletions.
4 changes: 2 additions & 2 deletions src/App.js
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ import { StableDiffusionSection } from './sections/stable-diffusion-section';
import { MyDesignsSection } from './sections/my-designs-section';

import { AIWriteMenu } from './ai-text';
// import { VideosSection } from './sections/video-section';
import { VideosSection } from './sections/video-section';
// import { UploadSection } from './sections/upload-section';

import { useProject } from './project';
Expand Down Expand Up @@ -49,7 +49,7 @@ DEFAULT_SECTIONS.push(QuotesSection, QrSection);
DEFAULT_SECTIONS.unshift(MyDesignsSection);

DEFAULT_SECTIONS.push(StableDiffusionSection);
// DEFAULT_SECTIONS.push(VideosSection);
DEFAULT_SECTIONS.push(VideosSection);

const isStandalone = () => {
return (
Expand Down
68 changes: 68 additions & 0 deletions src/sections/video-grid/video-grid.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
.video-grid {
height: 100%;
overflow: auto;
}

.video-grid__col {
width: 50%;
float: left;
}

.video-grid__item-wrapper {
width: 100%;
padding: 5px;
}

.video-grid__item-wrapper:hover .video-grid__item-credit {
opacity: 1;
}

.video-grid__item {
position: relative;
}

.video-grid__item img,video {
width: 100%;
cursor: pointer;
display: block;
max-height: 300px;
min-height: 50px;
object-fit: contain;
}

.video-grid__item-duration-wrapper {
position: absolute;
top: .5rem;
right: .5rem;
background-color: rgba(0, 0, 0, 0.5);
color: white;
padding: 2px 7px;
text-align: center;
display: flex;
justify-content: center;
align-items: center;
border-radius: 4rem;
}

.video-grid__item-duration {
font-size: 12px;
}

.video-grid__loader {
padding: 3rem;
}

.video-grid__item-credit {
position: absolute;
opacity: 0;
bottom: 0;
left: 0;
right: 0;
padding: 3px;
background: linear-gradient(to bottom, rgba(0, 0, 0, 0), rgba(0, 0, 0, 0.4), rgba(0, 0, 0, 0.6));
color: white;
font-size: 10px;
text-align: center;
}


112 changes: 112 additions & 0 deletions src/sections/video-grid/video-grid.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,112 @@
import React, { useCallback, useRef } from 'react';
import { registerNextDomDrop } from 'polotno/canvas/page';
import { Spinner } from '@blueprintjs/core';
import './video-grid.css';


export const VideoGrid = ({ items, onSelect, loadMore, isLoading, error, getCredit }) => {
const observer = useRef(null);

const lastPosElementRef = useCallback(
(node) => {
if (isLoading) return;
if (observer.current) observer.current.disconnect();

observer.current = new IntersectionObserver((entries) => {
if (entries[0].isIntersecting) {
loadMore(); // trigger loading
}
});

if (node) observer.current.observe(node);
},
[isLoading]
);

if (error) {
return <div>{error.message}</div>;
}

if (!items || items.length === 0) {
return null;
}

const odds = items.filter((_, idx) => idx % 2 === 1);
const evens = items.filter((_, idx) => idx % 2 === 0);


return <div className="video-grid">
{[odds, evens].map((col, idx) => (
<div key={idx} className="video-grid__col">
{col.map((item) =>
(<VideoItem key={item.id}
item={item}
onClick={() => onSelect(item)}
onDragStart={(e) => {
registerNextDomDrop((pos, el) => {
onSelect(item, pos, el);
});
}}
onDragEnd={() => registerNextDomDrop(null)}
getCredit={getCredit}/>
))}
<div className="video-grid__loader" ref={lastPosElementRef}>{isLoading && <Spinner/>}</div>
</div>
))}
</div>;
};

const VideoItem = ({ item, onClick, onDragEnd, onDragStart, getCredit }) => {
const videoRef = useRef(null);

const onHover = () => {
videoRef.current.play()?.catch(() => {
});
};

const onLeave = () => {
videoRef.current.pause()?.catch(() => {
});
videoRef.current.currentTime = 0;
};

const src = item.video_files.find((f) => f.quality === 'sd')?.link || '';

if (!src) {
return null;
}

const dateString = new Date(item.duration * 1000).toISOString();

let duration;
if (item.duration > 3600) {
duration = dateString.substring(11, 19);
} else {
duration = dateString.substring(14, 19);
}

return (
<div className="video-grid__item-wrapper">
<div className="video-grid__item"
draggable
onClick={onClick}
onDragEnd={onDragEnd}
onDragStart={onDragStart}
onMouseEnter={onHover}
onMouseLeave={onLeave}>
<video poster={item.image}
controls={false}
ref={videoRef}
muted
preload="none">
<source src={src}/>
</video>
<div className="video-grid__item-duration-wrapper">
<span
className="video-grid__item-duration">{duration}</span>
</div>
{getCredit && <div className="video-grid__item-credit">{getCredit(item)}</div>}
</div>
</div>
);
};
64 changes: 31 additions & 33 deletions src/sections/video-section.js
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from 'react';
import { InputGroup } from '@blueprintjs/core';
import { ImagesGrid } from 'polotno/side-panel/images-grid';
import { getVideoSize } from 'polotno/utils/video';
import { SectionTab } from 'polotno/side-panel';
import { useInfiniteAPI } from 'polotno/utils/use-api';
import { t } from 'polotno/utils/l10n';
import { Video } from '@blueprintjs/icons';
import { selectVideo } from 'polotno/side-panel/select-video';
import { VideoGrid } from './video-grid/video-grid';

// this is a demo key just for that project
// (!) please don't use it in your projects
Expand Down Expand Up @@ -50,44 +49,43 @@ export const VideosPanel = ({ store }) => {
Pexels
</a>
</p>
<ImagesGrid
images={data
?.map((item) => item.videos)
.flat()
.filter(Boolean)}
getPreview={(image) => image.image}
onSelect={async (image, pos, element) => {
const src =
image.video_files.find((f) => f.quality === 'hd')?.link ||
image.video_files[0].link;
<VideoGrid
items={data
?.map((item) => item.videos)
.flat()
.filter(Boolean)}
isLoading={isLoading}
error={error}
loadMore={!isReachingEnd && loadMore}
onSelect={async (image, pos, element) => {
const src =
image.video_files.find((f) => f.quality === 'hd')?.link ||
image.video_files[0].link;

selectVideo({
src,
store,
droppedPos: pos,
targetElement: element,
});
}}
isLoading={isLoading}
error={error}
loadMore={!isReachingEnd && loadMore}
getCredit={(image) => (
<span>
selectVideo({
src,
store,
droppedPos: pos,
targetElement: element,
});
}}
getCredit={(image) => (
<span>
Video by{' '}
<a href={image.user.url} target="_blank" rel="noreferrer">
<a href={image.user.url} target="_blank" rel="noreferrer">
{image.user.name}
</a>{' '}
on{' '}
<a
href="https://pexels.com/?utm_source=polotno&utm_medium=referral"
target="_blank"
rel="noreferrer noopener"
>
on{' '}
<a
href="https://pexels.com/?utm_source=polotno&utm_medium=referral"
target="_blank"
rel="noreferrer noopener"
>
Pexels
</a>
</span>
)}
/>
)}
/>
</div>
);
};
Expand Down

0 comments on commit 22c65cb

Please sign in to comment.