diff --git a/README.md b/README.md index a2d7494..235cc3f 100644 --- a/README.md +++ b/README.md @@ -3,7 +3,8 @@ # FlowOS Next - [![JavaScript Style Guide](https://cdn.rawgit.com/standard/standard/master/badge.svg)](https://github.com/standard/standard) + +
diff --git a/package-lock.json b/package-lock.json index c70befc..f1f5581 100644 --- a/package-lock.json +++ b/package-lock.json @@ -12,11 +12,11 @@ "@ptkdev/logger": "^1.8.0", "eruda": "^3.0.1", "filer": "^1.4.1", - "prism-code-editor": "^1.2.2", - "prismjs": "^1.29.0", + "prism-code-editor": "^2.0.1", "uuid": "^9.0.1" }, "devDependencies": { + "@types/node": "^20.8.7", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", "ts-standard": "^12.0.2", @@ -729,20 +729,18 @@ "dev": true }, "node_modules/@types/node": { - "version": "20.8.4", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.4.tgz", - "integrity": "sha512-ZVPnqU58giiCjSxjVUESDtdPk4QR5WQhhINbc9UBrKLU68MX5BF6kbQzTrkwbolyr0X8ChBpXfavr5mZFKZQ5A==", + "version": "20.8.7", + "resolved": "https://registry.npmjs.org/@types/node/-/node-20.8.7.tgz", + "integrity": "sha512-21TKHHh3eUHIi2MloeptJWALuCu5H7HQTdTrWIFReA8ad+aggoX+lRes3ex7/FtpC+sVUpFMQ+QTfYr74mruiQ==", "dev": true, - "optional": true, - "peer": true, "dependencies": { "undici-types": "~5.25.1" } }, "node_modules/@types/prismjs": { - "version": "1.26.1", - "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.1.tgz", - "integrity": "sha512-Q7jDsRbzcNHIQje15CS/piKhu6lMLb9jwjxSfEIi4KcFKXW23GoJMkwQiJ8VObyfx+VmUaDcJxXaWN+cTCjVog==" + "version": "1.26.2", + "resolved": "https://registry.npmjs.org/@types/prismjs/-/prismjs-1.26.2.tgz", + "integrity": "sha512-/r7Cp7iUIk7gts26mHXD66geUC+2Fo26TZYjQK6Nr4LDfi6lmdRmMqM0oPwfiMhUwoBAOFe8GstKi2pf6hZvwA==" }, "node_modules/@types/semver": { "version": "7.5.3", @@ -4768,19 +4766,11 @@ } }, "node_modules/prism-code-editor": { - "version": "1.2.2", - "resolved": "https://registry.npmjs.org/prism-code-editor/-/prism-code-editor-1.2.2.tgz", - "integrity": "sha512-jmVlSNCp40BWauhzjv3GGFmXVaZkXcuVa7G/5RWV+iSPAugYfL1gQlOkXxC+E2gd/Z3/wbQIEr5RC1kyoohqlg==", + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/prism-code-editor/-/prism-code-editor-2.0.1.tgz", + "integrity": "sha512-93APxLnz6ow6TU8Mw2MC16d/Xb4k2FdjfrzIqb1finFPB/X4ejQyngEF1NkHKpggrIvR33QodW638KeN/gXEfA==", "dependencies": { - "@types/prismjs": "^1.26.0" - } - }, - "node_modules/prismjs": { - "version": "1.29.0", - "resolved": "https://registry.npmjs.org/prismjs/-/prismjs-1.29.0.tgz", - "integrity": "sha512-Kx/1w86q/epKcmte75LNrEoT+lX8pBpavuAbvJWRXar7Hz8jrtF+e3vY751p0R8H9HdArwaCTNDDzHg/ScJK1Q==", - "engines": { - "node": ">=6" + "@types/prismjs": "^1.26.2" } }, "node_modules/process": { @@ -5807,9 +5797,7 @@ "version": "5.25.3", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.25.3.tgz", "integrity": "sha512-Ga1jfYwRn7+cP9v8auvEXN1rX3sWqlayd4HP7OKk4mZWylEmu3KzXDUGrQUN6Ol7qo1gPvB2e5gX6udnyEPgdA==", - "dev": true, - "optional": true, - "peer": true + "dev": true }, "node_modules/universalify": { "version": "2.0.0", diff --git a/package.json b/package.json index afab852..0148d15 100644 --- a/package.json +++ b/package.json @@ -14,6 +14,7 @@ "author": "", "license": "MIT", "devDependencies": { + "@types/node": "^20.8.7", "@types/uuid": "^9.0.5", "@types/web": "^0.0.117", "ts-standard": "^12.0.2", @@ -26,8 +27,7 @@ "@ptkdev/logger": "^1.8.0", "eruda": "^3.0.1", "filer": "^1.4.1", - "prism-code-editor": "^1.2.2", - "prismjs": "^1.29.0", + "prism-code-editor": "^2.0.1", "uuid": "^9.0.1" } } diff --git a/src/apps/editor.ts b/src/apps/editor.ts index 334198a..a54e4da 100644 --- a/src/apps/editor.ts +++ b/src/apps/editor.ts @@ -2,15 +2,11 @@ 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 'prismjs/components/prism-markup.js' -import 'prismjs/components/prism-clike.js' -import 'prismjs/components/prism-javascript.js' -import 'prismjs/components/prism-typescript.js' -import 'prismjs/components/prism-jsx.js' -import 'prismjs/components/prism-tsx.js' -import 'prism-code-editor/languages' -import 'prism-code-editor/prism-markdown' +// this will also import markup, clike, javascript, typescript and jsx +import 'prism-code-editor/grammars/tsx' +import 'prism-code-editor/grammars/css-extras' +import 'prism-code-editor/grammars/markdown' +import 'prism-code-editor/grammars/python' import { FlowWindow } from '../wm.ts' @@ -18,6 +14,26 @@ interface EditorConfig { path: string } +const fileLanguageMap: { + [key: string]: string +} = { + c: 'clike', + cpp: 'clike', + java: 'clike', + cs: 'clike', + ts: 'typescript', + js: 'javascript', + mjs: 'javascript', + cjs: 'javascript', + jsx: 'jsx', + tsx: 'tsx', + html: 'html', + md: 'markdown', + css: 'css', + xml: 'xml', + py: 'python' +} + export default class EditorApp implements App { meta = { name: 'Editor', @@ -58,7 +74,7 @@ export default class EditorApp implements App { -
+
` + // Get current data + const data = JSON.parse(await fs.promises.readFile(this.configFileLoc)) + let oldData = JSON.stringify(data) + + // Handle value changes + + win.content.getElementsByClassName('btn')[0].onclick = async () => { + data['clock-Type'] = '0' + win.content.getElementsByClassName('btn')[0].disabled = true + win.content.getElementsByClassName('btn')[1].disabled = false + settingsChange() + } + win.content.getElementsByClassName('btn')[1].onclick = async () => { + data['clock-Type'] = '1' + win.content.getElementsByClassName('btn')[0].disabled = false + win.content.getElementsByClassName('btn')[1].disabled = true + settingsChange() + } + + win.content.getElementsByClassName('btn')[2].addEventListener('change', () => { + data['tab-title'] = win.content.getElementsByClassName('btn')[2].value + settingsChange() + }) + + win.content.getElementsByClassName('btn')[6].addEventListener('change', () => { + if (isURL(win.content.getElementsByClassName('btn')[6].value) === true && win.content.getElementsByClassName('btn')[6].value !== '') { + data['flow-server'] = win.content.getElementsByClassName('btn')[6].value + win.content.getElementsByClassName('error-text')[1].textContent = '' + } else { + if (win.content.getElementsByClassName('btn')[6].value !== '') { + win.content.getElementsByClassName('error-text')[1].textContent = 'Please input a vaild URL' + } else { + win.content.getElementsByClassName('error-text')[1].textContent = '' + } + } + settingsChange() + }) + + win.content.getElementsByClassName('btn')[3].addEventListener('change', () => { + if (isURL(win.content.getElementsByClassName('btn')[3].value) === true && win.content.getElementsByClassName('btn')[4].value !== '') { + data['favicon-url'] = win.content.getElementsByClassName('btn')[3].value + win.content.getElementsByClassName('error-text')[0].textContent = '' + } else { + if (win.content.getElementsByClassName('btn')[4].value !== '') { + win.content.getElementsByClassName('error-text')[0].textContent = 'Please input a vaild URL' + } else { + win.content.getElementsByClassName('error-text')[0].textContent = '' + } + } + settingsChange() + }) + + win.content.getElementsByClassName('btn')[4].value = data['proxy-type'] + win.content.getElementsByClassName('btn')[4].addEventListener('change', (event: any) => { + data['proxy-type'] = event.target.value + settingsChange() + }) + + win.content.getElementsByClassName('btn')[5].value = data['search-engine'] + win.content.getElementsByClassName('btn')[5].addEventListener('change', (event: any) => { + data['search-engine'] = event.target.value + settingsChange() + }) + + // Handle saving. + + win.content.getElementsByClassName('save')[0].onclick = async () => { + await fs.promises.writeFile(this.configFileLoc, JSON.stringify(data)) + oldData = JSON.stringify(data) + settingsChange() + } + + // Display unsaved changes / prevent Save button from being clicked twice. + + function settingsChange (): void { + if (oldData !== JSON.stringify(data)) { + win.setTitle('Settings - Unsaved Changes') + win.content.getElementsByClassName('save')[0].disabled = false + } else { + win.setTitle('Settings') + win.content.getElementsByClassName('save')[0].disabled = true + } + } + // URL checker + + function isURL (input: string): any { + const regex = /https?:\/\/(www\.)?[-a-zA-Z0-9@:%._+~#=]{1,256}\.[a-zA-Z0-9()]{1,6}\b([-a-zA-Z0-9()@:%_+.~#?&//=]*)/ + return input.match(regex) + } + + // Set values + win.content.getElementsByClassName('btn')[0].disabled = true + win.content.getElementsByClassName('btn')[1].disabled = false + if (data['clock-Type'] === '0') { + win.content.getElementsByClassName('btn')[0].disabled = false + win.content.getElementsByClassName('btn')[1].disabled = true + } return win } diff --git a/src/assets/badge.png b/src/assets/badge.png new file mode 100644 index 0000000..cb05234 Binary files /dev/null and b/src/assets/badge.png differ diff --git a/src/files.d.ts b/src/files.d.ts deleted file mode 100644 index 2101ae6..0000000 --- a/src/files.d.ts +++ /dev/null @@ -1,5 +0,0 @@ -declare module '*.png' { - const image: string - export = image -} -declare module '*.json' diff --git a/src/plugins/apps.ts b/src/plugins/apps.ts index 60ad755..f17b3ef 100644 --- a/src/plugins/apps.ts +++ b/src/plugins/apps.ts @@ -12,6 +12,7 @@ export const run = (element: HTMLDivElement): void => { element.style.alignItems = 'center' element.style.gap = '5px' element.style.flex = '1' + window.addEventListener('app_opened', (e: AppOpenedEvent): void => { const appIcon = document.createElement('app') const app = e.detail.app @@ -19,7 +20,7 @@ export const run = (element: HTMLDivElement): void => { appIcon.style.background = 'var(--surface-0)' appIcon.style.padding = '5px 7.5px' appIcon.style.borderRadius = '5px' - appIcon.innerHTML = ` ${app.meta.name}` + appIcon.innerHTML = ` ${app.meta.name}` appIcon.onclick = async () => { const win = await e.detail.win win.focus() @@ -27,6 +28,7 @@ export const run = (element: HTMLDivElement): void => { } element.appendChild(appIcon) }) + window.addEventListener('app_closed', (e: AppClosedEvent): void => { const win = e.detail.win element.querySelector(`img[data-id="${win.id}"]`)?.parentElement?.remove() diff --git a/src/prism-code-editor.d.ts b/src/prism-code-editor.d.ts deleted file mode 100644 index 643089f..0000000 --- a/src/prism-code-editor.d.ts +++ /dev/null @@ -1,3 +0,0 @@ -declare module 'prism-code-editor'; -declare module 'prism-code-editor/setups'; -declare module 'prism-code-editor/prism-core'; diff --git a/src/types.ts b/src/types.ts index ef39528..d6d4715 100644 --- a/src/types.ts +++ b/src/types.ts @@ -44,7 +44,6 @@ export interface FlowWindowConfig { export interface App { meta: { - id: any name: string description: string pkg: string diff --git a/src/wm.ts b/src/wm.ts index 4119596..a3f9168 100644 --- a/src/wm.ts +++ b/src/wm.ts @@ -88,14 +88,14 @@ export class FlowWindow { this.focus() } - if (config.canResize === undefined) config.canResize = true + if (config.canResize === undefined || config.canResize === null) 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}
` } @@ -105,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() } diff --git a/tsconfig.json b/tsconfig.json index a2d9131..02d2cea 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -9,11 +9,14 @@ "jsx": "react", "jsxFactory": "h", "allowJs": true, - "moduleResolution": "node", + "moduleResolution": "bundler", "esModuleInterop": true, "declaration": true, "emitDeclarationOnly": true, "allowImportingTsExtensions": true, - "strictNullChecks": true + "strictNullChecks": true, + "skipLibCheck": true, + "isolatedModules": true, + "types": ["vite/client", "node"] } } \ No newline at end of file