Working mobile wde

This commit is contained in:
Gregory Brzezinski 2023-07-19 19:38:28 +03:00
parent 186ea27db8
commit edf011fccd
21 changed files with 830 additions and 68 deletions

View File

@ -2,20 +2,23 @@ package sunboard
import ( import (
"net/http" "net/http"
"personalwebsite/apps"
"personalwebsite/webfilesystem" "personalwebsite/webfilesystem"
"github.com/gin-gonic/gin" "github.com/gin-gonic/gin"
) )
type SunboardApp struct { type SunboardApp struct {
fs *webfilesystem.WebFileSystem fs *webfilesystem.WebFileSystem
appID string appID string
appStorage *apps.ApplicationsStorage
} }
func NewSunboardApp(webFs *webfilesystem.WebFileSystem) *SunboardApp { func NewSunboardApp(webFs *webfilesystem.WebFileSystem, appStorage *apps.ApplicationsStorage) *SunboardApp {
newApp := SunboardApp{ newApp := SunboardApp{
fs: webFs, fs: webFs,
appID: "Sunboard", appID: "Sunboard",
appStorage: appStorage,
} }
return &newApp return &newApp
} }
@ -30,6 +33,28 @@ func (a *SunboardApp) PublicRoutes(route *gin.RouterGroup) {
func (a *SunboardApp) PrivateRoutes(router *gin.RouterGroup) { func (a *SunboardApp) PrivateRoutes(router *gin.RouterGroup) {
router.POST("render", func(ctx *gin.Context) { router.POST("render", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "sunboard/sunboard.html", gin.H{}) appIcons := []appIcon{}
for _, app := range a.appStorage.Apps {
if app.GetAppID() == "Sunboard" {
continue
}
appIcons = append(appIcons, appIcon{
Type: "Icon",
Icon: "",
Lable: app.GetAppID(),
AppId: app.GetAppID(),
})
}
ctx.HTML(http.StatusOK, "sunboard/sunboard.html", gin.H{
"AppsIcons": appIcons,
})
}) })
} }
type appIcon struct {
AppId string
Type string
Icon string
Lable string
}

View File

