[🔨] Use standard-ts codestyle

This commit is contained in:
ThinLiquid 2023-10-16 15:25:19 +01:00
parent 2271b5130e
commit f935718ece
19 changed files with 3318 additions and 436 deletions

2889
package-lock.json generated

File diff suppressed because it is too large Load diff

View file

@ -26,6 +26,7 @@
"node-polyfill-webpack-plugin": "^2.0.1",
"source-map-loader": "^4.0.1",
"style-loader": "^3.3.3",
"ts-standard": "^12.0.2",
"typescript": "^5.2.2",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",

View file

@ -1,39 +1,38 @@
import icon from '../assets/icons/editor.png';
import { App } from "../types.ts";
import icon from '../assets/icons/editor.png'
import { App } from '../types.ts'
import { fullEditor } from "prism-code-editor/setups";
import Prism from "prism-code-editor/prism-core";
import { fullEditor } from 'prism-code-editor/setups'
import Prism from 'prism-code-editor/prism-core'
import "prismjs/components/prism-clike.js";
import "prismjs/components/prism-markup.js";
import "prismjs/components/prism-javascript.js";
import "prismjs/components/prism-typescript.js";
import "prismjs/components/prism-css.js";
import 'prismjs/components/prism-clike.js'
import 'prismjs/components/prism-markup.js'
import 'prismjs/components/prism-javascript.js'
import 'prismjs/components/prism-typescript.js'
import 'prismjs/components/prism-css.js'
import { FlowWindow } from '../wm.ts'
interface EditorConfig {
path: string;
path: string
}
export default class EditorApp implements App {
name = 'Editor';
pkg = 'flow.editor';
icon = icon;
version = '1.0.0';
name = 'Editor'
pkg = 'flow.editor'
icon = icon
version = '1.0.0'
constructor() {}
async open (data?: EditorConfig): Promise<FlowWindow> {
const { default: fs } = await import('fs')
async open(data?: EditorConfig) {
const { default: fs } = await import('fs');
const win = window.wm.createWindow({
const win = (window as any).wm.createWindow({
title: this.name,
icon: icon,
icon,
width: 500,
height: 400
});
})
if (data) {
win.setTitle('Editor - ' + data.path);
if (data != null) {
win.setTitle('Editor - ' + data.path)
const value = (await fs.promises.readFile(data.path)).toString()
const editor = fullEditor(
@ -41,11 +40,11 @@ export default class EditorApp implements App {
win.content,
{
language: data.path.split('.').at(-1),
theme: "github-dark",
theme: 'github-dark',
value
},
);
const style = document.createElement('style');
}
)
const style = document.createElement('style')
style.innerHTML = `
.prism-editor {
caret-color: var(--text);
@ -80,6 +79,6 @@ export default class EditorApp implements App {
editor.scrollContainer.appendChild(style)
}
return win;
return win
}
}

View file

@ -1,133 +1,131 @@
import icon from '../assets/icons/files.png';
import { App } from "../types.ts";
import icon from '../assets/icons/files.png'
import { App } from '../types.ts'
import flow from '../flow.ts';
import flow from '../flow.ts'
import { FlowWindow } from '../wm.ts'
export default class FilesApp implements App {
name = 'Files';
pkg = 'flow.files';
icon = icon;
version = '1.0.0';
name = 'Files'
pkg = 'flow.files'
icon = icon
version = '1.0.0'
constructor() {}
async open (): Promise<FlowWindow> {
const { default: fs } = await import('fs')
async open() {
const { default: fs } = await import('fs');
const win = window.wm.createWindow({
const win = (window as any).wm.createWindow({
title: this.name,
icon: icon,
icon,
width: 500,
height: 400
});
})
try {
await fs.mkdir('/home', () => {});
await fs.mkdir('/home/meow', () => {});
await fs.mkdir('/home', () => {})
await fs.mkdir('/home/meow', () => {})
} catch (e) {}
try {
await fs.writeFile('/home/owo1.txt', 'sussy', () => {});
await fs.writeFile('/home/owo2.html', '<body></body>', () => {});
await fs.writeFile('/home/owo.js', 'alert(`hi`)', () => {});
await fs.writeFile('/home/owo1.txt', 'sussy', () => {})
await fs.writeFile('/home/owo2.html', '<body></body>', () => {})
await fs.writeFile('/home/owo.js', 'alert(`hi`)', () => {})
} catch (e) {}
win.content.style.display = 'flex'
win.content.style.flexDirection = 'column'
win.content.style.display = 'flex';
win.content.style.flexDirection = 'column';
async function setDir(dir: string) {
async function setDir (dir: string): Promise<void> {
await fs.readdir(dir, (e, files) => {
const back = dir === '/' ? `<i class='bx bx-arrow-to-left'></i>` : `<i class='back bx bx-left-arrow-alt'></i>`;
const back = dir === '/' ? '<i class=\'bx bx-arrow-to-left\'></i>' : '<i class=\'back bx bx-left-arrow-alt\'></i>'
win.content.innerHTML = `
<div style="padding: 5px;display: flex;align-items: center;">${back}${dir}</div>
<div class="files" style="background: var(--base);flex: 1;border-radius: 10px;display: flex;flex-direction: column;"></div>
`;
`
if (back !== `<i class='bx bx-arrow-to-left'></i>`) {
(win.content.querySelector('.back') as HTMLElement).onclick = () => {
if (back !== '<i class=\'bx bx-arrow-to-left\'></i>') {
(win.content.querySelector('.back') as HTMLElement).onclick = async () => {
if (dir.split('/')[1] === dir.replace('/', '')) {
setDir('/' + dir.split('/')[0])
await setDir('/' + dir.split('/')[0])
} else {
setDir('/' + dir.split('/')[1])
await setDir('/' + dir.split('/')[1])
}
}
}
for (const file in files) {
const separator = dir === '/' ? '' : '/';
fs.stat(dir + separator + files[file], (e, fileStat) => {
const element = document.createElement('div');
element.setAttribute('style', 'padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;');
for (const file of files) {
const separator = dir === '/' ? '' : '/'
fs.stat(dir + separator + file, (e, fileStat) => {
const element = document.createElement('div')
element.setAttribute('style', 'padding: 5px;border-bottom: 1px solid var(--text);display:flex;align-items:center;gap: 5px;')
const genIcon = () => {
switch (files[file].split('.').at(-1)) {
const genIcon = (): string => {
switch (file.split('.').at(-1)) {
case 'js':
case 'mjs':
case 'cjs': {
return `<i class='bx bxs-file-js' ></i>`
return '<i class=\'bx bxs-file-js\' ></i>'
}
case 'html':
case 'htm': {
return `<i class='bx bxs-file-html' ></i>`
return '<i class=\'bx bxs-file-html\' ></i>'
}
case 'css': {
return `<i class='bx bxs-file-css' ></i>`
return '<i class=\'bx bxs-file-css\' ></i>'
}
case 'json': {
return `<i class='bx bxs-file-json' ></i>`
return '<i class=\'bx bxs-file-json\' ></i>'
}
case 'md': {
return `<i class='bx bxs-file-md' ></i>`
return '<i class=\'bx bxs-file-md\' ></i>'
}
case 'txt':
case 'text': {
return `<i class='bx bxs-file-txt' ></i>`
return '<i class=\'bx bxs-file-txt\' ></i>'
}
case 'png':
case 'apng': {
return `<i class='bx bxs-file-png' ></i>`
return '<i class=\'bx bxs-file-png\' ></i>'
}
case 'jpg':
case 'jpeg': {
return `<i class='bx bxs-file-jpg' ></i>`
return '<i class=\'bx bxs-file-jpg\' ></i>'
}
case 'gif': {
return `<i class='bx bxs-file-gif' ></i>`
return '<i class=\'bx bxs-file-gif\' ></i>'
}
default: {
return `<i class='bx bxs-file-blank' ></i>`
return '<i class=\'bx bxs-file-blank\' ></i>'
}
}
}
const icon = fileStat.isDirectory() ? `<i class='bx bx-folder'></i>` : genIcon()
const icon = fileStat.isDirectory() ? '<i class=\'bx bx-folder\'></i>' : genIcon()
element.innerHTML += `${icon} ${files[file]}`;
element.onclick = () => {
if (fileStat.isDirectory() === true) {
setDir(dir + separator + files[file]);
element.innerHTML += `${icon} ${file}`
element.onclick = async () => {
if (fileStat.isDirectory()) {
await setDir(dir + separator + file)
} else {
flow.openApp('flow.editor', { path: dir + separator + files[file] })
flow.openApp('flow.editor', { path: dir + separator + file })
}
};
win.content.querySelector('.files').appendChild(element);
});
}
});
}
setDir('/')
win.content.querySelector('.files').appendChild(element)
})
}
})
}
return win;
await setDir('/')
return win
}
}

View file

@ -1,22 +1,21 @@
import icon from '../assets/icons/music.png';
import { App } from "../types.ts";
import icon from '../assets/icons/music.png'
import { App } from '../types.ts'
import { FlowWindow } from '../wm.ts'
export default class MusicApp implements App {
name = 'Music';
pkg = 'flow.music';
icon = icon;
version = '1.0.0';
name = 'Music'
pkg = 'flow.music'
icon = icon
version = '1.0.0'
constructor() {}
async open() {
const win = window.wm.createWindow({
async open (): Promise<FlowWindow> {
const win = (window as any).wm.createWindow({
title: this.name,
icon: icon
});
icon
})
win.content.innerHTML = 'hi';
win.content.innerHTML = 'hi'
return win;
return win
}
}

View file

@ -1,28 +1,27 @@
import icon from '../assets/icons/settings.png';
import { App } from "../types.ts";
import icon from '../assets/icons/settings.png'
import { App } from '../types.ts'
import { FlowWindow } from '../wm.ts'
export default class SettingsApp implements App {
name = 'Settings';
pkg = 'flow.settings';
icon = icon;
version = '1.0.0';
name = 'Settings'
pkg = 'flow.settings'
icon = icon
version = '1.0.0'
constructor() {}
async open() {
const win = window.wm.createWindow({
async open (): Promise<FlowWindow> {
const win = (window as any).wm.createWindow({
title: this.name,
icon: icon,
icon,
width: 700,
height: 300
});
})
win.content.style.padding = '10px';
win.content.style.padding = '10px'
win.content.innerHTML = `
<h1>Settings</h1>
<p>owo2</p>
`;
`
return win;
return win
}
}

8
src/files.d.ts vendored
View file

@ -1,4 +1,4 @@
declare module "*.png";
declare module "*.svg";
declare module "*.jpeg";
declare module "*.jpg";
declare module '*.png';
declare module '*.svg';
declare module '*.jpeg';
declare module '*.jpg';

View file

@ -1,29 +1,29 @@
import { App } from './types.ts';
import { App } 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 SettingsApp from './apps/settings.ts'
import FilesApp from './apps/files.ts'
import MusicApp from './apps/music.ts'
import EditorApp from './apps/editor.ts'
interface Flow {
apps: {
[key: string]: App
},
openApp: Function;
}
openApp: Function
}
const flow: Flow = {
apps: {
"flow.settings": new SettingsApp(),
"flow.music": new MusicApp(),
"flow.files": new FilesApp(),
"flow.editor": new EditorApp(),
'flow.settings': new SettingsApp(),
'flow.music': new MusicApp(),
'flow.files': new FilesApp(),
'flow.editor': new EditorApp()
},
openApp(pkg: string, data: any) {
const win = this.apps[pkg].open(data);
const event = new CustomEvent('app_opened', { detail: { app: this.apps[pkg], win } });
window.dispatchEvent(event);
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 } })
window.dispatchEvent(event)
}
}
export default flow;
export default flow

View file

@ -1,12 +1,7 @@
import './style.less';
import './style.less'
import StatusBar from './statusbar.ts';
import WM from './wm.ts';
import StatusBar from './statusbar.ts'
import WM from './wm.ts'
declare global {
var wm: WM;
var statusBar: StatusBar;
}
window.statusBar = new StatusBar();
window.wm = new WM();
(window as any).statusBar = new StatusBar();
(window as any).wm = new WM()

View file

@ -4,14 +4,14 @@ export const meta = {
id: 'appview'
}
export const run = (element: HTMLDivElement) => {
element.style.display = 'flex';
element.style.alignItems = 'center';
element.style.justifyContent = 'center';
element.style.aspectRatio = '1 / 1';
element.innerHTML = `<i class='bx bx-rocket'></i>`;
export const run = (element: HTMLDivElement): void => {
element.style.display = 'flex'
element.style.alignItems = 'center'
element.style.justifyContent = 'center'
element.style.aspectRatio = '1 / 1'
element.innerHTML = '<i class=\'bx bx-rocket\'></i>'
element.onclick = () => {
window.wm.toggleLauncher();
(window as any).wm.toggleLauncher()
}
}

View file

@ -1,4 +1,4 @@
import { FlowWindow } from '../wm.ts';
import { AppOpenedEvent, AppClosedEvent } from '../types'
export const meta = {
name: 'Apps',
@ -6,30 +6,28 @@ export const meta = {
id: 'apps'
}
interface Status {
win: FlowWindow,
appElement: HTMLElement
}
export const run = (element: HTMLDivElement): void => {
element.style.display = 'flex'
element.style.alignItems = 'center'
element.style.gap = '10px'
element.style.paddingLeft = '15px'
element.style.paddingRight = '15px'
export const run = (element: HTMLDivElement) => {
element.style.display = 'flex';
element.style.alignItems = 'center';
element.style.gap = '10px';
element.style.paddingLeft = '15px';
element.style.paddingRight = '15px';
window.addEventListener('app_opened', async (e: CustomEvent) => {
const app = document.createElement('app');
app.innerHTML = `<img data-id="${(await e.detail.win).id}" src="${e.detail.app.icon}"/>`;
app.onclick = async () => {
const win = await e.detail.win;
await win.focus();
await win.toggleMin();
window.addEventListener('app_opened', (e: AppOpenedEvent): void => {
const appIcon = document.createElement('app')
const app = e.detail.app
const win = e.detail.win
appIcon.innerHTML = `<img data-id="${win.id}" src="${app.icon}"/>`
appIcon.onclick = async () => {
const win = await e.detail.win
win.focus()
win.toggleMin()
}
element.appendChild(app);
element.appendChild(appIcon)
})
window.addEventListener('app_closed', async (e: CustomEvent) => {
element.querySelector(`img[data-id="${(await e.detail.win).id}"]`).parentElement.remove();
window.addEventListener('app_closed', (e: AppClosedEvent): void => {
const win = e.detail.win
element.querySelector(`img[data-id="${win.id}"]`)?.parentElement?.remove()
})
}

View file

@ -4,8 +4,8 @@ export const meta = {
id: 'clock'
}
export const run = (element: HTMLDivElement) => {
element.style.display = 'flex';
element.style.alignItems = 'center';
element.innerText = '9:41 AM\n10/14/2023';
export const run = (element: HTMLDivElement): void => {
element.style.display = 'flex'
element.style.alignItems = 'center'
element.innerText = '9:41 AM\n10/14/2023'
}

View file

@ -4,11 +4,11 @@ export const meta = {
id: 'switcher'
}
export const run = (element: HTMLDivElement) => {
element.style.display = 'flex';
element.style.gap = '10px';
element.style.alignItems = 'center';
element.style.paddingLeft = '15px';
element.style.paddingRight = '15px';
element.innerHTML = `<i class='bx bxs-dice-1'></i><i class='bx bx-dice-2'></i><i class='bx bx-dice-3'></i>`;
export const run = (element: HTMLDivElement): void => {
element.style.display = 'flex'
element.style.gap = '10px'
element.style.alignItems = 'center'
element.style.paddingLeft = '15px'
element.style.paddingRight = '15px'
element.innerHTML = '<i class=\'bx bxs-dice-1\'></i><i class=\'bx bx-dice-2\'></i><i class=\'bx bx-dice-3\'></i>'
}

View file

@ -1,3 +1,3 @@
declare module "prism-code-editor";
declare module "prism-code-editor/setups";
declare module "prism-code-editor/prism-core";
declare module 'prism-code-editor';
declare module 'prism-code-editor/setups';
declare module 'prism-code-editor/prism-core';

View file

@ -1,38 +1,38 @@
import * as clock from './modules/clock.ts';
import * as switcher from './modules/switcher.ts';
import * as appView from './modules/appView.ts';
import * as apps from './modules/apps.ts';
import * as clock from './modules/clock.ts'
import * as switcher from './modules/switcher.ts'
import * as appView from './modules/appView.ts'
import * as apps from './modules/apps.ts'
import { StatusItem } from './types';
import { StatusItem } from './types'
class StatusBar {
items: StatusItem[] = [];
element: HTMLElement;
items: StatusItem[] = []
element: HTMLElement
constructor() {
this.element = document.createElement('toolbar');
constructor () {
this.element = document.createElement('toolbar')
document.body.appendChild(this.element);
document.body.appendChild(this.element)
this.add(appView);
this.add(apps);
this.add(clock);
this.add(switcher);
this.add(appView)
this.add(apps)
this.add(clock)
this.add(switcher)
}
add(item: StatusItem) {
add (item: StatusItem): void {
if (this.items.some(x => x.meta.id === item.meta.id)) {
console.error(`Unable to register tool; ${item.meta.id} is already registered.`);
console.error(`Unable to register tool; ${item.meta.id} is already registered.`)
} else {
const element = document.createElement('div');
element.setAttribute('data-toolbar-id', item.meta.id);
const element = document.createElement('div')
element.setAttribute('data-toolbar-id', item.meta.id)
this.items.push(item);
this.element.appendChild(element);
this.items.push(item)
this.element.appendChild(element)
item.run(element);
item.run(element)
}
}
}
export default StatusBar;
export default StatusBar

View file

@ -1,21 +1,34 @@
import { FlowWindow } from "./wm";
import { FlowWindow } from './wm'
export interface StatusItem {
meta: {
name: string;
description: string;
id: string;
},
run: Function;
name: string
description: string
id: string
}
run: Function
}
export interface App {
name: string;
pkg: string;
name: string
pkg: string
version: string;
version: string
icon: string;
icon: string
open(data: any): Promise<FlowWindow>;
open: (data: any) => Promise<FlowWindow>
}
export interface AppOpenedEvent extends CustomEvent {
detail: {
app: App
win: FlowWindow
}
}
export interface AppClosedEvent extends CustomEvent {
detail: {
win: FlowWindow
}
}

298
src/wm.ts
View file

@ -1,270 +1,262 @@
import flow from "./flow.ts";
import { v4 as uuid } from 'uuid';
import flow from './flow.ts'
import { v4 as uuid } from 'uuid'
interface FlowWindowConfig {
title: string;
icon: string;
title: string
icon: string
width?: number;
height?: number;
width?: number
height?: number
minWidth?: number;
minHeight?: number;
minWidth?: number
minHeight?: number
}
let focus = true;
function dragElement (element: HTMLElement, container: HTMLElement): void {
let posX = 0; let posY = 0
window.onfocus = () => focus = true;
window.onblur = () => focus = false;
element.querySelector('window-header')?.addEventListener('mousedown', dragMouseDown)
function dragElement(element: HTMLElement, container: HTMLElement) {
var posX = 0, posY = 0;
function dragMouseDown (e: MouseEvent): void {
e.preventDefault()
closeAll()
element.querySelector('window-header').addEventListener('mousedown', dragMouseDown);
posX = e.clientX
posY = e.clientY
function dragMouseDown(e: MouseEvent) {
e.preventDefault();
closeAll();
posX = e.clientX;
posY = e.clientY;
document.onmouseup = closeDragElement;
document.onmousemove = elementDrag;
document.onmouseup = closeDragElement
document.onmousemove = elementDrag
}
function elementDrag(e: MouseEvent) {
e.preventDefault();
function elementDrag (e: MouseEvent): void {
e.preventDefault()
// Calculate the distance the mouse has moved
const dx = e.clientX - posX;
const dy = e.clientY - posY;
const dx = e.clientX - posX
const dy = e.clientY - posY
// Calculate the new position for the element
const newTop = element.offsetTop + dy;
const newLeft = element.offsetLeft + dx;
const newTop = element.offsetTop + dy
const newLeft = element.offsetLeft + dx
// Get the container's dimensions
const containerWidth = container.offsetWidth;
const containerHeight = container.offsetHeight;
const containerWidth = container.offsetWidth
const containerHeight = container.offsetHeight
// Ensure the element stays within the container boundaries
if (newTop >= 0 && newTop + element.offsetHeight <= containerHeight) {
element.style.top = newTop + "px";
element.style.top = `${newTop}px`
}
if (newLeft >= 0 && newLeft + element.offsetWidth <= containerWidth) {
element.style.left = newLeft + "px";
element.style.left = `${newLeft}px`
}
// Update the last mouse position
posX = e.clientX;
posY = e.clientY;
posX = e.clientX
posY = e.clientY
}
function closeDragElement() {
document.onmouseup = null;
document.onmousemove = null;
container.onmouseleave = null;
function closeDragElement (): void {
document.onmouseup = null
document.onmousemove = null
container.onmouseleave = null
}
function closeAll () {
closeDragElement();
container.onmouseenter = null;
function closeAll (): void {
closeDragElement()
container.onmouseenter = null
}
}
export class FlowWindow {
element: HTMLElement;
element: HTMLElement
private header: HTMLElement;
content: HTMLElement;
private readonly header: HTMLElement
content: HTMLElement
maximized: boolean;
minimized: boolean;
maximized: boolean
minimized: boolean
width: number;
height: number;
width: number
height: number
isMinimized = false;
isMaximized = false;
isMinimized = false
isMaximized = false
wm: WM;
wm: WM
id = uuid();
id = uuid()
config: FlowWindowConfig;
config: FlowWindowConfig
constructor(wm: WM, config: FlowWindowConfig) {
this.wm = wm;
this.config = config;
constructor (wm: WM, config: FlowWindowConfig) {
this.wm = wm
this.config = config
this.element = document.createElement('window');
this.element = document.createElement('window')
this.element.style.zIndex = (wm.getHighestZIndex() + 1).toString();
this.element.style.position = 'absolute';
this.focus();
this.element.style.zIndex = (wm.getHighestZIndex() + 1).toString()
this.element.style.position = 'absolute'
this.focus()
this.element.onmousedown = () => {
this.focus()
};
}
this.element.style.width = `${config.width || 300}px`;
this.element.style.height = `${config.height || 200}px`;
this.element.style.width = `${config.width ?? 300}px`
this.element.style.height = `${config.height ?? 200}px`
this.header = document.createElement('window-header');
this.header = document.createElement('window-header')
this.header.innerHTML = `<img src="${config.icon}"></img> <div class="title">${config.title}</div><div style="flex:1;"></div><i id="min" class='bx bx-minus'></i><i id="max" class='bx bx-checkbox'></i><i id="close" class='bx bx-x'></i>`;
(this.header.querySelector('#close') as HTMLElement).onclick = () => {
this.close();
this.close()
}
(this.header.querySelector('#min') as HTMLElement).onclick = () => this.toggleMin();
(this.header.querySelector('#max') as HTMLElement).onclick = () => this.toggleMax();
(this.header.querySelector('#max') as HTMLElement).onclick = () => this.toggleMax()
this.content = document.createElement('window-content');
this.content = document.createElement('window-content')
this.element.appendChild(this.header);
this.element.appendChild(this.content);
this.element.appendChild(this.header)
this.element.appendChild(this.content)
dragElement(this.element, document.querySelector('window-area'));
dragElement(this.element, (document.querySelector('window-area') as HTMLElement))
}
toggleMin() {
toggleMin (): boolean {
if (this.isMinimized) {
this.element.style.pointerEvents = null;
this.element.style.opacity = '1';
this.element.style.pointerEvents = 'all'
this.element.style.opacity = '1'
} else {
this.element.style.pointerEvents = 'none';
this.element.style.opacity = '0';
this.element.style.pointerEvents = 'none'
this.element.style.opacity = '0'
}
this.isMinimized = !this.isMinimized;
this.isMinimized = !this.isMinimized
return this.isMinimized
}
private prevTop: string;
private prevLeft: string;
private prevWidth: string;
private prevHeight: string;
toggleMax() {
private prevTop: string
private prevLeft: string
private prevWidth: string
private prevHeight: string
toggleMax (): boolean {
if (this.isMaximized) {
this.element.style.width = this.prevWidth;
this.element.style.height = this.prevHeight;
this.element.style.top = this.prevTop;
this.element.style.left = this.prevLeft;
this.element.style.width = this.prevWidth
this.element.style.height = this.prevHeight
this.element.style.top = this.prevTop
this.element.style.left = this.prevLeft
} else {
this.prevTop = this.element.style.top;
this.prevLeft = this.element.style.left;
this.prevWidth = this.element.style.width;
this.prevHeight = this.element.style.height;
this.prevTop = this.element.style.top
this.prevLeft = this.element.style.left
this.prevWidth = this.element.style.width
this.prevHeight = this.element.style.height
this.element.style.top = '0';
this.element.style.left = '0';
this.element.style.width = 'calc(100% - 2px)';
this.element.style.height = 'calc(100% - 3px)';
this.element.style.top = '0'
this.element.style.left = '0'
this.element.style.width = 'calc(100% - 2px)'
this.element.style.height = 'calc(100% - 3px)'
}
this.isMaximized = !this.isMaximized;
this.isMaximized = !this.isMaximized
return this.isMaximized
}
focus() {
focus (): void {
if (this.element.style.zIndex !== this.wm.getHighestZIndex().toString()) {
this.element.style.zIndex = (this.wm.getHighestZIndex() + 1).toString();
this.element.style.zIndex = (this.wm.getHighestZIndex() + 1).toString()
}
}
close() {
this.element.remove();
const event = new CustomEvent('app_closed', { detail: { win: this } });
window.dispatchEvent(event);
close (): void {
this.element.remove()
const event = new CustomEvent('app_closed', { detail: { win: this } })
window.dispatchEvent(event)
}
setTitle(title: string) {
(this.header.querySelector('.title') as HTMLElement).innerText = title;
setTitle (title: string): void {
(this.header.querySelector('.title') as HTMLElement).innerText = title
}
}
class WM {
launcherOpen = false;
area: HTMLElement;
launcher: HTMLElement;
windows: FlowWindow[] = [];
launcherOpen = false
area: HTMLElement
launcher: HTMLElement
windows: FlowWindow[] = []
constructor() {
this.area = document.createElement('window-area');
this.launcher = document.createElement('launcher');
constructor () {
this.area = document.createElement('window-area')
this.launcher = document.createElement('launcher')
this.init();
this.init()
}
getHighestZIndex() {
getHighestZIndex (): number {
const indexes = this.windows.map((win: FlowWindow) => {
if (win.element.style.zIndex === '') return;
return parseInt(win.element.style.zIndex);
}).filter(x => x !== undefined);
return parseInt(win.element.style.zIndex)
})
const max = Math.max(...indexes);
const max = Math.max(...indexes)
if (max === -Infinity) {
return 0;
return 0
} else {
return max;
return max
}
}
createWindow(config: FlowWindowConfig): FlowWindow {
const win = new FlowWindow(this, config);
this.windows.push(win);
this.area.appendChild(win.element);
return win;
createWindow (config: FlowWindowConfig): FlowWindow {
const win = new FlowWindow(this, config)
this.windows.push(win)
this.area.appendChild(win.element)
return win
}
toggleLauncher() {
if (this.launcherOpen === true) {
this.launcher.style.opacity = '0';
this.launcher.style.backdropFilter = 'blur(0px)';
this.launcher.style.pointerEvents = 'none';
toggleLauncher (): boolean {
if (this.launcherOpen) {
this.launcher.style.opacity = '0'
this.launcher.style.backdropFilter = 'blur(0px)'
this.launcher.style.pointerEvents = 'none'
} else {
this.launcher.style.opacity = '1';
this.launcher.style.backdropFilter = 'blur(20px)';
this.launcher.style.pointerEvents = null;
this.launcher.style.opacity = '1'
this.launcher.style.backdropFilter = 'blur(20px)'
this.launcher.style.pointerEvents = 'all'
}
this.launcherOpen = !this.launcherOpen;
this.launcherOpen = !this.launcherOpen
return this.launcherOpen
}
private async init() {
private init (): void {
this.launcher.innerHTML = `
<input placeholder="Search"/>
<apps></apps>
`;
`
this.launcher.onclick = (e) => {
if(e.target !== e.currentTarget) return;
this.toggleLauncher();
if (e.target !== e.currentTarget) return
this.toggleLauncher()
}
(this.launcher.querySelector('apps') as HTMLElement).onclick = (e) => {
if(e.target !== e.currentTarget) return;
this.toggleLauncher();
if (e.target !== e.currentTarget) return
this.toggleLauncher()
}
this.launcher.style.opacity = '0';
this.launcher.style.filter = 'blur(0px)';
this.launcher.style.pointerEvents = 'none';
this.launcher.style.opacity = '0'
this.launcher.style.filter = 'blur(0px)'
this.launcher.style.pointerEvents = 'none'
for (const pkg in flow.apps) {
const app = document.createElement('app');
const app = document.createElement('app')
app.onclick = () => {
flow.openApp(pkg);
this.toggleLauncher();
flow.openApp(pkg)
this.toggleLauncher()
}
app.innerHTML = `<img src="${flow.apps[pkg].icon}"><div>${flow.apps[pkg].name}</div>`
this.launcher.querySelector('apps').appendChild(app);
this.launcher.querySelector('apps')?.appendChild(app)
}
document.body.appendChild(this.area);
document.body.appendChild(this.launcher);
document.body.appendChild(this.area)
document.body.appendChild(this.launcher)
}
}
export default WM;
export default WM

View file

@ -13,6 +13,7 @@
"esModuleInterop": true,
"declaration": true,
"emitDeclarationOnly": true,
"allowImportingTsExtensions": true
"allowImportingTsExtensions": true,
"strictNullChecks": true
}
}

View file

@ -1,13 +1,13 @@
const HtmlWebpackPlugin = require('html-webpack-plugin');
const { FilerWebpackPlugin } = require('filer/webpack');
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin');
const webpack = require('webpack');
const HtmlWebpackPlugin = require('html-webpack-plugin')
const { FilerWebpackPlugin } = require('filer/webpack')
const NodePolyfillPlugin = require('node-polyfill-webpack-plugin')
const webpack = require('webpack')
const path = require('path');
const path = require('path')
module.exports = {
entry: {
flow: './src/index.ts',
flow: './src/index.ts'
},
devtool: 'inline-source-map',
mode: 'production',
@ -16,24 +16,24 @@ module.exports = {
{
test: /\.less$/i,
use: [
"style-loader",
"css-loader",
"less-loader",
],
'style-loader',
'css-loader',
'less-loader'
]
},
{
test: /\.css$/i,
use: [
"style-loader",
"css-loader",
],
'style-loader',
'css-loader'
]
},
{
test: /\.(png|jpe?g|gif)$/i,
loader: 'file-loader',
options: {
outputPath: 'images',
},
outputPath: 'images'
}
},
{
test: /\.ts$/,
@ -42,33 +42,33 @@ module.exports = {
},
{
test: /\.js$/,
use: ["source-map-loader"],
enforce: "pre"
},
use: ['source-map-loader'],
enforce: 'pre'
}
],
]
},
resolve: {
extensions: ['.tsx', '.ts', '.js'],
extensions: ['.tsx', '.ts', '.js']
},
output: {
filename: '[name].bundle.js',
path: path.resolve(__dirname, 'dist'),
clean: true,
clean: true
},
devServer: {
static: {
directory: path.join(__dirname, 'dist'),
directory: path.join(__dirname, 'dist')
},
compress: true,
port: 9000,
port: 9000
},
plugins: [new HtmlWebpackPlugin(), new FilerWebpackPlugin(),
new NodePolyfillPlugin({
excludeAliases: ['console']
}),
new webpack.optimize.MinChunkSizePlugin({
minChunkSize: 50000,
minChunkSize: 50000
}),
new webpack.optimize.SplitChunksPlugin({
minSize: 45000,
@ -87,15 +87,15 @@ module.exports = {
cacheGroups: {
commons: {
test: /[\\/]node_modules[\\/]/,
name: "vendor",
chunks: "initial",
reuseExistingChunk: true,
name: 'vendor',
chunks: 'initial',
reuseExistingChunk: true
},
default: {
minChunks: 2,
reuseExistingChunk: true,
},
},
},
},
};
reuseExistingChunk: true
}
}
}
}
}