fix: improve mobile navigation and calculator usability
Publish GitHub Pages output / publish (push) Successful in 32s

This commit is contained in:
dal4segno committed 2026-09-21 11:30:22 +09:00
1 parent 3b1c1aeb6f
commit 0bdade44e3
11 files changed
+205 -22

No files matched your search

+70 -6
View File
@@ -317,6 +317,43 @@
boardViewport.scrollTop = contentY * boardZoom - pointerY;
}
async function changeBoardZoom(factor: number) {
if (!boardViewport) return;
const centerX = boardViewport.clientWidth / 2;
const centerY = boardViewport.clientHeight / 2;
const contentX = (boardViewport.scrollLeft + centerX) / boardZoom;
const contentY = (boardViewport.scrollTop + centerY) / boardZoom;
boardZoom = Math.max(0.4, Math.min(1.8, boardZoom * factor));
await tick();
boardViewport.scrollLeft = contentX * boardZoom - centerX;
boardViewport.scrollTop = contentY * boardZoom - centerY;
}
function manageCardDialog(node: HTMLElement) {
const previousFocus = document.activeElement;
const previousOverflow = document.body.style.overflow;
document.body.style.overflow = 'hidden';
node.focus();
function keydown(event: KeyboardEvent) {
if (event.key === 'Escape') { event.preventDefault(); selectedSocketGroupId = ''; }
if (event.key !== 'Tab') return;
const controls = Array.from(node.querySelectorAll<HTMLElement>('button:not(:disabled), input:not(:disabled), [tabindex="0"]'));
const first = controls[0];
const last = controls.at(-1);
if (event.shiftKey && (document.activeElement === first || document.activeElement === node)) {
event.preventDefault(); last?.focus();
} else if (!event.shiftKey && document.activeElement === last) {
event.preventDefault(); first?.focus();
}
}
node.addEventListener('keydown', keydown);
return { destroy() {
node.removeEventListener('keydown', keydown);
document.body.style.overflow = previousOverflow;
if (previousFocus instanceof HTMLElement) previousFocus.focus({ preventScroll: true });
} };
}
function startBoardDrag(event: PointerEvent) {
if (!boardViewport || event.button !== 0 || (event.target as HTMLElement).closest('.board-node')) return;
boardDragging = true;
@@ -1378,6 +1415,13 @@
<p><strong>{selectedActiveBoardNodeCount}</strong> / {selectedBoardNodeCount}개 활성화</p>
<div><button type="button" on:click={activateAllBlueNodes}>모든 파란 노드 활성화</button><button type="button" on:click={() => setAllBoardNodes(true)}>모두 활성화</button><button type="button" on:click={() => setAllBoardNodes(false)}>모두 해제</button></div>
</div>
<div class="board-zoom" aria-label="보드 확대 및 축소">
<button type="button" aria-label="보드 축소" disabled={boardZoom <= .4} on:click={() => changeBoardZoom(1 / 1.25)}>−</button>
<span>{Math.round(boardZoom * 100)}%</span>
<button type="button" aria-label="보드 확대" disabled={boardZoom >= 1.8} on:click={() => changeBoardZoom(1.25)}>+</button>
<button type="button" on:click={fitBoardViewport}>화면 맞춤</button>
</div>
<p class="board-note">보드의 빈 곳을 드래그하면 이동합니다. +·− 버튼으로 확대·축소하고, 보드 바깥을 쓸어 페이지를 이동하세요.</p>
<div
class="board-scroll"
class:dragging={boardDragging}
@@ -1451,7 +1495,7 @@
{#if selectedSocketGroupId}
<div class="card-picker-backdrop" role="presentation" on:click={(event) => { if (event.target === event.currentTarget) selectedSocketGroupId = ''; }}>
<div class="card-picker" role="dialog" aria-modal="true" aria-labelledby="card-picker-title" tabindex="-1">
<div class="card-picker" use:manageCardDialog role="dialog" aria-modal="true" aria-labelledby="card-picker-title" tabindex="-1">
<div class="card-picker-heading">
<div><p class="section-label">연결 노드</p><h3 id="card-picker-title">배치할 카드 선택</h3></div>
<button type="button" aria-label="닫기" on:click={() => selectedSocketGroupId = ''}>×</button>
@@ -1753,7 +1797,7 @@
.board-legend i { width: 9px; height: 9px; border-radius: 50%; }
.board-note { margin: 10px 0 0; color: #7f8999; font-size: 13px; line-height: 1.5; }
.card-picker-backdrop { position: fixed; inset: 0; z-index: 30; display: grid; place-items: center; padding: 20px; background: rgb(5 8 12 / 72%); }
.card-picker { width: min(620px, 100%); max-height: min(760px, calc(100vh - 40px)); overflow: hidden; border: 1px solid #3b4453; border-radius: 16px; background: #171c24; box-shadow: 0 20px 70px rgb(0 0 0 / 45%); }
.card-picker { display: flex; flex-direction: column; width: min(620px, 100%); max-height: min(760px, calc(100dvh - 40px)); overflow: hidden; border: 1px solid #3b4453; border-radius: 16px; background: #171c24; box-shadow: 0 20px 70px rgb(0 0 0 / 45%); }
.card-picker-heading { display: flex; align-items: center; justify-content: space-between; padding: 20px 20px 10px; }
.card-picker-heading h3 { margin: 2px 0 0; color: #edf0f5; font-size: 20px; }
.card-picker-heading button { width: 34px; height: 34px; border: 1px solid #3b4453; border-radius: 9px; color: #c9d0da; background: #242b36; font-size: 22px; cursor: pointer; }
@@ -1763,7 +1807,7 @@
.current-placement span { color: #d990af; font-size: 12px; font-weight: 850; }
.current-placement strong { overflow: hidden; color: #dce1e9; font-size: 14px; text-overflow: ellipsis; white-space: nowrap; }
.current-placement button { padding: 5px 8px; border: 1px solid #65404f; border-radius: 6px; color: #f0a8c5; background: transparent; font-size: 12px; cursor: pointer; }
.connect-card-list { display: grid; gap: 6px; max-height: 520px; overflow-y: auto; padding: 0 20px 20px; scrollbar-width: thin; }
.connect-card-list { min-height: 0; display: grid; gap: 6px; max-height: 520px; overflow-y: auto; padding: 0 20px 20px; scrollbar-width: thin; }
.connect-card-list > button { display: grid; grid-template-columns: 38px minmax(0, 1fr) 54px auto; align-items: center; gap: 11px; min-height: 66px; padding: 8px 10px; border: 1px solid #303845; border-radius: 10px; color: inherit; background: #12171e; text-align: left; cursor: pointer; }
.connect-card-list > button:hover, .connect-card-list > button.selected { border-color: #a95e7f; background: #211a23; }
.connect-card-rarity { color: #f1a5c5; font-size: 13px; font-weight: 900; }
@@ -1791,7 +1835,7 @@
aside { margin-top: 16px; padding: 18px 20px; border: 1px solid #292f3b; border-radius: 14px; color: #929cad; background: #151920; font-size: 13px; line-height: 1.6; }
aside strong { color: #cbd1db; }
aside p { margin: 5px 0 0; }
@media (max-width: 700px) {
@media (max-width: 900px) {
main { width: min(100% - 24px, 900px); padding-top: var(--page-content-top); }
.summary { grid-template-columns: repeat(2, 1fr); }
.settings-grid { grid-template-columns: 1fr; }
@@ -1822,11 +1866,31 @@
.efficiency-table-head, .efficiency-list > button { grid-template-columns: 28px 210px 100px 90px 110px 115px; min-width: 710px; }
.board-scroll { height: min(58vh, 560px); }
.card-picker-backdrop { align-items: end; padding: 0; }
.card-picker { max-height: 88vh; border-radius: 16px 16px 0 0; }
.connect-card-list { max-height: 56vh; }
.card-picker { max-height: 88dvh; padding-bottom: env(safe-area-inset-bottom); border-radius: 16px 16px 0 0; }
.connect-card-list { max-height: none; overflow-y: auto; }
.connect-card-list > button { grid-template-columns: 28px minmax(0, 1fr) 48px auto; gap: 7px; padding-inline: 8px; }
.connect-range-preview { width: 44px; height: 44px; }
.actions { display: grid; }
.actions .danger { margin: 10px 0 0; }
}
.card-picker-heading, .card-picker-note, .card-picker-search, .current-placement { flex-shrink: 0; }
.connect-card-list { grid-auto-rows: max-content; align-content: start; }
.board-zoom { display: flex; flex-wrap: wrap; align-items: center; gap: 8px; }
.board-zoom button { min-width: 44px; min-height: 44px; padding: 8px 12px; border: 1px solid #465064; border-radius: 8px; color: #d5dbe4; background: #202733; cursor: pointer; }
.board-zoom button:disabled { opacity: .45; cursor: default; }
.board-zoom span { min-width: 42px; text-align: center; }
.board-zoom + .board-note { margin-bottom: 10px; }
@media (max-width: 900px) {
.board-toolbar, .board-toolbar div { flex-wrap: wrap; }
.board-toolbar button, .card-picker-heading button { min-height: 44px; }
.card-picker-heading button { min-width: 44px; }
.card-table .table-row { grid-template-columns: 34px minmax(0, 1fr); }
.awakening-field { grid-column: 2; }
.awakening-stepper { height: 46px; grid-template-columns: 44px minmax(0, 1fr) 44px; }
.identity { flex-wrap: wrap; }
.identity strong, .max-awakening-check > strong, .connect-card-name strong, .current-placement strong { white-space: normal; overflow-wrap: anywhere; }
.connect-card-list > button { grid-template-columns: 28px minmax(0, 1fr) 48px; }
.connect-card-effect { grid-column: 2 / -1; justify-items: start; }
}
</style>