Merge branch 'master' into master

This commit is contained in:
ThinLiquid 2023-12-06 01:28:14 +00:00 committed by GitHub
commit 5e216d9ac8
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
54 changed files with 1291 additions and 22 deletions

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 22 KiB

45
src/assets/icons/calc.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

30
src/assets/icons/eog.svg Normal file

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 44 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.5 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 34 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 10 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 118 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.3 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 14 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 32 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 9.7 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 40 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 52 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 29 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 27 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 15 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 11 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 13 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 12 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 6.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.2 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 37 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 19 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 7.9 KiB

File diff suppressed because one or more lines are too long

After

Width:  |  Height:  |  Size: 8.7 KiB

View file

@ -98,7 +98,7 @@ toolbar {
window-area {
position: relative;
width: 100%;
width: calc(100% - 20px);
height: 100%;
overflow: hidden;
margin: 10px;

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/null.png'
import icon from '../../assets/icons/web-browser.svg'
import { App } from '../../types'
import FlowWindow from '../../structures/FlowWindow'

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/editor.png'
import icon from '../../assets/icons/text-editor.svg'
import { App } from '../../types'
import { fullEditor } from 'prism-code-editor/setups'

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/files.png'
import icon from '../../assets/icons/file-manager.svg'
import { App } from '../../types'
import FlowWindow from '../../structures/FlowWindow'

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/info.png'
import icon from '../../assets/icons/userinfo.svg'
import badge from '../../assets/badge.png'
import { App, PackageJSON } from '../../types'

View file

@ -1,7 +1,7 @@
import icon from '../../assets/icons/manager.png'
import icon from '../../assets/icons/software-properties.svg'
import { App, LoadedApp, LoadedPlugin } from '../../types'
import FlowWindow from '../../structures/FlowWindow'
import nullIcon from '../../assets/icons/null.png'
import nullIcon from '../../assets/icons/application-default-icon.svg'
export default class ManagerApp implements App {
meta = {

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/music.png'
import icon from '../../assets/icons/gnome-music.svg'
import { App } from '../../types'
import FlowWindow from '../../structures/FlowWindow'

View file

@ -1,4 +1,4 @@
import icon from '../../assets/icons/settings.png'
import icon from '../../assets/icons/preferences-system.svg'
import { App } from '../../types'
import FlowWindow from '../../structures/FlowWindow'

100
src/builtin/apps/store.ts Normal file
View file

@ -0,0 +1,100 @@
import icon from '../../assets/icons/softwarecenter.svg'
import { App, RepoData } from '../../types'
import FlowWindow from '../../structures/FlowWindow'
import { sanitize } from '../../utils'
import nullIcon from '../../assets/icons/application-default-icon.svg'
export default class MusicApp implements App {
meta = {
name: 'Store',
description: 'A simple store app.',
pkg: 'flow.store',
version: '1.0.0',
icon
}
async open (): Promise<FlowWindow> {
const win = window.wm.createWindow({
title: this.meta.name,
icon: this.meta.icon,
width: 500,
height: 700
})
win.content.style.background = 'var(--base)'
const config = await window.config()
fetch(config.SERVER_URL + '/apps/list/')
.then(async (res) => await res.json())
.then(handle)
.catch(e => console.error(e))
function handle (repos: RepoData[]): void {
win.content.innerHTML = `
<div class="repos" style="display: flex;flex-direction: column;gap: 10px;"></div>
`
repos.forEach((repo) => {
(win.content.querySelector('.repos') as HTMLElement).innerHTML += `
<div data-repo-id="${sanitize(repo.id)}" style="display: flex;flex-direction: column;gap: 10px;background: var(--surface-0);padding: 20px;margin: 10px;border-radius: 10px;">
<div style="flex: 1;">
<h2 style="margin: 0;margin-bottom: 10px;">${sanitize(repo.name)}</h2>
<code style="font-family: monospace;">${sanitize(repo.id)}</code>
</div>
<br/>
<div class="apps"></div>
</div>
`
repo.apps.forEach((app) => {
(win.content.querySelector(`div[data-repo-id="${sanitize(repo.id)}"] > .apps`) as HTMLElement).innerHTML += `
<div data-pkg="${sanitize(app.pkg)}" style="display: flex;gap: 20px;">
<img src="${sanitize(app.icon ?? nullIcon)}" height="59.5px" style="border-radius: var(--app-radius);">
<div>
<h3 style="margin: 0;margin-bottom: 10px;">${sanitize(app.name)}</h3>
<div style="display: flex;gap:5px;align-items: center;">
<code style="font-family: monospace;">${sanitize(app.pkg)}</code>
<span class="material-symbols-rounded">download</span>
</div>
</div>
</div>
`
window.fs.exists(`/Applications/${app.url.split('/').at(-1) as string}`, (exists) => {
if (exists) {
(win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).innerHTML = 'delete';
(win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => {
window.fs.unlink(`/Applications/${app.url.split('/').at(-1) as string}`, () => {
window.location.reload()
})
}
} else {
(win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => {
install(app.url)
}
}
});
(win.content.querySelector(`div[data-pkg="${sanitize(app.pkg)}"] div > .material-symbols-rounded`) as HTMLElement).onclick = () => {
install(app.url)
}
})
})
}
function install (url: string): void {
fetch(url).then(async (res) => await res.text())
.then((data) => {
window.fs.exists('/Applications', (exists) => {
if (!exists) window.fs.promises.mkdir('/Applications').catch(console.error)
window.fs.promises.writeFile(`/Applications/${url.split('/').at(-1) as string}`, data).then(() => window.location.reload()).catch(console.error)
})
}).catch(console.error)
}
return win
}
}

View file

@ -1,15 +1,17 @@
import { LoadedApp, LoadedPlugin } from '../types'
import nullIcon from '../assets/icons/application-default-icon.svg'
class Flow {
apps: LoadedApp[] = []
appList: string[] = [
'settings',
'music',
'files',
'editor',
'info',
'manager',
'browser'
'../builtin/apps/settings.ts',
'../builtin/apps/music.ts',
'../builtin/apps/files.ts',
'../builtin/apps/editor.ts',
'../builtin/apps/info.ts',
'../builtin/apps/manager.ts',
'../builtin/apps/browser.ts',
'../builtin/apps/store.ts'
]
plugins: LoadedPlugin[] = []
@ -22,15 +24,22 @@ class Flow {
window.preloader.setPending('apps')
window.preloader.setStatus('importing default apps...')
await (await window.fs.promises.readdir('/Applications')).forEach((file) => {
window.fs.promises.readFile('/Applications/' + file).then(content => {
this.appList.push(`data:text/javascript;base64,${btoa(content.toString())}`)
}).catch(console.error)
})
for (const appPath of this.appList) {
window.preloader.setStatus(`importing default apps\n${appPath}`)
const { default: ImportedApp } = await import(`../builtin/apps/${appPath}.ts`).catch(async (e: Error) => {
const { default: ImportedApp } = await import(`${appPath}`).catch(async (e: Error) => {
console.error(e)
await window.preloader.setError('apps')
window.preloader.setStatus(`unable to import ${appPath}\n${e.name}: ${e.message}`)
})
const app = new ImportedApp()
app.builtin = true
app.meta.icon = app.meta.icon ?? nullIcon
this.addApp(app)
}

View file

@ -2,6 +2,7 @@ import { v4 as uuid } from 'uuid'
import WindowManager from '../instances/WindowManager'
import { FlowWindowConfig } from '../types'
import { sanitize } from '../utils'
import nullIcon from '../assets/icons/application-default-icon.svg'
/**
* Makes an element draggable.
@ -109,9 +110,9 @@ class FlowWindow {
this.element.style.height = `${config.height ?? 200}px`
this.header = document.createElement('window-header')
this.header.innerHTML = `<img src="${sanitize(config.icon)}"></img> <div class="title">${sanitize(config.title)}</div><div style="flex:1;"></div><i id="min" class='material-symbols-rounded' style="margin-bottom: 5px;">minimize</i><i id="close" class='material-symbols-rounded'>close</i>`
this.header.innerHTML = `<img src="${sanitize(config.icon === '' ? nullIcon : config.icon)}"></img> <div class="title">${sanitize(config.title)}</div><div style="flex:1;"></div><i id="min" class='material-symbols-rounded' style="margin-bottom: 5px;">minimize</i><i id="close" class='material-symbols-rounded'>close</i>`
if (config.canResize) {
this.header.innerHTML = `<img src="${sanitize(config.icon)}"></img> <div class="title">${sanitize(config.title)}</div><div style="flex:1;"></div><i id="min" class='material-symbols-rounded' style="margin-bottom: 5px;">minimize</i><i id="max" class='material-symbols-rounded' style="font-size: 20px;">square</i><i id="close" class='material-symbols-rounded'>close</i>`
this.header.innerHTML = `<img src="${sanitize(config.icon === '' ? nullIcon : config.icon)}"></img> <div class="title">${sanitize(config.title)}</div><div style="flex:1;"></div><i id="min" class='material-symbols-rounded' style="margin-bottom: 5px;">minimize</i><i id="max" class='material-symbols-rounded' style="font-size: 20px;">square</i><i id="close" class='material-symbols-rounded'>close</i>`
}
(this.header.querySelector('#close') as HTMLElement).onclick = () => {

View file

@ -30,6 +30,11 @@ export interface PluginMeta extends BaseMeta {
icon?: string
}
export interface RepoAppMeta extends BaseMeta {
icon?: string
url: string
}
export interface Apps {
[key: string]: App
}
@ -79,3 +84,9 @@ export interface FlowConfig {
USERNAME: string
'24HOUR_CLOCK': boolean
}
export interface RepoData {
name: string
id: string
apps: RepoAppMeta[]
}

View file

@ -1,10 +1,8 @@
import { defineConfig } from 'vite'
import { nodePolyfills } from 'vite-plugin-node-polyfills'
import dynamicImport from 'vite-plugin-dynamic-import'
export default defineConfig({
plugins: [
nodePolyfills(),
dynamicImport()
nodePolyfills()
]
})