Compare commits

...

3 Commits

5 changed files with 112 additions and 51 deletions

View File

@@ -1,5 +1,17 @@
# 업데이트 로그 # 업데이트 로그
## 2026-03-31 v1.2.67
- 홈 화면 게임 템플릿 즐겨찾기 버튼 위치 변경은 유지하면서, 즐겨찾기 on/off 시 카드가 즉시 튀지 않고 부드럽게 재정렬되도록 이동/페이드 전환을 추가함.
- 별 아이콘을 눌렀을 때 카드가 즐겨찾기 우선순위 위치로 자연스럽게 이동해 전체 라이브러리 전환감이 덜 거칠게 보이도록 보정함.
## 2026-03-31 v1.2.66
- 내 티어표 카드 하단의 큰 삭제 버튼은 제거하고, 삭제는 상세 편집 화면에서만 하도록 흐름을 단순화함.
- 내 티어표 카드 그리드를 고정 4/3/2열에서 `auto-fit` 기반 최소 폭 카드로 바꾸고, 제목/메타가 좁은 화면에서도 말줄임과 유연한 폭 계산을 유지하도록 보정함.
## 2026-03-31 v1.2.65
- 에디터 옵션 토글의 라벨과 스위치 순서를 바꾼 뒤 체크 상태 셀렉터가 끊긴 문제를 보정해, 왼쪽 라벨·오른쪽 스위치 배치에서도 정상 동작하도록 수정함.
- 왼쪽 사이드 축소 상태 검색은 전용 모달의 기본 스타일이 빠져 있던 문제를 복구해, 다시 중앙 상단 검색 오버레이로 열리도록 정리함.
## 2026-03-31 v1.2.64 ## 2026-03-31 v1.2.64
- 메인 콘텐츠가 길어질 때 스크롤 끝이 화면 바닥에 붙지 않도록 중앙 워크스페이스 하단 여백을 추가하고, 긴 작업 화면에서도 마감선이 답답하지 않게 보정함. - 메인 콘텐츠가 길어질 때 스크롤 끝이 화면 바닥에 붙지 않도록 중앙 워크스페이스 하단 여백을 추가하고, 긴 작업 화면에서도 마감선이 답답하지 않게 보정함.
- 템플릿 요청 모달 입력창을 Settings 화면과 같은 어두운 언더라인 입력 문법으로 통일하고, 에디터의 공개/이름 표시 옵션은 체크박스 대신 스위치형 토글로 재구성함. - 템플릿 요청 모달 입력창을 Settings 화면과 같은 어두운 언더라인 입력 문법으로 통일하고, 에디터의 공개/이름 표시 옵션은 체크박스 대신 스위치형 토글로 재구성함.

View File

