Compare commits

...

3 Commits

Author SHA1 Message Date
ecd3e69b5a ui: refine editor sidebar scroll spacing 2026-04-06 13:55:05 +09:00
3dba9b0a4d ui: preserve editor sidebar end spacing 2026-04-06 13:51:57 +09:00
56b0035a45 ui: support Korean shortcut keys 2026-04-06 13:49:14 +09:00
4 changed files with 92 additions and 53 deletions

View File

@@ -1,5 +1,15 @@
# 의사결정 이력
## 2026-04-06 v1.4.101
- 실제 문제는 `editorCanvas` 자체보다 그 아래 `workspaceBody--localRail`의 하단 패딩까지 문서가 더 스크롤되는 구간에서 발생했다. 따라서 오른쪽 sticky 카드만 보정하는 것보다, 오른쪽 컬럼을 별도 래퍼로 감싸고 workspace 하단 패딩까지 고려한 여유 공간을 래퍼에 주는 편이 더 정확하다고 판단했다.
- 아이템 풀은 내부 스크롤이 필요하지만, 오른쪽 패널 안에서 스크롤바가 항상 보이면 작업 화면이 좁고 복잡해 보일 수 있으므로 스크롤 동작만 유지하고 스크롤바 시각 요소는 숨기는 편이 낫다고 정리했다.
## 2026-04-06 v1.4.100
- 오른쪽 아이템 패널은 sticky로 동작하지만 부모 컨테이너의 끝에 닿으면 sticky 제한 때문에 마지막 스크롤 위치에서 위쪽 여백이 무너져 보일 수 있다. 그래서 편집 캔버스 자체에 작은 하단 여유 공간을 두어 마지막 위치에서도 패널 주변 여백이 유지되도록 하는 편이 낫다고 판단했다.
## 2026-04-06 v1.4.99
- 단축키는 실제 키 위치 기준으로 기대하는 경우가 많으므로, 한글 입력 상태에서 S 자리 키가 `ㄴ`으로 들어와도 같은 “아이템 검색” 동작을 실행하고, F 자리 키가 `ㄹ`로 들어와도 같은 “전체 화면” 동작을 실행하는 편이 한국어 사용자에게 자연스럽다고 정리했다.
## 2026-04-06 v1.4.98
- 방송/편집처럼 화면을 자주 정리해야 하는 사용 흐름에서는 사이드 패널과 전체 화면 전환을 마우스로만 조작하면 반복 비용이 커진다. 그래서 `[`/`]`/`F`/`S`처럼 한 손으로 누르기 쉬운 단축키를 두되, 입력창에서는 단축키를 무시해 실제 텍스트 입력을 방해하지 않는 편이 맞다고 정리했다.
- `S`는 전역 템플릿 검색이 아니라 티어표 편집 화면의 아이템 검색으로 연결해야 하므로, 앱 셸이 편집 화면에 커스텀 이벤트를 보내고 편집 화면이 자신의 아이템 검색창에 포커스를 주는 방식으로 분리했다.

View File

@@ -1,5 +1,18 @@
# 업데이트 로그
## 2026-04-06 v1.4.101
- `workspaceBody--localRail`의 하단 패딩 구간까지 스크롤했을 때 오른쪽 아이템 카드가 sticky 기준 영역을 벗어나 상단에 붙어 보이던 문제를 보정했다. 오른쪽 sticky 컬럼을 래퍼로 감싸고 하단 여유 공간을 명시해 마지막 스크롤 위치에서도 여백이 유지되도록 했다.
- 티어표 편집 화면의 아이템 그리드 내부 스크롤은 유지하되, 시각적인 스크롤바는 보이지 않도록 정리했다.
- 확인: `npm run build`
## 2026-04-06 v1.4.100
- 티어표 편집 화면을 가장 아래까지 스크롤했을 때 오른쪽 아이템 카드가 부모 컨테이너 끝에 걸리며 상단 여백이 무너져 보일 수 있어, 편집 캔버스 하단에 sticky 여백용 패딩을 추가했다.
- 확인: `npm run build`
## 2026-04-06 v1.4.99
- 티어표 편집 화면의 아이템 검색/전체 화면 단축키를 한글 입력 상태에서도 쓸 수 있게 보정했다. `S`뿐 아니라 같은 물리 키에서 들어오는 `ㄴ`도 아이템 검색 포커스로 처리하고, `F` 자리에서 들어오는 `ㄹ`도 전체 화면 토글로 처리한다.
- 확인: `npm run build`
## 2026-04-06 v1.4.98
- 전역 단축키를 추가했다. `[`는 왼쪽 사이드 토글, `]`는 오른쪽 사이드 토글, `F`는 전체 화면 토글, `S`는 티어표 편집 화면의 아이템 검색창 포커스로 동작한다.
- 입력창, textarea, select, contenteditable 영역에서는 단축키가 동작하지 않도록 막아 검색이나 이름 입력을 방해하지 않게 했다.

