import { h, render } from 'vue' // 启动台应用 — 从 js/apps3.js 手动转写 import { el, iconImg } from '../../utils' import { Apps, stdMenus } from '../../composables/useApps' import LaunchpadComponent from './Launchpad.vue' import { ui as UI } from '../../composables/useUI' let _AppStoreApp: any = null export function setAppStoreForLaunchpad(a: any) { _AppStoreApp = a } export const Launchpad = { overlay: null as HTMLElement | null, show() { if (this.overlay) return this.hide() const ov = el('div', { class: 'launchpad', tabindex: '0' }) const search = el('input', { class: 'lp-search', type: 'search', placeholder: '搜索 App' }) as HTMLInputElement const grid = el('div', { class: 'lp-grid' }) ov.append(el('div', { class: 'lp-search-wrap' }, search), grid) const renderGrid = (q: string) => { grid.innerHTML = '' const apps = Object.values(Apps.registry) .filter((a: any) => a.id !== 'launchpad' && (!a.storeApp || (_AppStoreApp && _AppStoreApp.isInstalled(a.id)))) .filter((a: any) => !q || a.name.toLowerCase().includes(q.toLowerCase())) if (!apps.length) grid.append(el('div', { class: 'lp-empty', text: '没有匹配的 App' })) ;(apps as any[]).sort((a: any, b: any) => a.name.localeCompare(b.name, 'zh-Hans-CN')).forEach((app: any) => { const c = el('div', { class: 'lp-cell' }, iconImg(app.icon, '', app.name), el('div', { class: 'lp-name', text: app.name })) c.addEventListener('click', () => { this.hide(); Apps.open(app.id) }) grid.append(c) }) } renderGrid('') search.addEventListener('input', () => renderGrid(search.value.trim())) search.addEventListener('keydown', (e: KeyboardEvent) => { e.stopPropagation(); if (e.key === 'Escape') this.hide() }) ov.addEventListener('keydown', (e: KeyboardEvent) => { if (e.key === 'Escape') this.hide() }) ov.addEventListener('click', (e: Event) => { if (e.target === ov) this.hide() }) document.body.append(ov) this.overlay = ov setTimeout(() => { ov.classList.add('show'); search.focus() }, 10) }, hide() { if (!this.overlay) return const ov = this.overlay; this.overlay = null ov.classList.remove('show'); setTimeout(() => ov.remove(), 250) } }; (window as any).Launchpad = Launchpad // 注册启动台应用 Apps.register({ id: 'launchpad', name: '启动台', icon: '/assets/icons/launchpad.png', menus() { return stdMenus(this) }, render() { /* 不走 WM 窗口 */ }, open() { Launchpad.show() } }) // 扩展 Apps.open:拦截 launchpad/stickies/storeApp const _origOpen = Apps.open.bind(Apps) Apps.open = function (id: string, args?: any) { if (id === 'launchpad') { Launchpad.show(); return null } if (id === 'stickies' && !(args && args.noteId)) { (Apps.get('stickies') as any)?.openAll(); return null } const app = this.get(id) if (app && app.storeApp && !(_AppStoreApp && _AppStoreApp.isInstalled(id))) { UI.alert('尚未安装', `请先在 App Store 中获取"${app.name}"。`, '/assets/icons/appstore.png') return null } return _origOpen(id, args) }