@ -22,6 +22,10 @@ export default class FinderWindow{
async Init(finder, args, runContext){ async Init(finder, args, runContext){
this.#finder = finder this.#finder = finder
this.#wde = runContext.WDE this.#wde = runContext.WDE
if (runContext.isMobile){
this.CreateMobileView(args, runContext)
return
}
if (args[1] == "--desktop"){ if (args[1] == "--desktop"){
let desktopNode = document.body.querySelector(`#${args[2]}`) let desktopNode = document.body.querySelector(`#${args[2]}`)
if (desktopNode == null){ if (desktopNode == null){
@ -98,6 +102,33 @@ export default class FinderWindow{
this.RenderDir(args[0]) this.RenderDir(args[0])
} }
CreateDesktopWindow(){
}
/**
* @param {*} args
* @param {import("../../wde/wde-desktop").runContext} runContext
* @returns
*/
async CreateMobileView(args, runContext){
const params = new URLSearchParams({isMobile: false}) //FIXME
const response = await fetch(`/app/${this.#appId}/render?` + params,
{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
const error = await response.json()
this.#wde.Alert(error.message)
return
}
const html = await response.text()
console.log(this.#wde)
let newView = this.#wde.Decorat.CreateNewView(this.#appId,)
newView.innerHTML = html
}
/** /**
* @param {string} path * @param {string} path
*/ */

View File

@ -18,12 +18,21 @@ export default class Finder extends WDEApplication{
/** /**
* @param {string[]} args * @param {string[]} args
* @param {import("../../wde/wde-desktop.js").runContext} * @param {import("../../wde/wde-desktop.js").runContext} runContext
*/ */
async NewWindow(args, runContext){ async NewWindow(args, runContext){
let newFinder = new FinderWindow() let newFinder = new FinderWindow()
await newFinder.Init(this, args, runContext) await newFinder.Init(this, args, runContext)
}
/**
* @param {string[]} args
* @param {import("../../wde/wde-desktop.js").runContext} runContext
*/
async NewView(args, runContext){
let newFinderView = new FinderWindow(this, args, runContext)
await newFinderView.Init(this, args, runContext)
} }
/** /**

View File

@ -16,4 +16,36 @@ body{
user-select: none; /* Non-prefixed version, currently user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */ supported by Chrome, Edge, Opera and Firefox */
touch-action: manipulation; touch-action: manipulation;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
} }
#mobile-app-views{
width: 100%;
height: 100%;
// background-color: @col-ceil;
}
#controls-bar{
&:extend(.WdePrimitives.AdjectiveElement);
width: 100%;
height: 150px;
background-color: @col-argent;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.mobile-app-view{
// background-color: burlywood;
width: 100%;
height: 100%;
// position: absolute;
}

View File

@ -1,3 +1,27 @@
export default class MobileDecorat { export default class MobileDecorat {
/** @type {Element} */
#applicationsNode
constructor(){
this.#applicationsNode = document.body.querySelector("#mobile-app-views") //TODO validate
}
/**
* @param {string} appId
* @returns {Element}
*/
CreateNewView(appId){
let newView = document.createElement("div")
newView.setAttribute("class", "mobile-app-view")
newView.setAttribute("appId", appId)
this.#applicationsNode.appendChild(newView)
return newView
}
Open(){
}
BackAction(){
// console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.lastChild.remove()
}
} }

View File

@ -11,19 +11,15 @@ export default class MobileDesktop{
} }
async load(){ async load(){
this.createMainDivs() let view = this.#createDesktopView()
} }
async createMainDivs(){ async #createDesktopView(){
let sunboardNode = document.body.querySelector("#mobile-sunboard") let view = await this.#wde.Decorat.CreateNewView("Sunboard") //FIXME
if (sunboardNode == null){
// this.#wde.Alert("Desktop node not found")
return
}
const params = new URLSearchParams({ const params = new URLSearchParams({
// path: args[0] //FIXME // path: args[0] //FIXME
path: "/" path: "/" //FIXME
}) })
const response = await fetch(`/app/Sunboard/render?` + params, const response = await fetch(`/app/Sunboard/render?` + params,
{ {
@ -36,21 +32,17 @@ export default class MobileDesktop{
return return
} }
const html = await response.text() const html = await response.text()
sunboardNode.innerHTML = html view.innerHTML = html
console.log(this.#wde.FileView) let iconsList = view.querySelectorAll(".app-icon")
iconsList.forEach(element => {
let iconsNode = document.body.querySelector("#icons") let appId = element.getAttribute('appId')
element.addEventListener('click', () => {
this.fileView = new this.#wde.FileView( // console.log(appId)
iconsNode, // this.#wde.Decorat.CreateNewView(appId)
(event) =>{}, this.#wde.Open("/Applications/Finder.app", [""], "")
(event) => { }, })
(event, draggedElem) => {}, });
() => { }
)
// this.RenderDir(args[0])
return
} }
async createFileView(){ async createFileView(){

View File

@ -18,10 +18,44 @@
background-color: @col-ceil; background-color: @col-ceil;
} }
#down-bar{ // #down-bar{
&:extend(.WdePrimitives.AdjectiveElement); // &:extend(.WdePrimitives.AdjectiveElement);
width: 100%; // width: 100%;
height: 150px; // height: 150px;
background-color: @col-argent; // background-color: @col-argent;
// }
.apps-list{
/* Auto layout */
display: flex;
padding: 64px 32px;
align-items: flex-start;
align-content: flex-start;
gap: 103px 18px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon{
width: 100px;
height: 100px;
/* Auto layout */
display: flex;
padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon{
width: 64px;
height: 64px;
background-color: beige;
}
.app-icon .lable{
} }

View File

@ -83,8 +83,6 @@ export default class WebDesktopEnvironment{
} else { } else {
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext) WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
} }
} }
/** /**

View File

@ -1,7 +1,8 @@
import MobileDecorat from "./decorat/mobile-decorat.js" import MobileDecorat from "./decorat/mobile-decorat.js"
import MobileSunboard from "./sunboard/sunboard-mobile.js" import MobileSunboard from "./sunboard/sunboard-mobile.js"
import AbstractWebDesktopEnvironment from "./wde.js"
import WDEFileView from "./widgets/file-view/file-view.js" import WDEFileView from "./widgets/file-view/file-view.js"
export default class MobileWebDesktopEnvironment{ export default class MobileWebDesktopEnvironment extends AbstractWebDesktopEnvironment{
/** @type {MobileDecorat} */ /** @type {MobileDecorat} */
Decorat Decorat
/** @type {WDEFileView} */ /** @type {WDEFileView} */
@ -9,14 +10,41 @@ export default class MobileWebDesktopEnvironment{
/** @type {MobileSunboard} */ /** @type {MobileSunboard} */
#sunBoard #sunBoard
constructor(){ constructor(){
super()
document.body.style.setProperty('--zoom', 3) document.body.style.setProperty('--zoom', 3)
this.Decorat = new MobileDecorat() this.Decorat = new MobileDecorat()
this.FileView = WDEFileView this.FileView = WDEFileView
this.#sunBoard = new MobileSunboard(this) this.#sunBoard = new MobileSunboard(this)
this.#sunBoard this.loadWDE()
} }
loadWDE(){ loadWDE(){
this.#initControlsBar()
}
/**
* @param {string} appPath
* @param {string[]} args
* @param {string} runPath
*/
async Open(appPath, args, runPath){
super._Open(appPath, args, runPath, async (appManifest, runContext) => {
console.log(super._GetApp(appManifest.appId))
// console.log(super())
let contentView = await super._GetApp(appManifest.appId).NewWindow(args, runContext)
let view = this.Decorat.CreateNewView()
console.log(view)
view.appendChild(contentView)
// super._GetApp
})
}
#initControlsBar(){
let barNode = document.body.querySelector("#controls-bar")//TODO Validate
barNode.querySelector("#back").addEventListener('click', () => {
this.Decorat.BackAction()
})
} }
} }

78
front/src/wde/wde.js Normal file
View File

@ -0,0 +1,78 @@
import WDEApplication from "./application.js"
export default class AbstractWebDesktopEnvironment{
/** @type {Object<string, WDEApplication>} */
_applications = {}
constructor(){
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
async _FetchAppManifest(path){
console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
// WebDesktopEnvironment.Alert(error.message) //FIXME
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} appPath
* @param {string[]} args
* @param {string} runPath
* @param {callback} function
*/
async _Open(appPath, args, runPath, callback){
const appManifest = await this._FetchAppManifest(appPath)
if (appManifest === undefined) return //TODO return err
/**@type {runContext} */
const runContext = {
WDE: this,
isMobile: true,
bundlePath: appPath,
runPath: runPath
}
if (this._applications[appManifest.appId] === undefined){
this.#loadApp(appManifest, () => {
callback(appManifest, runContext)
})
} else {
callback(appManifest, runContext)
}
}
/**
* @param {*} appManifest
* @param {function} onload callback after script loading
*/
async #loadApp(appManifest, onload){
// console.log(appManifest)
// import(window.location.origin + appManifest.js[0]).then((app) => {
// console.log(window.location.origin + appManifest.js[0] == 'http://localhost:8080/res/dev-fs/wde/dist/finder.js')
// let kek = 'http://localhost:8080/res/dev-fs/wde/dist/finder.js'
import('http://localhost:8080/res/dev-fs/dist/finder.js').then((app) => {
let newApp = new app.default()
// if newApp //TODO Validate
this._applications[appManifest.appId] = newApp;
onload()
})
return //TODO return result
}
_GetApp(appId){
console.log(appId)
return this._applications[appId]
}
}

View File

@ -73,7 +73,7 @@ func main() {
imgViewerApp := imgviewer.NewImgViewerApp(webfs) imgViewerApp := imgviewer.NewImgViewerApp(webfs)
blogViewerApp := blogviewer.NewBlogViewerApp(webfs) blogViewerApp := blogviewer.NewBlogViewerApp(webfs)
blogWriterApp := blogwriter.NewBlogWriterApp(webfs) blogWriterApp := blogwriter.NewBlogWriterApp(webfs)
sunBoardApp := sunboard.NewSunboardApp(webfs) sunBoardApp := sunboard.NewSunboardApp(webfs, appsStorage)
appsStorage.Apps["personal-properties"] = persPropsApp appsStorage.Apps["personal-properties"] = persPropsApp
appsStorage.Apps["finder"] = finderApp appsStorage.Apps["finder"] = finderApp
appsStorage.Apps["img-viewer"] = imgViewerApp appsStorage.Apps["img-viewer"] = imgViewerApp

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -2,7 +2,7 @@
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/mobile.less ***! !*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/mobile.less ***!
\**********************************************************************************************************/ \**********************************************************************************************************/
.WdePrimitives.AdjectiveElement, .WdePrimitives.AdjectiveElement,
#down-bar { #controls-bar {
border: 1px solid #555555; border: 1px solid #555555;
} }
#mobile-sunboard { #mobile-sunboard {
@ -19,10 +19,31 @@
height: 100%; height: 100%;
background-color: #9999CC; background-color: #9999CC;
} }
#down-bar { .apps-list {
width: 100%; /* Auto layout */
height: 150px; display: flex;
background-color: #C0C0C0; padding: 64px 32px;
align-items: flex-start;
align-content: flex-start;
gap: 103px 18px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon {
width: 100px;
height: 100px;
/* Auto layout */
display: flex;
padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon {
width: 64px;
height: 64px;
background-color: beige;
} }
body { body {
zoom: var(--zoom); zoom: var(--zoom);
@ -45,5 +66,28 @@ body {
/* Non-prefixed version, currently /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */ supported by Chrome, Edge, Opera and Firefox */
touch-action: manipulation; touch-action: manipulation;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
#mobile-app-views {
width: 100%;
height: 100%;
}
#controls-bar {
width: 100%;
height: 150px;
background-color: #C0C0C0;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.mobile-app-view {
width: 100%;
height: 100%;
} }

