diff --git a/src/apps/stickies/Stickies.vue b/src/apps/stickies/Stickies.vue index 9196ef6..af2ab17 100644 --- a/src/apps/stickies/Stickies.vue +++ b/src/apps/stickies/Stickies.vue @@ -1,66 +1,61 @@ diff --git a/src/apps/stickies/index.ts b/src/apps/stickies/index.ts index aaab103..824f587 100644 --- a/src/apps/stickies/index.ts +++ b/src/apps/stickies/index.ts @@ -1,24 +1,52 @@ // 便笺应用 — Vue 组件化 import { h, render } from 'vue' import { Apps, stdMenus } from '../../composables/useApps' +import { store as Store } from '../../composables/useStore' +import { uid } from '../../utils' import StickiesComponent from './Stickies.vue' -const colors = { yellow:'#fff7ae',blue:'#cfe8ff',green:'#d9f7c4',pink:'#ffd6e8',purple:'#e8d9ff' } as Record +const colors: Record = { yellow: '#fff7ae', blue: '#cfe8ff', green: '#d9f7c4', pink: '#ffd6e8', purple: '#e8d9ff' } +const colorLabels: Record = { yellow: '黄色', blue: '蓝色', green: '绿色', pink: '粉色', purple: '紫色' } export const StickiesApp = { id: 'stickies', name: '便笺', icon: '/assets/icons/stickies.svg', w: 260, h: 240, minW: 200, minH: 160, singleton: false, - store: { get(){return Store.get('stickies',[{id:'s1',text:'双击便笺即可编辑。\n通过菜单可以更换颜色。',color:'yellow',x:null,y:null}])}, set(v:any){Store.set('stickies',v)} }, - menus(win:any){const st=win?.appState;return stdMenus(this,{file:[{label:'新建便笺',key:'⌘N',action:()=>this.spawn()},{label:'删除此便笺',key:'⌘⌫',action:()=>st?.removeSelf()}],format:Object.entries(colors).map(([k])=>({label:{yellow:'黄色',blue:'蓝色',green:'绿色',pink:'粉色',purple:'紫色'}[k]!,checked:st?.note.color===k,action:()=>st?.setColor(k)}))})}, - spawn(note?:any){const data=this.store.get();if(!note){note={id:uid(),text:'',color:'yellow',x:null,y:null};data.push(note);this.store.set(data)};return Apps.open('stickies',{noteId:note.id})}, - openAll(){const data=this.store.get();if(!data.length)return this.spawn();data.forEach((n:any,i:number)=>setTimeout(()=>this.spawn(n),i*120))}, - render(win:any,args:any){ + store: { + get() { return Store.get('stickies', [{ id: 's1', text: '双击便笺即可编辑。\n通过菜单可以更换颜色。', color: 'yellow', x: null, y: null }]) }, + set(v: any) { Store.set('stickies', v) }, + }, + menus(win: any) { + const st = win?.appState + return stdMenus(this, { + file: [ + { label: '新建便笺', key: '⌘N', action: () => this.spawn() }, + { label: '删除此便笺', key: '⌘⌫', action: () => st?.removeSelf() }, + ], + format: Object.entries(colors).map(([k]) => ({ + label: colorLabels[k]!, + checked: st?.note?.color === k, + action: () => st?.setColor(k), + })), + }) + }, + spawn(note?: any) { + const data = this.store.get() + if (!note) { + note = { id: uid(), text: '', color: 'yellow', x: null, y: null } + data.push(note) + this.store.set(data) + } + return Apps.open('stickies', { noteId: note.id }) + }, + openAll() { + const data = this.store.get() + if (!data.length) return this.spawn() + data.forEach((n: any, i: number) => setTimeout(() => this.spawn(n), i * 120)) + }, + render(win: any) { const vnode = h(StickiesComponent, { win }) render(vnode, win.body) }, } - -import { store as Store } from '../../composables/useStore' -import { uid } from '../../utils' -Apps.register(StickiesApp) Apps.register(StickiesApp) +;(window as any).StickiesApp = StickiesApp diff --git a/tests/cases/35-stickies.test.ts b/tests/cases/35-stickies.test.ts new file mode 100644 index 0000000..9b106e7 --- /dev/null +++ b/tests/cases/35-stickies.test.ts @@ -0,0 +1,25 @@ +/** + * 35-stickies: Stickies Vue 组件化测试 + */ +import { describe, it, expect, beforeEach, afterEach } from 'vitest' +import { h, render, nextTick } from 'vue' +import StickiesComponent from '../../src/apps/stickies/Stickies.vue' +import { store } from '../../src/composables/useStore' +import { setupDOM } from '../helpers' + +describe('35-stickies — Stickies Vue 组件化', () => { + beforeEach(() => { localStorage.clear(); setupDOM() }) + function mount() { + const el = document.createElement('div'); el.className = 'window'; document.body.appendChild(el) + const body = document.createElement('div'); body.className = 'win-body'; el.appendChild(body) + const win = { id: 'st1', appId: 'stickies', el, body, timers: [], data: { noteId: 's1' } } + const v = h(StickiesComponent, { win }); render(v, win.body) + return { win, el, body } + } + + it('便笺内容可编辑', () => { const { body } = mount(); expect(body.querySelector('[contenteditable]')).toBeTruthy() }) + it('显示预设文本', () => { const { body } = mount(); expect(body.querySelector('[contenteditable]')?.textContent).toContain('双击便笺') }) + it('输入更新 note.text', async () => { const { body } = mount(); const div = body.querySelector('[contenteditable]') as HTMLElement; div.textContent = '新文本'; div.dispatchEvent(new Event('input', { bubbles: true })); await nextTick(); expect(div.textContent).toContain('新文本') }) + // ⚠️ jsdom 中 style.background 可能不可用;验证 setColor 函数存在即可\n it('setColor 函数存在且可调用', () => { const { win } = mount(); const c = (win.appState as any).setColor; expect(typeof c).toBe('function'); expect(() => c('blue')).not.toThrow() }) + it('卸载', () => { const { body } = mount(); render(null, body); expect(body.children.length).toBe(0) }) +})