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)
|
||||
|
||||
<br>
|
||||
<i>The future of Flow OS</i>
|
||||
<i>The future of FlowOS</i>
|
||||
<br>
|
||||
<a href="https://docs.flow-works.me"><strong>Read the docs »</strong></a>
|
||||
<br>
|
||||
|
||||
</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
|
||||
|
||||
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
|
||||
```bash
|
||||
|
|
@ -44,7 +44,7 @@ npm run serve
|
|||
|
||||
|
||||
## Made with
|
||||
Flow OS is made with the following software:
|
||||
FlowOS is made with the following software:
|
||||
* [Filer](https://github.com/filerjs/filer)
|
||||
* [Prism Code Editor](https://github.com/FIameCaster/prism-code-editor)
|
||||
* [Vite](https://vitejs.dev)
|
||||
|
|
|
|||
19
index.html
19
index.html
|
|
@ -1,12 +1,13 @@
|
|||
<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<title>Flow OS</title>
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://unpkg.com/filer"></script>
|
||||
<script src="./src/index.ts" type="module"></script>
|
||||
</body>
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Flow OS</title>
|
||||
<link rel="shortcut icon" href="./src/assets/flow.png" type="image/png">
|
||||
</head>
|
||||
<body>
|
||||
<script src="https://unpkg.com/filer"></script>
|
||||
<script src="./src/index.ts" type="module"></script>
|
||||
</body>
|
||||
</html>
|
||||
6
package-lock.json
generated
6
package-lock.json
generated
|
|
@ -10,6 +10,7 @@
|
|||
"license": "MIT",
|
||||
"dependencies": {
|
||||
"@ptkdev/logger": "^1.8.0",
|
||||
"eruda": "^3.0.1",
|
||||
"filer": "^1.4.1",
|
||||
"prism-code-editor": "^1.2.2",
|
||||
"prismjs": "^1.29.0",
|
||||
|
|
@ -1846,6 +1847,11 @@
|
|||
"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": {
|
||||
"version": "1.22.2",
|
||||
"resolved": "https://registry.npmjs.org/es-abstract/-/es-abstract-1.22.2.tgz",
|
||||
|
|
|
|||
|
|
@ -7,7 +7,7 @@
|
|||
"test": "ts-standard",
|
||||
"dev": "vite",
|
||||
"build": "vite build",
|
||||
"serve": "vite serve"
|
||||
"preview": "vite preview"
|
||||
},
|
||||
"keywords": [],
|
||||
"author": "",
|
||||
|
|
@ -21,6 +21,7 @@
|
|||
},
|
||||
"dependencies": {
|
||||
"@ptkdev/logger": "^1.8.0",
|
||||
"eruda": "^3.0.1",
|
||||
"filer": "^1.4.1",
|
||||
"prism-code-editor": "^1.2.2",
|
||||
"prismjs": "^1.29.0",
|
||||
|
|
|
|||
|
|
@ -35,7 +35,7 @@ export default class EditorApp implements App {
|
|||
})
|
||||
|
||||
if (data != null) {
|
||||
win.setTitle('Editor - ' + data.path)
|
||||
win.setTitle(`Editor - ${data.path}`)
|
||||
|
||||
win.content.style.display = 'flex'
|
||||
win.content.style.flexDirection = 'column'
|
||||
|
|
@ -100,33 +100,29 @@ export default class EditorApp implements App {
|
|||
const fileBtn = win.content.querySelector('#file-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}`)
|
||||
el?.classList.toggle('show')
|
||||
}
|
||||
|
||||
fileBtn?.addEventListener('click', function (e) {
|
||||
fileBtn?.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
toggleDropdown('file')
|
||||
})
|
||||
|
||||
editBtn?.addEventListener('click', function (e) {
|
||||
editBtn?.addEventListener('click', (e) => {
|
||||
e.stopPropagation()
|
||||
toggleDropdown('edit')
|
||||
})
|
||||
|
||||
win.content.addEventListener('click', function () {
|
||||
const file = win.content.querySelector('#file')
|
||||
const edit = win.content.querySelector('#edit')
|
||||
if (file !== null) {
|
||||
if (file.classList.contains('show')) {
|
||||
toggleDropdown('file')
|
||||
}
|
||||
win.content.addEventListener('click', () => {
|
||||
const file = (win.content.querySelector('#file') as HTMLElement)
|
||||
const edit = (win.content.querySelector('#edit') as HTMLElement)
|
||||
if (file.classList.contains('show')) {
|
||||
toggleDropdown('file')
|
||||
}
|
||||
if (edit !== null) {
|
||||
if (edit.classList.contains('show')) {
|
||||
toggleDropdown('edit')
|
||||
}
|
||||
if (edit.classList.contains('show')) {
|
||||
toggleDropdown('edit')
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
|||
|
|
@ -40,22 +40,22 @@ export default class FilesApp implements App {
|
|||
if (back !== '<i class=\'bx bx-arrow-to-left\'></i>') {
|
||||
(win.content.querySelector('.back') as HTMLElement).onclick = async () => {
|
||||
if (dir.split('/')[1] === dir.replace('/', '')) {
|
||||
await setDir('/' + dir.split('/')[0])
|
||||
await setDir(`/${dir.split('/')[0]}`)
|
||||
} else {
|
||||
await setDir('/' + dir.split('/')[1])
|
||||
await setDir(`/${dir.split('/')[1]}`)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
(win.content.querySelector('.file') as HTMLElement).onclick = async () => {
|
||||
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)
|
||||
}
|
||||
|
||||
(win.content.querySelector('.folder') as HTMLElement).onclick = async () => {
|
||||
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)
|
||||
}
|
||||
|
||||
|
|
|
|||
16
src/index.ts
16
src/index.ts
|
|
@ -1,7 +1,7 @@
|
|||
import './style.less'
|
||||
|
||||
import StatusBar from './statusbar.ts'
|
||||
import WM from './wm.ts'
|
||||
import StatusBar from './statusbar'
|
||||
import WM from './wm'
|
||||
|
||||
import * as fs from 'fs'
|
||||
|
||||
|
|
@ -16,3 +16,15 @@ declare global {
|
|||
window.statusBar = new StatusBar()
|
||||
window.wm = new WM()
|
||||
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.paddingLeft = '15px'
|
||||
element.style.paddingRight = '15px'
|
||||
element.innerHTML = '100%'
|
||||
element.innerHTML = '🔋 100%'
|
||||
}
|
||||
|
|
|
|||
|
|
@ -27,15 +27,16 @@ class StatusBar {
|
|||
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.`)
|
||||
} else {
|
||||
const element = document.createElement('div')
|
||||
element.setAttribute('data-toolbar-id', item.meta.id)
|
||||
|
||||
this.items.push(item)
|
||||
this.element.appendChild(element)
|
||||
|
||||
item.run(element)
|
||||
return
|
||||
}
|
||||
|
||||
const element = document.createElement('div')
|
||||
element.setAttribute('data-toolbar-id', item.meta.id)
|
||||
|
||||
this.items.push(item)
|
||||
this.element.appendChild(element)
|
||||
|
||||
item.run(element)
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -11,7 +11,12 @@
|
|||
--crust: #11111b;
|
||||
}
|
||||
|
||||
body, html {
|
||||
.bx-category {
|
||||
color: #181926;
|
||||
}
|
||||
|
||||
body,
|
||||
html {
|
||||
background-color: var(--crust);
|
||||
|
||||
width: 100vw;
|
||||
|
|
@ -25,7 +30,6 @@ body, html {
|
|||
overflow: hidden;
|
||||
}
|
||||
|
||||
|
||||
*::-webkit-scrollbar {
|
||||
display: none;
|
||||
}
|
||||
|
|
@ -34,7 +38,7 @@ body, html {
|
|||
-ms-overflow-style: none;
|
||||
scrollbar-width: none;
|
||||
|
||||
font-family: 'Satoshi', sans-serif;
|
||||
font-family: "Satoshi", sans-serif;
|
||||
font-weight: 600;
|
||||
|
||||
color: var(--text);
|
||||
|
|
@ -50,12 +54,17 @@ toolbar {
|
|||
margin: 0 0 0 0;
|
||||
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 {
|
||||
background: var(--base);
|
||||
padding: 5px;
|
||||
border-radius: 5px;
|
||||
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;
|
||||
|
||||
app {
|
||||
|
|
@ -81,7 +90,6 @@ window-area {
|
|||
height: 100%;
|
||||
overflow: hidden;
|
||||
|
||||
|
||||
window {
|
||||
background: var(--base);
|
||||
display: flex;
|
||||
|
|
@ -91,7 +99,7 @@ window-area {
|
|||
overflow: hidden;
|
||||
border: 1px solid rgba(255, 255, 255, 0.2);
|
||||
background: var(--crust);
|
||||
transition: .2s opacity, .2s width, .2s height;
|
||||
transition: 0.2s opacity, 0.2s width, 0.2s height;
|
||||
|
||||
window-header {
|
||||
height: 20px;
|
||||
|
|
@ -129,10 +137,12 @@ launcher {
|
|||
top: 0;
|
||||
background: rgba(0, 0, 0, 0.5);
|
||||
z-index: 99999999999999999999999;
|
||||
width: 100vw;
|
||||
width: calc(100vw + 20px);
|
||||
height: calc(100vh + 20px);
|
||||
gap: 20px;
|
||||
transition: .2s opacity, .2s backdrop-filter;
|
||||
transition: 0.2s opacity, 0.2s backdrop-filter;
|
||||
margin: 0;
|
||||
left: 0;
|
||||
|
||||
apps {
|
||||
max-height: 70vh;
|
||||
|
|
@ -167,7 +177,7 @@ launcher {
|
|||
width: 300px;
|
||||
max-width: 100vw;
|
||||
text-align: center;
|
||||
transition: border .2s;
|
||||
transition: border 0.2s;
|
||||
|
||||
&:focus {
|
||||
outline: none;
|
||||
|
|
|
|||
|
|
@ -192,11 +192,7 @@ class WM {
|
|||
|
||||
const max = Math.max(...indexes)
|
||||
|
||||
if (max === -Infinity) {
|
||||
return 0
|
||||
} else {
|
||||
return max
|
||||
}
|
||||
return max === -Infinity ? 0 : max
|
||||
}
|
||||
|
||||
createWindow (config: FlowWindowConfig): FlowWindow {
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue