Reset repository to README title only
Approach is changing entirely; clearing prior implementation to start over from a clean slate. Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
This commit is contained in:
@@ -1,150 +0,0 @@
|
||||
<!doctype html>
|
||||
<html lang="ko">
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||
<title>MC Custom Installer</title>
|
||||
<link rel="stylesheet" href="./styles.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div class="shell">
|
||||
<aside class="steps">
|
||||
<h1>MC Custom Installer</h1>
|
||||
<ol>
|
||||
<li data-step="1" class="active">서버팩 선택</li>
|
||||
<li data-step="2">설치 경로 설정</li>
|
||||
<li data-step="3">JDK 확인 / 설치</li>
|
||||
<li data-step="4">다운로드 및 설치</li>
|
||||
<li data-step="5">서버 설정</li>
|
||||
<li data-step="6">포트포워딩 설정</li>
|
||||
<li data-step="7">클라이언트 적용</li>
|
||||
<li data-step="8">완료</li>
|
||||
</ol>
|
||||
</aside>
|
||||
|
||||
<main class="content">
|
||||
<section class="panel active" data-panel="1">
|
||||
<p class="eyebrow">STEP 1</p>
|
||||
<h2>서버팩 선택</h2>
|
||||
<label class="field">
|
||||
<span>manifest.json URL</span>
|
||||
<input id="manifestUrl" />
|
||||
</label>
|
||||
<p class="infoHint">설치기가 시작되면 서버팩 목록을 자동으로 불러옵니다.</p>
|
||||
<div id="packList" class="packList"></div>
|
||||
<div class="buttonRow end">
|
||||
<button id="toStep2" class="primary">다음</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="2">
|
||||
<p class="eyebrow">STEP 2</p>
|
||||
<h2>설치 경로 설정</h2>
|
||||
<label class="field">
|
||||
<span>설치 경로</span>
|
||||
<div class="inputRow">
|
||||
<input id="installPath" />
|
||||
<button id="browseInstallPath">폴더 선택</button>
|
||||
</div>
|
||||
</label>
|
||||
<p id="installPathWarning" class="warningText"></p>
|
||||
<div class="buttonRow between">
|
||||
<button data-back="1">이전</button>
|
||||
<button id="toStep3" class="primary">다음</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="3">
|
||||
<p class="eyebrow">STEP 3</p>
|
||||
<h2>JDK 확인 / 설치</h2>
|
||||
<div id="jdkRecommended" class="infoBox">선택한 서버팩의 권장 JDK 버전을 확인 중입니다.</div>
|
||||
<label class="field">
|
||||
<span>JDK 경로</span>
|
||||
<div class="inputRow">
|
||||
<input id="jdkPath" />
|
||||
<button id="browseJdkPath">폴더 선택</button>
|
||||
</div>
|
||||
</label>
|
||||
<div id="jdkStatus" class="infoBox"></div>
|
||||
<div class="buttonRow between">
|
||||
<button data-back="2">이전</button>
|
||||
<button id="toStep4" class="primary">다음</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="4">
|
||||
<p class="eyebrow">STEP 4</p>
|
||||
<h2>다운로드 및 설치</h2>
|
||||
<div class="buttonRow">
|
||||
<button id="startInstallButton" class="primary">설치 시작</button>
|
||||
</div>
|
||||
<div id="logView" class="logView"></div>
|
||||
<div id="eulaBlock" class="eulaBlock hidden">
|
||||
<p>Minecraft EULA를 확인한 뒤 동의 버튼을 눌러야 다음 단계로 진행됩니다.</p>
|
||||
<a id="eulaLink" class="eulaLink" href="#" target="_blank" rel="noreferrer">공식 EULA 원문 열기</a>
|
||||
<pre id="eulaText" class="eulaText"></pre>
|
||||
<button id="acceptEulaButton" class="primary">EULA 동의 후 계속</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="5">
|
||||
<p class="eyebrow">STEP 5</p>
|
||||
<h2>서버 설정</h2>
|
||||
<p>로컬 웹서버를 띄워 브라우저에서 설정 파일을 수정합니다.</p>
|
||||
<div class="buttonRow">
|
||||
<button id="openConfigEditorButton" class="primary">설정 편집기 열기</button>
|
||||
</div>
|
||||
<div id="configEditorStatus" class="infoBox"></div>
|
||||
<div class="buttonRow between">
|
||||
<button data-back="4">이전</button>
|
||||
<button id="toStep6" class="primary">다음</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="6">
|
||||
<p class="eyebrow">STEP 6</p>
|
||||
<h2>포트포워딩 설정</h2>
|
||||
<div class="buttonRow">
|
||||
<button id="configurePortButton" class="primary">포트 개방 확인 / 시도</button>
|
||||
</div>
|
||||
<div id="portStatusBox" class="infoBox"></div>
|
||||
<div class="buttonRow between">
|
||||
<button data-back="5">이전</button>
|
||||
<button id="toStep7" class="primary">다음</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="7">
|
||||
<p class="eyebrow">STEP 7</p>
|
||||
<h2>클라이언트 적용</h2>
|
||||
<p class="infoHint">런처 프로필, 로더 설치, 리소스팩, 쉐이더를 한 번에 적용합니다.</p>
|
||||
<div class="buttonRow">
|
||||
<button id="applyClientButton" class="primary">클라이언트 적용</button>
|
||||
</div>
|
||||
<div id="clientApplyStatus" class="infoBox"></div>
|
||||
<div class="buttonRow between">
|
||||
<button data-back="6">이전</button>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<section class="panel" data-panel="8">
|
||||
<p class="eyebrow">STEP 8</p>
|
||||
<h2>완료</h2>
|
||||
<label class="toggleRow">
|
||||
<input type="checkbox" id="createShortcutToggle" checked />
|
||||
<span>바탕화면에 서버 실행 바로가기 만들기</span>
|
||||
</label>
|
||||
<label class="toggleRow">
|
||||
<input type="checkbox" id="runServerToggle" checked />
|
||||
<span>서버 바로 실행</span>
|
||||
</label>
|
||||
<div class="buttonRow">
|
||||
<button id="openFolderButton">서버 폴더 열기</button>
|
||||
<button id="finishButton" class="primary">적용 및 완료</button>
|
||||
</div>
|
||||
</section>
|
||||
</main>
|
||||
</div>
|
||||
<script src="./renderer.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
@@ -1,304 +0,0 @@
|
||||
const state = {
|
||||
manifestUrl: '',
|
||||
selectedPack: null,
|
||||
selectedPackMeta: null,
|
||||
installPath: '',
|
||||
jdkPath: ''
|
||||
}
|
||||
|
||||
const panelMap = new Map([...document.querySelectorAll('.panel')].map((panel) => [panel.dataset.panel, panel]))
|
||||
const stepMap = new Map([...document.querySelectorAll('.steps li')].map((step) => [step.dataset.step, step]))
|
||||
const logView = document.getElementById('logView')
|
||||
const packList = document.getElementById('packList')
|
||||
const manifestUrlInput = document.getElementById('manifestUrl')
|
||||
const installPathInput = document.getElementById('installPath')
|
||||
const jdkPathInput = document.getElementById('jdkPath')
|
||||
const jdkStatus = document.getElementById('jdkStatus')
|
||||
const jdkRecommended = document.getElementById('jdkRecommended')
|
||||
const eulaBlock = document.getElementById('eulaBlock')
|
||||
const eulaText = document.getElementById('eulaText')
|
||||
const eulaLink = document.getElementById('eulaLink')
|
||||
const startInstallButton = document.getElementById('startInstallButton')
|
||||
const applyClientButton = document.getElementById('applyClientButton')
|
||||
const clientApplyStatus = document.getElementById('clientApplyStatus')
|
||||
|
||||
function setActiveStep(step) {
|
||||
for (const [key, panel] of panelMap.entries()) {
|
||||
panel.classList.toggle('active', key === String(step))
|
||||
}
|
||||
|
||||
for (const [key, item] of stepMap.entries()) {
|
||||
item.classList.toggle('active', key === String(step))
|
||||
}
|
||||
}
|
||||
|
||||
function appendLog(entry) {
|
||||
if (entry?.action === 'eula-required') {
|
||||
eulaText.textContent = entry.eulaText ?? ''
|
||||
eulaLink.href = entry.eulaUrl ?? '#'
|
||||
eulaBlock.classList.remove('hidden')
|
||||
return
|
||||
}
|
||||
|
||||
const line = `[${entry?.tone ?? 'info'}] ${entry?.message ?? ''}`
|
||||
logView.textContent += `${line}\n`
|
||||
logView.scrollTop = logView.scrollHeight
|
||||
}
|
||||
|
||||
function validateInstallPath(pathValue) {
|
||||
const warning = document.getElementById('installPathWarning')
|
||||
const hasHangul = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(pathValue)
|
||||
warning.textContent = hasHangul ? '경로에 한글이 포함되면 안 됩니다.' : ''
|
||||
return !hasHangul && pathValue.trim().length > 0
|
||||
}
|
||||
|
||||
function renderPackList(packs) {
|
||||
packList.innerHTML = ''
|
||||
packs.forEach((pack) => {
|
||||
const label = document.createElement('label')
|
||||
label.className = 'packOption'
|
||||
label.innerHTML = `
|
||||
<input type="radio" name="packChoice" value="${pack.file}" data-pack-name="${pack.name}" />
|
||||
<div>
|
||||
<strong>${pack.name}</strong>
|
||||
<span>${pack.file}</span>
|
||||
</div>
|
||||
`
|
||||
packList.appendChild(label)
|
||||
})
|
||||
}
|
||||
|
||||
async function loadPackManifest() {
|
||||
state.manifestUrl = manifestUrlInput.value.trim()
|
||||
state.selectedPack = null
|
||||
state.selectedPackMeta = null
|
||||
packList.innerHTML = '<div class="infoBox">서버팩 목록을 불러오는 중입니다.</div>'
|
||||
try {
|
||||
const manifest = await window.installerApi.loadPacks(state.manifestUrl)
|
||||
renderPackList(manifest.packs)
|
||||
} catch (error) {
|
||||
packList.innerHTML = `<div class="infoBox">${error.message}</div>`
|
||||
}
|
||||
}
|
||||
|
||||
async function loadSelectedPackMeta() {
|
||||
if (state.selectedPack == null) {
|
||||
state.selectedPackMeta = null
|
||||
return null
|
||||
}
|
||||
|
||||
const packMeta = await window.installerApi.inspectPack(state.manifestUrl, state.selectedPack.file)
|
||||
state.selectedPackMeta = packMeta
|
||||
return packMeta
|
||||
}
|
||||
|
||||
async function autoDetectJdkForSelectedPack() {
|
||||
const packMeta = await loadSelectedPackMeta()
|
||||
if (packMeta == null) {
|
||||
jdkRecommended.textContent = '먼저 서버팩을 선택하세요.'
|
||||
jdkStatus.textContent = ''
|
||||
return
|
||||
}
|
||||
|
||||
const recommendedVersion = packMeta.packDefinition.recommendedJdkVersion ?? null
|
||||
jdkRecommended.textContent = recommendedVersion != null
|
||||
? `선택한 서버팩의 권장 JDK 버전: ${recommendedVersion}`
|
||||
: '선택한 서버팩에 권장 JDK 버전 정보가 없습니다.'
|
||||
|
||||
jdkStatus.textContent = 'JDK 자동 탐색 중입니다.'
|
||||
const result = await window.installerApi.detectJdk(recommendedVersion)
|
||||
if (result.detected != null) {
|
||||
state.jdkPath = result.detected
|
||||
jdkPathInput.value = result.detected
|
||||
}
|
||||
|
||||
if (result.detected == null) {
|
||||
jdkStatus.textContent = '설치 가능한 JDK를 찾지 못했습니다.'
|
||||
return
|
||||
}
|
||||
|
||||
const pickedCandidate = result.candidates.find((candidate) => candidate.path === result.detected)
|
||||
const versionLabel = pickedCandidate?.majorVersion != null ? `JDK ${pickedCandidate.majorVersion}` : '버전 미확인 JDK'
|
||||
if (result.recommendedVersion != null && result.exactMatch) {
|
||||
jdkStatus.textContent = `권장 버전과 일치하는 ${versionLabel}를 자동 선택했습니다: ${result.detected}`
|
||||
return
|
||||
}
|
||||
|
||||
if (result.recommendedVersion != null) {
|
||||
jdkStatus.textContent = `권장 JDK ${result.recommendedVersion}은 찾지 못해 ${versionLabel}를 대신 선택했습니다: ${result.detected}`
|
||||
return
|
||||
}
|
||||
|
||||
jdkStatus.textContent = `자동 탐색 성공: ${versionLabel} / ${result.detected}`
|
||||
}
|
||||
|
||||
async function goToStep(step) {
|
||||
setActiveStep(step)
|
||||
|
||||
if (step === 3) {
|
||||
try {
|
||||
await autoDetectJdkForSelectedPack()
|
||||
} catch (error) {
|
||||
jdkStatus.textContent = error.message
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
async function bootstrap() {
|
||||
const defaults = await window.installerApi.getDefaults()
|
||||
state.manifestUrl = defaults.manifestUrl
|
||||
manifestUrlInput.value = defaults.manifestUrl
|
||||
await loadPackManifest()
|
||||
}
|
||||
|
||||
window.installerApi.onLog(appendLog)
|
||||
|
||||
packList.addEventListener('change', () => {
|
||||
const checked = packList.querySelector('input[name="packChoice"]:checked')
|
||||
if (checked == null) {
|
||||
state.selectedPack = null
|
||||
state.selectedPackMeta = null
|
||||
return
|
||||
}
|
||||
state.selectedPack = {
|
||||
file: checked.value,
|
||||
name: checked.dataset.packName ?? checked.value
|
||||
}
|
||||
state.selectedPackMeta = null
|
||||
})
|
||||
|
||||
document.querySelectorAll('[data-back]').forEach((button) => {
|
||||
button.addEventListener('click', async () => {
|
||||
await goToStep(button.dataset.back)
|
||||
})
|
||||
})
|
||||
|
||||
manifestUrlInput.addEventListener('change', async () => {
|
||||
await loadPackManifest()
|
||||
})
|
||||
|
||||
document.getElementById('toStep2').addEventListener('click', async () => {
|
||||
if (state.selectedPack == null) {
|
||||
alert('서버팩을 먼저 선택하세요.')
|
||||
return
|
||||
}
|
||||
await goToStep(2)
|
||||
})
|
||||
|
||||
document.getElementById('browseInstallPath').addEventListener('click', async () => {
|
||||
const selected = await window.installerApi.chooseDirectory()
|
||||
if (selected != null) {
|
||||
state.installPath = selected
|
||||
installPathInput.value = selected
|
||||
validateInstallPath(selected)
|
||||
}
|
||||
})
|
||||
|
||||
installPathInput.addEventListener('input', (event) => {
|
||||
state.installPath = event.target.value
|
||||
validateInstallPath(state.installPath)
|
||||
})
|
||||
|
||||
document.getElementById('toStep3').addEventListener('click', async () => {
|
||||
if (!validateInstallPath(state.installPath)) {
|
||||
alert('올바른 설치 경로를 입력하세요.')
|
||||
return
|
||||
}
|
||||
await goToStep(3)
|
||||
})
|
||||
|
||||
document.getElementById('browseJdkPath').addEventListener('click', async () => {
|
||||
const selected = await window.installerApi.chooseJdk()
|
||||
if (selected != null) {
|
||||
state.jdkPath = selected
|
||||
jdkPathInput.value = selected
|
||||
}
|
||||
})
|
||||
|
||||
jdkPathInput.addEventListener('input', (event) => {
|
||||
state.jdkPath = event.target.value
|
||||
})
|
||||
|
||||
document.getElementById('toStep4').addEventListener('click', async () => {
|
||||
if (state.jdkPath.trim().length === 0) {
|
||||
alert('JDK 경로를 지정하세요.')
|
||||
return
|
||||
}
|
||||
await goToStep(4)
|
||||
})
|
||||
|
||||
startInstallButton.addEventListener('click', async () => {
|
||||
if (state.selectedPack == null) {
|
||||
alert('서버팩을 먼저 선택하세요.')
|
||||
return
|
||||
}
|
||||
|
||||
logView.textContent = ''
|
||||
eulaBlock.classList.add('hidden')
|
||||
eulaText.textContent = ''
|
||||
startInstallButton.disabled = true
|
||||
|
||||
try {
|
||||
const result = await window.installerApi.startInstall({
|
||||
manifestUrl: state.manifestUrl,
|
||||
packFile: state.selectedPack.file,
|
||||
installPath: state.installPath,
|
||||
jdkPath: state.jdkPath
|
||||
})
|
||||
if (result.warning != null) {
|
||||
appendLog({ message: result.warning, tone: 'warn' })
|
||||
}
|
||||
await goToStep(result.nextStep)
|
||||
} finally {
|
||||
startInstallButton.disabled = false
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById('acceptEulaButton').addEventListener('click', async () => {
|
||||
await window.installerApi.acceptEula()
|
||||
eulaBlock.classList.add('hidden')
|
||||
})
|
||||
|
||||
document.getElementById('openConfigEditorButton').addEventListener('click', async () => {
|
||||
const url = await window.installerApi.openConfigEditor()
|
||||
document.getElementById('configEditorStatus').textContent = `브라우저에서 열림: ${url}`
|
||||
})
|
||||
|
||||
document.getElementById('toStep6').addEventListener('click', async () => {
|
||||
await goToStep(6)
|
||||
})
|
||||
|
||||
document.getElementById('configurePortButton').addEventListener('click', async () => {
|
||||
const result = await window.installerApi.configurePort()
|
||||
document.getElementById('portStatusBox').textContent = result.message
|
||||
})
|
||||
|
||||
document.getElementById('toStep7').addEventListener('click', async () => {
|
||||
await goToStep(7)
|
||||
})
|
||||
|
||||
applyClientButton.addEventListener('click', async () => {
|
||||
applyClientButton.disabled = true
|
||||
clientApplyStatus.textContent = '클라이언트 적용 중입니다.'
|
||||
try {
|
||||
const result = await window.installerApi.applyClient()
|
||||
clientApplyStatus.textContent = result.message
|
||||
await goToStep(result.nextStep)
|
||||
} finally {
|
||||
applyClientButton.disabled = false
|
||||
}
|
||||
})
|
||||
|
||||
document.getElementById('openFolderButton').addEventListener('click', async () => {
|
||||
await window.installerApi.openFolder()
|
||||
})
|
||||
|
||||
document.getElementById('finishButton').addEventListener('click', async () => {
|
||||
const createShortcut = document.getElementById('createShortcutToggle').checked
|
||||
const runServer = document.getElementById('runServerToggle').checked
|
||||
await window.installerApi.createShortcut(createShortcut)
|
||||
await window.installerApi.runServer(runServer)
|
||||
alert('설치가 완료되었습니다.')
|
||||
})
|
||||
|
||||
bootstrap()
|
||||
@@ -1,196 +0,0 @@
|
||||
:root {
|
||||
color-scheme: dark;
|
||||
--bg: #0b100d;
|
||||
--panel: #141b17;
|
||||
--soft: #1d2721;
|
||||
--line: #2a362f;
|
||||
--text: #f2f4f3;
|
||||
--muted: #a9b2ad;
|
||||
--accent: #f0bf57;
|
||||
--warn: #ffb36b;
|
||||
}
|
||||
|
||||
* { box-sizing: border-box; }
|
||||
|
||||
body {
|
||||
margin: 0;
|
||||
font-family: "Segoe UI", sans-serif;
|
||||
background:
|
||||
radial-gradient(circle at top left, rgba(240, 191, 87, 0.16), transparent 28%),
|
||||
linear-gradient(180deg, #0b100d 0%, #121914 100%);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.shell {
|
||||
display: grid;
|
||||
grid-template-columns: 280px 1fr;
|
||||
min-height: 100vh;
|
||||
}
|
||||
|
||||
.steps {
|
||||
padding: 30px 24px;
|
||||
background: rgba(10, 14, 12, 0.78);
|
||||
border-right: 1px solid var(--line);
|
||||
}
|
||||
|
||||
.steps h1 {
|
||||
margin: 0 0 20px;
|
||||
font-size: 28px;
|
||||
}
|
||||
|
||||
.steps ol {
|
||||
list-style: none;
|
||||
padding: 0;
|
||||
margin: 0;
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
}
|
||||
|
||||
.steps li {
|
||||
padding: 14px 16px;
|
||||
border-radius: 16px;
|
||||
background: rgba(255, 255, 255, 0.02);
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.steps li.active {
|
||||
background: var(--accent);
|
||||
color: #1b1408;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.content {
|
||||
padding: 34px;
|
||||
}
|
||||
|
||||
.panel {
|
||||
display: none;
|
||||
max-width: 920px;
|
||||
background: rgba(20, 27, 23, 0.92);
|
||||
border: 1px solid var(--line);
|
||||
border-radius: 28px;
|
||||
padding: 28px;
|
||||
}
|
||||
|
||||
.panel.active { display: block; }
|
||||
|
||||
.eyebrow {
|
||||
margin: 0 0 10px;
|
||||
color: var(--accent);
|
||||
letter-spacing: 0.28em;
|
||||
font-size: 12px;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
h2 { margin: 0 0 20px; font-size: 34px; }
|
||||
|
||||
.field { display: grid; gap: 8px; margin-bottom: 16px; }
|
||||
|
||||
.infoHint {
|
||||
margin: 0 0 16px;
|
||||
color: var(--muted);
|
||||
}
|
||||
|
||||
.field input {
|
||||
width: 100%;
|
||||
min-height: 48px;
|
||||
padding: 12px 14px;
|
||||
border-radius: 16px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--soft);
|
||||
color: var(--text);
|
||||
}
|
||||
|
||||
.inputRow,
|
||||
.buttonRow {
|
||||
display: flex;
|
||||
gap: 12px;
|
||||
flex-wrap: wrap;
|
||||
}
|
||||
|
||||
.buttonRow { margin-top: 18px; }
|
||||
.buttonRow.end { justify-content: flex-end; }
|
||||
.buttonRow.between { justify-content: space-between; }
|
||||
|
||||
button {
|
||||
min-height: 44px;
|
||||
padding: 0 18px;
|
||||
border-radius: 999px;
|
||||
border: 1px solid var(--line);
|
||||
background: transparent;
|
||||
color: var(--text);
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
button.primary {
|
||||
background: var(--accent);
|
||||
border: none;
|
||||
color: #1c1509;
|
||||
font-weight: 700;
|
||||
}
|
||||
|
||||
.packList {
|
||||
display: grid;
|
||||
gap: 12px;
|
||||
margin-top: 18px;
|
||||
}
|
||||
|
||||
.packOption {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
padding: 16px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid var(--line);
|
||||
background: rgba(255,255,255,0.02);
|
||||
}
|
||||
|
||||
.packOption strong {
|
||||
display: block;
|
||||
font-size: 18px;
|
||||
}
|
||||
|
||||
.warningText {
|
||||
color: var(--warn);
|
||||
min-height: 20px;
|
||||
}
|
||||
|
||||
.infoBox,
|
||||
.logView,
|
||||
.eulaBlock {
|
||||
margin-top: 16px;
|
||||
padding: 16px;
|
||||
border-radius: 18px;
|
||||
border: 1px solid var(--line);
|
||||
background: var(--soft);
|
||||
}
|
||||
|
||||
.logView {
|
||||
height: 320px;
|
||||
overflow: auto;
|
||||
font-family: Consolas, monospace;
|
||||
white-space: pre-wrap;
|
||||
}
|
||||
|
||||
.hidden { display: none; }
|
||||
|
||||
.toggleRow {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
gap: 12px;
|
||||
margin-top: 16px;
|
||||
}
|
||||
|
||||
.eulaLink {
|
||||
color: var(--accent);
|
||||
}
|
||||
|
||||
.eulaText {
|
||||
margin-top: 14px;
|
||||
max-height: 260px;
|
||||
overflow: auto;
|
||||
white-space: pre-wrap;
|
||||
font-family: Consolas, monospace;
|
||||
font-size: 13px;
|
||||
line-height: 1.55;
|
||||
}
|
||||
Reference in New Issue
Block a user