@@ -893,6 +893,60 @@ function submitGlobalSearch() {
display: none; display: none;
} }
.collapsedSearchModal {
position: fixed;
inset: 0;
z-index: 35;
display: flex;
justify-content: center;
align-items: flex-start;
padding: 88px 20px 20px;
background: rgba(0, 0, 0, 0.44);
backdrop-filter: blur(6px);
}
.collapsedSearchBar {
width: min(520px, calc(100vw - 32px));
display: flex;
align-items: center;
gap: 14px;
padding: 18px 22px;
border-radius: 24px;
border: 1px solid rgba(255, 255, 255, 0.1);
background: rgba(26, 26, 26, 0.96);
box-shadow: 0 28px 60px rgba(0, 0, 0, 0.34);
}
.collapsedSearchBar__icon {
width: 28px;
height: 28px;
display: inline-flex;
align-items: center;
justify-content: center;
flex: 0 0 auto;
}
.collapsedSearchBar__icon img {
width: 28px;
height: 28px;
display: block;
filter: brightness(0) saturate(100%) invert(94%) sepia(6%) saturate(207%) hue-rotate(186deg) brightness(96%) contrast(92%);
}
.collapsedSearchBar__input {
min-width: 0;
flex: 1;
border: 0;
background: transparent;
color: rgba(255, 255, 255, 0.92);
font-size: 18px;
font-weight: 700;
outline: none;
}
.collapsedSearchBar__input::placeholder {
color: rgba(255, 255, 255, 0.46);
}
.localRightRailRoot { .localRightRailRoot {
min-height: auto; min-height: auto;
@@ -1087,10 +1141,11 @@ function submitGlobalSearch() {
} }
.collapsedSearchModal { .collapsedSearchModal {
padding-top: 72px; padding: 72px 16px 16px;
} }
.collapsedSearchBar { .collapsedSearchBar {
width: min(100%, calc(100vw - 24px));
padding: 16px 18px; padding: 16px 18px;
border-radius: 20px; border-radius: 20px;
} }

View File

@@ -82,7 +82,7 @@ function thumbUrl(g) {
</section> </section>
<div v-if="error" class="error">{{ error }}</div> <div v-if="error" class="error">{{ error }}</div>
<section v-if="games.length" class="libraryGrid"> <TransitionGroup v-if="games.length" name="libraryCard" tag="section" class="libraryGrid">
<article v-for="g in games" :key="g.id" class="libraryCard"> <article v-for="g in games" :key="g.id" class="libraryCard">
<button <button
class="libraryCard__favorite" class="libraryCard__favorite"
@@ -104,7 +104,7 @@ function thumbUrl(g) {
</div> </div>
</button> </button>
</article> </article>
</section> </TransitionGroup>
<div v-else class="libraryEmpty">{{ query ? '검색어에 맞는 게임 템플릿이 없어요.' : '표시할 게임 템플릿이 없어요.' }}</div> <div v-else class="libraryEmpty">{{ query ? '검색어에 맞는 게임 템플릿이 없어요.' : '표시할 게임 템플릿이 없어요.' }}</div>
</template> </template>
@@ -139,6 +139,7 @@ function thumbUrl(g) {
gap: 12px; gap: 12px;
box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04); box-shadow: inset 0 1px 0 rgba(255, 255, 255, 0.04);
transition: transform 0.16s ease, background 0.16s ease; transition: transform 0.16s ease, background 0.16s ease;
will-change: transform, opacity;
} }
.libraryCard:hover { .libraryCard:hover {
background: rgba(70, 70, 70, 0.96); background: rgba(70, 70, 70, 0.96);
@@ -156,8 +157,8 @@ function thumbUrl(g) {
} }
.libraryCard__favorite { .libraryCard__favorite {
position: absolute; position: absolute;
top: 12px; bottom: 24px;
right: 12px; right: 14px;
width: 34px; width: 34px;
height: 34px; height: 34px;
border-radius: 999px; border-radius: 999px;
@@ -206,6 +207,24 @@ function thumbUrl(g) {
overflow: hidden; overflow: hidden;
text-overflow: ellipsis; text-overflow: ellipsis;
} }
.libraryCard-move,
.libraryCard-enter-active,
.libraryCard-leave-active {
transition: transform 280ms ease, opacity 220ms ease;
}
.libraryCard-enter-from,
.libraryCard-leave-to {
opacity: 0;
transform: translateY(10px) scale(0.985);
}
.libraryCard-leave-active {
position: absolute;
width: calc(100% - 0px);
pointer-events: none;
}
.libraryEmpty { .libraryEmpty {
padding: 20px 0; padding: 20px 0;
color: rgba(255, 255, 255, 0.62); color: rgba(255, 255, 255, 0.62);

View File

@@ -54,18 +54,6 @@ function openList(t) {
router.push(`/editor/${t.gameId}/${t.id}`) router.push(`/editor/${t.gameId}/${t.id}`)
} }
async function removeList(t) {
error.value = ''
try {
const ok = window.confirm(`"${t.title}" 티어표를 삭제할까요?`)
if (!ok) return
await api.deleteTierList(t.id)
myLists.value = myLists.value.filter((entry) => entry.id !== t.id)
toast.success('티어표를 삭제했어요.')
} catch (e) {
error.value = '티어표 삭제에 실패했어요.'
}
}
</script> </script>
<template> <template>
@@ -101,7 +89,6 @@ async function removeList(t) {
</div> </div>
</div> </div>
</button> </button>
<button class="link link--danger" @click="removeList(t)">삭제</button>
</article> </article>
</div> </div>
</div> </div>
@@ -115,25 +102,17 @@ async function removeList(t) {
border-radius: 0; border-radius: 0;
padding: 0; padding: 0;
} }
.link {
padding: 10px 12px;
border-radius: 14px;
border: 1px solid rgba(255, 255, 255, 0.14);
background: rgba(255, 255, 255, 0.06);
color: rgba(255, 255, 255, 0.92);
cursor: pointer;
font-weight: 800;
}
.empty { .empty {
opacity: 0.75; opacity: 0.75;
} }
.list { .list {
display: grid; display: grid;
grid-template-columns: repeat(4, minmax(0, 1fr)); grid-template-columns: repeat(auto-fit, minmax(260px, 1fr));
gap: 18px; gap: 18px;
} }
.boardCard { .boardCard {
display: grid; display: grid;
min-width: 0;
border-radius: 22px; border-radius: 22px;
border: 1px solid rgba(255, 255, 255, 0.16); border: 1px solid rgba(255, 255, 255, 0.16);
background: rgba(62, 62, 62, 0.82); background: rgba(62, 62, 62, 0.82);
@@ -184,30 +163,40 @@ async function removeList(t) {
border-radius: 18px; border-radius: 18px;
} }
.boardCard__title { .boardCard__title {
font-weight: 900; flex: 1 1 auto;
min-width: 0; min-width: 0;
font-weight: 900;
font-size: 18px; font-size: 18px;
white-space: nowrap; line-height: 1.3;
display: -webkit-box;
-webkit-line-clamp: 2;
-webkit-box-orient: vertical;
overflow: hidden; overflow: hidden;
text-overflow: ellipsis;
} }
.boardCard__head { .boardCard__head {
padding: 16px 18px 18px; padding: 16px 18px 18px;
display: grid; display: grid;
gap: 6px; gap: 8px;
min-width: 0;
} }
.boardCard__titleRow, .boardCard__titleRow,
.boardCard__metaRow { .boardCard__metaRow {
display: flex; display: flex;
gap: 10px; gap: 10px;
min-width: 0;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
} }
.boardCard__titleRow {
align-items: flex-start;
}
.boardCard__metaRow { .boardCard__metaRow {
align-items: flex-end; align-items: flex-end;
} }
.boardCard__author { .boardCard__author {
flex: 1 1 auto;
min-width: 0; min-width: 0;
display: inline-flex; display: inline-flex;
gap: 7px; gap: 7px;
@@ -246,21 +235,6 @@ async function removeList(t) {
.boardCard__date { .boardCard__date {
font-size: 10px; font-size: 10px;
} }
.link--danger {
background: rgba(239, 68, 68, 0.14);
border-color: rgba(239, 68, 68, 0.28);
margin: 0 18px 18px;
}
@media (max-width: 1400px) {
.list {
grid-template-columns: repeat(3, minmax(0, 1fr));
}
}
@media (max-width: 1024px) {
.list {
grid-template-columns: repeat(2, minmax(0, 1fr));
}
}
@media (max-width: 720px) { @media (max-width: 720px) {
.list { .list {
grid-template-columns: 1fr; grid-template-columns: 1fr;

View File

@@ -992,13 +992,13 @@ onUnmounted(() => {
<div class="editorSidebar__section editorSidebar__section--footer"> <div class="editorSidebar__section editorSidebar__section--footer">
<label class="toggleSwitch" :class="{ 'toggleSwitch--disabled': !canEdit }"> <label class="toggleSwitch" :class="{ 'toggleSwitch--disabled': !canEdit }">
<input v-model="isPublic" type="checkbox" :disabled="!canEdit" /> <input v-model="isPublic" type="checkbox" :disabled="!canEdit" />
<span class="toggleSwitch__track"><span class="toggleSwitch__thumb"></span></span>
<span class="toggleSwitch__label">공개</span> <span class="toggleSwitch__label">공개</span>
<span class="toggleSwitch__track"><span class="toggleSwitch__thumb"></span></span>
</label> </label>
<label class="toggleSwitch" :class="{ 'toggleSwitch--disabled': !canEdit }"> <label class="toggleSwitch" :class="{ 'toggleSwitch--disabled': !canEdit }">
<input v-model="showCharacterNames" type="checkbox" :disabled="!canEdit" /> <input v-model="showCharacterNames" type="checkbox" :disabled="!canEdit" />
<span class="toggleSwitch__track"><span class="toggleSwitch__thumb"></span></span>
<span class="toggleSwitch__label">캐릭터 이름 표시</span> <span class="toggleSwitch__label">캐릭터 이름 표시</span>
<span class="toggleSwitch__track"><span class="toggleSwitch__thumb"></span></span>
</label> </label>
<div class="editorSidebar__actionGrid"> <div class="editorSidebar__actionGrid">
<button class="btn btn--ghost editorSidebar__button" @click="downloadImage">이미지 다운로드</button> <button class="btn btn--ghost editorSidebar__button" @click="downloadImage">이미지 다운로드</button>
@@ -1137,6 +1137,7 @@ onUnmounted(() => {
.toggleSwitch { .toggleSwitch {
display: inline-flex; display: inline-flex;
align-items: center; align-items: center;
justify-content: space-between;
gap: 12px; gap: 12px;
padding: 10px 12px; padding: 10px 12px;
border-radius: 14px; border-radius: 14px;
@@ -1175,11 +1176,11 @@ onUnmounted(() => {
font-weight: 800; font-weight: 800;
color: rgba(255, 255, 255, 0.9); color: rgba(255, 255, 255, 0.9);
} }
.toggleSwitch input:checked + .toggleSwitch__track { .toggleSwitch input:checked ~ .toggleSwitch__track {
background: rgba(96, 165, 250, 0.34); background: rgba(96, 165, 250, 0.34);
border-color: rgba(96, 165, 250, 0.42); border-color: rgba(96, 165, 250, 0.42);
} }
.toggleSwitch input:checked + .toggleSwitch__track .toggleSwitch__thumb { .toggleSwitch input:checked ~ .toggleSwitch__track .toggleSwitch__thumb {
transform: translateX(18px); transform: translateX(18px);
} }
.toggleSwitch--disabled { .toggleSwitch--disabled {