2026-07-21 16:13:16 +08:00

70 lines
4.2 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

import { h, render } from 'vue'
// 预览应用 — 从 js/apps2.js 手动转写
import { el, iconImg, clamp } from '../../utils'
import { fs as FS } from '../../composables/useFS'
import { wm as WM } from '../../composables/useWM'
import { Apps, stdMenus } from '../../composables/useApps'
import PreviewComponent from './Preview.vue'
import { WALLPAPERS } from '../../composables/useSettings'
export const PreviewApp = {
id: 'preview', name: '预览', icon: '/assets/icons/preview.svg',
w: 720, h: 540, minW: 380, minH: 280, singleton: false,
menus(win: any) {
const st = win?.appState
return stdMenus(this, {
view: [
{ label: '放大', key: '⌘+', action: () => st?.zoom(0.2) },
{ label: '缩小', key: '⌘−', action: () => st?.zoom(-0.2) },
{ label: '实际大小', key: '⌘0', action: () => st?.zoomReset() },
]
})
},
render(win: any, args: any) {
const st = win.appState = { scale: 1, rot: 0, path: args.path || null, isPdf: false }
win.body.classList.add('preview-body')
const zOut = el('button', { class: 'fb-btn', text: '', title: '缩小' })
const zIn = el('button', { class: 'fb-btn', text: '', title: '放大' })
const rotBtn = el('button', { class: 'fb-btn', html: '⟳', title: '旋转' })
const infoEl = el('span', { class: 'preview-info' })
const toolbar = el('div', { class: 'fb-toolbar preview-toolbar' }, zOut, zIn, rotBtn, infoEl)
const stage = el('div', { class: 'preview-stage' })
win.body.append(toolbar, stage)
st.zoom = (d: number) => { st.scale = clamp(st.scale + d, 0.2, 4); apply() }
st.zoomReset = () => { st.scale = 1; st.rot = 0; apply() }
zIn.addEventListener('click', () => st.zoom(0.2))
zOut.addEventListener('click', () => st.zoom(-0.2))
rotBtn.addEventListener('click', () => { st.rot = (st.rot + 90) % 360; apply() })
let contentEl: HTMLElement | null = null
const apply = () => { if (contentEl) contentEl.style.transform = `scale(${st.scale}) rotate(${st.rot}deg)`; infoEl.textContent = `缩放 ${Math.round(st.scale * 100)}%` + (st.isPdf ? ' · 第 1 页,共 1 页' : '') }
const showError = (msg: string) => { stage.innerHTML = ''; stage.append(el('div', { class: 'empty-state' }, el('div', { class: 'es-icon', text: '🚫' }), el('div', { text: '无法打开此文件' }), el('div', { class: 'preview-err-sub', text: msg }))); infoEl.textContent = '' }
if (args.asset) st.path = args.asset
if (!st.path) {
const gallery = el('div', { class: 'preview-gallery' })
WALLPAPERS.forEach((w: any) => {
const im = iconImg(w.src, '', w.name)
const cell = el('div', { class: 'preview-cell' }, im, el('div', { class: 'photo-name', text: w.name }))
cell.addEventListener('click', () => { Apps.open('preview', { asset: w.src, name: w.name }) })
gallery.append(cell)
})
stage.append(gallery); infoEl.textContent = '点击查看大图'; WM.setTitle(win, '图片集 — 预览'); return
}
const asset = args.asset || null
const ext = (st.path.split('.').pop() || '').toLowerCase()
if (asset || ['png', 'jpg', 'jpeg', 'gif', 'webp', 'svg'].includes(ext)) {
const src = asset || st.path
contentEl = el('img', { class: 'preview-img', alt: args.name || FS.baseName(src) }) as HTMLElement
;(contentEl as any).addEventListener('error', () => showError('图片数据不可用(虚拟文件或资源缺失)。'))
;(contentEl as HTMLImageElement).src = src
stage.append(el('div', { class: 'preview-canvas' }, contentEl))
WM.setTitle(win, (args.name || FS.baseName(src)) + ' — 预览'); apply()
} else if (ext === 'pdf') {
contentEl = el('div', { class: 'preview-pdf' }, el('div', { class: 'preview-pdf-badge', text: 'PDF' }), el('div', { class: 'preview-pdf-name', text: FS.baseName(st.path) }), el('div', { class: 'preview-pdf-sub', text: '虚拟 PDF 文档 · 第 1 页,共 1 页' }))
st.isPdf = true; stage.append(el('div', { class: 'preview-canvas' }, contentEl)); apply()
} else {
try { const txt = FS.read(st.path); contentEl = el('pre', { class: 'preview-text', text: txt }); stage.append(el('div', { class: 'preview-canvas' }, contentEl)); apply() } catch (e: any) { showError(e.message) }
}
}
}
Apps.register(PreviewApp)