diff --git a/docs/update.md b/docs/update.md index deb992a..62c8133 100644 --- a/docs/update.md +++ b/docs/update.md @@ -91,3 +91,10 @@ - **커스텀 아이템 조회 강화**: 사용자 커스텀 아이템 목록에 파일명 검색, `50/200` 단위 페이지네이션, 다운로드 흐름 추가 - **회원 비밀번호 초기화 추가**: 관리자 페이지와 API에서 회원 비밀번호를 직접 재설정할 수 있도록 기능 추가 - **가변 티어 행 지원**: 티어표 에디터에서 `S~D` 고정 5단이 아니라 티어 행을 직접 추가/삭제할 수 있도록 보강 + +## 2026-03-19 v0.1.14 +- **커스텀 아이템 카드 반응형 수정**: 관리자 아이템 관리 탭의 커스텀 아이템 카드에서 이미지 폭을 유동값으로 조정하고, 텍스트 영역에 `min-width: 0`과 강제 줄바꿈 기준을 추가해 카드 바깥 overflow를 방지 + +## 2026-03-19 v0.1.15 +- **셀렉트 화살표 여백 정리**: 전역 `select` 스타일에 커스텀 화살표 위치와 오른쪽 여백을 추가해 텍스트와 화살표가 지나치게 붙지 않도록 조정 +- **티어표 다운로드 결과 개선**: `TierEditorView`의 이미지 저장을 Blob 다운로드 방식으로 바꾸고, 캡처 대상을 보드 영역만 포함하는 전용 export 뷰로 분리해 우측 아이템 영역과 편집용 버튼/입력 UI가 저장 이미지에 섞이지 않도록 수정 diff --git a/frontend/src/style.css b/frontend/src/style.css index 527d4fb..dc26237 100644 --- a/frontend/src/style.css +++ b/frontend/src/style.css @@ -54,6 +54,21 @@ body { margin: 0; } +select { + appearance: none; + -webkit-appearance: none; + -moz-appearance: none; + background-image: + linear-gradient(45deg, transparent 50%, rgba(255, 255, 255, 0.78) 50%), + linear-gradient(135deg, rgba(255, 255, 255, 0.78) 50%, transparent 50%); + background-position: + calc(100% - 18px) calc(50% - 2px), + calc(100% - 12px) calc(50% - 2px); + background-size: 6px 6px, 6px 6px; + background-repeat: no-repeat; + padding-right: 36px; +} + h1, h2 { font-family: var(--heading); diff --git a/frontend/src/views/AdminView.vue b/frontend/src/views/AdminView.vue index f126944..f62bc72 100644 --- a/frontend/src/views/AdminView.vue +++ b/frontend/src/views/AdminView.vue @@ -497,12 +497,10 @@ function fmt(ts) { -
현재 목록은 사용자 커스텀 이미지 전용입니다. 여기서 보는 항목은 게임 기본 아이템 삭제와 연결되지 않아요.
-
조건에 맞는 커스텀 아이템이 없어요.
@@ -726,6 +724,7 @@ function fmt(ts) { margin-top: 0; } .btn { + font-size: 12px; margin-top: 12px; padding: 10px 12px; border-radius: 12px; @@ -751,9 +750,6 @@ function fmt(ts) { .btn--ghost { background: rgba(255, 255, 255, 0.03); } -.btn--small { - width: 100%; -} .detailHead { display: flex; gap: 12px; @@ -866,7 +862,7 @@ function fmt(ts) { .customItemGrid { margin-top: 14px; display: grid; - grid-template-columns: repeat(auto-fill, minmax(220px, 1fr)); + grid-template-columns: repeat(2, minmax(0, 1fr)); gap: 12px; } .customItemCard { @@ -874,27 +870,39 @@ function fmt(ts) { border-radius: 16px; background: rgba(255, 255, 255, 0.04); overflow: hidden; + display: flex; + gap: 12px; + align-items: flex-start; + padding: 12px; + min-width: 0; } .customItemCard__image { - width: min(100%, 150px); + width: clamp(88px, 22vw, 150px); + flex: 0 1 150px; aspect-ratio: 1 / 1; object-fit: cover; display: block; - margin: 12px auto 0; border-radius: 12px; background: rgba(0, 0, 0, 0.18); } .customItemCard__body { - display: grid; + display: flex; + flex-direction: column; gap: 6px; - padding: 12px; + min-width: 0; + flex: 1 1 auto; } .customItemCard__title { + min-width: 0; + overflow-wrap: anywhere; + word-break: break-word; font-weight: 900; } .customItemCard__meta { opacity: 0.72; font-size: 13px; + min-width: 0; + overflow-wrap: anywhere; word-break: break-word; } .pager { @@ -979,5 +987,12 @@ function fmt(ts) { .userList { grid-template-columns: 1fr; } + .customItemCard { + align-items: stretch; + } + .customItemCard__image { + width: clamp(72px, 28vw, 120px); + flex-basis: 120px; + } } diff --git a/frontend/src/views/TierEditorView.vue b/frontend/src/views/TierEditorView.vue index f503347..f2341da 100644 --- a/frontend/src/views/TierEditorView.vue +++ b/frontend/src/views/TierEditorView.vue @@ -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(() => {
-
+
-
+
+
{{ title || gameName || gameId }}
+
- - - + +
{
+