文件
csp/ref/CSP-Minecraft-UI-Kit/html/pages/code-editor.html

619 行
23 KiB
HTML

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Minecraft Code Editor</title>
<link href="https://cdnjs.cloudflare.com/ajax/libs/remixicon/4.6.0/remixicon.min.css" rel="stylesheet">
<style>
@font-face {
font-family: 'DelaGothicOne';
src: url('https://assets-persist.lovart.ai/agent-static-assets/DelaGothicOne-Regular.ttf');
}
@font-face {
font-family: 'MiSans';
src: url('https://assets-persist.lovart.ai/agent-static-assets/MiSans-Regular.ttf');
}
@font-face {
font-family: 'PixelCode';
src: local('Courier New'), monospace; /* Fallback for code */
}
:root {
--mc-wood-light: #A07F53;
--mc-wood-dark: #765637;
--mc-stone: #757575;
--mc-stone-dark: #3b3b3b;
--mc-obsidian: #18181F;
--mc-grass: #7CB342;
--mc-grass-dark: #558B2F;
--mc-gold: #FFB300;
--mc-gold-dark: #FF8F00;
--mc-diamond: #00BCD4;
--mc-redstone: #F44336;
--mc-text-shadow: 2px 2px 0px #000;
--mc-border-light: rgba(255, 255, 255, 0.4);
--mc-border-dark: rgba(0, 0, 0, 0.4);
}
* {
box-sizing: border-box;
margin: 0;
padding: 0;
}
body {
width: 1920px;
height: 1080px; /* Fixed height for preview, though body usually auto */
background-color: #121212;
font-family: 'MiSans', sans-serif;
color: white;
overflow: hidden;
display: flex;
flex-direction: column;
}
/* Minecraft Texture Classes */
.bg-wood {
background-color: var(--mc-wood-dark);
background-image:
linear-gradient(90deg, rgba(0,0,0,0.1) 50%, transparent 50%),
linear-gradient(rgba(0,0,0,0.1) 50%, transparent 50%);
background-size: 4px 4px;
box-shadow: inset 0 0 40px rgba(0,0,0,0.5);
}
.bg-stone {
background-color: var(--mc-stone);
background-image:
radial-gradient(circle at 2px 2px, rgba(255,255,255,0.1) 1px, transparent 1px),
radial-gradient(circle at 10px 10px, rgba(0,0,0,0.1) 2px, transparent 2px);
background-size: 20px 20px;
}
.bg-obsidian {
background-color: #1a1a24;
background-image:
repeating-linear-gradient(45deg, rgba(255,255,255,0.02) 0px, rgba(255,255,255,0.02) 1px, transparent 1px, transparent 10px),
repeating-linear-gradient(-45deg, rgba(255,255,255,0.02) 0px, rgba(255,255,255,0.02) 1px, transparent 1px, transparent 10px);
}
/* Typography */
h1, h2, h3, .mc-font {
font-family: 'DelaGothicOne', cursive;
letter-spacing: 1px;
text-shadow: 2px 2px 0 rgba(0,0,0,0.5);
}
/* 3D Button Style */
.mc-btn {
border: 4px solid #000;
border-top-color: rgba(255,255,255,0.5);
border-left-color: rgba(255,255,255,0.5);
border-bottom-color: rgba(0,0,0,0.5);
border-right-color: rgba(0,0,0,0.5);
padding: 8px 16px;
font-family: 'DelaGothicOne', cursive;
cursor: pointer;
text-transform: uppercase;
font-size: 14px;
display: inline-flex;
align-items: center;
gap: 8px;
transition: transform 0.1s;
image-rendering: pixelated;
}
.mc-btn:active {
border-top-color: rgba(0,0,0,0.5);
border-left-color: rgba(0,0,0,0.5);
border-bottom-color: rgba(255,255,255,0.5);
border-right-color: rgba(255,255,255,0.5);
transform: translateY(2px);
}
.btn-green { background-color: var(--mc-grass); color: white; text-shadow: 1px 1px 0 #000; }
.btn-gold { background-color: var(--mc-gold); color: #3e2723; text-shadow: none; }
.btn-stone { background-color: var(--mc-stone); color: white; }
.btn-icon { padding: 8px; }
/* Scrollbar */
::-webkit-scrollbar { width: 12px; height: 12px; }
::-webkit-scrollbar-track { background: #2b2b2b; }
::-webkit-scrollbar-thumb {
background: #555;
border: 2px solid #2b2b2b;
border-top-color: #777;
border-left-color: #777;
}
/* Navigation */
.navbar {
height: 60px;
background-color: #212121;
border-bottom: 4px solid #000;
display: flex;
align-items: center;
padding: 0 24px;
gap: 20px;
position: relative;
z-index: 10;
}
.nav-logo { font-size: 24px; color: var(--mc-grass); }
.nav-item { color: #aaa; text-decoration: none; font-family: 'DelaGothicOne'; font-size: 14px; }
.nav-item:hover { color: white; text-decoration: underline; }
/* Main Layout */
.main-container {
display: flex;
height: calc(100vh - 60px);
position: relative;
}
/* Left Panel */
.left-panel {
width: 40%;
height: 100%;
display: flex;
flex-direction: column;
border-right: 4px solid #000;
position: relative;
}
.problem-content {
flex: 1;
overflow-y: auto;
padding: 32px;
}
.paper-card {
background-color: #FDF5E6; /* Old Lace */
color: #333;
padding: 24px;
border: 4px solid #333;
box-shadow: 8px 8px 0 rgba(0,0,0,0.3);
margin-bottom: 24px;
position: relative;
}
.paper-card::before {
content: '';
position: absolute;
top: -4px; left: -4px; right: -4px; bottom: -4px;
border: 2px solid #5d4037;
pointer-events: none;
}
.difficulty-badge {
background-color: var(--mc-grass);
color: white;
padding: 4px 8px;
font-size: 12px;
border: 2px solid #33691E;
display: inline-block;
margin-left: 10px;
font-family: 'DelaGothicOne';
vertical-align: middle;
}
.code-block-display {
background-color: #263238;
color: #eceff1;
padding: 12px;
border-left: 4px solid var(--mc-grass);
font-family: 'PixelCode', monospace;
margin: 10px 0;
white-space: pre-wrap;
}
.panel-footer {
height: 70px;
background-color: rgba(0,0,0,0.3);
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 24px;
border-top: 4px solid #3e2723;
}
/* Right Panel */
.right-panel {
width: 60%;
display: flex;
flex-direction: column;
background-color: #1e1e1e;
}
.toolbar {
height: 56px;
display: flex;
align-items: center;
justify-content: space-between;
padding: 0 16px;
border-bottom: 4px solid #000;
}
.toolbar-group {
display: flex;
gap: 12px;
align-items: center;
}
.code-editor-wrapper {
flex: 1;
display: flex;
overflow: hidden;
position: relative;
}
.line-numbers {
width: 48px;
background-color: #121217;
color: #546e7a;
text-align: right;
padding: 16px 8px;
font-family: 'PixelCode', monospace;
font-size: 16px;
line-height: 1.5;
user-select: none;
border-right: 2px solid #333;
}
.code-area {
flex: 1;
background-color: transparent;
color: #d4d4d4;
padding: 16px;
font-family: 'PixelCode', monospace;
font-size: 16px;
line-height: 1.5;
overflow: auto;
white-space: pre;
outline: none;
}
/* Syntax Highlighting Colors */
.token-keyword { color: #cc7832; font-weight: bold; }
.token-type { color: #e0c46c; }
.token-string { color: #6a8759; }
.token-comment { color: #808080; font-style: italic; }
.token-number { color: #6897bb; }
.status-bar {
height: 32px;
background-color: #2d2d2d;
border-top: 2px solid #444;
display: flex;
align-items: center;
padding: 0 16px;
font-size: 12px;
gap: 20px;
color: #aaa;
font-family: 'PixelCode', monospace;
}
.combo-counter {
color: var(--mc-gold);
font-weight: bold;
display: flex;
align-items: center;
gap: 4px;
}
/* Test Panel */
.test-panel {
height: 220px;
border-top: 4px solid #000;
display: flex;
flex-direction: column;
transition: height 0.3s;
}
.test-panel.collapsed { height: 40px; }
.test-header {
height: 40px;
display: flex;
align-items: center;
padding: 0 16px;
background-color: rgba(0,0,0,0.2);
border-bottom: 2px solid #444;
cursor: pointer;
}
.tab-btn {
padding: 6px 16px;
background: none;
border: none;
color: #aaa;
cursor: pointer;
font-family: 'DelaGothicOne';
font-size: 12px;
}
.tab-btn.active { color: white; border-bottom: 2px solid var(--mc-grass); }
.test-content {
flex: 1;
padding: 16px;
display: flex;
gap: 16px;
overflow: hidden;
}
.test-case-item {
flex: 1;
background-color: rgba(0,0,0,0.3);
border: 2px solid #444;
padding: 12px;
font-family: 'PixelCode', monospace;
font-size: 14px;
}
.test-case-status { display: flex; justify-content: space-between; margin-bottom: 8px; font-weight: bold; }
.status-pass { color: var(--mc-grass); }
.status-fail { color: var(--mc-redstone); }
/* XP Overlay */
.xp-overlay {
position: absolute;
top: 50%; left: 50%;
transform: translate(-50%, -50%);
font-size: 64px;
color: #B9F6CA;
text-shadow: 4px 4px 0 #1B5E20;
font-family: 'DelaGothicOne';
opacity: 0;
pointer-events: none;
z-index: 100;
}
@keyframes xpFloat {
0% { opacity: 0; transform: translate(-50%, -20%); }
20% { opacity: 1; transform: translate(-50%, -50%); }
80% { opacity: 1; transform: translate(-50%, -60%); }
100% { opacity: 0; transform: translate(-50%, -100%); }
}
.animate-xp { animation: xpFloat 2s ease-out forwards; }
/* Confetti */
.confetti {
position: absolute;
width: 8px; height: 8px;
background: var(--mc-diamond);
animation: fall 3s linear forwards;
z-index: 99;
}
@keyframes fall {
to { transform: translateY(100vh) rotate(720deg); }
}
/* Select styling */
.mc-select {
background: var(--mc-stone-dark);
border: 2px solid #000;
color: white;
padding: 4px 8px;
font-family: 'PixelCode', monospace;
cursor: pointer;
outline: none;
}
</style>
</head>
<body>
<!-- Top Navigation -->
<nav class="navbar bg-stone">
<div class="nav-logo mc-font"><i class="ri-box-3-fill"></i> MINECODE</div>
<a href="#" class="nav-item">Problems</a>
<a href="#" class="nav-item">Contest</a>
<a href="#" class="nav-item">Discuss</a>
<div style="flex:1"></div>
<div class="nav-item" style="color:var(--mc-gold)">LVL 24</div>
<img src="https://api.dicebear.com/7.x/pixel-art/svg?seed=Steve" alt="User" style="width: 32px; height: 32px; border: 2px solid white;">
</nav>
<div class="main-container">
<!-- Left Panel: Problem -->
<aside class="left-panel bg-wood">
<div class="problem-content">
<div style="display:flex; align-items:center; justify-content:space-between; margin-bottom: 20px;">
<h1 style="font-size: 28px; color: #3E2723;">1. Two Sum</h1>
<span class="difficulty-badge">EASY</span>
</div>
<div class="paper-card">
<p style="margin-bottom: 16px; line-height: 1.6;">
Given an array of integers <code>nums</code> and an integer <code>target</code>, return <i>indices</i> of the two numbers such that they add up to <code>target</code>.
</p>
<p style="line-height: 1.6;">
You may assume that each input would have <strong>exactly one solution</strong>, and you may not use the same element twice.
</p>
</div>
<div style="margin-bottom: 24px;">
<h3 style="color:#3E2723; margin-bottom:10px;">Example 1:</h3>
<div class="code-block-display">Input: nums = [2,7,11,15], target = 9
Output: [0,1]
Explanation: Because nums[0] + nums[1] == 9, we return [0, 1].</div>
</div>
<div style="margin-bottom: 24px;">
<h3 style="color:#3E2723; margin-bottom:10px;">Example 2:</h3>
<div class="code-block-display">Input: nums = [3,2,4], target = 6
Output: [1,2]</div>
</div>
<div style="margin-bottom: 24px;">
<h3 style="color:#3E2723; margin-bottom:10px; display:flex; align-items:center;">
<i class="ri-book-mark-fill" style="margin-right:8px;"></i> Hints
</h3>
<div style="background: rgba(0,0,0,0.1); padding: 10px; border: 2px dashed #5D4037; color: #3E2723;">
Try using a Hash Map to store visited numbers.
</div>
</div>
</div>
<div class="panel-footer">
<button class="mc-btn btn-stone"><i class="ri-star-fill"></i> Bookmark</button>
<div style="display: flex; gap: 10px;">
<button class="mc-btn btn-stone btn-icon"><i class="ri-share-forward-fill"></i></button>
<button class="mc-btn btn-stone btn-icon"><i class="ri-file-list-3-fill"></i></button>
</div>
</div>
</aside>
<!-- Right Panel: Editor -->
<main class="right-panel">
<!-- Toolbar -->
<div class="toolbar bg-stone">
<div class="toolbar-group">
<select class="mc-select">
<option>C++</option>
<option>Java</option>
<option>Python</option>
</select>
<button class="mc-btn btn-stone btn-icon" style="padding:4px 8px;"><i class="ri-settings-3-fill"></i></button>
<div style="color:#bbb; font-size:12px;">Size: 14px</div>
</div>
<div class="toolbar-group">
<button class="mc-btn btn-green" onclick="runCode()"><i class="ri-play-fill"></i> Run</button>
<button class="mc-btn btn-gold" onclick="submitCode()"><i class="ri-upload-cloud-2-fill"></i> Submit</button>
</div>
</div>
<!-- Code Editor -->
<div class="code-editor-wrapper bg-obsidian">
<div class="line-numbers">
1<br>2<br>3<br>4<br>5<br>6<br>7<br>8<br>9<br>10<br>11
</div>
<div class="code-area" contenteditable="true" spellcheck="false">
<span class="token-keyword">class</span> Solution {
<span class="token-keyword">public</span>:
<span class="token-type">vector</span>&lt;<span class="token-type">int</span>&gt; twoSum(<span class="token-type">vector</span>&lt;<span class="token-type">int</span>&gt;& nums, <span class="token-type">int</span> target) {
<span class="token-type">unordered_map</span>&lt;<span class="token-type">int</span>, <span class="token-type">int</span>&gt; hash;
<span class="token-keyword">for</span> (<span class="token-type">int</span> i = <span class="token-number">0</span>; i < nums.size(); i++) {
<span class="token-type">int</span> complement = target - nums[i];
<span class="token-keyword">if</span> (hash.find(complement) != hash.end()) {
<span class="token-keyword">return</span> {hash[complement], i};
}
hash[nums[i]] = i;
}
<span class="token-keyword">return</span> {};
}
};</div>
</div>
<!-- Status Bar -->
<div class="status-bar">
<span>Ready</span>
<span style="border-left: 1px solid #555; height: 16px;"></span>
<span><i class="ri-time-fill"></i> 0ms</span>
<span><i class="ri-sd-card-mini-fill"></i> 0KB</span>
<div style="flex:1"></div>
<div class="combo-counter"><i class="ri-fire-fill"></i> COMBO x5</div>
</div>
<!-- Test Panel -->
<div class="test-panel bg-stone" id="testPanel">
<div class="test-header" onclick="toggleTestPanel()">
<i class="ri-terminal-box-fill" style="margin-right: 10px; color: #ccc;"></i>
<span class="mc-font" style="font-size: 14px; color: #eee; flex:1">Test Console</span>
<i class="ri-arrow-up-s-line" id="toggleIcon"></i>
</div>
<div style="background: rgba(0,0,0,0.4); padding: 0 16px; display: flex; border-bottom: 2px solid #444;">
<button class="tab-btn active">Test Cases</button>
<button class="tab-btn">Result</button>
</div>
<div class="test-content">
<div class="test-case-item">
<div class="test-case-status">Case 1 <i class="ri-checkbox-circle-fill status-pass"></i></div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Input</div>
<div style="color: #fff; margin-bottom: 8px;">nums = [2,7,11,15], target = 9</div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Expected</div>
<div style="color: #fff;">[0,1]</div>
</div>
<div class="test-case-item">
<div class="test-case-status">Case 2 <i class="ri-checkbox-circle-fill status-pass"></i></div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Input</div>
<div style="color: #fff; margin-bottom: 8px;">nums = [3,2,4], target = 6</div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Expected</div>
<div style="color: #fff;">[1,2]</div>
</div>
<div class="test-case-item" style="border-color: #F44336; opacity: 0.8;">
<div class="test-case-status">Case 3 <i class="ri-close-circle-fill status-fail"></i></div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Input</div>
<div style="color: #fff; margin-bottom: 8px;">nums = [3,3], target = 6</div>
<div style="color: #888; font-size: 12px; margin-bottom: 4px;">Expected</div>
<div style="color: #fff;">[0,1]</div>
</div>
</div>
</div>
</main>
</div>
<!-- XP Animation Overlay -->
<div id="xpDisplay" class="xp-overlay">+50 XP</div>
<script>
function toggleTestPanel() {
const panel = document.getElementById('testPanel');
const icon = document.getElementById('toggleIcon');
panel.classList.toggle('collapsed');
if(panel.classList.contains('collapsed')) {
icon.classList.remove('ri-arrow-down-s-line');
icon.classList.add('ri-arrow-up-s-line');
} else {
icon.classList.remove('ri-arrow-up-s-line');
icon.classList.add('ri-arrow-down-s-line');
}
}
function runCode() {
// Simulate running code
const btn = document.querySelector('.btn-green');
btn.innerHTML = '<i class="ri-loader-4-line ri-spin"></i> Running...';
setTimeout(() => {
btn.innerHTML = '<i class="ri-play-fill"></i> Run';
document.getElementById('testPanel').classList.remove('collapsed');
}, 1000);
}
function submitCode() {
const btn = document.querySelector('.btn-gold');
const originalContent = btn.innerHTML;
btn.innerHTML = '<i class="ri-loader-4-line ri-spin"></i> ...';
setTimeout(() => {
btn.innerHTML = originalContent;
showXP();
createConfetti();
}, 1500);
}
function showXP() {
const xp = document.getElementById('xpDisplay');
xp.classList.remove('animate-xp');
void xp.offsetWidth; // trigger reflow
xp.classList.add('animate-xp');
}
function createConfetti() {
const colors = ['#F44336', '#2196F3', '#FFEB3B', '#4CAF50', '#FF9800'];
for(let i=0; i<50; i++) {
const conf = document.createElement('div');
conf.className = 'confetti';
conf.style.left = Math.random() * 100 + 'vw';
conf.style.top = '-10px';
conf.style.backgroundColor = colors[Math.floor(Math.random() * colors.length)];
conf.style.animationDuration = (Math.random() * 2 + 2) + 's';
document.body.appendChild(conf);
setTimeout(() => conf.remove(), 4000);
}
}
</script>
</body>
</html>