460 lines
18 KiB
HTML
460 lines
18 KiB
HTML
<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Construct Expansion Pack Generator</title>
|
|
<link rel="icon" href="image.jpg" type="image/x-icon">
|
|
<script src="libs/jszip.min.js"></script>
|
|
<script src="libs/spark-md5.min.js"></script>
|
|
<script src="js/utils.umd.js"></script>
|
|
<script src="./js/convert/litematicToNbt/litematic-to-nbt.umd.js"></script>
|
|
<script src="./js/convert/nbtToMcbe/nbt-to-mcstructure.umd.js"></script>
|
|
<style>
|
|
:root {
|
|
--ov-bg: #0f0f1a;
|
|
--ov-bg2: #1a1a2e;
|
|
--ov-card: rgba(255,255,255,0.05);
|
|
--ov-card-border: rgba(255,255,255,0.08);
|
|
--ov-accent: #f97316;
|
|
--ov-accent2: #fb923c;
|
|
--ov-file: rgba(251, 146, 60, 0.3);
|
|
--ov-text: #e2e8f0;
|
|
--ov-text2: #94a3b8;
|
|
--ov-danger: #ef4444;
|
|
--ov-success: #22c55e;
|
|
--ov-radius: 16px;
|
|
--ov-file-bord: rgba(255,255,255,0.16);
|
|
--ov-shadow: 0 8px 32px rgba(0,0,0,0);
|
|
}
|
|
@media (prefers-color-scheme: light) {
|
|
:root {
|
|
--ov-bg: #f1f5f9;
|
|
--ov-bg2: #e2e8f0;
|
|
--ov-card: rgba(255,255,255,0.05);
|
|
--ov-card-border: rgba(0,0,0,0.06);
|
|
--ov-accent: #7c3aed;
|
|
--ov-accent2: #06b6d4;
|
|
--ov-file: rgba(124,58,237,0.3);
|
|
--ov-text: #1e293b;
|
|
--ov-text2: #64748b;
|
|
--ov-file-bord: rgba(0, 0, 0, 0.16);
|
|
|
|
--ov-shadow: 0 8px 32px rgba(0,0,0,0);
|
|
}
|
|
}
|
|
* { margin:0; padding:0; box-sizing:border-box; }
|
|
body {
|
|
font-family: 'Inter', -apple-system, BlinkMacSystemFont, 'Segoe UI', sans-serif;
|
|
background: var(--ov-bg);
|
|
color: var(--ov-text);
|
|
min-height: 100vh;
|
|
line-height: 1.6;
|
|
}
|
|
/* 导航栏 */
|
|
.ov-nav {
|
|
display: flex; align-items: center; justify-content: space-between;
|
|
padding: 16px 32px;
|
|
background: var(--ov-card);
|
|
backdrop-filter: blur(20px);
|
|
border-bottom: 1px solid var(--ov-card-border);
|
|
position: sticky; top: 0; z-index: 100;
|
|
}
|
|
.ov-nav-brand { display:flex; align-items:center; gap:10px; font-weight:700; font-size:18px; }
|
|
.ov-nav-brand img { width:32px; height:32px; border-radius:8px; }
|
|
/* 语言切换 */
|
|
.lang-toggle {
|
|
background: transparent; color: var(--ov-accent);
|
|
border: 1.5px solid var(--ov-accent); border-radius: 20px;
|
|
padding: 5px 16px; font-size: 13px; font-weight: 600;
|
|
cursor: pointer; transition: all 0.25s ease;
|
|
}
|
|
.lang-toggle:hover { background: var(--ov-accent); color: #fff; }
|
|
.lang-toggle:active { transform: scale(0.95); }
|
|
/* 主内容 */
|
|
.ov-main { max-width: 720px; margin: 0 auto; padding: 40px 20px 60px; }
|
|
/* Hero */
|
|
.ov-hero { text-align: center; margin-bottom: 40px; }
|
|
.ov-hero h1 {
|
|
font-size: 36px; font-weight: 800;
|
|
background: linear-gradient(135deg, var(--ov-accent), var(--ov-accent2));
|
|
-webkit-background-clip: text; -webkit-text-fill-color: transparent;
|
|
background-clip: text; margin-bottom: 12px;
|
|
}
|
|
.ov-hero p { color: var(--ov-text2); font-size: 16px; letter-spacing: 0.5px; }
|
|
/* 卡片 */
|
|
.ov-card {
|
|
background: var(--ov-card);
|
|
backdrop-filter: blur(16px);
|
|
border: 1px solid var(--ov-card-border);
|
|
border-radius: var(--ov-radius);
|
|
padding: 28px; margin-bottom: 20px;
|
|
box-shadow: var(--ov-shadow);
|
|
}
|
|
.ov-card h2 {
|
|
font-size: 18px; font-weight: 700; margin-bottom: 18px;
|
|
display: flex; align-items: center; gap: 8px;
|
|
}
|
|
.ov-card h2 .ov-hint { font-size: 12px; font-weight: 400; color: var(--ov-text2); margin-left: auto; }
|
|
/* 拖放区域 */
|
|
#dropZone {
|
|
border: 2px dashed var(--ov-file); border-radius: 12px;
|
|
padding: 40px 20px; text-align: center; cursor: pointer;
|
|
transition: all 0.3s ease; background: rgba(124,58,237,0.03);
|
|
}
|
|
#dropZone:hover, #dropZone.drag-over {
|
|
border-color: var(--ov-accent); background: rgba(124,58,237,0.08);
|
|
}
|
|
#dropZone span { color: var(--ov-text2); font-size: 15px; display: block; margin-bottom: 14px; }
|
|
/* 按钮统一 */
|
|
button {
|
|
background: transparent; color: var(--ov-accent);
|
|
border: 1.5px solid var(--ov-accent); border-radius: 10px;
|
|
padding: 10px 24px; font-size: 14px; font-weight: 600;
|
|
cursor: pointer; transition: all 0.25s ease;
|
|
}
|
|
button:hover { background: var(--ov-accent); color: #fff; }
|
|
button:active { transform: scale(0.97); }
|
|
button.danger { color: var(--ov-danger); border-color: var(--ov-danger); }
|
|
button.danger:hover { background: var(--ov-danger); color: #fff; }
|
|
/* 文件列表 */
|
|
#fileList button{
|
|
padding: 5px 12px;
|
|
}
|
|
#fileList { margin-top: 14px; }
|
|
.file-item {
|
|
display: flex; justify-content: space-between; align-items: center;
|
|
background: rgba(255,255,255,0.06); border: 1px solid var(--ov-file-bord);
|
|
border-radius: 16px; padding: 16px 20px; margin-bottom: 12px;
|
|
animation: fileItemIn 0.35s ease both;
|
|
}
|
|
.file-item:hover {
|
|
background: rgba(255,255,255,0.12);
|
|
transform: translateX(2px);
|
|
border-color: var(--ov-file-bord);
|
|
}
|
|
.file-item.removing {
|
|
animation: fileItemOut 0.25s ease both;
|
|
}
|
|
.file-info { display: flex; align-items: center; gap: 14px; flex-wrap: wrap; }
|
|
.file-name { font-weight: 700; font-size: 15px; color: var(--ov-text); }
|
|
.file-size { color: var(--ov-text2); font-size: 13px; }
|
|
.file-type-badge {
|
|
display: inline-block; padding: 4px 12px; border-radius: 999px;
|
|
font-size: 10px; font-weight: 700; color: #fff;
|
|
}
|
|
.file-type-badge[style*="background"] {
|
|
box-shadow: 0 0 0 1px rgba(255,255,255,0.08) inset;
|
|
}
|
|
@keyframes fileItemIn {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(10px) scale(0.98);
|
|
height: 0;
|
|
margin-bottom: 0;
|
|
padding: 0 20px;
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
height: auto;
|
|
margin-bottom: 12px;
|
|
padding: 16px 20px;
|
|
}
|
|
}
|
|
@keyframes fileItemOut {
|
|
from {
|
|
opacity: 1;
|
|
transform: translateY(0) scale(1);
|
|
height: auto;
|
|
margin-bottom: 12px;
|
|
padding: 16px 20px;
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: translateY(-10px) scale(0.98);
|
|
height: 0;
|
|
margin-bottom: 0;
|
|
padding: 0 20px;
|
|
}
|
|
}
|
|
/* 输入框 */
|
|
input[type="text"] {
|
|
background: rgba(255,255,255,0.05); color: var(--ov-text);
|
|
border: 1px solid var(--ov-card-border); border-radius: 10px;
|
|
padding: 10px 16px; font-size: 14px; width: 100%; max-width: 320px;
|
|
transition: border-color 0.25s ease;
|
|
}
|
|
input[type="text"]:focus { outline: none; border-color: var(--ov-accent); }
|
|
/* 进度条 */
|
|
.progress-container {
|
|
width: 100%; height: 8px; background: rgba(255,255,255,0.06);
|
|
border-radius: 4px; overflow: hidden; margin: 14px 0; border: none;
|
|
}
|
|
#progressFill {
|
|
height: 100%; border-radius: 4px; width: 0%;
|
|
background: linear-gradient(90deg, var(--ov-accent), var(--ov-accent2));
|
|
transition: width 0.3s ease;
|
|
}
|
|
/* 状态消息 */
|
|
#statusMessage { padding: 10px 16px; border-radius: 10px; font-size: 13px; margin-top: 10px; }
|
|
/* 下载区域 */
|
|
#downloadArea {
|
|
margin-top: 20px; padding: 14px;
|
|
background: rgba(34,197,94,0.08); border: 1px solid rgba(34,197,94,0.2);
|
|
border-radius: var(--ov-radius); text-align: center;
|
|
transition: height 0.3s ease;
|
|
}
|
|
#downloadArea h3 { color: var(--ov-success); margin-bottom: 10px; font-size: 18px; }
|
|
#downloadArea p { color: var(--ov-success); margin-bottom: 16px; font-size: 14px; }
|
|
/* 底部 */
|
|
.ov-footer {
|
|
text-align: center; padding: 24px; color: var(--ov-text2); font-size: 13px;
|
|
border-top: 1px solid var(--ov-card-border); margin-top: 40px;
|
|
}
|
|
.ov-footer a { color: var(--ov-accent2); text-decoration: none; }
|
|
.ov-footer a:hover { text-decoration: underline; }
|
|
/* 入场动画 - 遮罩滑出效果 */
|
|
@keyframes ovReveal {
|
|
from {
|
|
clip-path: inset(0 0 100% 0);
|
|
opacity: 0;
|
|
transform: translateY(12px);
|
|
}
|
|
to {
|
|
clip-path: inset(0 0 0 0);
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
@keyframes ovRevealDown {
|
|
from {
|
|
clip-path: inset(100% 0 0 0);
|
|
opacity: 0;
|
|
transform: translateY(-12px);
|
|
}
|
|
to {
|
|
clip-path: inset(0 0 0 0);
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
@keyframes ovRevealLR {
|
|
from {
|
|
clip-path: inset(0 100% 0 0);
|
|
opacity: 0;
|
|
transform: translateX(-8px);
|
|
}
|
|
to {
|
|
clip-path: inset(0 0 0 0);
|
|
opacity: 1;
|
|
transform: translateX(0);
|
|
}
|
|
}
|
|
/* 标题持续渐变变色 */
|
|
@keyframes ovColorShift {
|
|
0%, 100% { filter: hue-rotate(0deg); }
|
|
50% { filter: hue-rotate(30deg); }
|
|
}
|
|
.ov-nav {
|
|
animation: ovRevealDown 0.7s cubic-bezier(0.22, 1, 0.36, 1) both;
|
|
}
|
|
.ov-hero h1 {
|
|
animation:
|
|
ovRevealLR 0.9s cubic-bezier(0.22, 1, 0.36, 1) 0.2s both,
|
|
ovGradientShift 6s ease-in-out 1.1s infinite;
|
|
background: linear-gradient(135deg, #7c3aed, #06b6d4, #7c3aed);
|
|
background-size: 200% 200%;
|
|
-webkit-background-clip: text;
|
|
color: transparent;
|
|
}
|
|
.ov-hero p {
|
|
animation: ovReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.35s both;
|
|
}
|
|
.upload-card {
|
|
animation: ovReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.5s both;
|
|
}
|
|
.config-card {
|
|
opacity: 0;
|
|
transform: translateY(12px);
|
|
}
|
|
.config-card.animated {
|
|
animation: ovReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) 0.1s both;
|
|
}
|
|
.progress-card,
|
|
#downloadArea {
|
|
opacity: 0;
|
|
transform: translateY(10px);
|
|
}
|
|
.progress-card.screen-enter,
|
|
#downloadArea.screen-enter {
|
|
animation: screenEnter 0.45s ease both;
|
|
}
|
|
.progress-card.screen-exit,
|
|
#downloadArea.screen-exit {
|
|
animation: screenExit 0.3s ease both;
|
|
}
|
|
.progress-card {
|
|
animation: none;
|
|
}
|
|
#downloadArea {
|
|
background-color: rgba(40, 167, 69, 0.1);
|
|
border: 1px solid var(#28a745);
|
|
border-radius: 8px;
|
|
text-align: center;
|
|
backdrop-filter: blur(20px);
|
|
}
|
|
#downloadArea h3 {
|
|
font-size: 20px;
|
|
letter-spacing: 0.2px;
|
|
}
|
|
#downloadArea button {
|
|
padding: 12px 26px;
|
|
border-radius: 14px;
|
|
}
|
|
.progress-container {
|
|
background: rgba(255,255,255,0.08);
|
|
}
|
|
.progress-card .progress-container {
|
|
background: rgba(255,255,255,0.08);
|
|
border: 1px solid rgba(255,255,255,0.08);
|
|
}
|
|
#statusMessage {
|
|
animation: ovReveal 0.7s cubic-bezier(0.22, 1, 0.36, 1) 0.6s both;
|
|
}
|
|
@keyframes screenEnter {
|
|
from {
|
|
opacity: 0;
|
|
transform: translateY(15px);
|
|
}
|
|
to {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
}
|
|
@keyframes screenExit {
|
|
from {
|
|
opacity: 1;
|
|
transform: translateY(0);
|
|
}
|
|
to {
|
|
opacity: 0;
|
|
transform: translateY(15px);
|
|
}
|
|
}
|
|
@keyframes ovGradientShift {
|
|
0%, 100% {
|
|
background-position: 0% 50%;
|
|
}
|
|
50% {
|
|
background-position: 100% 50%;
|
|
}
|
|
}
|
|
.ov-footer {
|
|
animation: ovReveal 0.8s cubic-bezier(0.22, 1, 0.36, 1) 1s both;
|
|
}
|
|
/* 移动端适配 */
|
|
body.device-mobile .ov-nav { padding: 10px 16px; }
|
|
body.device-mobile .ov-main { padding: 18px 16px 32px; }
|
|
body.device-mobile .ov-main .ov-card { margin: 0 auto 12px; max-width: calc(100% - 16px); }
|
|
body.device-mobile .ov-hero h1 { font-size: 20px; line-height: 1.25; }
|
|
body.device-mobile .ov-hero p { font-size: 12px; line-height: 1.5; }
|
|
body.device-mobile .ov-card { padding: 14px; margin-bottom: 12px; }
|
|
body.device-mobile .ov-card h2 { font-size: 15px; }
|
|
body.device-mobile .ov-card h2 .ov-hint { font-size: 10px; }
|
|
body.device-mobile #dropZone { padding: 20px 14px; }
|
|
body.device-mobile button { padding: 8px 14px; font-size: 13px; }
|
|
body.device-mobile .file-item button { padding: 8px 12px; font-size: 12px }
|
|
body.device-mobile .lang-toggle { width: auto; padding: 4px 10px; font-size: 12px; }
|
|
body.device-mobile input[type="text"] { max-width: 100%; font-size: 13px; }
|
|
body.device-mobile .file-item { align-items: stretch; padding: 10px 12px; }
|
|
body.device-mobile .file-info { flex-direction: column; align-items: flex-start; gap: 6px; display: unset}
|
|
body.device-mobile .file-name { font-size: 14px; word-break: break-word; }
|
|
body.device-mobile .file-size { font-size: 12px; }
|
|
body.device-mobile .file-type-badge { display: none; }
|
|
body.device-mobile .file-item { gap: 10px; }
|
|
</style>
|
|
</head>
|
|
<body data-i18n-title="OV_PAGE_TITLE">
|
|
<!-- 导航栏 -->
|
|
<nav class="ov-nav">
|
|
<div class="ov-nav-brand">
|
|
<img src="image.jpg" alt="Icon">
|
|
<span data-i18n="OV_MAIN_TITLE">Construct Expansion Pack Generator</span>
|
|
|
|
</div>
|
|
<button id="langSwitchBtn" class="lang-toggle" onclick="switchLang(currentLang==='zh'?'en':'zh')">EN</button>
|
|
</nav>
|
|
|
|
<div class="ov-main">
|
|
<!-- Hero -->
|
|
<div class="ov-hero">
|
|
<h1 data-i18n="OV_MAIN_TITLE">Construct Pack Generator</h1>
|
|
<p data-i18n="OV_SUB_TITLE">a platform for generating expansion packs of Construct, enabling users to upload .mcstructure | .nbt | .litematic files</p>
|
|
</div>
|
|
|
|
<!-- 上传区域 -->
|
|
<div class="ov-card upload-card">
|
|
<h2>
|
|
<span data-i18n="SECTION_UPLOAD">Upload Files</span>
|
|
<span class="ov-hint" data-i18n="FORMAT_HINT">Supported: .mcstructure | .nbt | .litematic</span>
|
|
</h2>
|
|
<div id="dropZone">
|
|
<span data-i18n="DROP_ZONE_TEXT">Drag files here or click to select</span>
|
|
<button id="selectFilesBtn" data-i18n="SELECT_FILES_BTN">Select Files</button>
|
|
<input type="file" id="fileInput" multiple accept=".mcstructure,.nbt,.litematic" style="display:none;">
|
|
</div>
|
|
<div id="fileList"></div>
|
|
</div>
|
|
|
|
<!-- 状态消息 -->
|
|
<div id="statusMessage" data-i18n="OV_STATUS_HINT">Open in browser for best experience</div>
|
|
|
|
<!-- 配置 -->
|
|
<div class="ov-card config-card">
|
|
<h2 data-i18n="SECTION_CONFIG">Configuration</h2>
|
|
<div style="margin-bottom:20px;">
|
|
<label for="projectName" style="display:block;margin-bottom:8px;font-weight:500;font-size:14px;" data-i18n="LABEL_PROJECT_NAME">Pack Name:</label>
|
|
<input type="text" id="projectName" value="My Construct Pack" data-i18n="DEFAULT_PROJECT_NAME" data-i18n-attr="value">
|
|
</div>
|
|
<button id="processBtn" data-i18n="BTN_PROCESS">Process & Generate Addon</button>
|
|
</div>
|
|
|
|
<!-- 进度 -->
|
|
<div id="progressArea" class="ov-card progress-card" style="display:none;">
|
|
<h2 data-i18n="SECTION_PROGRESS">Processing Progress</h2>
|
|
<div class="progress-container"><div id="progressFill"></div></div>
|
|
<div id="progressText" style="text-align:center;font-size:13px;color:var(--ov-text2);">0%</div>
|
|
</div>
|
|
|
|
<!-- 下载 -->
|
|
<div id="downloadArea" style="display:none;">
|
|
<h3 data-i18n="SECTION_DOWNLOAD">Download Your Pack</h3>
|
|
<p data-i18n="DOWNLOAD_READY">Import Into MCBE & Load It In The World</p>
|
|
<button id="downloadBtn" data-i18n="DOWNLOAD_BTN">Download</button>
|
|
</div>
|
|
|
|
<!-- 底部 -->
|
|
<div class="ov-footer">
|
|
<span data-i18n="OV_FOOTER_POWERED">Powered by Sea-of-Stars-Studio</span>
|
|
·
|
|
<a href="https://github.com/Sea-of-Stars-studio/sea-of-stars-studio.github.io/issues" target="_blank" data-i18n="FOOTER_SPONSOR">Report Bug</a>
|
|
·
|
|
<a href="https://github.com/ForestOfLight/Construct/releases" target="_blank" data-i18n="DL_PAGE_TITLE">Download Construct</a>
|
|
</div>
|
|
</div>
|
|
|
|
<script>
|
|
// 海外版默认英文,除非用户手动切换过
|
|
(function() {
|
|
try {
|
|
var saved = localStorage.getItem('lang');
|
|
currentLang = (saved && i18n[saved]) ? saved : 'en';
|
|
} catch(e) { currentLang = 'en'; }
|
|
})();
|
|
</script>
|
|
<script src="js/script.uni.js"></script>
|
|
<script>applyI18n();</script>
|
|
</body>
|
|
</html>
|