duqing2026's picture
升级优化
8661be0
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>Code Snapshot Studio - 代码截图工坊</title>
<script src="https://cdn.tailwindcss.com"></script>
<script src="https://unpkg.com/vue@3/dist/vue.global.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/prism.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/plugins/autoloader/prism-autoloader.min.js"></script>
<script src="https://html2canvas.hertzen.com/dist/html2canvas.min.js"></script>
<!-- Default Theme -->
<link id="prism-theme" rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/prism/1.29.0/themes/prism-tomorrow.min.css">
<!-- Icons -->
<link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/6.4.0/css/all.min.css">
<!-- Custom Styles -->
<link rel="stylesheet" href="/static/style.css">
</head>
<body class="h-screen flex flex-col overflow-hidden">
{% raw %}
<div id="app" class="flex-1 flex flex-col h-full">
<!-- Header -->
<header class="bg-white border-b border-gray-200 px-4 lg:px-6 py-3 flex items-center justify-between shadow-sm z-30">
<div class="flex items-center gap-3">
<button @click="toggleSidebar" class="lg:hidden text-gray-600 hover:text-indigo-600 transition-colors">
<i class="fa-solid fa-bars text-xl"></i>
</button>
<div class="w-8 h-8 bg-gradient-to-br from-indigo-500 to-purple-600 rounded-lg flex items-center justify-center text-white font-bold">
<i class="fa-solid fa-camera"></i>
</div>
<h1 class="text-lg lg:text-xl font-bold text-gray-800 tracking-tight truncate">Code Snapshot Studio</h1>
</div>
<div class="flex items-center gap-4">
<button @click="copyImage" :disabled="isExporting"
class="bg-white border border-gray-300 hover:bg-gray-50 text-gray-700 px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2 shadow-sm whitespace-nowrap hidden sm:flex">
<i class="fa-regular fa-copy"></i>
<span>复制图片</span>
</button>
<button @click="exportImage" :disabled="isExporting"
class="bg-indigo-600 hover:bg-indigo-700 disabled:bg-indigo-400 text-white px-4 py-2 rounded-lg font-medium transition-colors flex items-center gap-2 shadow-sm whitespace-nowrap">
<i v-if="!isExporting" class="fa-solid fa-download"></i>
<i v-else class="fa-solid fa-spinner fa-spin"></i>
<span>{{ isExporting ? '导出中...' : '导出 PNG' }}</span>
</button>
</div>
</header>
<!-- Main Content -->
<main class="flex-1 flex overflow-hidden relative">
<!-- Mobile Backdrop -->
<div v-if="showSidebar" @click="showSidebar = false" class="fixed inset-0 bg-black/20 z-20 lg:hidden backdrop-blur-sm transition-opacity"></div>
<!-- Sidebar Controls -->
<aside :class="['w-80 bg-white border-r border-gray-200 overflow-y-auto p-6 flex flex-col gap-6 shadow-[4px_0_24px_rgba(0,0,0,0.02)] z-30 absolute inset-y-0 left-0 lg:static sidebar-transition transform', showSidebar ? 'translate-x-0' : '-translate-x-full lg:translate-x-0']">
<!-- Code Input -->
<div class="flex flex-col gap-2">
<label class="text-sm font-semibold text-gray-700 flex justify-between items-center">
代码内容
<button @click="clearCode" class="text-xs text-red-500 hover:text-red-700 font-normal hover:underline" title="清空代码">
清空
</button>
</label>
<textarea v-model="code" class="w-full h-48 p-3 border border-gray-300 rounded-lg text-sm font-mono focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 outline-none resize-none bg-gray-50" placeholder="在此粘贴你的代码..."></textarea>
</div>
<!-- Language & Theme -->
<div class="grid grid-cols-2 gap-4">
<div class="flex flex-col gap-2">
<label class="text-sm font-semibold text-gray-700 flex justify-between items-center">
语言
<button @click="loadExample" class="text-xs text-indigo-600 hover:text-indigo-800 font-normal hover:underline" title="加载示例代码">
示例
</button>
</label>
<select v-model="language" @change="onLanguageChange" class="w-full p-2 border border-gray-300 rounded-lg text-sm bg-white focus:ring-2 focus:ring-indigo-500 outline-none">
<option value="javascript">JavaScript</option>
<option value="typescript">TypeScript</option>
<option value="python">Python</option>
<option value="java">Java</option>
<option value="go">Go</option>
<option value="rust">Rust</option>
<option value="html">HTML</option>
<option value="css">CSS</option>
<option value="sql">SQL</option>
<option value="bash">Bash</option>
<option value="json">JSON</option>
</select>
</div>
<div class="flex flex-col gap-2">
<label class="text-sm font-semibold text-gray-700">主题</label>
<select v-model="theme" @change="changeTheme" class="w-full p-2 border border-gray-300 rounded-lg text-sm bg-white focus:ring-2 focus:ring-indigo-500 outline-none">
<option value="tomorrow">Dark (Tomorrow)</option>
<option value="okaidia">Okaidia</option>
<option value="solarizedlight">Solarized Light</option>
<option value="twilight">Twilight</option>
<option value="default">Default</option>
</select>
</div>
</div>
<!-- Background -->
<div class="flex flex-col gap-2">
<label class="text-sm font-semibold text-gray-700">背景风格</label>
<div class="grid grid-cols-5 gap-2">
<button v-for="(bg, index) in backgrounds" :key="index"
@click="currentBg = bg"
:class="['w-8 h-8 rounded-full border-2 transition-all', currentBg.value === bg.value ? 'border-indigo-600 scale-110 shadow-md' : 'border-transparent hover:scale-105']"
:style="{ background: bg.value }"
:title="bg.name">
</button>
</div>
</div>
<!-- Settings -->
<div class="space-y-4 border-t border-gray-100 pt-4">
<div class="flex items-center justify-between">
<label class="text-sm font-medium text-gray-700">窗口控件</label>
<input type="checkbox" v-model="showWindowControls" class="w-4 h-4 text-indigo-600 rounded focus:ring-indigo-500">
</div>
<div class="flex items-center justify-between">
<label class="text-sm font-medium text-gray-700">行号</label>
<input type="checkbox" v-model="showLineNumbers" class="w-4 h-4 text-indigo-600 rounded focus:ring-indigo-500">
</div>
<div class="flex items-center justify-between">
<label class="text-sm font-medium text-gray-700">窗口阴影</label>
<input type="checkbox" v-model="showShadow" class="w-4 h-4 text-indigo-600 rounded focus:ring-indigo-500">
</div>
<div class="flex flex-col gap-2">
<div class="flex justify-between">
<label class="text-sm font-medium text-gray-700">内边距 (Padding)</label>
<span class="text-xs text-gray-500">{{ padding }}px</span>
</div>
<input type="range" v-model="padding" min="16" max="128" step="8" class="w-full h-2 bg-gray-200 rounded-lg appearance-none cursor-pointer accent-indigo-600">
</div>
<div class="flex flex-col gap-2">
<label class="text-sm font-medium text-gray-700">窗口标题</label>
<input type="text" v-model="windowTitle" class="w-full p-2 border border-gray-300 rounded-lg text-sm outline-none focus:ring-2 focus:ring-indigo-500" placeholder="例如: app.py">
</div>
</div>
</aside>
<!-- Preview Area -->
<section class="flex-1 bg-gray-100 flex items-center justify-center p-4 lg:p-8 overflow-auto relative w-full">
<!-- Grid Background Pattern -->
<div class="absolute inset-0 opacity-[0.03]"
style="background-image: radial-gradient(#000 1px, transparent 1px); background-size: 20px 20px;">
</div>
<!-- The Snapshot Card -->
<div ref="snapshotCard" class="preview-container relative flex items-center justify-center min-w-[300px] lg:min-w-[400px]"
:style="{ background: currentBg.value, padding: padding + 'px' }">
<!-- Window -->
<div class="bg-[#1e1e1e] rounded-xl overflow-hidden min-w-[300px] max-w-[90vw] lg:max-w-4xl w-auto"
:class="{'shadow-2xl': showShadow, 'shadow-none': !showShadow}"
:style="{ backgroundColor: themeBgColor }">
<!-- Window Header -->
<div v-if="showWindowControls || windowTitle" class="px-4 py-3 flex items-center relative bg-white/5 border-b border-white/5">
<!-- Controls -->
<div v-if="showWindowControls" class="flex gap-2 absolute left-4">
<div class="w-3 h-3 rounded-full bg-[#ff5f56] border border-[#e0443e]"></div>
<div class="w-3 h-3 rounded-full bg-[#ffbd2e] border border-[#dea123]"></div>
<div class="w-3 h-3 rounded-full bg-[#27c93f] border border-[#1aab29]"></div>
</div>
<!-- Title -->
<div class="w-full text-center text-xs font-medium text-gray-400 font-sans select-none truncate px-12">
{{ windowTitle }}
</div>
</div>
<!-- Code Content -->
<div class="p-0 overflow-hidden overflow-x-auto">
<pre class="!m-0 !p-6 !bg-transparent text-sm leading-relaxed outline-none code-font"
:class="{'line-numbers': showLineNumbers}"><code :class="'language-' + language" ref="codeBlock">{{ code }}</code></pre>
</div>
</div>
</div>
</section>
</main>
</div>
{% endraw %}
<!-- App Logic -->
<script src="/static/script.js"></script>
</body>
</html>