에디터 미디어 선택 로직 분리
This commit is contained in:
153
lib/markdown-editor-media.js
Normal file
153
lib/markdown-editor-media.js
Normal file
@@ -0,0 +1,153 @@
|
||||
import {
|
||||
getPostBodyPreviewThumbnailUrl,
|
||||
isPageCoverThumbnailUrl,
|
||||
isPostBodyThumbnailUrl,
|
||||
isPostCardThumbnailUrl,
|
||||
withGeneratedImageCacheVersion
|
||||
} from './post-card-thumbnail-url.js'
|
||||
|
||||
/**
|
||||
* 파일 크기를 표시용 문자열로 변환한다.
|
||||
* @param {number} size - 바이트 크기
|
||||
* @returns {string} 표시용 크기
|
||||
*/
|
||||
export const formatMediaFileSize = (size) => {
|
||||
const value = Number(size || 0)
|
||||
|
||||
if (!Number.isFinite(value) || value <= 0) {
|
||||
return ''
|
||||
}
|
||||
|
||||
if (value < 1024) {
|
||||
return `${value} B`
|
||||
}
|
||||
|
||||
if (value < 1024 * 1024) {
|
||||
return `${Math.round(value / 1024)} KB`
|
||||
}
|
||||
|
||||
return `${(value / 1024 / 1024).toFixed(1).replace(/\.0$/, '')} MB`
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 항목 종류를 반환한다.
|
||||
* @param {Object} item - 미디어 항목
|
||||
* @returns {'image'|'video'|'audio'|'file'} 미디어 종류
|
||||
*/
|
||||
export const getMediaItemKind = (item) => {
|
||||
if (item?.kind) {
|
||||
return item.kind
|
||||
}
|
||||
|
||||
const source = `${item?.extension || ''} ${item?.url || ''}`.toLowerCase()
|
||||
|
||||
if (/\.(jpe?g|png|webp|gif)(\?|$)/i.test(source)) {
|
||||
return 'image'
|
||||
}
|
||||
|
||||
if (/\.(mp4|webm|mov)(\?|$)/i.test(source)) {
|
||||
return 'video'
|
||||
}
|
||||
|
||||
if (/\.(mp3|wav|ogg|m4a)(\?|$)/i.test(source)) {
|
||||
return 'audio'
|
||||
}
|
||||
|
||||
return 'file'
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 항목이 현재 선택 대상과 맞는지 확인한다.
|
||||
* @param {Object} item - 미디어 항목
|
||||
* @param {string} target - 선택 대상
|
||||
* @returns {boolean} 선택 가능 여부
|
||||
*/
|
||||
export const isMediaItemSelectableForTarget = (item, target) => {
|
||||
if (isPostCardThumbnailUrl(item?.url) || isPostBodyThumbnailUrl(item?.url) || isPageCoverThumbnailUrl(item?.url)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const kind = getMediaItemKind(item)
|
||||
|
||||
if (['image', 'gallery', 'active-gallery'].includes(target)) {
|
||||
return kind === 'image'
|
||||
}
|
||||
|
||||
return kind === target
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 선택 모달에서 사용할 가벼운 이미지 미리보기 URL을 반환한다.
|
||||
* 선택·삽입 값은 원본 URL을 유지하고, 화면 표시만 파생 이미지를 우선 사용한다.
|
||||
* @param {Object} item - 미디어 항목
|
||||
* @returns {string} 미리보기 URL
|
||||
*/
|
||||
export const getMediaPickerPreviewUrl = (item) => {
|
||||
const url = String(item?.url || '')
|
||||
|
||||
if (getMediaItemKind(item) !== 'image') {
|
||||
return url
|
||||
}
|
||||
|
||||
if (item?.bodyThumbnailStatus?.hasThumbnail) {
|
||||
return withGeneratedImageCacheVersion(getPostBodyPreviewThumbnailUrl(url), `${item?.updatedAt || ''}-${item?.size || ''}`)
|
||||
}
|
||||
|
||||
if (item?.thumbnailStatus?.hasThumbnail && item.thumbnailStatus.thumbnailUrl) {
|
||||
return withGeneratedImageCacheVersion(item.thumbnailStatus.thumbnailUrl, `${item?.updatedAt || ''}-${item?.size || ''}`)
|
||||
}
|
||||
|
||||
return url
|
||||
}
|
||||
|
||||
/**
|
||||
* 드롭된 파일이 현재 미디어 선택 대상에 맞는지 확인한다.
|
||||
* @param {{ type?: string }} file - 브라우저 파일
|
||||
* @param {string} target - 선택 대상
|
||||
* @returns {boolean} 허용 여부
|
||||
*/
|
||||
export const isUploadFileAllowedForMediaTarget = (file, target) => {
|
||||
const type = String(file?.type || '')
|
||||
|
||||
if (['image', 'gallery', 'active-gallery'].includes(target)) {
|
||||
return type.startsWith('image/')
|
||||
}
|
||||
|
||||
if (target === 'video') {
|
||||
return type.startsWith('video/')
|
||||
}
|
||||
|
||||
if (target === 'audio') {
|
||||
return type.startsWith('audio/')
|
||||
}
|
||||
|
||||
return !type.startsWith('image/') && !type.startsWith('video/') && !type.startsWith('audio/')
|
||||
}
|
||||
|
||||
/**
|
||||
* 미디어 항목으로 Prose 미디어 블록을 만든다.
|
||||
* @param {'video'|'audio'|'file'} blockType - 블록 유형
|
||||
* @param {Object} item - 미디어 항목
|
||||
* @returns {string[]} 마크다운 줄
|
||||
*/
|
||||
export const createMediaBlockMarkdown = (blockType, item) => {
|
||||
const title = item.title || item.name || ''
|
||||
|
||||
if (blockType === 'video') {
|
||||
return [':::video', `url=${item.url}`, `title=${title}`, 'caption=', ':::']
|
||||
}
|
||||
|
||||
if (blockType === 'audio') {
|
||||
return [':::audio', `url=${item.url}`, `title=${title}`, 'description=', ':::']
|
||||
}
|
||||
|
||||
return [
|
||||
':::file',
|
||||
`url=${item.url}`,
|
||||
`title=${item.name || title}`,
|
||||
'description=',
|
||||
`name=${item.name || title}`,
|
||||
`size=${formatMediaFileSize(item.size)}`,
|
||||
':::'
|
||||
]
|
||||
}
|
||||
Reference in New Issue
Block a user