View File

@@ -143,7 +143,7 @@ const guideSteps = [
title: '단축키로 빠른 조작',
summary: '사이드 패널과 전체 화면을 키보드로 빠르게 전환합니다.',
description:
'[ 키는 왼쪽 사이드를 열고 닫고, ] 키는 오른쪽 사이드를 열고 닫습니다. F 키는 전체 화면 보기 토글, S 키는 티어표 편집 화면의 아이템 검색창으로 바로 이동할 때 사용할 수 있어요. 각종 모달은 Esc 키로 닫을 수 있습니다. 단, 검색창이나 입력칸에 글을 쓰는 중에는 단축키가 동작하지 않도록 처리되어 있어요.',
'[ 키는 왼쪽 사이드를 열고 닫고, ] 키는 오른쪽 사이드를 열고 닫습니다. F 키는 전체 화면 보기 토글, S 키는 티어표 편집 화면의 아이템 검색창으로 바로 이동할 때 사용할 수 있어요. 한글 입력 상태에서는 F 자리의 ㄹ, S 자리의 ㄴ 키도 같은 단축키로 처리됩니다. 각종 모달은 Esc 키로 닫을 수 있습니다. 단, 검색창이나 입력칸에 글을 쓰는 중에는 단축키가 동작하지 않도록 처리되어 있어요.',
},
]
const currentGuideStep = computed(() => guideSteps[guideStepIndex.value] || guideSteps[0])
@@ -367,12 +367,12 @@ function handleGlobalKeydown(event) {
toggleRightRail()
return
}
if (String(event.key || '').toLowerCase() === 'f') {
if (['f', 'ㄹ'].includes(String(event.key || '').toLowerCase())) {
event.preventDefault()
toggleFullscreen()
return
}
if (String(event.key || '').toLowerCase() === 's' && ['editEditor', 'newEditor'].includes(String(route.name || ''))) {
if (['s', 'ㄴ'].includes(String(event.key || '').toLowerCase()) && ['editEditor', 'newEditor'].includes(String(route.name || ''))) {
event.preventDefault()
window.dispatchEvent(new CustomEvent('tier-maker:focus-editor-item-search'))
}

View File

@@ -1809,59 +1809,61 @@ onUnmounted(() => {
</div>
</div>
<div ref="sidebarEl" class="sidebar" :style="{ '--editor-sidebar-max-height': editorSidebarMaxHeight || undefined }">
<div class="sidebar__titleRow">
<div class="sidebar__title">아이템</div>
<div class="sidebar__count">{{ visiblePoolCount }} / {{ pool.length }}</div>
</div>
<div class="sidebar__hint">
{{ canEdit ? '아이템을 드래그하거나, 클릭으로 선택한 뒤 원하는 셀/풀을 클릭해서 옮길 수 있어요.' : '공개 티어표는 보기 전용입니다.' }}
</div>
<input
ref="poolSearchEl"
v-model="poolSearchQuery"
class="sidebar__search"
type="text"
maxlength="60"
placeholder="아이템 이름 검색"
/>
<div
ref="poolEl"
class="pool"
:class="{ 'pool--clickTarget': canEdit && !!selectedItemId }"
data-list-type="pool"
@click.self="moveSelectedItemToPool"
>
<div class="sidebarStickyFrame">
<div ref="sidebarEl" class="sidebar" :style="{ '--editor-sidebar-max-height': editorSidebarMaxHeight || undefined }">
<div class="sidebar__titleRow">
<div class="sidebar__title">아이템</div>
<div class="sidebar__count">{{ visiblePoolCount }} / {{ pool.length }}</div>
</div>
<div class="sidebar__hint">
{{ canEdit ? '아이템을 드래그하거나, 클릭으로 선택한 뒤 원하는 셀/풀을 클릭해서 옮길 수 있어요.' : '공개 티어표는 보기 전용입니다.' }}
</div>
<input
ref="poolSearchEl"
v-model="poolSearchQuery"
class="sidebar__search"
type="text"
maxlength="60"
placeholder="아이템 이름 검색"
/>
<div
v-for="id in pool"
:key="id"
class="poolItem"
:class="{
'poolItem--readonly': !canEdit,
'poolItem--hidden': !isPoolItemVisible(id),
'poolItem--selected': selectedItemId === id,
}"
:data-item-id="id"
@click.stop="selectItemByClick(id)"
ref="poolEl"
class="pool"
:class="{ 'pool--clickTarget': canEdit && !!selectedItemId }"
data-list-type="pool"
@click.self="moveSelectedItemToPool"
>
<img
:src="resolveItemSrc(itemsById[id])"
class="thumb"
:alt="itemsById[id]?.label || id"
draggable="false"
/>
<div class="poolItem__label">{{ itemsById[id]?.label || id }}</div>
<button
v-if="canRemoveEditorItem(id)"
class="poolItem__deleteBtn"
type="button"
title="커스텀 이미지 제거"
@pointerdown.stop
@click.stop="deleteEditorItem(id)"
<div
v-for="id in pool"
:key="id"
class="poolItem"
:class="{
'poolItem--readonly': !canEdit,
'poolItem--hidden': !isPoolItemVisible(id),
'poolItem--selected': selectedItemId === id,
}"
:data-item-id="id"
@click.stop="selectItemByClick(id)"
>
삭제
</button>
<div v-if="!canEdit" class="poolItem__state">미배치</div>
<img
:src="resolveItemSrc(itemsById[id])"
class="thumb"
:alt="itemsById[id]?.label || id"
draggable="false"
/>
<div class="poolItem__label">{{ itemsById[id]?.label || id }}</div>
<button
v-if="canRemoveEditorItem(id)"
class="poolItem__deleteBtn"
type="button"
title="커스텀 이미지 제거"
@pointerdown.stop
@click.stop="deleteEditorItem(id)"
>
삭제
</button>
<div v-if="!canEdit" class="poolItem__state">미배치</div>
</div>
</div>
</div>
</div>
@@ -2022,6 +2024,13 @@ onUnmounted(() => {
grid-template-columns: minmax(0, clamp(680px, 58vw, 960px)) minmax(280px, 1fr);
gap: 16px;
align-items: start;
padding-bottom: 14px;
}
.sidebarStickyFrame {
min-width: 0;
align-self: stretch;
box-sizing: border-box;
padding-bottom: 46px;
}
.editorMain__title {
font-size: 28px;
@@ -3145,11 +3154,15 @@ onUnmounted(() => {
flex: 1 1 auto;
min-height: 0;
overflow-y: auto;
scrollbar-width: none;
display: grid;
grid-template-columns: repeat(auto-fill, minmax(96px, 1fr));
gap: 10px;
align-content: start;
}
.pool::-webkit-scrollbar {
display: none;
}
.pool--clickTarget {
cursor: copy;
}
@@ -3342,6 +3355,9 @@ onUnmounted(() => {
max-height: none;
overflow: visible;
}
.sidebarStickyFrame {
padding-bottom: 0;
}
.pool {
overflow: visible;
grid-template-columns: repeat(6, minmax(0, 1fr));