릴리스: v0.1.15 다운로드와 반응형 UI 보정

This commit is contained in:
2026-03-19 17:35:38 +09:00
parent b97d7eacda
commit a1afa658c2
4 changed files with 100 additions and 21 deletions

View File

@@ -30,10 +30,12 @@ const description = ref('')
const isPublic = ref(false)
const error = ref('')
const isSaving = ref(false)
const isExporting = ref(false)
const ownerId = ref('')
const isDragActive = ref(false)
const boardEl = ref(null)
const exportBoardEl = ref(null)
const groupListEl = ref(null)
const poolEl = ref(null)
const groupDropEls = ref({})
@@ -211,11 +213,25 @@ function onDropFiles(event) {
async function downloadImage() {
if (!boardEl.value) return
const dataUrl = await htmlToImage.toPng(boardEl.value, { pixelRatio: 2, backgroundColor: '#0b1220' })
const a = document.createElement('a')
a.href = dataUrl
a.download = `${(title.value || gameName.value || 'tierlist').trim()}.png`
a.click()
isExporting.value = true
await nextTick()
try {
const targetEl = exportBoardEl.value || boardEl.value
const blob = await htmlToImage.toBlob(targetEl, { pixelRatio: 2, backgroundColor: '#0b1220' })
if (!blob) throw new Error('image_export_failed')
const url = URL.createObjectURL(blob)
const a = document.createElement('a')
a.href = url
a.download = `${(title.value || gameName.value || 'tierlist').trim()}.png`
document.body.appendChild(a)
a.click()
a.remove()
URL.revokeObjectURL(url)
} finally {
isExporting.value = false
}
}
async function uploadPendingCustomItems() {
@@ -375,15 +391,22 @@ onUnmounted(() => {
<section class="layout">
<div ref="boardEl" class="board">
<div v-if="canEdit" class="boardTools">
<div v-if="canEdit && !isExporting" class="boardTools">
<button class="btn btn--ghost" @click="addGroup">티어 추가</button>
</div>
<div ref="groupListEl" class="rows">
<div ref="exportBoardEl" class="exportBoard" :class="{ 'exportBoard--active': isExporting }">
<div v-if="isExporting" class="exportBoard__title">{{ title || gameName || gameId }}</div>
<div ref="groupListEl" class="rows">
<div v-for="g in groups" :key="g.id" class="row">
<div class="row__label">
<span class="grab" title="드래그로 순서 변경" data-group-handle></span>
<input v-model="g.name" class="groupName" :readonly="!canEdit" />
<button v-if="canEdit" class="rowRemoveBtn" :disabled="groups.length <= 1" @click="removeGroup(g.id)">삭제</button>
<template v-if="isExporting">
<div class="row__exportName">{{ g.name }}</div>
</template>
<template v-else>
<span class="grab" title="드래그로 순서 변경" data-group-handle></span>
<input v-model="g.name" class="groupName" :readonly="!canEdit" />
<button v-if="canEdit" class="rowRemoveBtn" :disabled="groups.length <= 1" @click="removeGroup(g.id)">삭제</button>
</template>
</div>
<div
class="row__drop"
@@ -398,6 +421,7 @@ onUnmounted(() => {
</div>
</div>
</div>
</div>
</div>
<div class="sidebar">
@@ -522,6 +546,7 @@ onUnmounted(() => {
display: grid;
grid-template-columns: 1fr 320px;
gap: 14px;
align-items: start;
}
.error {
margin: 10px 0 14px;
@@ -535,12 +560,23 @@ onUnmounted(() => {
background: rgba(255, 255, 255, 0.04);
border-radius: 16px;
padding: 12px;
align-self: start;
}
.boardTools {
display: flex;
justify-content: flex-end;
margin-bottom: 10px;
}
.exportBoard--active {
display: grid;
gap: 12px;
}
.exportBoard__title {
font-size: 28px;
font-weight: 900;
letter-spacing: -0.03em;
text-align: left;
}
.rows {
display: grid;
gap: 10px;
@@ -587,6 +623,12 @@ onUnmounted(() => {
outline: none;
min-width: 0;
}
.row__exportName {
width: 100%;
text-align: left;
font-weight: 900;
word-break: break-word;
}
.rowRemoveBtn {
padding: 6px 10px;
border-radius: 10px;