diff --git a/src/apps/editor.ts b/src/apps/editor.ts index eacf3bc..f3643f4 100644 --- a/src/apps/editor.ts +++ b/src/apps/editor.ts @@ -30,8 +30,7 @@ export default class EditorApp implements App { title: this.name, icon, width: 500, - height: 400, - canResize: true + height: 400 }) if (data != null) { diff --git a/src/apps/files.ts b/src/apps/files.ts index 5c2d5d5..6ddaa50 100644 --- a/src/apps/files.ts +++ b/src/apps/files.ts @@ -1,7 +1,6 @@ import icon from '../assets/icons/files.png' import { App } from '../types.ts' -import flow from '../flow.ts' import { FlowWindow } from '../wm.ts' import { Stats } from 'fs' @@ -17,8 +16,7 @@ export default class FilesApp implements App { title: this.name, icon, width: 500, - height: 400, - canResize: true + height: 400 }) win.content.style.display = 'flex' @@ -121,7 +119,7 @@ export default class FilesApp implements App { if (fileStat.isDirectory()) { await setDir(dir + separator + file) } else { - flow.openApp('flow.editor', { path: dir + separator + file }) + await window.flow.openApp('flow.editor', { path: dir + separator + file }) } } diff --git a/src/apps/info.ts b/src/apps/info.ts index 2e69b75..00b7178 100644 --- a/src/apps/info.ts +++ b/src/apps/info.ts @@ -25,6 +25,7 @@ export default class SettingsApp implements App { win.content.style.flexDirection = 'column' win.content.style.justifyContent = 'center' win.content.style.alignItems = 'center' + win.content.style.background = 'var(--base)' win.content.innerHTML = `

FlowOS

diff --git a/src/apps/manager.ts b/src/apps/manager.ts new file mode 100644 index 0000000..cfc064f --- /dev/null +++ b/src/apps/manager.ts @@ -0,0 +1,40 @@ +import icon from '../assets/icons/manager.png' +import { App } from '../types.ts' +import { FlowWindow } from '../wm.ts' + +export default class ManagerApp implements App { + name = 'Manager' + pkg = 'flow.manager' + icon = icon + version = '1.0.0' + + async open (): Promise { + const win = window.wm.createWindow({ + title: this.name, + icon, + width: 350, + height: 500 + }) + + win.content.style.display = 'flex' + win.content.style.flexDirection = 'column' + win.content.style.gap = '10px' + win.content.style.padding = '10px' + win.content.style.background = 'var(--base)' + win.content.innerHTML = ` + ${window.flow.apps.map(app => { + return ` +
+ +
+

${app.name} ${(app.builtin ?? false) ? '(builtin)' : ''}

+

${app.pkg} (v${app.version})

+
+
+ ` + }).join('')} + ` + + return win + } +} diff --git a/src/apps/music.ts b/src/apps/music.ts index f31ad2b..c7fe8f2 100644 --- a/src/apps/music.ts +++ b/src/apps/music.ts @@ -13,10 +13,10 @@ export default class MusicApp implements App { title: this.name, icon, width: 700, - height: 300, - canResize: true + height: 300 }) + win.content.style.background = 'var(--base)' win.content.innerHTML = 'hi' return win diff --git a/src/apps/settings.ts b/src/apps/settings.ts index 3354c83..42285c2 100644 --- a/src/apps/settings.ts +++ b/src/apps/settings.ts @@ -13,10 +13,10 @@ export default class SettingsApp implements App { title: this.name, icon, width: 700, - height: 300, - canResize: true + height: 300 }) + win.content.style.background = 'var(--base)' win.content.style.padding = '10px' win.content.innerHTML = `

Settings

diff --git a/src/assets/icons/manager.png b/src/assets/icons/manager.png new file mode 100644 index 0000000..1a1ccfd Binary files /dev/null and b/src/assets/icons/manager.png differ diff --git a/src/flow.ts b/src/flow.ts index bf53e0c..151deef 100644 --- a/src/flow.ts +++ b/src/flow.ts @@ -1,24 +1,67 @@ -import { Flow } from './types.ts' +import { App, LoadedApp } from './types.ts' -import SettingsApp from './apps/settings.ts' -import FilesApp from './apps/files.ts' -import MusicApp from './apps/music.ts' -import EditorApp from './apps/editor.ts' -import InfoApp from './apps/info.ts' +class Flow { + apps: LoadedApp[] = [] + appList = [ + 'settings', + 'music', + 'files', + 'editor', + 'info', + 'manager' + ] -const flow: Flow = { - apps: { - 'flow.settings': new SettingsApp(), - 'flow.music': new MusicApp(), - 'flow.files': new FilesApp(), - 'flow.editor': new EditorApp(), - 'flow.info': new InfoApp() - }, - async openApp (pkg: string, data: any) { - const win = this.apps[pkg].open(data) - const event = new CustomEvent('app_opened', { detail: { app: this.apps[pkg], win: await win } }) + async init (): Promise { + window.preloader.setPending('apps') + window.preloader.setStatus('importing default apps...') + + for (const appPath of this.appList) { + const { default: ImportedApp } = await import(`./apps/${appPath}.ts`) + const app = new ImportedApp() + app.builtin = true + + window.preloader.setStatus(`importing default apps\n${appPath}`) + this.add(app) + } + + window.wm.launcher.style.opacity = '0' + window.wm.launcher.style.filter = 'blur(0px)' + window.wm.launcher.style.pointerEvents = 'none' + + window.preloader.setStatus('adding apps to app launcher...') + + this.apps.forEach((app) => { + window.preloader.setStatus(`adding apps to app launcher\n${app.name}`) + const appElement = document.createElement('app') + appElement.onclick = async () => { + await window.flow.openApp(app.pkg) + window.wm.toggleLauncher() + } + appElement.innerHTML = `
${app.name}
` + window.wm.launcher.querySelector('apps')?.appendChild(appElement) + }) + + document.body.appendChild(window.wm.windowArea) + document.body.appendChild(window.wm.launcher) + + await window.preloader.setDone('apps') + } + + add (app: App): void { + if (this.apps.some(x => x.pkg === app.pkg)) { + console.error(`Unable to register app; ${app.pkg} is already registered.`) + return + } + + this.apps.push(app) + } + + async openApp (pkg: string, data?: any): Promise { + const app = this.apps.find(x => x.pkg === pkg) + const win = app?.open(data) + const event = new CustomEvent('app_opened', { detail: { app, win: await win } }) window.dispatchEvent(event) } } -export default flow +export default Flow diff --git a/src/index.ts b/src/index.ts index 312bb1c..13febd1 100644 --- a/src/index.ts +++ b/src/index.ts @@ -3,15 +3,17 @@ import './style.less' import Preloader from './preloader' import StatusBar from './statusbar' import WM from './wm' +import Flow from './flow' import * as fs from 'fs' declare global { interface Window { preloader: Preloader + flow: Flow + fs: typeof fs statusBar: StatusBar wm: WM - fs: typeof fs } } @@ -28,6 +30,7 @@ if (params.get('debug') !== null && params.get('debug') !== undefined) { } window.preloader = new Preloader() +window.flow = new Flow() window.statusBar = new StatusBar() window.wm = new WM(); @@ -39,6 +42,8 @@ window.wm = new WM(); await window.statusBar.init() await window.wm.init() + await window.flow.init() + window.preloader.setStatus('') window.preloader.finish() })().catch(e => console.error) diff --git a/src/modules/appLauncher.ts b/src/modules/appLauncher.ts index 14c263b..3d13dac 100644 --- a/src/modules/appLauncher.ts +++ b/src/modules/appLauncher.ts @@ -1,7 +1,7 @@ export const meta = { - name: 'App View', - description: 'Opens the app view.', - id: 'appview' + name: 'App Launcher', + description: 'Opens the app launcher.', + id: 'applauncher' } export const run = (element: HTMLDivElement): void => { diff --git a/src/types.ts b/src/types.ts index f978b3b..be3293b 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,15 +44,16 @@ export interface FlowWindowConfig { width?: number height?: number - canResize: boolean + canResize?: boolean minWidth?: number minHeight?: number } -export interface Flow { - apps: { - [key: string]: App - } - openApp: Function +export interface Apps { + [key: string]: App +} + +export interface LoadedApp extends App { + builtin: boolean } diff --git a/src/wm.ts b/src/wm.ts index 82b6d40..4119596 100644 --- a/src/wm.ts +++ b/src/wm.ts @@ -1,4 +1,3 @@ -import flow from './flow.ts' import { v4 as uuid } from 'uuid' import { FlowWindowConfig } from './types.ts' @@ -89,12 +88,14 @@ export class FlowWindow { this.focus() } + if (config.canResize === undefined) config.canResize = true + this.element.style.width = `${config.width ?? 300}px` this.element.style.height = `${config.height ?? 200}px` this.header = document.createElement('window-header') this.header.innerHTML = `
${config.title}
` - if (config.canResize) { + if (!config.canResize) { this.header.innerHTML = `
${config.title}
` } @@ -104,7 +105,7 @@ export class FlowWindow { (this.header.querySelector('#min') as HTMLElement).onclick = () => this.toggleMin() - if (config.canResize) { + if (!config.canResize) { (this.header.querySelector('#max') as HTMLElement).onclick = () => this.toggleMax() } @@ -234,26 +235,6 @@ class WM { this.toggleLauncher() } - this.launcher.style.opacity = '0' - this.launcher.style.filter = 'blur(0px)' - this.launcher.style.pointerEvents = 'none' - - window.preloader.setStatus('adding apps to app launcher...') - - for (const pkg in flow.apps) { - window.preloader.setStatus(`adding apps to app launcher\n${flow.apps[pkg].name}`) - const app = document.createElement('app') - app.onclick = () => { - flow.openApp(pkg) - this.toggleLauncher() - } - app.innerHTML = `
${flow.apps[pkg].name}
` - this.launcher.querySelector('apps')?.appendChild(app) - } - - document.body.appendChild(this.windowArea) - document.body.appendChild(this.launcher) - await window.preloader.setDone('window manager') } }