70 lines
4.2 KiB
TypeScript
70 lines
4.2 KiB
TypeScript
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)
|