installer: split host/participant choice into its own tab
Previously the multi-mode role pick appeared as a sub-section that expanded inline under the single/multi cards. Per request, separate it into a dedicated page reached by pressing Next on the mode tab. - renderStep2 now only handles mode selection (single/multi). Next routes single → step4 directly, multi → renderStep2Role. - New renderStep2Role shows the host/participant cards on its own page with back to renderStep2. Next routes host → step3, participant → step4. - backToPrevStep in step4 and the back from sub31 in step3 updated so the role tab is the correct intermediate landing for multi flows. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -159,19 +159,10 @@ function renderStep2() {
|
|||||||
'<button id="single" type="button" data-mode="single"><strong>' + tt('step2.singleTitle') + '</strong><br><small>' + tt('step2.singleHint') + '</small></button>' +
|
'<button id="single" type="button" data-mode="single"><strong>' + tt('step2.singleTitle') + '</strong><br><small>' + tt('step2.singleHint') + '</small></button>' +
|
||||||
'<button id="multi" type="button" data-mode="multi"><strong>' + tt('step2.multiTitle') + '</strong><br><small>' + tt('step2.multiHint') + '</small></button>' +
|
'<button id="multi" type="button" data-mode="multi"><strong>' + tt('step2.multiTitle') + '</strong><br><small>' + tt('step2.multiHint') + '</small></button>' +
|
||||||
'</div>' +
|
'</div>' +
|
||||||
'<div id="roleSection" hidden style="margin-top:16px;">' +
|
|
||||||
'<h3>' + tt('step2.roleHeading') + '</h3>' +
|
|
||||||
'<div class="cardChoice">' +
|
|
||||||
'<button type="button" data-role="host"><strong>' + tt('step2.hostTitle') + '</strong><br><small>' + tt('step2.hostHint') + '</small></button>' +
|
|
||||||
'<button type="button" data-role="participant"><strong>' + tt('step2.participantTitle') + '</strong><br><small>' + tt('step2.participantHint') + '</small></button>' +
|
|
||||||
'</div>' +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
||||||
pageHost.appendChild(section)
|
pageHost.appendChild(section)
|
||||||
var nextBtn = section.querySelector('#next')
|
var nextBtn = section.querySelector('#next')
|
||||||
var modeButtons = section.querySelectorAll('[data-mode]')
|
var modeButtons = section.querySelectorAll('[data-mode]')
|
||||||
var roleSection = section.querySelector('#roleSection')
|
|
||||||
var roleButtons = section.querySelectorAll('[data-role]')
|
|
||||||
|
|
||||||
function applyMode(mode) {
|
function applyMode(mode) {
|
||||||
state.mode = mode
|
state.mode = mode
|
||||||
@@ -179,18 +170,50 @@ function renderStep2() {
|
|||||||
if (btn.getAttribute('data-mode') === mode) btn.classList.add('selected')
|
if (btn.getAttribute('data-mode') === mode) btn.classList.add('selected')
|
||||||
else btn.classList.remove('selected')
|
else btn.classList.remove('selected')
|
||||||
})
|
})
|
||||||
if (mode === 'multi') {
|
|
||||||
roleSection.hidden = false
|
|
||||||
// 역할이 이미 골라져 있으면 그대로, 아니면 사용자가 골라야 next 활성화.
|
|
||||||
nextBtn.disabled = !state.role
|
|
||||||
} else {
|
|
||||||
roleSection.hidden = true
|
|
||||||
state.role = null
|
|
||||||
roleButtons.forEach(function (btn) { btn.classList.remove('selected') })
|
|
||||||
nextBtn.disabled = false
|
nextBtn.disabled = false
|
||||||
|
// 모드가 바뀌면 이전에 골랐던 역할은 의미가 없어진다. 멀티→싱글 전환 시 잔존하던
|
||||||
|
// role 이 다음 단계 분기에 영향 주지 않도록 명시적으로 초기화.
|
||||||
|
if (mode !== 'multi') state.role = null
|
||||||
}
|
}
|
||||||
|
|
||||||
|
modeButtons.forEach(function (btn) {
|
||||||
|
btn.addEventListener('click', function () {
|
||||||
|
applyMode(btn.getAttribute('data-mode'))
|
||||||
|
})
|
||||||
|
})
|
||||||
|
|
||||||
|
if (state.mode === 'single' || state.mode === 'multi') {
|
||||||
|
applyMode(state.mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
nextBtn.addEventListener('click', function () {
|
||||||
|
if (!state.mode) return
|
||||||
|
state.stepDone[2] = true
|
||||||
|
// 멀티는 호스트/참가자 선택 탭을 거친다. 싱글은 곧장 클라이언트(step4) 로.
|
||||||
|
if (state.mode === 'multi') renderStep2Role()
|
||||||
|
else renderStep4()
|
||||||
|
})
|
||||||
|
section.querySelector('#back').addEventListener('click', renderStep1)
|
||||||
|
}
|
||||||
|
|
||||||
|
function renderStep2Role() {
|
||||||
|
// 스텝 인디케이터는 여전히 2 단계 안쪽이다 — 호스트/참가자 선택은 모드 선택의
|
||||||
|
// 하위 결정이기 때문. 별도 탭으로 분리해서 한 화면에 한 결정만 보이도록 한다.
|
||||||
|
setActiveStep(2)
|
||||||
|
clearPage()
|
||||||
|
var section = document.createElement('section')
|
||||||
|
section.className = 'page'
|
||||||
|
section.innerHTML =
|
||||||
|
'<h2>' + tt('step2.roleHeading') + '</h2>' +
|
||||||
|
'<div class="cardChoice">' +
|
||||||
|
'<button type="button" data-role="host"><strong>' + tt('step2.hostTitle') + '</strong><br><small>' + tt('step2.hostHint') + '</small></button>' +
|
||||||
|
'<button type="button" data-role="participant"><strong>' + tt('step2.participantTitle') + '</strong><br><small>' + tt('step2.participantHint') + '</small></button>' +
|
||||||
|
'</div>' +
|
||||||
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
||||||
|
pageHost.appendChild(section)
|
||||||
|
var nextBtn = section.querySelector('#next')
|
||||||
|
var roleButtons = section.querySelectorAll('[data-role]')
|
||||||
|
|
||||||
function applyRole(role) {
|
function applyRole(role) {
|
||||||
state.role = role
|
state.role = role
|
||||||
roleButtons.forEach(function (btn) {
|
roleButtons.forEach(function (btn) {
|
||||||
@@ -200,32 +223,21 @@ function renderStep2() {
|
|||||||
nextBtn.disabled = false
|
nextBtn.disabled = false
|
||||||
}
|
}
|
||||||
|
|
||||||
modeButtons.forEach(function (btn) {
|
|
||||||
btn.addEventListener('click', function () {
|
|
||||||
applyMode(btn.getAttribute('data-mode'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
roleButtons.forEach(function (btn) {
|
roleButtons.forEach(function (btn) {
|
||||||
btn.addEventListener('click', function () {
|
btn.addEventListener('click', function () {
|
||||||
applyRole(btn.getAttribute('data-role'))
|
applyRole(btn.getAttribute('data-role'))
|
||||||
})
|
})
|
||||||
})
|
})
|
||||||
|
|
||||||
if (state.mode === 'single' || state.mode === 'multi') {
|
if (state.role === 'host' || state.role === 'participant') applyRole(state.role)
|
||||||
applyMode(state.mode)
|
|
||||||
if (state.mode === 'multi' && state.role) applyRole(state.role)
|
|
||||||
}
|
|
||||||
|
|
||||||
nextBtn.addEventListener('click', function () {
|
nextBtn.addEventListener('click', function () {
|
||||||
if (!state.mode) return
|
if (!state.role) return
|
||||||
if (state.mode === 'multi' && !state.role) return
|
// 호스트는 서버 설치(step3) 부터, 참가자는 클라이언트(step4) 로 바로.
|
||||||
state.stepDone[2] = true
|
if (state.role === 'host') renderStep3()
|
||||||
// 멀티+호스트 만 서버 설치(step3) 를 거친다.
|
|
||||||
// 싱글, 멀티+참가자 는 곧장 클라이언트(step4) 로.
|
|
||||||
if (state.mode === 'multi' && state.role === 'host') renderStep3()
|
|
||||||
else renderStep4()
|
else renderStep4()
|
||||||
})
|
})
|
||||||
section.querySelector('#back').addEventListener('click', renderStep1)
|
section.querySelector('#back').addEventListener('click', renderStep2)
|
||||||
}
|
}
|
||||||
|
|
||||||
function renderStep3() {
|
function renderStep3() {
|
||||||
@@ -239,7 +251,8 @@ function renderStep3() {
|
|||||||
pageHost.appendChild(section)
|
pageHost.appendChild(section)
|
||||||
var subHost = section.querySelector('#subHost')
|
var subHost = section.querySelector('#subHost')
|
||||||
|
|
||||||
function show31() { subHost.innerHTML = ''; renderSubStep31(subHost, renderStep2, show32) }
|
// step3 는 멀티+호스트 만 진입하므로 sub31 의 back 은 역할 선택 탭으로.
|
||||||
|
function show31() { subHost.innerHTML = ''; renderSubStep31(subHost, renderStep2Role, show32) }
|
||||||
function show32() { subHost.innerHTML = ''; renderSubStep32(subHost, show31, show33) }
|
function show32() { subHost.innerHTML = ''; renderSubStep32(subHost, show31, show33) }
|
||||||
function show33() { subHost.innerHTML = ''; renderSubStep33(subHost, show32, show34) }
|
function show33() { subHost.innerHTML = ''; renderSubStep33(subHost, show32, show34) }
|
||||||
function show34() { subHost.innerHTML = ''; renderSubStep34(subHost, show33, show35) }
|
function show34() { subHost.innerHTML = ''; renderSubStep34(subHost, show33, show35) }
|
||||||
@@ -629,9 +642,10 @@ function renderStep4() {
|
|||||||
state.client.installPlatform = platformType !== 'vanilla'
|
state.client.installPlatform = platformType !== 'vanilla'
|
||||||
|
|
||||||
// 멀티+호스트 만 step3 (서버 설치) 를 거쳤으므로 거기로 돌아간다.
|
// 멀티+호스트 만 step3 (서버 설치) 를 거쳤으므로 거기로 돌아간다.
|
||||||
// 싱글 / 멀티+참가자 는 step2 로 되돌아간다.
|
// 멀티+참가자 는 직전 화면이 역할 선택 탭이므로 거기로, 싱글은 모드 탭으로.
|
||||||
function backToPrevStep() {
|
function backToPrevStep() {
|
||||||
if (state.mode === 'multi' && state.role === 'host') renderStep3()
|
if (state.mode === 'multi' && state.role === 'host') renderStep3()
|
||||||
|
else if (state.mode === 'multi') renderStep2Role()
|
||||||
else renderStep2()
|
else renderStep2()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user