릴리스: v1.3.49 템플릿 요청 저장 흐름과 관리자 미리보기 정리

This commit is contained in:
2026-04-01 19:01:07 +09:00
parent d5b4de1629
commit 66d408dca8
8 changed files with 184 additions and 177 deletions

View File

@@ -1381,7 +1381,14 @@ function previewRequestGroupCellItems(preview, group, columnIndex) {
}
function previewRequestPoolItems(preview) {
const groupedIds = new Set((preview?.snapshotGroups || []).flatMap((group) => group.itemIds || []))
const groupedIds = new Set(
(preview?.snapshotGroups || []).flatMap((group) => {
if (Array.isArray(group?.cells) && group.cells.length) {
return group.cells.flatMap((cell) => (Array.isArray(cell) ? cell : []))
}
return group.itemIds || []
})
)
return (preview?.snapshotItems || []).filter((item) => !groupedIds.has(item.id))
}
@@ -2278,24 +2285,21 @@ async function saveFeaturedOrder() {
</div>
<div v-if="previewTierList?.requestPreview" class="requestPreview">
<div class="requestPreview__frame">
<div class="requestPreview__header">
<div class="requestPreview__heroTitle">{{ previewTierList.title || '티어표 미리보기' }}</div>
<div v-if="previewTierList.description" class="requestPreview__desc">{{ previewTierList.description }}</div>
<div class="requestPreview__meta">
{{ previewRequestHasColumns(previewTierList) ? (previewRequestColumns(previewTierList).length + '열 구성') : '단일 열 구성' }} ·
{{ previewTierList.snapshotGroups?.length || 0 }} ·
{{ previewTierList.snapshotItems?.length || 0 }} 아이템
</div>
<div class="requestPreview__sheet">
<div class="requestPreview__title">{{ previewTierList.title || '티어표 미리보기' }}</div>
<div v-if="previewTierList.description" class="requestPreview__description">{{ previewTierList.description }}</div>
<div class="requestPreview__meta">
{{ previewRequestHasColumns(previewTierList) ? (previewRequestColumns(previewTierList).length + '열 구성') : '단일 열 구성' }} ·
{{ previewTierList.snapshotGroups?.length || 0 }} ·
{{ previewTierList.snapshotItems?.length || 0 }} 아이템
</div>
<div class="requestPreview__board requestPreview__board--full">
<div v-if="previewRequestHasColumns(previewTierList)" class="requestPreview__boardHead">
<div class="requestPreview__rowLabel requestPreview__rowLabel--head"></div>
<div class="requestPreview__columnLabels" :style="previewRequestGridStyle(previewTierList)">
<div v-if="previewRequestHasColumns(previewTierList)" class="requestPreview__columns">
<div class="requestPreview__columnsSpacer" aria-hidden="true"></div>
<div class="requestPreview__columnsGrid" :style="previewRequestGridStyle(previewTierList)">
<div
v-for="(column, columnIndex) in previewRequestColumns(previewTierList)"
:key="column.id"
class="requestPreview__columnLabel"
class="requestPreview__columnHeader"
>
{{ column.name || ('열 ' + (columnIndex + 1)) }}
</div>
@@ -2303,38 +2307,37 @@ async function saveFeaturedOrder() {
</div>
<div class="requestPreview__rows">
<div v-for="group in previewTierList.snapshotGroups" :key="group.id" class="requestPreview__row">
<div class="requestPreview__rowLabel">{{ group.name }}</div>
<div class="requestPreview__cells" :style="previewRequestGridStyle(previewTierList)">
<div class="requestPreview__label">{{ group.name }}</div>
<div class="requestPreview__dropGrid" :style="previewRequestGridStyle(previewTierList)">
<div
v-for="(column, columnIndex) in previewRequestColumns(previewTierList)"
:key="group.id + '-' + column.id"
class="requestPreview__cell"
class="requestPreview__dropColumn"
>
<div class="requestPreview__rowItems">
<div class="requestPreview__drop">
<div
v-for="item in previewRequestGroupCellItems(previewTierList, group, columnIndex)"
:key="item.id"
class="requestPreview__item"
>
<img class="requestPreview__itemThumb" :src="toApiUrl(item.src)" :alt="item.label" />
<div v-if="previewTierList.snapshotShowCharacterNames" class="requestPreview__itemLabel">{{ item.label }}</div>
<img class="thumb requestPreview__itemThumb" :src="toApiUrl(item.src)" :alt="item.label" />
<div v-if="previewTierList.snapshotShowCharacterNames" class="itemNameOverlay requestPreview__itemLabel">{{ item.label }}</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div v-if="previewRequestPoolItems(previewTierList).length" class="requestPreview__pool">
<div class="requestPreview__poolLabel">남은 아이템</div>
<div class="requestPreview__rowItems requestPreview__rowItems--pool">
<div class="requestPreview__poolTitle">남은 아이템</div>
<div class="requestPreview__poolGrid">
<div
v-for="item in previewRequestPoolItems(previewTierList)"
:key="item.id"
class="requestPreview__item requestPreview__item--muted"
class="requestPreview__poolItem requestPreview__item requestPreview__item--muted"
>
<img class="requestPreview__itemThumb" :src="toApiUrl(item.src)" :alt="item.label" />
<div v-if="previewTierList.snapshotShowCharacterNames" class="requestPreview__itemLabel">{{ item.label }}</div>
<img class="thumb requestPreview__itemThumb" :src="toApiUrl(item.src)" :alt="item.label" />
<div v-if="previewTierList.snapshotShowCharacterNames" class="itemNameOverlay requestPreview__itemLabel">{{ item.label }}</div>
</div>
</div>
</div>
@@ -3887,9 +3890,14 @@ async function saveFeaturedOrder() {
display: grid;
gap: 12px;
align-self: start;
align-content: start;
}
.templateRequestCard__preview {
align-self: start;
display: block;
width: 100%;
line-height: 0;
vertical-align: top;
}
.templateRequestCard__thumbMeta {
display: grid;
@@ -3916,97 +3924,103 @@ async function saveFeaturedOrder() {
}
.requestPreview {
display: grid;
gap: 18px;
}
.requestPreview__frame {
.requestPreview__sheet {
display: grid;
gap: 26px;
gap: 16px;
width: 100%;
max-width: 1280px;
margin: 0 auto;
padding: 28px;
border-radius: 24px;
border: 1px solid var(--theme-border);
background: color-mix(in srgb, var(--theme-main-bg) 92%, transparent);
max-height: min(78vh, 980px);
overflow: auto;
overscroll-behavior: contain;
}
.requestPreview__header {
display: grid;
gap: 10px;
}
.requestPreview__heroTitle {
font-size: clamp(30px, 3vw, 48px);
line-height: 1.08;
.requestPreview__title {
font-size: 28px;
font-weight: 900;
letter-spacing: -0.04em;
letter-spacing: -0.03em;
}
.requestPreview__description {
margin-top: -8px;
font-size: 14px;
line-height: 1.6;
color: var(--theme-text-muted);
}
.requestPreview__meta {
color: var(--theme-text-soft);
font-size: 13px;
}
.requestPreview__desc {
color: var(--theme-text-muted);
line-height: 1.7;
white-space: pre-line;
font-size: 15px;
}
.requestPreview__board,
.requestPreview__pool {
.requestPreview__columns {
display: grid;
gap: 14px;
grid-template-columns: 132px 1fr;
gap: 10px;
margin-bottom: 10px;
}
.requestPreview__boardHead,
.requestPreview__row {
display: grid;
grid-template-columns: 120px minmax(0, 1fr);
gap: 16px;
align-items: start;
}
.requestPreview__rowLabel,
.requestPreview__poolLabel,
.requestPreview__columnLabel {
font-size: 15px;
font-weight: 900;
color: var(--theme-text-strong);
}
.requestPreview__rowLabel--head {
color: var(--theme-text-faint);
}
.requestPreview__columnLabels,
.requestPreview__cells {
display: grid;
gap: 14px;
}
.requestPreview__columnLabel,
.requestPreview__cell {
.requestPreview__columnsSpacer {
min-width: 0;
}
.requestPreview__columnLabel {
padding: 8px 4px;
text-align: center;
}
.requestPreview__cell {
min-height: 134px;
padding: 14px;
border-radius: 18px;
border: 1px solid var(--theme-border);
background: var(--theme-surface-soft);
}
.requestPreview__rowItems {
.requestPreview__columnsGrid {
display: grid;
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
gap: 12px;
gap: 10px;
}
.requestPreview__rowItems--pool {
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
.requestPreview__columnHeader {
min-height: 20px;
font-size: 12px;
font-weight: 800;
text-align: center;
opacity: 0.72;
}
.requestPreview__rows {
display: grid;
gap: 10px;
}
.requestPreview__row {
display: grid;
grid-template-columns: 132px 1fr;
gap: 10px;
}
.requestPreview__label {
display: grid;
place-items: center;
padding: 10px 12px;
text-align: center;
font-weight: 900;
border-radius: 14px;
background: var(--theme-surface-soft-2);
border: 1px solid var(--theme-border-strong);
}
.requestPreview__dropGrid {
display: grid;
gap: 10px;
}
.requestPreview__dropColumn {
display: grid;
gap: 8px;
}
.requestPreview__drop {
border-radius: 14px;
background: var(--theme-pill-bg);
border: 1px solid var(--theme-border);
min-height: calc(var(--thumb-size, 80px) + 24px);
padding: 10px;
display: flex;
flex-wrap: wrap;
gap: 8px;
align-content: flex-start;
}
.requestPreview__item {
display: inline-flex;
position: relative;
overflow: hidden;
border-radius: 16px;
border: 1px solid rgba(255, 255, 255, 0.12);
background: var(--theme-surface-soft);
min-height: 84px;
}
.requestPreview__item--muted {
opacity: 0.52;
filter: grayscale(0.2) brightness(0.78);
filter: grayscale(0.22) brightness(0.78);
}
.requestPreview__itemThumb {
width: 100%;
@@ -4027,6 +4041,24 @@ async function saveFeaturedOrder() {
text-align: center;
line-height: 1.3;
}
.requestPreview__pool {
display: grid;
gap: 10px;
padding-top: 8px;
}
.requestPreview__poolTitle {
font-weight: 900;
opacity: 0.82;
}
.requestPreview__poolGrid {
display: flex;
flex-wrap: wrap;
gap: 8px;
}
.requestPreview__poolItem {
display: inline-flex;
position: relative;
}
.tierAdminList {
margin-top: 14px;
display: grid;
@@ -4051,11 +4083,13 @@ async function saveFeaturedOrder() {
align-self: start;
display: block;
width: 100%;
line-height: 0;
}
.tierAdminCard__thumb {
width: 100%;
aspect-ratio: 16 / 9;
object-fit: cover;
object-position: top center;
display: block;
border-radius: 14px;
background: var(--theme-surface-soft);
@@ -4200,6 +4234,9 @@ async function saveFeaturedOrder() {
}
.modalCard--preview {
width: min(1200px, 100%);
max-height: calc(100dvh - 40px);
overflow: auto;
overscroll-behavior: contain;
}
.modalCard__titleRow {
display: flex;