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 (
"net/http"
"personalwebsite/apps"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type SunboardApp struct {
fs *webfilesystem.WebFileSystem
appID string
fs *webfilesystem.WebFileSystem
appID string
appStorage *apps.ApplicationsStorage
}
func NewSunboardApp(webFs *webfilesystem.WebFileSystem) *SunboardApp {
func NewSunboardApp(webFs *webfilesystem.WebFileSystem, appStorage *apps.ApplicationsStorage) *SunboardApp {
newApp := SunboardApp{
fs: webFs,
appID: "Sunboard",
fs: webFs,
appID: "Sunboard",
appStorage: appStorage,
}
return &newApp
}
@ -30,6 +33,28 @@ func (a *SunboardApp) PublicRoutes(route *gin.RouterGroup) {
func (a *SunboardApp) PrivateRoutes(router *gin.RouterGroup) {
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){
this.#finder = finder
this.#wde = runContext.WDE
if (runContext.isMobile){
this.CreateMobileView(args, runContext)
return
}
if (args[1] == "--desktop"){
let desktopNode = document.body.querySelector(`#${args[2]}`)
if (desktopNode == null){
@ -98,6 +102,33 @@ export default class FinderWindow{
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
*/

View File

@ -18,12 +18,21 @@ export default class Finder extends WDEApplication{
/**
* @param {string[]} args
* @param {import("../../wde/wde-desktop.js").runContext}
* @param {import("../../wde/wde-desktop.js").runContext} runContext
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
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
supported by Chrome, Edge, Opera and Firefox */
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 {
/** @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(){
this.createMainDivs()
let view = this.#createDesktopView()
}
async createMainDivs(){
let sunboardNode = document.body.querySelector("#mobile-sunboard")
if (sunboardNode == null){
// this.#wde.Alert("Desktop node not found")
return
}
async #createDesktopView(){
let view = await this.#wde.Decorat.CreateNewView("Sunboard") //FIXME
const params = new URLSearchParams({
// path: args[0] //FIXME
path: "/"
path: "/" //FIXME
})
const response = await fetch(`/app/Sunboard/render?` + params,
{
@ -36,21 +32,17 @@ export default class MobileDesktop{
return
}
const html = await response.text()
sunboardNode.innerHTML = html
view.innerHTML = html
console.log(this.#wde.FileView)
let iconsNode = document.body.querySelector("#icons")
this.fileView = new this.#wde.FileView(
iconsNode,
(event) =>{},
(event) => { },
(event, draggedElem) => {},
() => { }
)
// this.RenderDir(args[0])
return
let iconsList = view.querySelectorAll(".app-icon")
iconsList.forEach(element => {
let appId = element.getAttribute('appId')
element.addEventListener('click', () => {
// console.log(appId)
// this.#wde.Decorat.CreateNewView(appId)
this.#wde.Open("/Applications/Finder.app", [""], "")
})
});
}
async createFileView(){

View File

@ -18,10 +18,44 @@
background-color: @col-ceil;
}
#down-bar{
&:extend(.WdePrimitives.AdjectiveElement);
width: 100%;
height: 150px;
background-color: @col-argent;
// #down-bar{
// &:extend(.WdePrimitives.AdjectiveElement);
// width: 100%;
// height: 150px;
// 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 {
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
}
}
/**

View File

@ -1,7 +1,8 @@
import MobileDecorat from "./decorat/mobile-decorat.js"
import MobileSunboard from "./sunboard/sunboard-mobile.js"
import AbstractWebDesktopEnvironment from "./wde.js"
import WDEFileView from "./widgets/file-view/file-view.js"
export default class MobileWebDesktopEnvironment{
export default class MobileWebDesktopEnvironment extends AbstractWebDesktopEnvironment{
/** @type {MobileDecorat} */
Decorat
/** @type {WDEFileView} */
@ -9,14 +10,41 @@ export default class MobileWebDesktopEnvironment{
/** @type {MobileSunboard} */
#sunBoard
constructor(){
super()
document.body.style.setProperty('--zoom', 3)
this.Decorat = new MobileDecorat()
this.FileView = WDEFileView
this.#sunBoard = new MobileSunboard(this)
this.#sunBoard
this.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)
blogViewerApp := blogviewer.NewBlogViewerApp(webfs)
blogWriterApp := blogwriter.NewBlogWriterApp(webfs)
sunBoardApp := sunboard.NewSunboardApp(webfs)
sunBoardApp := sunboard.NewSunboardApp(webfs, appsStorage)
appsStorage.Apps["personal-properties"] = persPropsApp
appsStorage.Apps["finder"] = finderApp
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 ***!
\**********************************************************************************************************/
.WdePrimitives.AdjectiveElement,
#down-bar {
#controls-bar {
border: 1px solid #555555;
}
#mobile-sunboard {
@ -19,10 +19,31 @@
height: 100%;
background-color: #9999CC;
}
#down-bar {
width: 100%;
height: 150px;
background-color: #C0C0C0;
.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;
}
body {
zoom: var(--zoom);
@ -45,5 +66,28 @@ body {
/* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
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)
let kek = new WebDesktopEnvironment.default()
</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 id="applications"></div>
</body>
</html>

View File

@ -1,6 +1,15 @@
{{ define "sunboard/sunboard.html" }}
<div id="icons"></div>
<div id="down-bar"></div>
<div id="icons">
<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 }}