|
|
|
|
@@ -98,6 +98,7 @@ const featuredSortable = ref(null)
|
|
|
|
|
const userAvatarInputs = ref({})
|
|
|
|
|
const isGameLoading = ref(false)
|
|
|
|
|
const gameCreateModalOpen = ref(false)
|
|
|
|
|
const previousBodyOverflow = ref('')
|
|
|
|
|
|
|
|
|
|
const hasSelectedGame = computed(() => !!selectedGame.value?.game?.id)
|
|
|
|
|
const canApplyThumbnail = computed(() => !!thumbFile.value && !!selectedGameId.value)
|
|
|
|
|
@@ -196,6 +197,19 @@ const adminOverviewStats = computed(() => {
|
|
|
|
|
{ label: '활동 계정', value: `${users.value.filter((user) => user.tierListCount > 0).length}` },
|
|
|
|
|
]
|
|
|
|
|
})
|
|
|
|
|
const isAnyModalOpen = computed(
|
|
|
|
|
() =>
|
|
|
|
|
gameCreateModalOpen.value ||
|
|
|
|
|
userEditModalOpen.value ||
|
|
|
|
|
userPasswordModalOpen.value ||
|
|
|
|
|
userDeleteModalOpen.value ||
|
|
|
|
|
userRoleModalOpen.value ||
|
|
|
|
|
importModalOpen.value ||
|
|
|
|
|
customItemModalOpen.value ||
|
|
|
|
|
customItemDeleteModalOpen.value ||
|
|
|
|
|
imageResetModalOpen.value ||
|
|
|
|
|
previewModalOpen.value
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
function handleAdminPopState() {
|
|
|
|
|
if (customItemDeleteModalOpen.value) {
|
|
|
|
|
@@ -208,15 +222,40 @@ function handleAdminPopState() {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function handleAdminKeydown(event) {
|
|
|
|
|
if (event.key !== 'Escape') return
|
|
|
|
|
if (customItemDeleteModalOpen.value) {
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
closeCustomItemDeleteModal()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (customItemModalOpen.value) {
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
closeCustomItemModal()
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
if (previewModalOpen.value) {
|
|
|
|
|
event.preventDefault()
|
|
|
|
|
closePreviewModal()
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
onMounted(async () => {
|
|
|
|
|
if (typeof window !== 'undefined') window.addEventListener('popstate', handleAdminPopState)
|
|
|
|
|
if (typeof window !== 'undefined') {
|
|
|
|
|
window.addEventListener('popstate', handleAdminPopState)
|
|
|
|
|
window.addEventListener('keydown', handleAdminKeydown)
|
|
|
|
|
}
|
|
|
|
|
await auth.refresh()
|
|
|
|
|
await Promise.all([refreshGames(), refreshCustomItems(), refreshAdminTierLists(), refreshUsers(), refreshTemplateRequests(), refreshImageDiagnostics()])
|
|
|
|
|
await syncFeaturedSortable()
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
onUnmounted(() => {
|
|
|
|
|
if (typeof window !== 'undefined') window.removeEventListener('popstate', handleAdminPopState)
|
|
|
|
|
if (typeof window !== 'undefined') {
|
|
|
|
|
window.removeEventListener('popstate', handleAdminPopState)
|
|
|
|
|
window.removeEventListener('keydown', handleAdminKeydown)
|
|
|
|
|
}
|
|
|
|
|
if (typeof document !== 'undefined') document.body.style.overflow = previousBodyOverflow.value || ''
|
|
|
|
|
clearPreviewUrl('item')
|
|
|
|
|
clearPreviewUrl('thumb')
|
|
|
|
|
destroyFeaturedSortable()
|
|
|
|
|
@@ -267,6 +306,22 @@ watch(
|
|
|
|
|
}
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
watch(
|
|
|
|
|
() => isAnyModalOpen.value,
|
|
|
|
|
(open) => {
|
|
|
|
|
if (typeof document === 'undefined') return
|
|
|
|
|
if (open) {
|
|
|
|
|
if (!previousBodyOverflow.value) previousBodyOverflow.value = document.body.style.overflow || ''
|
|
|
|
|
document.body.style.overflow = 'hidden'
|
|
|
|
|
return
|
|
|
|
|
}
|
|
|
|
|
document.body.style.overflow = previousBodyOverflow.value || ''
|
|
|
|
|
previousBodyOverflow.value = ''
|
|
|
|
|
},
|
|
|
|
|
{ immediate: true }
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
function resetMessages() {
|
|
|
|
|
error.value = ''
|
|
|
|
|
success.value = ''
|
|
|
|
|
@@ -680,6 +735,7 @@ async function createGame() {
|
|
|
|
|
const data = await res.json()
|
|
|
|
|
await refreshGames()
|
|
|
|
|
selectedGameId.value = data.game.id
|
|
|
|
|
if (customItemModalOpen.value) customItemModalTargetGameId.value = data.game.id
|
|
|
|
|
closeGameCreateModal()
|
|
|
|
|
await loadGame()
|
|
|
|
|
success.value = '게임이 생성됐어요. 이어서 썸네일과 기본 아이템을 관리할 수 있어요.'
|
|
|
|
|
@@ -1203,6 +1259,32 @@ async function promoteCustomItem(item) {
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function buildModalItemFromTierListItem(item, tierList) {
|
|
|
|
|
const matchedItem = customItems.value.find((entry) => entry.id === item?.id || entry.src === item?.src)
|
|
|
|
|
const id = matchedItem?.id || item?.id || ''
|
|
|
|
|
return {
|
|
|
|
|
...matchedItem,
|
|
|
|
|
...item,
|
|
|
|
|
id,
|
|
|
|
|
label: item?.label || matchedItem?.label || '이름 없음',
|
|
|
|
|
src: item?.src || matchedItem?.src || '',
|
|
|
|
|
sourceType: matchedItem?.sourceType || (String(id).startsWith('asset:') ? 'template' : 'user'),
|
|
|
|
|
sourceLabel: matchedItem?.sourceLabel || '티어표 추가 아이템',
|
|
|
|
|
ownerName: matchedItem?.ownerName || tierListAuthorDisplayName(tierList),
|
|
|
|
|
linkedGames: Array.isArray(matchedItem?.linkedGames) ? matchedItem.linkedGames : [],
|
|
|
|
|
usageCount: matchedItem?.usageCount || 0,
|
|
|
|
|
canDelete: typeof matchedItem?.canDelete === 'boolean' ? matchedItem.canDelete : false,
|
|
|
|
|
isPromoting: false,
|
|
|
|
|
createdAt: matchedItem?.createdAt || item?.createdAt || tierList?.updatedAt || tierList?.createdAt || Date.now(),
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function openTierListExtraItemModal(item, tierList) {
|
|
|
|
|
if (!item) return
|
|
|
|
|
openCustomItemModal(buildModalItemFromTierListItem(item, tierList))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function tierListThumbUrl(tierList) {
|
|
|
|
|
return tierList.thumbnailSrc ? toApiUrl(tierList.thumbnailSrc) : ''
|
|
|
|
|
}
|
|
|
|
|
@@ -1233,6 +1315,38 @@ function previewRequestGroupItems(preview, group) {
|
|
|
|
|
return (group?.itemIds || []).map((itemId) => itemsById[itemId]).filter(Boolean)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function previewRequestColumns(preview) {
|
|
|
|
|
const groups = Array.isArray(preview?.snapshotGroups) ? preview.snapshotGroups : []
|
|
|
|
|
const columnSource = groups.find((group) => Array.isArray(group?.columnNames) && group.columnNames.length) || null
|
|
|
|
|
const namedColumns = Array.isArray(columnSource?.columnNames) ? columnSource.columnNames : []
|
|
|
|
|
const cellCount = Math.max(1, namedColumns.length, ...groups.map((group) => (Array.isArray(group?.cells) ? group.cells.length : 0)))
|
|
|
|
|
|
|
|
|
|
return Array.from({ length: cellCount }, (_, index) => ({
|
|
|
|
|
id: namedColumns[index]?.id || ('column-' + index),
|
|
|
|
|
name: namedColumns[index]?.name || '',
|
|
|
|
|
}))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previewRequestHasColumns(preview) {
|
|
|
|
|
const columns = previewRequestColumns(preview)
|
|
|
|
|
return columns.length > 1 || columns.some((column) => column.name)
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previewRequestGridStyle(preview) {
|
|
|
|
|
const count = previewRequestColumns(preview).length
|
|
|
|
|
return { gridTemplateColumns: 'repeat(' + count + ', minmax(0, 1fr))' }
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previewRequestGroupCellItems(preview, group, columnIndex) {
|
|
|
|
|
const itemsById = previewRequestItemsById(preview)
|
|
|
|
|
if (Array.isArray(group?.cells?.[columnIndex])) {
|
|
|
|
|
return group.cells[columnIndex].map((itemId) => itemsById[itemId]).filter(Boolean)
|
|
|
|
|
}
|
|
|
|
|
if (columnIndex === 0) return previewRequestGroupItems(preview, group)
|
|
|
|
|
return []
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
function previewRequestPoolItems(preview) {
|
|
|
|
|
const groupedIds = new Set((preview?.snapshotGroups || []).flatMap((group) => group.itemIds || []))
|
|
|
|
|
return (preview?.snapshotItems || []).filter((item) => !groupedIds.has(item.id))
|
|
|
|
|
@@ -1709,7 +1823,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
<div v-if="!adminTierLists.length" class="hint">조건에 맞는 티어표가 없어요.</div>
|
|
|
|
|
<div v-else class="tierAdminList">
|
|
|
|
|
<article v-for="tierList in adminTierLists" :key="tierList.id" class="tierAdminCard">
|
|
|
|
|
<div class="tierAdminCard__preview" @click="openAdminTierList(tierList)">
|
|
|
|
|
<div class="tierAdminCard__preview">
|
|
|
|
|
<img v-if="tierListThumbUrl(tierList)" class="tierAdminCard__thumb" :src="tierListThumbUrl(tierList)" :alt="tierList.title" />
|
|
|
|
|
<div v-else class="tierAdminCard__thumb tierAdminCard__thumb--empty"></div>
|
|
|
|
|
</div>
|
|
|
|
|
@@ -1724,7 +1838,6 @@ async function saveFeaturedOrder() {
|
|
|
|
|
</div>
|
|
|
|
|
<div class="tierAdminCard__meta">{{ fmt(tierList.updatedAt) }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small" @click="openAdminTierList(tierList)">완성본 보기</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div class="tierAdminCard__stats">
|
|
|
|
|
@@ -1735,7 +1848,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
<div v-if="tierList.extraItems?.length" class="tierAdminSection">
|
|
|
|
|
<div class="tierAdminSection__title">추가로 넣은 아이템</div>
|
|
|
|
|
<div class="tierAdminItemList">
|
|
|
|
|
<button v-for="item in tierList.extraItems" :key="item.id" class="tierAdminItem" @click="openTierListImportModal(tierList, [item])">
|
|
|
|
|
<button v-for="item in tierList.extraItems" :key="item.id" class="tierAdminItem" @click="openTierListExtraItemModal(item, tierList)">
|
|
|
|
|
<img class="tierAdminItem__thumb" :src="toApiUrl(item.src)" :alt="item.label" />
|
|
|
|
|
<div class="tierAdminItem__title">{{ item.label }}</div>
|
|
|
|
|
</button>
|
|
|
|
|
@@ -2009,6 +2122,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
<div class="customItemModal__pickerHead">
|
|
|
|
|
<div class="customItemModal__pickerEyebrow">GAME PICKER</div>
|
|
|
|
|
<div class="customItemModal__pickerTitle">템플릿으로 추가할 게임</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small customItemModal__createGameButton" type="button" @click="openGameCreateModal">새 템플릿 만들기</button>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="customItemModal__pickerControls">
|
|
|
|
|
<input v-model="customItemModalGameQuery" class="input input--dense" placeholder="게임 이름, ID 검색" />
|
|
|
|
|
@@ -2044,6 +2158,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
<div class="customItemModal__source">{{ modalTargetCustomItem.sourceLabel }}</div>
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
<img class="customItemModal__image" :src="toApiUrl(modalTargetCustomItem.src)" :alt="modalTargetCustomItem.label" />
|
|
|
|
|
<div class="customItemModal__labelEditor">
|
|
|
|
|
<label class="field">
|
|
|
|
|
<span class="field__label">아이템 이름</span>
|
|
|
|
|
@@ -2053,7 +2168,6 @@ async function saveFeaturedOrder() {
|
|
|
|
|
{{ customItemModalLabelSaving ? '저장중...' : '이름 저장' }}
|
|
|
|
|
</button>
|
|
|
|
|
</div>
|
|
|
|
|
<img class="customItemModal__image" :src="toApiUrl(modalTargetCustomItem.src)" :alt="modalTargetCustomItem.label" />
|
|
|
|
|
<div class="customItemModal__metaList">
|
|
|
|
|
<div class="customItemModal__metaRow"><span>파일</span><strong :title="modalTargetCustomItem.src.split('/').pop()">{{ modalTargetCustomItem.src.split('/').pop() }}</strong></div>
|
|
|
|
|
<div class="customItemModal__metaRow"><span>업로더/출처</span><strong :title="modalTargetCustomItem.ownerName">{{ modalTargetCustomItem.ownerName }}</strong></div>
|
|
|
|
|
@@ -2110,32 +2224,64 @@ async function saveFeaturedOrder() {
|
|
|
|
|
<div class="modalCard__title">{{ previewTierList?.title || '티어표 미리보기' }}</div>
|
|
|
|
|
<button class="btn btn--ghost btn--small" @click="closePreviewModal">닫기</button>
|
|
|
|
|
</div>
|
|
|
|
|
|
|
|
|
|
<div v-if="previewTierList?.requestPreview" class="requestPreview">
|
|
|
|
|
<img
|
|
|
|
|
v-if="previewTierList.thumbnailSrc"
|
|
|
|
|
class="requestPreview__thumb"
|
|
|
|
|
:src="toApiUrl(previewTierList.thumbnailSrc)"
|
|
|
|
|
:alt="previewTierList.title"
|
|
|
|
|
/>
|
|
|
|
|
<div v-if="previewTierList.description" class="requestPreview__desc">{{ previewTierList.description }}</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__rowItems">
|
|
|
|
|
<div class="requestPreview__summary">
|
|
|
|
|
<div class="requestPreview__summaryBody">
|
|
|
|
|
<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>
|
|
|
|
|
<img
|
|
|
|
|
v-if="previewTierList.thumbnailSrc"
|
|
|
|
|
class="requestPreview__summaryThumb"
|
|
|
|
|
:src="toApiUrl(previewTierList.thumbnailSrc)"
|
|
|
|
|
:alt="previewTierList.title"
|
|
|
|
|
/>
|
|
|
|
|
</div>
|
|
|
|
|
<div class="requestPreview__board">
|
|
|
|
|
<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-for="item in previewRequestGroupItems(previewTierList, group)"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
class="requestPreview__item"
|
|
|
|
|
v-for="(column, columnIndex) in previewRequestColumns(previewTierList)"
|
|
|
|
|
:key="column.id"
|
|
|
|
|
class="requestPreview__columnLabel"
|
|
|
|
|
>
|
|
|
|
|
<img class="requestPreview__itemThumb" :src="toApiUrl(item.src)" :alt="item.label" />
|
|
|
|
|
<div v-if="previewTierList.snapshotShowCharacterNames" class="requestPreview__itemLabel">{{ item.label }}</div>
|
|
|
|
|
{{ column.name || ('열 ' + (columnIndex + 1)) }}
|
|
|
|
|
</div>
|
|
|
|
|
</div>
|
|
|
|
|
</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
|
|
|
|
|
v-for="(column, columnIndex) in previewRequestColumns(previewTierList)"
|
|
|
|
|
:key="group.id + '-' + column.id"
|
|
|
|
|
class="requestPreview__cell"
|
|
|
|
|
>
|
|
|
|
|
<div class="requestPreview__rowItems">
|
|
|
|
|
<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>
|
|
|
|
|
</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">
|
|
|
|
|
<div class="requestPreview__rowItems requestPreview__rowItems--pool">
|
|
|
|
|
<div
|
|
|
|
|
v-for="item in previewRequestPoolItems(previewTierList)"
|
|
|
|
|
:key="item.id"
|
|
|
|
|
@@ -3219,8 +3365,8 @@ async function saveFeaturedOrder() {
|
|
|
|
|
}
|
|
|
|
|
.customItemModal {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 300px minmax(0, 1fr);
|
|
|
|
|
min-height: min(820px, calc(100dvh - 48px));
|
|
|
|
|
grid-template-columns: 340px minmax(0, 1fr);
|
|
|
|
|
min-height: min(860px, calc(100dvh - 40px));
|
|
|
|
|
align-items: stretch;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__pickerPanel {
|
|
|
|
|
@@ -3234,7 +3380,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__pickerHead {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__pickerEyebrow {
|
|
|
|
|
font-size: 11px;
|
|
|
|
|
@@ -3256,6 +3402,9 @@ async function saveFeaturedOrder() {
|
|
|
|
|
max-height: 440px;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__createGameButton {
|
|
|
|
|
justify-self: start;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__gameItem {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 4px;
|
|
|
|
|
@@ -3298,13 +3447,18 @@ async function saveFeaturedOrder() {
|
|
|
|
|
align-content: start;
|
|
|
|
|
gap: 18px;
|
|
|
|
|
overflow: auto;
|
|
|
|
|
padding-right: 2px;
|
|
|
|
|
padding-right: 6px;
|
|
|
|
|
scrollbar-width: none;
|
|
|
|
|
-ms-overflow-style: none;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__content::-webkit-scrollbar {
|
|
|
|
|
width: 0;
|
|
|
|
|
height: 0;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__labelEditor {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: minmax(0, 1fr) auto;
|
|
|
|
|
display: flex;
|
|
|
|
|
flex-direction: column;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
align-items: end;
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__renameButton {
|
|
|
|
|
white-space: nowrap;
|
|
|
|
|
@@ -3397,9 +3551,9 @@ async function saveFeaturedOrder() {
|
|
|
|
|
text-align: center;
|
|
|
|
|
}
|
|
|
|
|
.modalCard--customItem {
|
|
|
|
|
width: min(1360px, calc(100vw - 40px));
|
|
|
|
|
min-width: min(800px, calc(100vw - 40px));
|
|
|
|
|
height: min(820px, calc(100dvh - 40px));
|
|
|
|
|
width: min(1480px, calc(100vw - 40px));
|
|
|
|
|
min-width: min(980px, calc(100vw - 40px));
|
|
|
|
|
height: min(860px, calc(100dvh - 40px));
|
|
|
|
|
max-height: calc(100dvh - 40px);
|
|
|
|
|
padding: 0;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
@@ -3753,41 +3907,81 @@ async function saveFeaturedOrder() {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 18px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__thumb {
|
|
|
|
|
.requestPreview__summary {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: minmax(0, 1fr) 220px;
|
|
|
|
|
gap: 16px;
|
|
|
|
|
align-items: start;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__summaryBody {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 8px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__summaryThumb {
|
|
|
|
|
width: 100%;
|
|
|
|
|
max-height: 240px;
|
|
|
|
|
aspect-ratio: 16 / 9;
|
|
|
|
|
object-fit: cover;
|
|
|
|
|
border-radius: 18px;
|
|
|
|
|
border: 1px solid var(--theme-border);
|
|
|
|
|
background: var(--theme-surface-soft);
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__meta {
|
|
|
|
|
color: var(--theme-text-soft);
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__desc {
|
|
|
|
|
color: var(--theme-text-muted);
|
|
|
|
|
line-height: 1.6;
|
|
|
|
|
white-space: pre-line;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rows,
|
|
|
|
|
.requestPreview__board,
|
|
|
|
|
.requestPreview__pool {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__boardHead,
|
|
|
|
|
.requestPreview__row {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: 88px minmax(0, 1fr);
|
|
|
|
|
grid-template-columns: 92px minmax(0, 1fr);
|
|
|
|
|
gap: 12px;
|
|
|
|
|
align-items: start;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rowLabel,
|
|
|
|
|
.requestPreview__poolLabel {
|
|
|
|
|
.requestPreview__poolLabel,
|
|
|
|
|
.requestPreview__columnLabel {
|
|
|
|
|
font-size: 13px;
|
|
|
|
|
font-weight: 800;
|
|
|
|
|
color: rgba(255, 255, 255, 0.86);
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rowLabel--head {
|
|
|
|
|
color: var(--theme-text-faint);
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__columnLabels,
|
|
|
|
|
.requestPreview__cells {
|
|
|
|
|
display: grid;
|
|
|
|
|
gap: 12px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__columnLabel,
|
|
|
|
|
.requestPreview__cell {
|
|
|
|
|
min-width: 0;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__cell {
|
|
|
|
|
padding: 10px;
|
|
|
|
|
border-radius: 16px;
|
|
|
|
|
border: 1px solid var(--theme-border);
|
|
|
|
|
background: var(--theme-surface-soft);
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rowItems {
|
|
|
|
|
display: grid;
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(72px, 1fr));
|
|
|
|
|
gap: 10px;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rowItems--pool {
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__rowItems--pool {
|
|
|
|
|
grid-template-columns: repeat(auto-fill, minmax(84px, 1fr));
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__item {
|
|
|
|
|
position: relative;
|
|
|
|
|
overflow: hidden;
|
|
|
|
|
@@ -3834,7 +4028,7 @@ async function saveFeaturedOrder() {
|
|
|
|
|
padding: 16px;
|
|
|
|
|
}
|
|
|
|
|
.tierAdminCard__preview {
|
|
|
|
|
cursor: pointer;
|
|
|
|
|
cursor: default;
|
|
|
|
|
}
|
|
|
|
|
.tierAdminCard__thumb {
|
|
|
|
|
width: 100%;
|
|
|
|
|
@@ -4043,8 +4237,14 @@ async function saveFeaturedOrder() {
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
min-height: auto;
|
|
|
|
|
}
|
|
|
|
|
.requestPreview__summary,
|
|
|
|
|
.requestPreview__boardHead,
|
|
|
|
|
.requestPreview__row {
|
|
|
|
|
grid-template-columns: 1fr;
|
|
|
|
|
}
|
|
|
|
|
.modalCard--customItem {
|
|
|
|
|
width: min(100%, calc(100vw - 24px));
|
|
|
|
|
min-width: 0;
|
|
|
|
|
height: min(100%, calc(100dvh - 24px));
|
|
|
|
|
}
|
|
|
|
|
.customItemModal__pickerPanel {
|
|
|
|
|
|