diff --git a/package-lock.json b/package-lock.json index 2389362..54eafd2 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "flowos", - "version": "2.4.0", + "version": "2.4.1", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "flowos", - "version": "2.4.0", + "version": "2.4.1", "license": "MIT", "dependencies": { "ansi-to-html": "^0.7.2", diff --git a/package.json b/package.json index 6fd5e60..7d5eae8 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "flowos", - "version": "2.4.0", + "version": "2.4.1", "description": "The most aesthetic webOS.", "main": "src/bootloader.ts", "scripts": { diff --git a/src/assets/icons/fruits/cherries.png b/src/assets/icons/fruits/cherries.png new file mode 100644 index 0000000..6b62da8 Binary files /dev/null and b/src/assets/icons/fruits/cherries.png differ diff --git a/src/assets/icons/fruits/fruits.png b/src/assets/icons/fruits/fruits.png new file mode 100644 index 0000000..cbca829 Binary files /dev/null and b/src/assets/icons/fruits/fruits.png differ diff --git a/src/assets/icons/fruits/lemon.png b/src/assets/icons/fruits/lemon.png new file mode 100644 index 0000000..996c366 Binary files /dev/null and b/src/assets/icons/fruits/lemon.png differ diff --git a/src/assets/icons/fruits/tangerine.png b/src/assets/icons/fruits/tangerine.png new file mode 100644 index 0000000..d7af755 Binary files /dev/null and b/src/assets/icons/fruits/tangerine.png differ diff --git a/src/system/VirtualFS.ts b/src/system/VirtualFS.ts index 2344b20..d90be08 100644 --- a/src/system/VirtualFS.ts +++ b/src/system/VirtualFS.ts @@ -25,6 +25,12 @@ export const defaultFS: { root: Directory } = { deleteable: false, permission: Permission.USER, children: { + 'Fruits.app': { + type: 'file', + deleteable: true, + permission: Permission.USER, + content: Buffer.from('apps/Fruits') + }, 'Info.app': { type: 'file', deleteable: true, diff --git a/src/system/apps/Fruits.ts b/src/system/apps/Fruits.ts new file mode 100644 index 0000000..e0c25ea --- /dev/null +++ b/src/system/apps/Fruits.ts @@ -0,0 +1,137 @@ +import HTML from '../../HTML' +import { Process } from '../../types' + +import icon from '../../assets/icons/fruits/fruits.png' +import cherriesIcon from '../../assets/icons/fruits/cherries.png' +import lemonIcon from '../../assets/icons/fruits/lemon.png' +import tangerineIcon from '../../assets/icons/fruits/tangerine.png' + +const SlotMachine: Process = { + config: { + name: 'Fruits', + type: 'process', + icon, + targetVer: '1.0.0-indev.0' + }, + run: async (process): Promise => { + const win = await process.loadLibrary('lib/WindowManager').then((wm: any) => { + return wm.createWindow({ + title: 'Fruits', + icon, + width: 400, + height: 500, + canResize: false + }, process) + }) + + const setupWindowStyles = (): void => { + win.content.style.padding = '20px' + win.content.style.textAlign = 'center' + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + win.content.style.justifyContent = 'center' + win.content.style.alignItems = 'center' + win.content.style.background = '#181825' + } + + const createReelContainer = (): HTML => { + return new HTML('div').appendTo(win.content).style({ + position: 'relative', + display: 'flex', + justifyContent: 'center', + marginBottom: '20px', + height: '150px', + overflow: 'hidden' + }) + } + + const createOverlay = (parentElement: HTML): void => { + new HTML('div').appendTo(parentElement).style({ + position: 'absolute', + top: '0', + left: '0', + width: '100%', + height: '100%', + background: '#000', + opacity: '0.5' + }) + } + + const icons = [cherriesIcon, lemonIcon, tangerineIcon] + + const getRandomIcon = (): string => icons[Math.floor(Math.random() * icons.length)] + + const slotIcons = [getRandomIcon(), getRandomIcon(), getRandomIcon()] + + const updateReel = (reelContainer: HTML): void => { + reelContainer.clear() + slotIcons.forEach((icon) => { + new HTML('img').attr({ + src: icon, + width: '100', + height: '100' + }).appendTo(reelContainer) + }) + } + + let isSpinning = false + + const spinSlotMachine = (): void => { + if (isSpinning) return + + isSpinning = true + + const spinDuration = 3000 + const frameDuration = 100 + const winColor = '#FFD700' + + let frameCount = 0 + const totalFrames = spinDuration / frameDuration + + const spinInterval = setInterval(() => { + if (frameCount < totalFrames - 1) { + slotIcons.unshift(getRandomIcon()) + slotIcons.pop() + } + + updateReel(reelContainer) + + frameCount++ + + if (frameCount === totalFrames) { + clearInterval(spinInterval) + + if (slotIcons[0] === slotIcons[1] && slotIcons[1] === slotIcons[2]) { + const button = win.content.querySelector('button') + button.style.transition = 'background-color 0.5s ease-out' + button.style.backgroundColor = winColor + + setTimeout(() => { + button.style.transition = 'background-color 0.5s ease' + button.style.backgroundColor = '#3498db' + }, 3000) + } + + isSpinning = false + } + }, frameDuration) + } + + setupWindowStyles() + + const reelContainer = createReelContainer() + createOverlay(reelContainer) + + updateReel(reelContainer) + + new HTML('button') + .text('Spin') + .on('click', spinSlotMachine) + .appendTo(win.content) + .attr({ + style: 'font-size: 18px; padding: 10px 20px; background: #3498db; color: #fff; border: none; border-radius: 5px; cursor: pointer; margin-top: 20px' + }) + } +} + +export default SlotMachine