Build installer and management site from spec

This commit is contained in:
2026-05-07 23:22:34 +09:00
parent 0b061e63b7
commit af6e559682
33 changed files with 7125 additions and 1 deletions

31
views/index.ejs Normal file
View File

@@ -0,0 +1,31 @@
<!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">
<header class="hero">
<div>
<p class="eyebrow">MC CUSTOM</p>
<h1>마인크래프트 서버팩 목록</h1>
<p class="heroText">manifest.json에 등록된 서버팩을 한 줄 카드 목록으로 제공합니다.</p>
</div>
<a class="primaryLink" href="/op">관리자 로그인</a>
</header>
<main class="pageWrap">
<section class="cardRow">
<% packs.forEach((pack) => { %>
<article class="packCard">
<h2><%= pack.name %></h2>
<p>manifest 키: <code><%= pack.file %></code></p>
<a class="ghostLink" href="/manifest/<%= pack.file %>.json">JSON 보기</a>
</article>
<% }) %>
</section>
</main>
</body>
</html>

33
views/op/dashboard.ejs Normal file
View File

@@ -0,0 +1,33 @@
<!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="toolbar">
<form method="post" action="/op/dashboard/packs">
<button class="primaryButton" type="submit">서버팩 추가</button>
</form>
<form method="post" action="/op/dashboard/packs/delete" class="deleteForm">
<button class="dangerButton" type="submit">선택 삭제</button>
<div class="cardRow">
<% packs.forEach((pack) => { %>
<label class="packCard selectableCard">
<input type="checkbox" name="packKeys" value="<%= pack.file %>" />
<span class="selectionTitle"><%= pack.name %></span>
<span><code><%= pack.file %></code></span>
<a class="ghostLink" href="/op/dashboard/<%= pack.file %>">편집</a>
</label>
<% }) %>
</div>
</form>
</section>
</main>
</body>
</html>

75
views/op/editor.ejs Normal file
View File

@@ -0,0 +1,75 @@
<!doctype html>
<html lang="ko">
<head>
<meta charset="utf-8" />
<meta name="viewport" content="width=device-width, initial-scale=1" />
<title><%= packEntry?.name ?? packKey %> 편집</title>
<link rel="stylesheet" href="/static/styles.css" />
</head>
<body class="siteBody">
<%- include('../partials/navbar', { userId }) %>
<main class="pageWrap">
<section class="editorWrap">
<div class="editorHeader">
<div>
<p class="eyebrow">PACK EDITOR</p>
<h1><%= packEntry?.name ?? packKey %></h1>
</div>
<a class="ghostLink" href="/op/dashboard">목록으로</a>
</div>
<form method="post" class="editorForm">
<div class="gridTwo">
<label>
<span>서버팩 이름</span>
<input name="displayName" value="<%= packEntry?.name ?? '' %>" required />
</label>
<label>
<span>JSON 파일 이름</span>
<input name="fileName" value="<%= packKey %>" required />
</label>
</div>
<label>
<span>설명</span>
<textarea name="description"><%= pack.description ?? '' %></textarea>
</label>
<div class="gridTwo">
<label>
<span>마인크래프트 버전</span>
<select name="mcVersion" required>
<% releases.forEach((release) => { %>
<option value="<%= release.id %>" <%= release.id === pack.mcVersion ? 'selected' : '' %>><%= release.id %></option>
<% }) %>
</select>
</label>
<label>
<span>packPath</span>
<input name="packPath" value="<%= pack.packPath %>" required />
</label>
<label>
<span>서버 최소 램</span>
<input type="number" name="serverMinRam" value="<%= pack.serverMinRam %>" required />
</label>
<label>
<span>서버 최대 램</span>
<input type="number" name="serverMaxRam" value="<%= pack.serverMaxRam %>" required />
</label>
<label>
<span>클라이언트 최소 램</span>
<input type="number" name="clientMinRam" value="<%= pack.clientMinRam %>" required />
</label>
<label>
<span>클라이언트 권장 램</span>
<input type="number" name="clientRecommendedRam" value="<%= pack.clientRecommendedRam %>" required />
</label>
</div>
<button class="primaryButton" type="submit">적용</button>
</form>
</section>
</main>
</body>
</html>

29
views/op/login.ejs Normal file
View File

@@ -0,0 +1,29 @@
<!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 adminLoginBody">
<main class="loginPanel">
<p class="eyebrow">OP LOGIN</p>
<h1>관리자 로그인</h1>
<form method="post" action="/op/login" class="stackForm">
<label>
<span>아이디</span>
<input name="id" required />
</label>
<label>
<span>비밀번호</span>
<input type="password" name="password" required />
</label>
<% if (errorMessage) { %>
<p class="errorText"><%= errorMessage %></p>
<% } %>
<button class="primaryButton" type="submit">로그인</button>
</form>
</main>
</body>
</html>

12
views/partials/navbar.ejs Normal file
View File

@@ -0,0 +1,12 @@
<header class="adminHeader">
<a class="brandLink" href="/op/dashboard">
<span class="brandMark">MC</span>
<span>관리자 페이지</span>
</a>
<details class="userMenu">
<summary><%= userId %></summary>
<form method="post" action="/op/logout">
<button type="submit">로그아웃</button>
</form>
</details>
</header>