Spaces:
Sleeping
Sleeping
Commit ·
85cae67
1
Parent(s): 5897cf2
丰富功能和优化
Browse files- app.py +14 -2
- templates/index.html +40 -16
app.py
CHANGED
|
@@ -37,6 +37,8 @@ def generate():
|
|
| 37 |
if file.filename == '':
|
| 38 |
return jsonify({'error': 'No selected file'}), 400
|
| 39 |
bg_color_hex = request.form.get('bgColor', '')
|
|
|
|
|
|
|
| 40 |
fill_color = (255, 255, 255, 0)
|
| 41 |
theme_color = "#ffffff"
|
| 42 |
if bg_color_hex and bg_color_hex != 'transparent':
|
|
@@ -71,14 +73,24 @@ def generate():
|
|
| 71 |
img_192.save(android192_io, format='PNG')
|
| 72 |
android192_io.seek(0)
|
| 73 |
zf.writestr('android-chrome-192x192.png', android192_io.read())
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 74 |
android512_io = io.BytesIO()
|
| 75 |
img_512 = img_square.resize(ANDROID_512_SIZE, Image.Resampling.LANCZOS)
|
| 76 |
img_512.save(android512_io, format='PNG')
|
| 77 |
android512_io.seek(0)
|
| 78 |
zf.writestr('android-chrome-512x512.png', android512_io.read())
|
| 79 |
manifest = {
|
| 80 |
-
"name":
|
| 81 |
-
"short_name":
|
| 82 |
"icons": [
|
| 83 |
{
|
| 84 |
"src": "/android-chrome-192x192.png",
|
|
|
|
| 37 |
if file.filename == '':
|
| 38 |
return jsonify({'error': 'No selected file'}), 400
|
| 39 |
bg_color_hex = request.form.get('bgColor', '')
|
| 40 |
+
site_name = request.form.get('siteName', 'My Website') or 'My Website'
|
| 41 |
+
short_name = request.form.get('shortName', 'Website') or 'Website'
|
| 42 |
fill_color = (255, 255, 255, 0)
|
| 43 |
theme_color = "#ffffff"
|
| 44 |
if bg_color_hex and bg_color_hex != 'transparent':
|
|
|
|
| 73 |
img_192.save(android192_io, format='PNG')
|
| 74 |
android192_io.seek(0)
|
| 75 |
zf.writestr('android-chrome-192x192.png', android192_io.read())
|
| 76 |
+
favicon32_io = io.BytesIO()
|
| 77 |
+
img_32 = img_square.resize((32, 32), Image.Resampling.LANCZOS)
|
| 78 |
+
img_32.save(favicon32_io, format='PNG')
|
| 79 |
+
favicon32_io.seek(0)
|
| 80 |
+
zf.writestr('favicon-32x32.png', favicon32_io.read())
|
| 81 |
+
favicon16_io = io.BytesIO()
|
| 82 |
+
img_16 = img_square.resize((16, 16), Image.Resampling.LANCZOS)
|
| 83 |
+
img_16.save(favicon16_io, format='PNG')
|
| 84 |
+
favicon16_io.seek(0)
|
| 85 |
+
zf.writestr('favicon-16x16.png', favicon16_io.read())
|
| 86 |
android512_io = io.BytesIO()
|
| 87 |
img_512 = img_square.resize(ANDROID_512_SIZE, Image.Resampling.LANCZOS)
|
| 88 |
img_512.save(android512_io, format='PNG')
|
| 89 |
android512_io.seek(0)
|
| 90 |
zf.writestr('android-chrome-512x512.png', android512_io.read())
|
| 91 |
manifest = {
|
| 92 |
+
"name": site_name,
|
| 93 |
+
"short_name": short_name,
|
| 94 |
"icons": [
|
| 95 |
{
|
| 96 |
"src": "/android-chrome-192x192.png",
|
templates/index.html
CHANGED
|
@@ -137,6 +137,26 @@
|
|
| 137 |
</div>
|
| 138 |
</div>
|
| 139 |
</div>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 140 |
</div>
|
| 141 |
|
| 142 |
<!-- Generate Button -->
|
|
@@ -234,11 +254,7 @@
|
|
| 234 |
</button>
|
| 235 |
</div>
|
| 236 |
<div class="p-4 overflow-x-auto relative group">
|
| 237 |
-
<pre class="text-xs md:text-sm font-mono text-indigo-100 leading-relaxed whitespace-pre-wrap break-all"><code>
|
| 238 |
-
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
| 239 |
-
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
| 240 |
-
<link rel="manifest" href="/site.webmanifest"><span v-if="bgColor !== 'transparent'" class="text-green-300">
|
| 241 |
-
<meta name="theme-color" content="{{ bgColor }}"></span></code></pre>
|
| 242 |
</div>
|
| 243 |
</div>
|
| 244 |
</div>
|
|
@@ -292,6 +308,8 @@
|
|
| 292 |
const errorMsg = ref('');
|
| 293 |
const copyText = ref('复制');
|
| 294 |
const bgColor = ref('transparent');
|
|
|
|
|
|
|
| 295 |
const activeTab = ref('browser');
|
| 296 |
|
| 297 |
const presetColors = ['#ffffff', '#000000', '#f8fafc', '#1e293b', '#4f46e5', '#ef4444', '#10b981'];
|
|
@@ -300,6 +318,17 @@
|
|
| 300 |
return bgColor.value === 'transparent' ? 'transparent' : bgColor.value;
|
| 301 |
});
|
| 302 |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 303 |
const handleFileSelect = (event) => {
|
| 304 |
const selectedFile = event.target.files[0];
|
| 305 |
processFile(selectedFile);
|
|
@@ -339,7 +368,6 @@
|
|
| 339 |
previewUrl.value = '';
|
| 340 |
errorMsg.value = '';
|
| 341 |
bgColor.value = 'transparent';
|
| 342 |
-
// Reset input
|
| 343 |
const input = document.querySelector('input[type="file"]');
|
| 344 |
if (input) input.value = '';
|
| 345 |
};
|
|
@@ -353,6 +381,8 @@
|
|
| 353 |
const formData = new FormData();
|
| 354 |
formData.append('file', file.value);
|
| 355 |
formData.append('bgColor', bgColor.value);
|
|
|
|
|
|
|
| 356 |
|
| 357 |
try {
|
| 358 |
const response = await fetch('/api/generate', {
|
|
@@ -384,16 +414,7 @@
|
|
| 384 |
};
|
| 385 |
|
| 386 |
const copyCode = () => {
|
| 387 |
-
|
| 388 |
-
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
| 389 |
-
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
| 390 |
-
<link rel="manifest" href="/site.webmanifest">`;
|
| 391 |
-
|
| 392 |
-
if (bgColor.value !== 'transparent') {
|
| 393 |
-
code += `\n<meta name="theme-color" content="${bgColor.value}">`;
|
| 394 |
-
}
|
| 395 |
-
|
| 396 |
-
navigator.clipboard.writeText(code).then(() => {
|
| 397 |
copyText.value = '已复制!';
|
| 398 |
setTimeout(() => copyText.value = '复制', 2000);
|
| 399 |
});
|
|
@@ -411,6 +432,9 @@
|
|
| 411 |
bgColor,
|
| 412 |
presetColors,
|
| 413 |
finalBgColor,
|
|
|
|
|
|
|
|
|
|
| 414 |
activeTab,
|
| 415 |
handleFileSelect,
|
| 416 |
handleDrop,
|
|
|
|
| 137 |
</div>
|
| 138 |
</div>
|
| 139 |
</div>
|
| 140 |
+
<div class="grid grid-cols-1 sm:grid-cols-2 gap-4">
|
| 141 |
+
<div>
|
| 142 |
+
<label class="block text-sm font-medium text-slate-700 mb-1">站点名称 (name)</label>
|
| 143 |
+
<input
|
| 144 |
+
v-model="siteName"
|
| 145 |
+
type="text"
|
| 146 |
+
class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
| 147 |
+
placeholder="My Website"
|
| 148 |
+
>
|
| 149 |
+
</div>
|
| 150 |
+
<div>
|
| 151 |
+
<label class="block text-sm font-medium text-slate-700 mb-1">PWA 短名称 (short_name)</label>
|
| 152 |
+
<input
|
| 153 |
+
v-model="shortName"
|
| 154 |
+
type="text"
|
| 155 |
+
class="w-full border border-slate-300 rounded-lg px-3 py-2 text-sm focus:outline-none focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500"
|
| 156 |
+
placeholder="Website"
|
| 157 |
+
>
|
| 158 |
+
</div>
|
| 159 |
+
</div>
|
| 160 |
</div>
|
| 161 |
|
| 162 |
<!-- Generate Button -->
|
|
|
|
| 254 |
</button>
|
| 255 |
</div>
|
| 256 |
<div class="p-4 overflow-x-auto relative group">
|
| 257 |
+
<pre class="text-xs md:text-sm font-mono text-indigo-100 leading-relaxed whitespace-pre-wrap break-all"><code>{{ htmlSnippet }}</code></pre>
|
|
|
|
|
|
|
|
|
|
|
|
|
| 258 |
</div>
|
| 259 |
</div>
|
| 260 |
</div>
|
|
|
|
| 308 |
const errorMsg = ref('');
|
| 309 |
const copyText = ref('复制');
|
| 310 |
const bgColor = ref('transparent');
|
| 311 |
+
const siteName = ref('My Website');
|
| 312 |
+
const shortName = ref('Website');
|
| 313 |
const activeTab = ref('browser');
|
| 314 |
|
| 315 |
const presetColors = ['#ffffff', '#000000', '#f8fafc', '#1e293b', '#4f46e5', '#ef4444', '#10b981'];
|
|
|
|
| 318 |
return bgColor.value === 'transparent' ? 'transparent' : bgColor.value;
|
| 319 |
});
|
| 320 |
|
| 321 |
+
const htmlSnippet = computed(() => {
|
| 322 |
+
let code = `<link rel="apple-touch-icon" sizes="180x180" href="/apple-touch-icon.png">
|
| 323 |
+
<link rel="icon" type="image/png" sizes="32x32" href="/favicon-32x32.png">
|
| 324 |
+
<link rel="icon" type="image/png" sizes="16x16" href="/favicon-16x16.png">
|
| 325 |
+
<link rel="manifest" href="/site.webmanifest">`;
|
| 326 |
+
if (bgColor.value !== 'transparent') {
|
| 327 |
+
code += `\n<meta name="theme-color" content="${bgColor.value}">`;
|
| 328 |
+
}
|
| 329 |
+
return code;
|
| 330 |
+
});
|
| 331 |
+
|
| 332 |
const handleFileSelect = (event) => {
|
| 333 |
const selectedFile = event.target.files[0];
|
| 334 |
processFile(selectedFile);
|
|
|
|
| 368 |
previewUrl.value = '';
|
| 369 |
errorMsg.value = '';
|
| 370 |
bgColor.value = 'transparent';
|
|
|
|
| 371 |
const input = document.querySelector('input[type="file"]');
|
| 372 |
if (input) input.value = '';
|
| 373 |
};
|
|
|
|
| 381 |
const formData = new FormData();
|
| 382 |
formData.append('file', file.value);
|
| 383 |
formData.append('bgColor', bgColor.value);
|
| 384 |
+
formData.append('siteName', siteName.value || 'My Website');
|
| 385 |
+
formData.append('shortName', shortName.value || 'Website');
|
| 386 |
|
| 387 |
try {
|
| 388 |
const response = await fetch('/api/generate', {
|
|
|
|
| 414 |
};
|
| 415 |
|
| 416 |
const copyCode = () => {
|
| 417 |
+
navigator.clipboard.writeText(htmlSnippet.value).then(() => {
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
| 418 |
copyText.value = '已复制!';
|
| 419 |
setTimeout(() => copyText.value = '复制', 2000);
|
| 420 |
});
|
|
|
|
| 432 |
bgColor,
|
| 433 |
presetColors,
|
| 434 |
finalBgColor,
|
| 435 |
+
siteName,
|
| 436 |
+
shortName,
|
| 437 |
+
htmlSnippet,
|
| 438 |
activeTab,
|
| 439 |
handleFileSelect,
|
| 440 |
handleDrop,
|