diff --git a/installer-rp/renderer.js b/installer-rp/renderer.js index 8d705ca..57b2fe0 100644 --- a/installer-rp/renderer.js +++ b/installer-rp/renderer.js @@ -141,14 +141,36 @@ function renderStep1() { } // 약관 동의 페이지: 1단계 직후, 2단계 설치 진입 전에 노출. -// rp 인스톨러는 리소스팩·설치기 두 약관만 확인·동의하면 된다. +// v0.3.4~ : 사이트의 visibility 토글에 따라 표시할 약관이 결정된다. 목록이 비면 단계를 건너뛴다. function renderAgreement() { setActiveStep(1) clearPage() - var KINDS = [ - { id: 'resourcepack', tab: tt('agreement.tabResourcepack') }, - { id: 'installer-rp', tab: tt('agreement.tabInstaller') } - ] + var loadingSection = document.createElement('section') + loadingSection.className = 'page' + loadingSection.innerHTML = '
' + escapeHtml(tt('agreement.loading')) + '
' + pageHost.appendChild(loadingSection) + + api.getTermsList().then(function (res) { + if (!res || !res.ok) { + renderStep2() + return + } + var terms = (res.terms || []).map(function (t) { + return { id: t.kind, tab: t.label } + }) + if (terms.length === 0) { + renderStep2() + return + } + clearPage() + renderAgreementWithKinds(terms) + }).catch(function () { + renderStep2() + }) +} + +function renderAgreementWithKinds(KINDS) { var section = document.createElement('section') section.className = 'page' section.innerHTML = diff --git a/installer/renderer.js b/installer/renderer.js index 6ed3820..634bc69 100644 --- a/installer/renderer.js +++ b/installer/renderer.js @@ -149,15 +149,38 @@ function renderStep1() { } // 약관 동의 페이지: 음악퀴즈 선택 직후, 싱글/멀티 선택(step2) 진입 전에 노출. -// 메인 설치기는 맵·모드·설치기 세 약관을 모두 확인·동의해야 다음 단계로 갈 수 있다. +// v0.3.4~ : 어떤 약관을 표시할지는 사이트(/manifest/terms/' + tt('agreement.loading') + '
' + pageHost.appendChild(loadingSection) + + installerApi.getTermsList().then(function (res) { + if (!res || !res.ok) { + // 목록 조회 실패면 약관 단계를 건너뛴다 (서버가 구버전일 수도 있으므로 차단보다 통과 선호). + renderStep2() + return + } + var terms = (res.terms || []).map(function (t) { + return { id: t.kind, tab: t.label } + }) + if (terms.length === 0) { + renderStep2() + return + } + clearPage() + renderAgreementWithKinds(terms) + }).catch(function () { + renderStep2() + }) +} + +function renderAgreementWithKinds(KINDS) { var section = document.createElement('section') section.className = 'page' section.innerHTML = diff --git a/locales/server/ko-kr.json b/locales/server/ko-kr.json index 42360ee..7817d0d 100644 --- a/locales/server/ko-kr.json +++ b/locales/server/ko-kr.json @@ -160,7 +160,11 @@ "slashQuote": "인용", "slashCode": "코드", "leaveConfirm": "저장하지 않은 변경사항이 있습니다.\n저장 없이 이 페이지를 떠나시겠습니까?", - "builtinBadge": "기본", + "visibilityHeading": "표시 대상 (중복 선택 가능)", + "visibilityInstaller": "설치기에 표시", + "visibilityInstallerRp": "리소스팩 설치기에 표시", + "visibilityInstallerShort": "설치기", + "visibilityInstallerRpShort": "리소스팩", "addHeading": "약관 추가", "kindLabel": "식별자", "kindPlaceholder": "예: privacy", diff --git a/package.json b/package.json index 4f40de1..9f158d0 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "minecraft-music-quiz-installer", - "version": "0.3.3", + "version": "0.3.4", "description": "마인크래프트 음악퀴즈 간편설치기 + 관리 사이트", "main": "dist/installer/main.js", "scripts": { diff --git a/public/termsEditor.js b/public/termsEditor.js index 567d322..39e1e45 100644 --- a/public/termsEditor.js +++ b/public/termsEditor.js @@ -15,6 +15,8 @@ var dirtyMark = document.getElementById('dirty-mark') var saveBtn = document.getElementById('saveBtn') var tabBtns = document.querySelectorAll('.tabBar .tabBtn') + var visInstaller = document.getElementById('visInstaller') + var visInstallerRp = document.getElementById('visInstallerRp') editor.value = INITIAL || '' var dirty = false @@ -23,6 +25,10 @@ dirtyMark.hidden = !v } + // 토글이 바뀌어도 dirty 표시. 저장 시 함께 전송된다. + if (visInstaller) visInstaller.addEventListener('change', function () { setDirty(true) }) + if (visInstallerRp) visInstallerRp.addEventListener('change', function () { setDirty(true) }) + // ─── markdown 미리 보기용 미니 렌더러 ──────────────────────────────── // 정식 markdown 파서는 아니지만, 본 편집기가 만들어 내는 형태(#, ##, ###, // - , 1. , > , ---, ``` , 토글 details) 정도는 충실히 처리한다. @@ -162,10 +168,13 @@ function save() { status.classList.remove('error') status.textContent = I18N.saving + var payload = { content: editor.value } + if (visInstaller) payload.showInInstaller = !!visInstaller.checked + if (visInstallerRp) payload.showInInstallerRp = !!visInstallerRp.checked fetch('/op/agreement/' + encodeURIComponent(PACK_KEY) + '/' + encodeURIComponent(TERM_KIND), { method: 'POST', headers: { 'Content-Type': 'application/json' }, - body: JSON.stringify({ content: editor.value }) + body: JSON.stringify(payload) }).then(function (r) { return r.json().then(function (j) { return { ok: r.ok && j && j.ok !== false, body: j } }) }).then(function (res) { diff --git a/src/installer-rp/main.ts b/src/installer-rp/main.ts index fe68299..ecf7a6f 100644 --- a/src/installer-rp/main.ts +++ b/src/installer-rp/main.ts @@ -252,12 +252,13 @@ ipcMain.handle('rp:packs:select', async (_event, packKey: string) => { ipcMain.handle('rp:i18n:dict', () => localeDict) // ── IPC: 약관 다운로드 ────────────────────────────── -// 사이트가 /manifest/terms/<%= t('terms.slashHint') %>