Merge branch 'master' of https://github.com/Flow-Works/FlowOS-2.0
This commit is contained in:
commit
df8209bf2c
12 changed files with 88 additions and 63 deletions
2
.github/FUNDING.yml
vendored
Normal file
2
.github/FUNDING.yml
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
# These are supported funding model platforms
|
||||||
|
ko_fi: flowworks
|
||||||
10
README.md
10
README.md
|
|
@ -13,20 +13,20 @@
|
||||||
[](https://github.com/Flow-Works/FlowOS-2.0/actions/workflows/build.yml)
|
[](https://github.com/Flow-Works/FlowOS-2.0/actions/workflows/build.yml)
|
||||||
|
|
||||||
<br>
|
<br>
|
||||||
<i>The future of Flow OS</i>
|
<i>The future of FlowOS</i>
|
||||||
<br>
|
<br>
|
||||||
<a href="https://docs.flow-works.me"><strong>Read the docs »</strong></a>
|
<a href="https://docs.flow-works.me"><strong>Read the docs »</strong></a>
|
||||||
<br>
|
<br>
|
||||||
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
## What is Flow OS?
|
## What is FlowOS?
|
||||||
|
|
||||||
Flow OS is a web OS proxy made for the Titanium Network 2023 Proxathon. It's extremly customizable with an API to make your own apps, themes, and modules.
|
FlowOS is a web OS proxy made for the Titanium Network 2023 Proxathon. It's extremly customizable with an API to make your own apps, themes, and modules.
|
||||||
|
|
||||||
## Getting Started
|
## Getting Started
|
||||||
|
|
||||||
To run Flow OS on your local machine, you need Node.js 16 or above.
|
To run FlowOS on your local machine, you need Node.js 16 or above.
|
||||||
|
|
||||||
1. Clone the repository
|
1. Clone the repository
|
||||||
```bash
|
```bash
|
||||||
|
|
@ -44,7 +44,7 @@ npm run serve
|
||||||
|
|
||||||
|
|
||||||
## Made with
|
## Made with
|
||||||
Flow OS is made with the following software:
|
FlowOS is made with the following software:
|
||||||
* [Filer](https://github.com/filerjs/filer)
|
* [Filer](https://github.com/filerjs/filer)
|
||||||
* [Prism Code Editor](https://github.com/FIameCaster/prism-code-editor)
|
* [Prism Code Editor](https://github.com/FIameCaster/prism-code-editor)
|
||||||
* [Vite](https://vitejs.dev)
|
* [Vite](https://vitejs.dev)
|
||||||
|
|
|
||||||
13
index.html
13
index.html
|
|
@ -1,12 +1,13 @@
|
||||||
<!DOCTYPE html>
|
<!DOCTYPE html>
|
||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8">
|
<meta charset="UTF-8" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
<title>Flow OS</title>
|
<title>Flow OS</title>
|
||||||
</head>
|
<link rel="shortcut icon" href="./src/assets/flow.png" type="image/png">
|
||||||
<body>
|
</head>
|
||||||
|
<body>
|
||||||
<script src="https://unpkg.com/filer"></script>
|
<script src="https://unpkg.com/filer"></script>
|
||||||
<script src="./src/index.ts" type="module"></script>
|
<script src="./src/index.ts" type="module"></script>
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -10,6 +10,7 @@
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ptkdev/logger": "^1.8.0",
|
"@ptkdev/logger": "^1.8.0",
|
||||||
|
"eruda": "^3.0.1",
|
||||||
"filer": "^1.4.1",
|
"filer": "^1.4.1",
|
||||||
"prism-code-editor": "^1.2.2",
|
"prism-code-editor": "^1.2.2",
|
||||||
"prismjs": "^1.29.0",
|
"prismjs": "^1.29.0",
|
||||||
|
|
@ -1846,6 +1847,11 @@
|
||||||
"is-arrayish": "^0.2.1"
|
"is-arrayish": "^0.2.1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eruda": {
|
||||||
|
"version": "3.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/eruda/-/eruda-3.0.1.tgz",
|
||||||
|
"integrity": "sha512-6q1Xdwga4JTr1mKSW4mzuWSSbmXgqpm/8Wa1QGFGfCWRjC0bCQjbS4u06M1te1moucIS3hBLlbSTPWYH2W0qbQ=="
|
||||||
|
},
|
||||||
"node_modules/es-abstract": {
|
"node_modules/es-abstract": {
|
||||||
"version": "1.22.2",
|
"version": "1.22.2",
|
||||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz",
|
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz",
|
||||||
|
|
|
||||||
|
|
@ -7,7 +7,7 @@
|
||||||
"test": "ts-standard",
|
"test": "ts-standard",
|
||||||
"dev": "vite",
|
"dev": "vite",
|
||||||
"build": "vite build",
|
"build": "vite build",
|
||||||
"serve": "vite serve"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"keywords": [],
|
"keywords": [],
|
||||||
"author": "",
|
"author": "",
|
||||||
|
|
@ -21,6 +21,7 @@
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@ptkdev/logger": "^1.8.0",
|
"@ptkdev/logger": "^1.8.0",
|
||||||
|
"eruda": "^3.0.1",
|
||||||
"filer": "^1.4.1",
|
"filer": "^1.4.1",
|
||||||
"prism-code-editor": "^1.2.2",
|
"prism-code-editor": "^1.2.2",
|
||||||
"prismjs": "^1.29.0",
|
"prismjs": "^1.29.0",
|
||||||
|
|
|
||||||
|
|
@ -35,7 +35,7 @@ export default class EditorApp implements App {
|
||||||
})
|
})
|
||||||
|
|
||||||
if (data != null) {
|
if (data != null) {
|
||||||
win.setTitle('Editor - ' + data.path)
|
win.setTitle(`Editor - ${data.path}`)
|
||||||
|
|
||||||
win.content.style.display = 'flex'
|
win.content.style.display = 'flex'
|
||||||
win.content.style.flexDirection = 'column'
|
win.content.style.flexDirection = 'column'
|
||||||
|
|
@ -100,34 +100,30 @@ export default class EditorApp implements App {
|
||||||
const fileBtn = win.content.querySelector('#file-open')
|
const fileBtn = win.content.querySelector('#file-open')
|
||||||
const editBtn = win.content.querySelector('#edit-open')
|
const editBtn = win.content.querySelector('#edit-open')
|
||||||
|
|
||||||
const toggleDropdown = function (id: string): void {
|
const toggleDropdown = (id: string): void => {
|
||||||
const el = win.content.querySelector(`#${id}`)
|
const el = win.content.querySelector(`#${id}`)
|
||||||
el?.classList.toggle('show')
|
el?.classList.toggle('show')
|
||||||
}
|
}
|
||||||
|
|
||||||
fileBtn?.addEventListener('click', function (e) {
|
fileBtn?.addEventListener('click', (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
toggleDropdown('file')
|
toggleDropdown('file')
|
||||||
})
|
})
|
||||||
|
|
||||||
editBtn?.addEventListener('click', function (e) {
|
editBtn?.addEventListener('click', (e) => {
|
||||||
e.stopPropagation()
|
e.stopPropagation()
|
||||||
toggleDropdown('edit')
|
toggleDropdown('edit')
|
||||||
})
|
})
|
||||||
|
|
||||||
win.content.addEventListener('click', function () {
|
win.content.addEventListener('click', () => {
|
||||||
const file = win.content.querySelector('#file')
|
const file = (win.content.querySelector('#file') as HTMLElement)
|
||||||
const edit = win.content.querySelector('#edit')
|
const edit = (win.content.querySelector('#edit') as HTMLElement)
|
||||||
if (file !== null) {
|
|
||||||
if (file.classList.contains('show')) {
|
if (file.classList.contains('show')) {
|
||||||
toggleDropdown('file')
|
toggleDropdown('file')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
if (edit !== null) {
|
|
||||||
if (edit.classList.contains('show')) {
|
if (edit.classList.contains('show')) {
|
||||||
toggleDropdown('edit')
|
toggleDropdown('edit')
|
||||||
}
|
}
|
||||||
}
|
|
||||||
})
|
})
|
||||||
|
|
||||||
const value = (await window.fs.promises.readFile(data.path)).toString()
|
const value = (await window.fs.promises.readFile(data.path)).toString()
|
||||||
|
|
|
||||||
|
|
@ -40,22 +40,22 @@ export default class FilesApp implements App {
|
||||||
if (back !== '<i class=\'bx bx-arrow-to-left\'></i>') {
|
if (back !== '<i class=\'bx bx-arrow-to-left\'></i>') {
|
||||||
(win.content.querySelector('.back') as HTMLElement).onclick = async () => {
|
(win.content.querySelector('.back') as HTMLElement).onclick = async () => {
|
||||||
if (dir.split('/')[1] === dir.replace('/', '')) {
|
if (dir.split('/')[1] === dir.replace('/', '')) {
|
||||||
await setDir('/' + dir.split('/')[0])
|
await setDir(`/${dir.split('/')[0]}`)
|
||||||
} else {
|
} else {
|
||||||
await setDir('/' + dir.split('/')[1])
|
await setDir(`/${dir.split('/')[1]}`)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
(win.content.querySelector('.file') as HTMLElement).onclick = async () => {
|
(win.content.querySelector('.file') as HTMLElement).onclick = async () => {
|
||||||
const title: string = prompt('Enter file name') ?? 'new-file.txt'
|
const title: string = prompt('Enter file name') ?? 'new-file.txt'
|
||||||
await window.fs.promises.open(dir + '/' + title, 'w')
|
await window.fs.promises.open(`${dir}/${title}`, 'w')
|
||||||
await setDir(dir)
|
await setDir(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
(win.content.querySelector('.folder') as HTMLElement).onclick = async () => {
|
(win.content.querySelector('.folder') as HTMLElement).onclick = async () => {
|
||||||
const title: string = prompt('Enter folder name') ?? 'new-folder'
|
const title: string = prompt('Enter folder name') ?? 'new-folder'
|
||||||
await window.fs.promises.mkdir(dir + '/' + title)
|
await window.fs.promises.mkdir(`${dir}/${title}`)
|
||||||
await setDir(dir)
|
await setDir(dir)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
16
src/index.ts
16
src/index.ts
|
|
@ -1,7 +1,7 @@
|
||||||
import './style.less'
|
import './style.less'
|
||||||
|
|
||||||
import StatusBar from './statusbar.ts'
|
import StatusBar from './statusbar'
|
||||||
import WM from './wm.ts'
|
import WM from './wm'
|
||||||
|
|
||||||
import * as fs from 'fs'
|
import * as fs from 'fs'
|
||||||
|
|
||||||
|
|
@ -16,3 +16,15 @@ declare global {
|
||||||
window.statusBar = new StatusBar()
|
window.statusBar = new StatusBar()
|
||||||
window.wm = new WM()
|
window.wm = new WM()
|
||||||
window.fs = new (window as any).Filer.FileSystem()
|
window.fs = new (window as any).Filer.FileSystem()
|
||||||
|
|
||||||
|
const params = new URLSearchParams(window.location.search)
|
||||||
|
|
||||||
|
async function enableDebug (): Promise<void> {
|
||||||
|
const { default: eruda } = await import('eruda')
|
||||||
|
eruda.init()
|
||||||
|
return await Promise.resolve()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (params.get('debug') !== null && params.get('debug') !== undefined) {
|
||||||
|
enableDebug().catch(e => console.error(e))
|
||||||
|
}
|
||||||
|
|
|
||||||
|
|
@ -9,5 +9,5 @@ export const run = (element: HTMLDivElement): void => {
|
||||||
element.style.alignItems = 'center'
|
element.style.alignItems = 'center'
|
||||||
element.style.paddingLeft = '15px'
|
element.style.paddingLeft = '15px'
|
||||||
element.style.paddingRight = '15px'
|
element.style.paddingRight = '15px'
|
||||||
element.innerHTML = '100%'
|
element.innerHTML = '🔋 100%'
|
||||||
}
|
}
|
||||||
|
|
|
||||||
|
|
@ -27,7 +27,9 @@ class StatusBar {
|
||||||
add (item: StatusItem): void {
|
add (item: StatusItem): void {
|
||||||
if (this.items.some(x => x.meta.id === item.meta.id)) {
|
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 {
|
return
|
||||||
|
}
|
||||||
|
|
||||||
const element = document.createElement('div')
|
const element = document.createElement('div')
|
||||||
element.setAttribute('data-toolbar-id', item.meta.id)
|
element.setAttribute('data-toolbar-id', item.meta.id)
|
||||||
|
|
||||||
|
|
@ -36,7 +38,6 @@ class StatusBar {
|
||||||
|
|
||||||
item.run(element)
|
item.run(element)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export default StatusBar
|
export default StatusBar
|
||||||
|
|
|
||||||
|
|
@ -11,7 +11,12 @@
|
||||||
--crust: #11111b;
|
--crust: #11111b;
|
||||||
}
|
}
|
||||||
|
|
||||||
body, html {
|
.bx-category {
|
||||||
|
color: #181926;
|
||||||
|
}
|
||||||
|
|
||||||
|
body,
|
||||||
|
html {
|
||||||
background-color: var(--crust);
|
background-color: var(--crust);
|
||||||
|
|
||||||
width: 100vw;
|
width: 100vw;
|
||||||
|
|
@ -25,7 +30,6 @@ body, html {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
*::-webkit-scrollbar {
|
*::-webkit-scrollbar {
|
||||||
display: none;
|
display: none;
|
||||||
}
|
}
|
||||||
|
|
@ -34,7 +38,7 @@ body, html {
|
||||||
-ms-overflow-style: none;
|
-ms-overflow-style: none;
|
||||||
scrollbar-width: none;
|
scrollbar-width: none;
|
||||||
|
|
||||||
font-family: 'Satoshi', sans-serif;
|
font-family: "Satoshi", sans-serif;
|
||||||
font-weight: 600;
|
font-weight: 600;
|
||||||
|
|
||||||
color: var(--text);
|
color: var(--text);
|
||||||
|
|
@ -50,12 +54,17 @@ toolbar {
|
||||||
margin: 0 0 0 0;
|
margin: 0 0 0 0;
|
||||||
justify-content: center;
|
justify-content: center;
|
||||||
|
|
||||||
|
div[data-toolbar-id="appview"] {
|
||||||
|
background: rgb(150, 181, 246);
|
||||||
|
background: linear-gradient(45deg, rgba(150, 181, 246, 1) 0%, rgba(150, 181, 246, 1) 12%, rgba(77, 129, 236, 1) 100%);
|
||||||
|
color: black;
|
||||||
|
}
|
||||||
& > div {
|
& > div {
|
||||||
background: var(--base);
|
background: var(--base);
|
||||||
padding: 5px;
|
padding: 5px;
|
||||||
border-radius: 5px;
|
border-radius: 5px;
|
||||||
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1), 0 0px 10px rgba(0, 0, 0, 0.1);
|
box-shadow: 0 10px 10px rgba(0, 0, 0, 0.1), 0 0px 10px rgba(0, 0, 0, 0.1);
|
||||||
height: 40px!important;
|
height: 40px !important;
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
||||||
app {
|
app {
|
||||||
|
|
@ -81,7 +90,6 @@ window-area {
|
||||||
height: 100%;
|
height: 100%;
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
|
|
||||||
|
|
||||||
window {
|
window {
|
||||||
background: var(--base);
|
background: var(--base);
|
||||||
display: flex;
|
display: flex;
|
||||||
|
|
@ -91,7 +99,7 @@ window-area {
|
||||||
overflow: hidden;
|
overflow: hidden;
|
||||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||||
background: var(--crust);
|
background: var(--crust);
|
||||||
transition: .2s opacity, .2s width, .2s height;
|
transition: 0.2s opacity, 0.2s width, 0.2s height;
|
||||||
|
|
||||||
window-header {
|
window-header {
|
||||||
height: 20px;
|
height: 20px;
|
||||||
|
|
@ -129,10 +137,12 @@ launcher {
|
||||||
top: 0;
|
top: 0;
|
||||||
background: rgba(0, 0, 0, 0.5);
|
background: rgba(0, 0, 0, 0.5);
|
||||||
z-index: 99999999999999999999999;
|
z-index: 99999999999999999999999;
|
||||||
width: 100vw;
|
width: calc(100vw + 20px);
|
||||||
height: calc(100vh + 20px);
|
height: calc(100vh + 20px);
|
||||||
gap: 20px;
|
gap: 20px;
|
||||||
transition: .2s opacity, .2s backdrop-filter;
|
transition: 0.2s opacity, 0.2s backdrop-filter;
|
||||||
|
margin: 0;
|
||||||
|
left: 0;
|
||||||
|
|
||||||
apps {
|
apps {
|
||||||
max-height: 70vh;
|
max-height: 70vh;
|
||||||
|
|
@ -167,7 +177,7 @@ launcher {
|
||||||
width: 300px;
|
width: 300px;
|
||||||
max-width: 100vw;
|
max-width: 100vw;
|
||||||
text-align: center;
|
text-align: center;
|
||||||
transition: border .2s;
|
transition: border 0.2s;
|
||||||
|
|
||||||
&:focus {
|
&:focus {
|
||||||
outline: none;
|
outline: none;
|
||||||
|
|
|
||||||
|
|
@ -192,11 +192,7 @@ class WM {
|
||||||
|
|
||||||
const max = Math.max(...indexes)
|
const max = Math.max(...indexes)
|
||||||
|
|
||||||
if (max === -Infinity) {
|
return max === -Infinity ? 0 : max
|
||||||
return 0
|
|
||||||
} else {
|
|
||||||
return max
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
createWindow (config: FlowWindowConfig): FlowWindow {
|
createWindow (config: FlowWindowConfig): FlowWindow {
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue