auto-save 2026-04-19 23:13 (~2)

This commit is contained in:
2026-04-19 23:13:45 +08:00
parent 8c7a8e1dc2
commit 00fe936342
2 changed files with 38 additions and 9 deletions

View File

@@ -335,6 +335,13 @@
"message": "auto-save 2026-04-19 23:02 (~1)",
"hash": "84d1d75",
"files_changed": 1
},
{
"ts": "2026-04-19T23:08:15+08:00",
"type": "commit",
"message": "auto-save 2026-04-19 23:08 (~1)",
"hash": "8c7a8e1",
"files_changed": 1
}
]
}

View File

@@ -154,6 +154,20 @@ export const USER_VIEW_HTML = String.raw`<!DOCTYPE html>
<template x-if="selectedType === 'image'">
<div class="p-4"><img :src="selectedUrl" class="max-w-full rounded shadow-lg"/></div>
</template>
<template x-if="selectedType === 'html'">
<div class="h-full flex flex-col">
<div class="px-3 py-1.5 bg-[#0f1522] border-b border-gray-800 text-xs flex justify-between items-center">
<span class="text-gray-500">🎮 HTML 实时预览(沙盒 iframe,JS 可跑)</span>
<div class="flex gap-2">
<button @click="htmlMode='preview'" :class="htmlMode==='preview'?'text-emerald-400':'text-gray-500'" class="hover:text-white">▶ 玩</button>
<button @click="htmlMode='source'" :class="htmlMode==='source'?'text-emerald-400':'text-gray-500'" class="hover:text-white">&lt;&gt; 源码</button>
<a :href="'data:text/html;charset=utf-8,' + encodeURIComponent(selectedContent)" target="_blank" class="text-gray-500 hover:text-white">↗ 新窗口</a>
</div>
</div>
<iframe x-show="htmlMode==='preview'" :srcdoc="selectedContent" sandbox="allow-scripts allow-same-origin allow-forms allow-pointer-lock allow-popups allow-modals" class="flex-1 bg-white" style="border:0"></iframe>
<pre x-show="htmlMode==='source'" class="text-xs text-gray-300 p-4 whitespace-pre-wrap break-all flex-1 overflow-auto scrollbar" x-text="selectedContent"></pre>
</div>
</template>
<template x-if="selectedType === 'text'">
<pre class="text-xs text-gray-300 p-4 whitespace-pre-wrap break-all" x-text="selectedContent"></pre>
</template>
@@ -208,6 +222,7 @@ function userView() {
selectedType: '',
selectedContent: '',
selectedUrl: '',
htmlMode: 'preview',
get sortedFiles() {
return [...this.files].sort((a, b) => b.mtime - a.mtime);
},
@@ -260,19 +275,26 @@ function userView() {
this.selectedSize = f.size;
const ext = f.path.slice(f.path.lastIndexOf('.')).toLowerCase();
const isImage = ['.png', '.jpg', '.jpeg', '.gif', '.webp', '.svg'].includes(ext);
const isHtml = ['.html', '.htm'].includes(ext);
const url = '../api/file?userId=' + encodeURIComponent(this.userId) + '&path=' + encodeURIComponent(f.path) + '&token=' + encodeURIComponent(this.token);
if (isImage) {
this.selectedType = 'image';
this.selectedUrl = url;
return;
}
const r = await fetch(url);
if (!r.ok) {
this.selectedType = 'error';
this.selectedContent = '加载失败: ' + await r.text();
return;
}
const content = await r.text();
this.selectedContent = content;
if (isHtml) {
this.selectedType = 'html';
this.htmlMode = 'preview';
} else {
const r = await fetch(url);
if (r.ok) {
this.selectedType = 'text';
this.selectedContent = await r.text();
} else {
this.selectedType = 'error';
this.selectedContent = '加载失败: ' + await r.text();
}
this.selectedType = 'text';
}
},
iconFor(path) {
@@ -282,7 +304,7 @@ function userView() {
'.json': '{}', '.md': '📝', '.txt': '📄',
'.csv': '📊', '.tsv': '📊', '.xlsx': '📊',
'.png': '🖼', '.jpg': '🖼', '.jpeg': '🖼', '.gif': '🖼', '.webp': '🖼',
'.html': '🌐', '.css': '🎨',
'.html': '🎮', '.htm': '🎮', '.css': '🎨',
'.pdf': '📕', '.zip': '📦',
})[ext] ?? '📄';
},