|
|
|
|
@@ -119,10 +119,7 @@ const copiedFromLabel = computed(() => {
|
|
|
|
|
if (sourceSnapshotAuthor.value) parts.push(sourceSnapshotAuthor.value)
|
|
|
|
|
return parts.join(' · ') || '복사해 온 티어표'
|
|
|
|
|
})
|
|
|
|
|
const customItems = computed(() =>
|
|
|
|
|
Object.values(itemsById.value)
|
|
|
|
|
.filter((item) => item?.origin === 'custom')
|
|
|
|
|
)
|
|
|
|
|
const customItems = computed(() => getOrderedItems().filter((item) => item?.origin === 'custom'))
|
|
|
|
|
const hasSavedTierList = computed(() => !!(persistedTierListId.value || (tierListId.value && tierListId.value !== 'new')))
|
|
|
|
|
const canRequestTemplateCreate = computed(
|
|
|
|
|
() => canEdit.value && hasSavedTierList.value && gameId.value === 'freeform' && customItems.value.length > 0
|
|
|
|
|
@@ -166,6 +163,29 @@ function formatExportDate(ts) {
|
|
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getOrderedItemIds() {
|
|
|
|
|
const orderedIds = []
|
|
|
|
|
const seen = new Set()
|
|
|
|
|
const pushId = (itemId) => {
|
|
|
|
|
if (!itemId || seen.has(itemId) || !itemsById.value[itemId]) return
|
|
|
|
|
seen.add(itemId)
|
|
|
|
|
orderedIds.push(itemId)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
pool.value.forEach(pushId)
|
|
|
|
|
groups.value.forEach((group) => {
|
|
|
|
|
;(group.cells || []).forEach((cell) => {
|
|
|
|
|
;(cell || []).forEach(pushId)
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
Object.keys(itemsById.value).forEach(pushId)
|
|
|
|
|
return orderedIds
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function getOrderedItems() {
|
|
|
|
|
return getOrderedItemIds().map((itemId) => itemsById.value[itemId]).filter(Boolean)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function setIconSize(nextSize) {
|
|
|
|
|
iconSize.value = nextSize
|
|
|
|
|
}
|
|
|
|
|
@@ -655,7 +675,7 @@ function buildPayload(existingId) {
|
|
|
|
|
sourceSnapshotTitle: sourceSnapshotTitle.value || '',
|
|
|
|
|
sourceSnapshotAuthor: sourceSnapshotAuthor.value || '',
|
|
|
|
|
groups: buildGroupPayload(),
|
|
|
|
|
pool: Object.values(itemsById.value),
|
|
|
|
|
pool: getOrderedItems(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -722,6 +742,7 @@ function closeTemplateUpdateModal() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openDeleteModal() {
|
|
|
|
|
if (!hasSavedTierList.value) return
|
|
|
|
|
isDeleteModalOpen.value = true
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -730,11 +751,12 @@ function closeDeleteModal() {
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async function confirmDeleteTierList() {
|
|
|
|
|
if (!canEdit.value || isNewTierList.value || isDeleting.value) return
|
|
|
|
|
const currentTierListId = persistedTierListId.value || (tierListId.value && tierListId.value !== 'new' ? tierListId.value : '')
|
|
|
|
|
if (!canEdit.value || !currentTierListId || isDeleting.value) return
|
|
|
|
|
error.value = ''
|
|
|
|
|
try {
|
|
|
|
|
isDeleting.value = true
|
|
|
|
|
await api.deleteTierList(tierListId.value)
|
|
|
|
|
await api.deleteTierList(currentTierListId)
|
|
|
|
|
closeDeleteModal()
|
|
|
|
|
toast.success('티어표를 삭제했어요.')
|
|
|
|
|
router.push(gameId.value === 'freeform' ? '/me' : `/games/${gameId.value}`)
|
|
|
|
|
@@ -792,7 +814,7 @@ async function requestTemplate(type) {
|
|
|
|
|
isPublic: !!isPublic.value,
|
|
|
|
|
showCharacterNames: !!showCharacterNames.value,
|
|
|
|
|
groups: buildGroupPayload(),
|
|
|
|
|
boardItems: Object.values(itemsById.value),
|
|
|
|
|
boardItems: getOrderedItems(),
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (type === 'create') closeTemplateRequestModal()
|
|
|
|
|
@@ -1185,10 +1207,10 @@ onUnmounted(() => {
|
|
|
|
|
@dragleave="onDragLeave"
|
|
|
|
|
@drop.prevent="onDropFiles"
|
|
|
|
|
>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="dropzone__iconWrap">
|
|
|
|
|
<SvgIcon :src="addPhotoAlternateIcon" alt="" class="dropzone__icon" />
|
|
|
|
|
</div>
|
|
|
|
|
<div>
|
|
|
|
|
<div class="dropzone__title">커스텀 이미지 추가</div>
|
|
|
|
|
<div class="dropzone__desc">이곳으로 이미지를 드래그하거나 파일 선택으로 한 번에 추가할 수 있어요.</div>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -1302,7 +1324,7 @@ onUnmounted(() => {
|
|
|
|
|
<button v-if="canEdit" class="btn btn--save editorSidebar__button" :disabled="isSaving" @click="save">{{ isSaving ? '저장중...' : '저장' }}</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="editorSidebar__utilityLinks">
|
|
|
|
|
<button v-if="canEdit && !isNewTierList" class="editorSidebar__utilityLink editorSidebar__utilityLink--danger" @click="openDeleteModal">삭제하기</button>
|
|
|
|
|
<button v-if="canEdit && hasSavedTierList" class="editorSidebar__utilityLink editorSidebar__utilityLink--danger" @click="openDeleteModal">삭제하기</button>
|
|
|
|
|
<button v-if="canDuplicate" class="editorSidebar__utilityLink" @click="duplicateCurrentTierList">복사해서 내 티어표로 가져오기</button>
|
|
|
|
|
<button
|
|
|
|
|
v-if="canRequestTemplateCreate"
|
|
|
|
|
@@ -2110,20 +2132,21 @@ onUnmounted(() => {
|
|
|
|
|
.dropzone__button {
|
|
|
|
|
min-width: 124px;
|
|
|
|
|
min-height: 34px;
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
.dropzone__iconWrap {
|
|
|
|
|
/* .dropzone__iconWrap {
|
|
|
|
|
width: 52px;
|
|
|
|
|
height: 52px;
|
|
|
|
|
display: grid;
|
|
|
|
|
place-items: center;
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
background: color-mix(in srgb, var(--theme-text) 10%, transparent);
|
|
|
|
|
}
|
|
|
|
|
} */
|
|
|
|
|
|
|
|
|
|
.dropzone__icon {
|
|
|
|
|
width: 28px;
|
|
|
|
|
height: 28px;
|
|
|
|
|
width: 48px;
|
|
|
|
|
height: 48px;
|
|
|
|
|
opacity: 0.86;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
@@ -2334,10 +2357,11 @@ onUnmounted(() => {
|
|
|
|
|
}
|
|
|
|
|
.dropzone {
|
|
|
|
|
margin-top: 12px;
|
|
|
|
|
padding: 14px;
|
|
|
|
|
padding: 28px 22px;
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
border: 1px dashed rgba(255, 255, 255, 0.18);
|
|
|
|
|
background: var(--theme-surface-soft);
|
|
|
|
|
border: 2px dashed color-mix(in srgb, var(--theme-border-strong) 82%, rgba(255, 255, 255, 0.12));
|
|
|
|
|
background: linear-gradient(180deg, color-mix(in srgb, var(--theme-card-bg) 88%, white 4%), color-mix(in srgb, var(--theme-card-bg-hover) 82%, white 6%)),
|
|
|
|
|
radial-gradient(circle at top, color-mix(in srgb, var(--theme-accent) 12%, transparent), transparent 60%);
|
|
|
|
|
}
|
|
|
|
|
.dropzone--active {
|
|
|
|
|
border-color: rgba(110, 231, 183, 0.6);
|
|
|
|
|
|