Skip to content

Commit

Permalink
🌟feat: support previewing videos and audio #18
Browse files Browse the repository at this point in the history
  • Loading branch information
blinko-space committed Nov 7, 2024
1 parent dc509b5 commit c1377b0
Show file tree
Hide file tree
Showing 8 changed files with 1,399 additions and 29 deletions.
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"name": "blinko",
"version": "0.0.20",
"version": "0.0.21",
"private": true,
"browser": {
"fs": false,
Expand Down
1,323 changes: 1,321 additions & 2 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

68 changes: 52 additions & 16 deletions src/components/Common/Editor/attachmentsRender.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -39,50 +39,87 @@ const AttachmentsRender = observer(({ files, preview = false, columns = 3 }: IPr
}
})
}))
const DeleteIcon = observer(({ className, file }: { className: string, file: FileType }) => {

const DeleteIcon = observer(({ className, file, size = 20 }: { className: string, file: FileType, size?: number }) => {
return <>
<TipsPopover isLoading={store.deleteFile.loading.value} content={t('this-operation-will-be-delete-resource-are-you-sure')}
onConfirm={async e => {
store.deleteFile.call(file)
}}>
<Icon className={className}
icon="basil:cross-solid" width="20" height="20" />
<div className={`opacity-70 hover:opacity-100 !bg-foreground cursor-pointer rounded-sm transition-al ${className}`}>
<Icon className='white' icon="basil:cross-solid" width={size} height={size} />
</div>

</TipsPopover >
</>
})

const DownloadIcon = observer(({ className, file, size = 20 }: { className: string, file: FileType, size?: number }) => {
return <div className={`hidden p-1 group-hover:block transition-all absolute z-10 right-[5px] top-[5px] !text-background opacity-70 hover:opacity-100 !bg-foreground cursor-pointer rounded-sm transition-all ${className}`}>
<Icon onClick={() => {
helper.download.downloadByLink(file.uploadPromise.value)
}} icon="tabler:download" width="15" height="15" />
</div>
})

return <>
{/* image render */}
<div className={`columns-${columns} md:columns-${columns}`}>
<PhotoProvider>
{files?.filter(i => i.isImage).map((file, index) => (
{files?.filter(i => i.previewType == 'image').map((file, index) => (
<div className='relative group'>
{file.uploadPromise?.loading?.value && <div className='absolute inset-0 flex items-center justify-center w-full h-full'>
<Icon icon="line-md:uploading-loop" width="40" height="40" />
</div>}

<PhotoView width={150} src={file.preview} >
<Image
src={file.preview}
className='rounded-lg mb-4'
// onLoad={() => { URL.revokeObjectURL(file.preview) }}
/>
<Image src={file.preview} className='rounded-lg mb-4' />
</PhotoView>

{!file.uploadPromise?.loading?.value && !preview &&
<DeleteIcon className='absolute z-10 right-[5px] top-[5px] !text-background opacity-80 hover:opacity-100 bg-foreground cursor-pointer rounded-sm transition-all'
<DeleteIcon className='absolute z-10 right-[5px] top-[5px]'
file={file} />
}
{preview && <Icon onClick={() => {
helper.download.downloadByLink(file.uploadPromise.value)
}} className='hidden er:block transition-all absolute z-10 right-[5px] top-[5px] !text-background opacity-80 hover:opacity-100 bg-foreground cursor-pointer rounded-sm transition-all' icon="tabler:download" width="15" height="15" />
{preview && <DownloadIcon className=''
file={file} />
}
</div>
))}
</PhotoProvider>
</div>

{/* video render */}
<div className={`columns-1 md:columns-1`}>
{files?.filter(i => i.previewType == 'video').map((file, index) => (
<div className='group relative flex p-2 items-center gap-2 cursor-pointer tansition-all rounded-2xl'>
<video src={file.preview} id="player" playsInline controls className='rounded-2xl w-full z-0' />
{!file.uploadPromise?.loading?.value && !preview &&
<DeleteIcon className='absolute z-10 right-[5px] top-[5px]'
file={file} />
}
{preview && <DownloadIcon className='top-[8px] right-[8px]' file={file} />}
</div>
))}
</div>

{/* audio render */}
<div className={`columns-1 md:columns-1`}>
{files?.filter(i => i.previewType == 'audio').map((file, index) => (
<div className='group relative flex p-2 items-center gap-2 cursor-pointer tansition-all rounded-2xl'>
<audio src={file.preview} id="player" playsInline controls className='rounded-2xl w-full' />
{!file.uploadPromise?.loading?.value && !preview &&
<DeleteIcon className='absolute z-10 right-[5px] top-[5px]'
file={file} />
}
{preview && <DownloadIcon className='top-[8px] right-[8px]' file={file} />}
</div>
))}
</div >


{/* other file render */}
<div className={`${helper.env.isIOS ? 'columns-1' : 'columns-' + columns} mt-3 select-none`}>
{files?.filter(i => !i.isImage).map((file, index) => (
{files?.filter(i => i.previewType == 'other').map((file, index) => (
<div onClick={() => {
if (preview) {
helper.download.downloadByLink(file.uploadPromise.value)
Expand All @@ -91,8 +128,7 @@ const AttachmentsRender = observer(({ files, preview = false, columns = 3 }: IPr
<FileIcons path={file.name} isLoading={file.uploadPromise?.loading?.value} />
<div className='truncate text-sm font-bold'>{file.name}</div>
{!file.uploadPromise?.loading?.value && !preview &&
<DeleteIcon className='ml-auto w-[35px] !text-foreground hover:bg-background cursor-pointer rounded-sm tansition-all'
file={file} />}
<DeleteIcon className='ml-auto w-[35px]' file={file} />}
</div>
))}
</div >
Expand Down
9 changes: 4 additions & 5 deletions src/components/Common/Editor/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -41,11 +41,11 @@ export const HandleFileType = (originFiles: Attachment[]): FileType[] => {
if (originFiles.length == 0) return []
const res = originFiles?.map(file => {
const extension = helper.getFileExtension(file.name)
const previewType = helper.getFileType(file.name)
return {
name: file.name,
size: file.size,
//@ts-ignore
isImage: 'JPEG/JPG/PNG/BMP/TIFF/TIF/WEBP/SVG'.includes(extension?.toUpperCase() ?? null),
previewType,
extension: extension ?? '',
preview: file.path,
uploadPromise: new PromiseState({ function: async () => file.path })
Expand All @@ -56,7 +56,6 @@ export const HandleFileType = (originFiles: Attachment[]): FileType[] => {
}



const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot, originFiles }: IProps) => {
const { t } = useTranslation()
const isPc = useMediaQuery('(min-width: 768px)')
Expand Down Expand Up @@ -134,11 +133,11 @@ const Editor = observer(({ content, onChange, onSend, isSendLoading, bottomSlot,
uploadFiles(acceptedFiles) {
const _acceptedFiles = acceptedFiles.map(file => {
const extension = helper.getFileExtension(file.name)
const previewType = helper.getFileType(file.name)
return {
name: file.name,
size: file.size,
//@ts-ignore
isImage: 'JPEG/JPG/PNG/BMP/TIFF/TIF/WEBP/SVG'.includes(extension?.toUpperCase() ?? null),
previewType,
extension: extension ?? '',
preview: URL.createObjectURL(file),
uploadPromise: new PromiseState({
Expand Down
2 changes: 1 addition & 1 deletion src/components/Common/Editor/type.ts
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ export type OnSendContentType = {
export type FileType = {
name: string
size: number
isImage: boolean
previewType: 'image' | 'audio' | 'video' | 'other'
extension: string
preview: any
uploadPromise: PromiseState<any>
Expand Down
16 changes: 13 additions & 3 deletions src/lib/helper.ts
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
import { type Tag } from '@/server/types';
import { _ } from './lodash';
import i18n from './i18n';
import { FileType } from '@/components/Common/Editor/type';

const valMap = {
undefined: '',
Expand Down Expand Up @@ -111,9 +112,18 @@ export const helper = {
}
return null
},
isImage(filename: string) {
const extension = helper.getFileExtension(filename) ?? '';
return 'JPEG/JPG/PNG/BMP/TIFF/TIF/WEBP/SVG'.includes(extension?.toUpperCase() ?? null)
getFileType(filename: string): FileType['previewType'] {
const extension = helper.getFileExtension(filename) ?? ''
if ('jpeg/jpg/png/bmp/tiff/tif/webp/svg'.includes(extension?.toLowerCase() ?? null)) {
return 'image'
}
if ('mp4/webm/ogg/mov/wmv'.includes(extension?.toLowerCase() ?? null)) {
return 'video';
}
if ('mp3/aac/wav/ogg'.includes(extension?.toLowerCase() ?? null)) {
return 'audio';
}
return 'other'
},
promise: {
async sleep(ms) {
Expand Down
2 changes: 1 addition & 1 deletion src/pages/resources.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ const Page = observer(() => {
const extension = helper.getFileExtension(i.path)
return <Card shadow="none" className="group bg-background cursor-pointer px-4 pt-4 mb-4 pb-2 flex flex-col gap-2 items-center">
{
helper.isImage(i.path) ?
helper.getFileType(i.path) == 'image' ?
<PhotoView width={150} src={i.path} >
<Image radius="sm" className="w-full" src={i.path} alt='' />
</PhotoView> :
Expand Down
6 changes: 6 additions & 0 deletions src/styles/editor.css
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@

o {
background-color: transparent !important;
}

.ͼ1x {
background-color: var(--background);
color: var(--foreground);
Expand Down Expand Up @@ -37,6 +39,10 @@
color: #3B82F6 !important;
}

.mdxeditor-toolbar .white {
color: white !important;
}

.mdxeditor-toolbar .primary-foreground {
color: var(--primary-foreground) !important;
}
Expand Down

0 comments on commit c1377b0

Please sign in to comment.