Files
minecraft_launcher/views/op/datapack.ejs
claude-bot a532ce5507 Fix op page UI: button underline, tab panel duplication, header spacing
- /op/dashboard: remove underline from <a class="secondaryButton"> by adding
  text-decoration:none + inline-flex centering on .primaryButton/.secondaryButton/
  .dangerButton, plus margin-left:auto on .dashboardActions so the buttons stick
  to the right side of the row even when the header is laid out as flex+wrap.
- /op/list/<pack>: fix the duplicate "save/clear + playlist URL" UI showing in
  the active tab. .tabPanel had a baseline `display: block;` that overrode the
  browser default `[hidden] { display: none }`. Add an explicit
  `.tabPanel[hidden] { display: none !important }` rule so the inactive panel
  actually hides.
- /op/list, /op/list/<pack>, /op/datapack: bump the gap between the "돌아가기"
  ghost link and the page title from 8px to 20px.
- docs/yt-dlp-setup.md: install guide (single-binary curl + pipx + apt) since
  the server doesn't have pip/pipx/yt-dlp installed. Server keeps the graceful
  "수동 입력으로 진행" fallback when yt-dlp is missing.
2026-05-12 13:11:44 +09:00

122 lines
5.0 KiB
Plaintext
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title>데이터팩 수정</title>
<link rel="stylesheet" href="/static/styles.css" />
</head>
<body class="siteBody">
<%- include('../partials/navbar', { userId }) %>
<main class="pageWrap">
<section class="dashboardHeader">
<div>
<a class="ghostLink" href="/op/dashboard">← 돌아가기</a>
<h1 style="margin-top:20px;">데이터팩 수정</h1>
</div>
</section>
<section class="dpControls">
<button type="button" class="primaryButton" id="pickPackBtn">음악퀴즈 선택</button>
<span class="muted" id="pickedLabel">선택된 음악퀴즈 없음</span>
</section>
<p class="muted" id="countLabel"></p>
<section class="dpActions" hidden id="dpActions">
<button type="button" class="secondaryButton" id="exportBtn">데이터팩 출력</button>
<button type="button" class="secondaryButton" id="copyBtn">복사</button>
<span class="statusText" id="dp-status"></span>
</section>
<pre class="codeBlock" id="codeOut" hidden></pre>
</main>
<!-- 음악퀴즈 선택 팝업 -->
<div class="modalOverlay" id="pickModal" hidden>
<div class="modalCard">
<header><h3>음악퀴즈 선택</h3>
<button class="modalClose" type="button" data-modal-close>×</button>
</header>
<div class="modalBody">
<div class="cardRow horizontalScroll" id="pickList">
<% items.forEach(function (item) { %>
<article class="packCard pickable" data-key="<%= item.key %>" data-name="<%= item.definition ? item.definition.name : item.key %>">
<h2><%= item.definition ? item.definition.name : item.key %></h2>
<p class="muted"><%= item.key %>.json</p>
<% if (item.definition) { %>
<ul class="metaList">
<li>MC <%= item.definition.mcVersion %></li>
<li>플랫폼 <%= item.definition.platform.type %></li>
</ul>
<% } %>
</article>
<% }) %>
</div>
</div>
</div>
</div>
<script>
(function () {
var pickModal = document.getElementById('pickModal')
var pickedKey = ''
document.getElementById('pickPackBtn').addEventListener('click', function () {
pickModal.hidden = false
})
document.querySelectorAll('[data-modal-close]').forEach(function (b) {
b.addEventListener('click', function () { pickModal.hidden = true })
})
pickModal.addEventListener('click', function (e) {
if (e.target === pickModal) pickModal.hidden = true
})
document.querySelectorAll('#pickList .pickable').forEach(function (card) {
card.addEventListener('click', function () {
pickedKey = card.getAttribute('data-key')
var name = card.getAttribute('data-name')
document.getElementById('pickedLabel').textContent = '선택: ' + name
pickModal.hidden = true
document.getElementById('dpActions').hidden = false
// 곡 수 미리 가져오기
fetch('/op/list/' + encodeURIComponent(pickedKey)).catch(function () {})
// 더 직접적으로: generate 호출 시점에 카운트도 나옴. 일단 비워둠.
document.getElementById('countLabel').textContent = ''
document.getElementById('codeOut').hidden = true
})
})
document.getElementById('exportBtn').addEventListener('click', function () {
if (!pickedKey) return
var s = document.getElementById('dp-status')
s.textContent = '출력 중…'; s.classList.remove('error')
fetch('/op/datapack/' + encodeURIComponent(pickedKey) + '/generate')
.then(function (r) { return r.text().then(function (t) { return { ok: r.ok, text: t } }) })
.then(function (res) {
if (!res.ok) {
s.textContent = '실패: ' + res.text; s.classList.add('error')
return
}
var out = document.getElementById('codeOut')
out.textContent = res.text
out.hidden = false
// 첫줄/둘째줄에서 카운트 가져와 표기
var m = res.text.match(/총\s+(\d+)곡/)
if (m) document.getElementById('countLabel').textContent = '총 ' + m[1] + '개의 음악을 찾았습니다.'
s.textContent = '출력 완료'
})
.catch(function (err) { s.textContent = '실패: ' + err.message; s.classList.add('error') })
})
document.getElementById('copyBtn').addEventListener('click', function () {
var out = document.getElementById('codeOut')
if (out.hidden) return
navigator.clipboard.writeText(out.textContent).then(function () {
var s = document.getElementById('dp-status')
s.textContent = '복사됨'
s.classList.remove('error')
})
})
})()
</script>
</body>
</html>