149
res/dev-fs/wde/dist/desktop.js vendored Normal file

File diff suppressed because one or more lines are too long

159
res/dev-fs/wde/dist/finder.js vendored Normal file

File diff suppressed because one or more lines are too long

14
res/dev-fs/wde/dist/init.js vendored Normal file
View File

@ -0,0 +1,14 @@
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/
/******/
/******/ })()
;

49
res/dev-fs/wde/dist/mobile.js vendored Normal file
View File

@ -0,0 +1,49 @@
/*
* ATTENTION: The "eval" devtool has been used (maybe by default in mode: "development").
* This devtool is neither made for production nor for readable output files.
* It uses "eval()" calls to create a separate source file in the browser devtools.
* If you are trying to read the output file, select a different devtool (https://webpack.js.org/configuration/devtool/)
* or disable the default devtool with "devtool: false".
* If you are looking for production-ready output files, see mode: "production" (https://webpack.js.org/configuration/mode/).
*/
/******/ (() => { // webpackBootstrap
/******/ "use strict";
/******/ var __webpack_modules__ = ({
/***/ "./src/mobile.js":
/*!***********************!*\
!*** ./src/mobile.js ***!
\***********************/
/***/ ((__unused_webpack___webpack_module__, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\nObject(function webpackMissingModule() { var e = new Error(\"Cannot find module './wde/wde-mobile'\"); e.code = 'MODULE_NOT_FOUND'; throw e; }());\n\nrequire(\"./mobile.less\");\ndocument.addEventListener('DOMContentLoaded', function () {\n var wde = new Object(function webpackMissingModule() { var e = new Error(\"Cannot find module './wde/wde-mobile'\"); e.code = 'MODULE_NOT_FOUND'; throw e; }())();\n}, false);\n\n//# sourceURL=webpack://my-webpack-project/./src/mobile.js?");
/***/ })
/******/ });
/************************************************************************/
/******/ // The require scope
/******/ var __webpack_require__ = {};
/******/
/************************************************************************/
/******/ /* webpack/runtime/make namespace object */
/******/ (() => {
/******/ // define __esModule on exports
/******/ __webpack_require__.r = (exports) => {
/******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) {
/******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' });
/******/ }
/******/ Object.defineProperty(exports, '__esModule', { value: true });
/******/ };
/******/ })();
/******/
/************************************************************************/
/******/
/******/ // startup
/******/ // Load entry module and return exports
/******/ // This entry module can't be inlined because the eval devtool is used.
/******/ var __webpack_exports__ = {};
/******/ __webpack_modules__["./src/mobile.js"](0, __webpack_exports__, __webpack_require__);
/******/
/******/ })()
;

View File

@ -11,8 +11,22 @@
// console.log(WebDesktopEnvironment) // console.log(WebDesktopEnvironment)
let kek = new WebDesktopEnvironment.default() let kek = new WebDesktopEnvironment.default()
</script> </script>
<div id="mobile-sunboard"> <!-- <div id="mobile-sunboard">
</div> -->
<div id="mobile-app-views"></div>
<div id="controls-bar">
<div id="back" class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
</div>
<div class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
</div>
<div class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
</div>
</div> </div>
<div id="applications"></div>
</body> </body>
</html> </html>

View File

@ -1,6 +1,15 @@
{{ define "sunboard/sunboard.html" }} {{ define "sunboard/sunboard.html" }}
<div id="icons"></div> <div id="icons">
<div id="down-bar"></div> <div class="apps-list NoClick">
{{ range $appIcon := .AppsIcons }}
<div fileType="{{ $appIcon.Type }}" class="app-icon Click" appId="{{$appIcon.AppId}}" name="{{$appIcon.Lable}}">
<!-- <div class="Icon NoClick"></div> -->
<img class="icon NoClick" src="{{ $appIcon.Icon }}">
<div class="lable NoClick">{{ $appIcon.Lable }}</div>
</div>
{{ end }}
</div>
</div>
{{ end }} {{ end }}