미디어 업로드와 태그 표시 수정
This commit is contained in:
@@ -130,6 +130,13 @@ const mediaPickerAccept = computed(() => {
|
||||
return '.pdf,.zip,.txt,.csv,.docx,.xlsx,.pptx'
|
||||
})
|
||||
|
||||
/**
|
||||
* 게시물 카드용 파생 썸네일 URL인지 확인한다.
|
||||
* @param {string|null|undefined} url - 미디어 URL
|
||||
* @returns {boolean} 카드 썸네일 여부
|
||||
*/
|
||||
const isPostCardThumbnailMediaUrl = (url) => /^\/uploads\/posts\/\d{4}\/\d{2}\/thumbs\/[^/?#]+-card\.webp$/i.test(String(url || ''))
|
||||
|
||||
/** 작성 textarea 최소 높이(px) */
|
||||
const MIN_TEXTAREA_HEIGHT_PX = 620
|
||||
|
||||
@@ -1530,6 +1537,10 @@ const getMediaItemKind = (item) => {
|
||||
* @returns {boolean} 선택 가능 여부
|
||||
*/
|
||||
const isMediaItemSelectableForTarget = (item) => {
|
||||
if (isPostCardThumbnailMediaUrl(item?.url)) {
|
||||
return false
|
||||
}
|
||||
|
||||
const kind = getMediaItemKind(item)
|
||||
|
||||
if (['image', 'gallery', 'active-gallery'].includes(mediaPickerTarget.value)) {
|
||||
@@ -2946,7 +2957,7 @@ const uploadMediaFiles = async (files) => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadAndInsert = async (files, target = 'image') => {
|
||||
if (!files?.length) {
|
||||
if (!files?.length || isUploading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -2993,7 +3004,7 @@ const handleFileInput = async (event, target) => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const uploadFromMediaModal = async (files) => {
|
||||
if (!files?.length) {
|
||||
if (!files?.length || isUploading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
@@ -3024,6 +3035,11 @@ const uploadFromMediaModal = async (files) => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleMediaModalDrop = async (event) => {
|
||||
if (isUploading.value) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
const files = Array.from(event.dataTransfer?.files || []).filter(isUploadFileAllowedForPicker)
|
||||
|
||||
if (!files.length) {
|
||||
@@ -3095,6 +3111,10 @@ const mediaPickerUploadHint = computed(() => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handlePaste = async (event) => {
|
||||
if (isUploading.value) {
|
||||
return
|
||||
}
|
||||
|
||||
const imageFiles = Array.from(event.clipboardData?.files || []).filter((file) => file.type.startsWith('image/'))
|
||||
|
||||
if (!imageFiles.length) {
|
||||
@@ -3122,6 +3142,11 @@ const handlePaste = async (event) => {
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
const handleDrop = async (event) => {
|
||||
if (isUploading.value) {
|
||||
event.preventDefault()
|
||||
return
|
||||
}
|
||||
|
||||
const imageFiles = Array.from(event.dataTransfer?.files || []).filter((file) => file.type.startsWith('image/'))
|
||||
|
||||
if (!imageFiles.length) {
|
||||
@@ -3413,24 +3438,29 @@ const handleKeydown = (event) => {
|
||||
</template>
|
||||
<div
|
||||
v-else
|
||||
class="admin-markdown-editor__media-upload-zone grid min-h-[420px] place-items-center rounded border border-dashed border-[#cfd5da] bg-[#fafafa] text-center"
|
||||
class="admin-markdown-editor__media-upload-zone relative grid min-h-[420px] place-items-center overflow-hidden rounded border border-dashed border-[#cfd5da] bg-[#fafafa] text-center"
|
||||
:class="isUploading ? 'admin-markdown-editor__media-upload-zone--uploading select-none border-[#8e9cac] bg-[#f3f5f7]' : ''"
|
||||
@dragover.prevent
|
||||
@drop.prevent="handleMediaModalDrop"
|
||||
>
|
||||
<div class="admin-markdown-editor__media-upload-inner grid gap-3 px-6">
|
||||
<p class="admin-markdown-editor__media-upload-title text-lg font-semibold text-[#15171a]">
|
||||
파일을 끌어 업로드
|
||||
{{ isUploading ? '업로드 중입니다' : '파일을 끌어 업로드' }}
|
||||
</p>
|
||||
<p class="admin-markdown-editor__media-upload-or text-sm text-[#6b7280]">
|
||||
또는
|
||||
{{ isUploading ? '잠시만 기다려 주세요.' : '또는' }}
|
||||
</p>
|
||||
<label class="admin-markdown-editor__media-upload-button mx-auto inline-flex h-10 cursor-pointer items-center justify-center rounded border border-[#2b78d0] px-8 text-sm font-semibold text-[#1f6fbf] transition-colors hover:bg-blue-50">
|
||||
<label
|
||||
class="admin-markdown-editor__media-upload-button mx-auto inline-flex h-10 items-center justify-center rounded border border-[#2b78d0] px-8 text-sm font-semibold text-[#1f6fbf] transition-colors hover:bg-blue-50"
|
||||
:class="isUploading ? 'cursor-not-allowed border-[#c8ced3] text-[#8e9cac] hover:bg-transparent' : 'cursor-pointer'"
|
||||
>
|
||||
{{ isUploading ? '업로드 중' : '파일 선택' }}
|
||||
<input
|
||||
class="sr-only"
|
||||
type="file"
|
||||
:accept="mediaPickerAccept"
|
||||
:multiple="isGalleryMediaPicker"
|
||||
:disabled="isUploading"
|
||||
@change="uploadFromMediaModal($event.target.files); $event.target.value = ''"
|
||||
>
|
||||
</label>
|
||||
@@ -3438,6 +3468,17 @@ const handleKeydown = (event) => {
|
||||
{{ mediaPickerUploadHint }}
|
||||
</p>
|
||||
</div>
|
||||
<div
|
||||
v-if="isUploading"
|
||||
class="admin-markdown-editor__media-upload-overlay pointer-events-none absolute inset-0 grid place-items-center bg-white/72 backdrop-blur-[1px]"
|
||||
aria-live="polite"
|
||||
>
|
||||
<div class="admin-markdown-editor__media-upload-loading grid w-full max-w-sm gap-4 px-8 text-center">
|
||||
<span class="admin-markdown-editor__media-upload-spinner mx-auto size-8 rounded-full border-2 border-[#d7dde2] border-t-[#15171a]" aria-hidden="true" />
|
||||
<strong class="text-sm font-semibold text-[#15171a]">업로드 중입니다</strong>
|
||||
<span class="admin-markdown-editor__media-upload-skeleton h-2 overflow-hidden rounded-full bg-[#e3e6e8]" aria-hidden="true" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -3480,4 +3521,49 @@ const handleKeydown = (event) => {
|
||||
.admin-markdown-editor__gutter::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
||||
.admin-markdown-editor__media-upload-zone--uploading::before {
|
||||
position: absolute;
|
||||
inset: 0;
|
||||
content: '';
|
||||
background: linear-gradient(110deg, transparent 0%, rgba(255, 255, 255, 0.72) 45%, transparent 72%);
|
||||
transform: translateX(-100%);
|
||||
animation: admin-markdown-editor-upload-sheen 1.4s ease-in-out infinite;
|
||||
}
|
||||
|
||||
.admin-markdown-editor__media-upload-spinner {
|
||||
animation: admin-markdown-editor-upload-spin 0.8s linear infinite;
|
||||
}
|
||||
|
||||
.admin-markdown-editor__media-upload-skeleton::before {
|
||||
display: block;
|
||||
width: 40%;
|
||||
height: 100%;
|
||||
content: '';
|
||||
border-radius: inherit;
|
||||
background: linear-gradient(90deg, transparent, rgba(255, 255, 255, 0.86), transparent);
|
||||
animation: admin-markdown-editor-upload-skeleton 1.15s ease-in-out infinite;
|
||||
}
|
||||
|
||||
@keyframes admin-markdown-editor-upload-spin {
|
||||
to {
|
||||
transform: rotate(360deg);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes admin-markdown-editor-upload-sheen {
|
||||
to {
|
||||
transform: translateX(100%);
|
||||
}
|
||||
}
|
||||
|
||||
@keyframes admin-markdown-editor-upload-skeleton {
|
||||
from {
|
||||
transform: translateX(-120%);
|
||||
}
|
||||
|
||||
to {
|
||||
transform: translateX(260%);
|
||||
}
|
||||
}
|
||||
</style>
|
||||
|
||||
Reference in New Issue
Block a user