Compare commits

...

30 Commits

Author SHA1 Message Date
264a8d38d6 update ignore 2023-07-24 03:31:56 +03:00
38c1d03755 delete build files 2023-07-24 03:31:25 +03:00
71d5e34e49 update gitignore 2023-07-24 03:29:37 +03:00
5ff8696ea4 Delete files 2023-07-24 03:29:27 +03:00
74cb1ced32 add .env to ignore 2023-07-24 03:28:32 +03:00
e76c55f2c3 fixes 2023-07-24 03:27:53 +03:00
3b5b00f5b0 more work 2023-07-23 06:12:17 +03:00
b79b65868c icons and title-bar as widget 2023-07-23 02:55:08 +03:00
766b7ac4bf Merge branch 'webpack' of http://192.168.88.228:9101/cyber-dream/personal-website into webpack 2023-07-23 01:01:03 +03:00
d1c5e8ea15 mobile finder 2023-07-23 01:00:51 +03:00
559c22f626 Fix wde fs import 2023-07-22 21:16:00 +03:00
265f57e2de rename finder template 2023-07-22 21:15:42 +03:00
46e3bcf865 Add obsolete notation 2023-07-22 21:15:17 +03:00
68664c1bf3 Add todo 2023-07-22 18:56:51 +03:00
3636cb86e2 New icons format 2023-07-22 18:55:23 +03:00
9f60c185ad fixes 2023-07-22 04:10:00 +03:00
ec9ef532f6 delete duplicates 2023-07-22 04:05:34 +03:00
71431790b5 quick fix aboutme 2023-07-22 03:50:58 +03:00
41bd2a43b8 finder rework 2023-07-22 03:48:45 +03:00
bd0f77b1b6 Add todo to line in wde 2023-07-21 17:44:01 +03:00
bc71ca9682 Fix deprecated variable use 2023-07-21 17:43:37 +03:00
c5c277f516 working mobile and desktop 2023-07-21 04:42:12 +03:00
d018477fe3 trys 2023-07-21 01:05:06 +03:00
d61fa2bd4b Working mobile and desktop views 2023-07-20 02:11:53 +03:00
edf011fccd Working mobile wde 2023-07-19 19:38:28 +03:00
186ea27db8 Trys with mobile wde 2023-07-19 04:35:17 +03:00
cb1dfce2a9 Working desktop 2023-07-19 04:06:13 +03:00
0e9720d295 Merge branch 'refs/heads/main' into webpack 2023-07-19 01:23:06 +03:00
de0ad81615 Update apps 2023-07-18 23:47:12 +03:00
488f3a56b9 test webpack 2023-07-18 20:15:06 +03:00
96 changed files with 10218 additions and 283 deletions

5
.env
View File

@ -1,5 +0,0 @@
MONGO_CONNECT=mongodb://localhost:27017
DATABASE=personal-website
COLLECTION_WEBFS=webfs2
PUBLIC_PORT=7070
PRIVATE_PORT=8080

9
.gitignore vendored
View File

@ -22,4 +22,11 @@
go.work
/__debug_bin
/.env
.env
front/dist/*
front/node_modules
.parcel-cache
**/node_modules/
front/node_modules/*

View File

@ -1,14 +1,17 @@
package blogwriter
import (
"personalwebsite/apps"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type BlogWriterApplication struct {
fs *webfilesystem.WebFileSystem
appID string
fs *webfilesystem.WebFileSystem
appID string
path string
manifest apps.ApplicationManifest
}
func NewBlogWriterApp(webfs *webfilesystem.WebFileSystem) *BlogWriterApplication {
@ -17,11 +20,17 @@ func NewBlogWriterApp(webfs *webfilesystem.WebFileSystem) *BlogWriterApplication
appID: "BlogWriter",
}
}
func (bw *BlogWriterApplication) GetManifest() apps.ApplicationManifest {
return bw.manifest
}
func (bw *BlogWriterApplication) GetAppID() string {
return bw.appID
}
func (bw *BlogWriterApplication) GetPath() string {
return bw.path
}
func (bw *BlogWriterApplication) PublicRoutes(routes *gin.RouterGroup) {}
func (bw *BlogWriterApplication) PrivateRoutes(routes *gin.RouterGroup) {

View File

@ -5,9 +5,11 @@ import (
"html/template"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"personalwebsite/libs"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
@ -15,19 +17,41 @@ import (
)
type AboutMeApp struct {
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
titleBarConfig wde.TitleBarConfig //TODO to app manifest?
path string
manifest apps.ApplicationManifest
}
func NewAboutMeApp(webFs *webfilesystem.WebFileSystem) *AboutMeApp {
manifest := apps.ApplicationManifest{}
_, err := webFs.Read(path.Join("/Applications/AboutMe.app", ".appmanifest"), &manifest)
if err != nil {
panic(err)
}
newApp := AboutMeApp{
fs: webFs,
appID: "AboutMe",
path: "/Applications/AboutMe.app",
titleBarConfig: wde.TitleBarConfig{
Lable: "About Me",
CloseButton: true,
HasIcon: true,
IconPath: "/Icons/GenericApp.icn",
IconSize: "16",
},
manifest: manifest,
}
return &newApp
}
func (p *AboutMeApp) GetPath() string {
return p.path
}
func (p *AboutMeApp) GetManifest() apps.ApplicationManifest {
return p.manifest
}
func (p *AboutMeApp) PublicRoutes(route *gin.RouterGroup) {
route.POST("render", func(ctx *gin.Context) {
filePath := ctx.Query("path")
@ -57,13 +81,13 @@ func (p *AboutMeApp) PublicRoutes(route *gin.RouterGroup) {
func (p *AboutMeApp) PrivateRoutes(router *gin.RouterGroup) {
p.PublicRoutes(router)
// router.GET("writeMock", func(ctx *gin.Context) {
// err := p.WriteMock()
// if err != nil {
// ctx.Status(http.StatusInternalServerError)
// }
// ctx.Status(http.StatusOK)
// })
router.GET("writeMock", func(ctx *gin.Context) {
err := p.WriteMock()
if err != nil {
ctx.Status(http.StatusInternalServerError)
}
ctx.Status(http.StatusOK)
})
router.GET("getMock", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, PropertiesFileData{
@ -153,72 +177,22 @@ func (p *AboutMeApp) GetAppID() string {
return p.appID
}
// func (p *AboutMeApp) WriteMock() error {
// fileHeader := webfilesystem.FileHeader{
// MongoId: primitive.NewObjectID(),
// Name: "aboutme.props",
// Type: "personal-properties",
// Icon: "",
// }
// fileData := PropertiesFileData{
// Header: HeaderIsland{
// Name: "Test Name",
// IconPath: "test icon path",
// Info1: "Info1",
// Info2: "Info2",
// },
// Props: []PropIsland{
// {
// Header: "Test Prop Header",
// Props: []PropElement{
// {
// Key: "Test key",
// KeyComments: []string{"Test key comment 1", "Test key comment 1"},
// Values: []Value{
// {
// Blocks: []ValueBlock{
// {
// Type: "string",
// Data: []string{"aappo"},
// },
// {
// Type: "link",
// Data: []string{"https://ya.ru", "Azazaza"},
// },
// },
// },
// },
// },
// },
// },
// {
// Header: "Test Prop Header 2",
// Props: []PropElement{
// {
// Key: "Test key",
// KeyComments: []string{"Test key comment 1", "Test key comment 1"},
// Values: []Value{
// {
// Blocks: []ValueBlock{
// {
// Type: "string",
// Data: []string{"aappo"},
// },
// {
// Type: "link",
// Data: []string{"https://ya.ru", "Azazaza"},
// },
// },
// },
// },
// },
// },
// },
// },
// }
// _, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData)
// return err
// }
func (p *AboutMeApp) WriteMock() error {
fileHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: "aboutme.props",
Type: "personal-properties",
Icon: "",
}
fileData := PropertiesFileData{
Header: HeaderIsland{
Name: "Test Name",
IconPath: "test icon path",
},
}
_, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData)
return err
}
func (p *AboutMeApp) Read(filePath string) (*PropertiesFileData, error) {
propData := PropertiesFileData{}
@ -236,7 +210,12 @@ func (p *AboutMeApp) Edit(filePath string, blogData PropertiesFileData) error {
propsPath := path.Join(filePath, "aboutme.props")
fileHeader, err := p.fs.Read(propsPath, nil)
if err != nil {
return err
if err.Error() == "file not found" { //FIXME
p.WriteMock()
p.Edit(filePath, blogData)
} else {
return err
}
}
if fileHeader.Type != "personal-properties" {
return errors.New("wrong file type")
@ -298,9 +277,10 @@ func (p *AboutMeApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, e
}
return gin.H{
"HeaderProps": propsData.Header,
"Links": absoluteLinks,
"Islands": renderedIslands,
"TitleBarConfig": p.titleBarConfig,
"HeaderProps": propsData.Header,
"Links": absoluteLinks,
"Islands": renderedIslands,
}, nil
}

View File

@ -1,5 +1,6 @@
package appCtx
//TODO to websiteapp package
type AppContext struct {
IsMobile bool `json:"isMobile"`
BundlePath string `json:"bundlePath"`

View File

@ -4,6 +4,7 @@ import (
"errors"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"personalwebsite/libs"
@ -14,9 +15,11 @@ import (
)
type BlogViewerApplication struct {
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
path string
manifest apps.ApplicationManifest
}
func NewBlogViewerApp(webFs *webfilesystem.WebFileSystem) *BlogViewerApplication {
@ -26,10 +29,18 @@ func NewBlogViewerApp(webFs *webfilesystem.WebFileSystem) *BlogViewerApplication
mLib: libs.MarkdownLib{},
}
}
func (b *BlogViewerApplication) GetManifest() apps.ApplicationManifest {
return b.manifest
}
func (b *BlogViewerApplication) GetAppID() string {
return b.appID
}
func (b *BlogViewerApplication) GetPath() string {
return b.path
}
func (b *BlogViewerApplication) PrivateRoutes(route *gin.RouterGroup) {
b.PublicRoutes(route)

View File

@ -1,6 +1,8 @@
package finder
import (
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
@ -9,24 +11,49 @@ import (
)
type FinderApplication struct {
fs *webfilesystem.WebFileSystem
appID string
fs *webfilesystem.WebFileSystem
appID string
titleBarConfig wde.TitleBarConfig
path string
manifest apps.ApplicationManifest
// manifest apps.ApplicationManifest
}
func NewFinderApplication(webFs *webfilesystem.WebFileSystem) *FinderApplication {
manifest := apps.ApplicationManifest{}
_, err := webFs.Read(path.Join("/Applications/Finder.app", ".appmanifest"), &manifest)
if err != nil {
panic(err)
}
return &FinderApplication{
fs: webFs,
path: "/Applications/Finder.app",
appID: "Finder",
titleBarConfig: wde.TitleBarConfig{
Lable: "Finder",
CloseButton: true,
HasIcon: true,
IconPath: "/Icons/GenericFolder.icn",
IconSize: "16",
},
manifest: manifest,
}
}
func (f *FinderApplication) GetManifest() apps.ApplicationManifest {
return f.manifest
}
func (f *FinderApplication) GetAppID() string {
return f.appID
}
func (f *FinderApplication) GetPath() string {
return f.path
}
func (f *FinderApplication) Render(appCtx appCtx.AppContext) gin.H {
return gin.H{}
return gin.H{
"TitleBarConfig": f.titleBarConfig,
}
}
func (f *FinderApplication) RenderPublicContextMenu(context string, filePath string, data string) gin.H {

View File

@ -5,6 +5,7 @@ import (
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
mobile "github.com/floresj/go-contrib-mobile"
"github.com/gin-gonic/gin"
)
@ -18,12 +19,22 @@ func (f *FinderApplication) PublicRoutes(routes *gin.RouterGroup) {
})
return
}
ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(appCtx))
d := mobile.GetDevice(ctx)
switch {
case d.Mobile():
ctx.HTML(http.StatusOK, "templates/finder/mobile-app.tmpl", gin.H{
// "autostart": autostart,
})
default:
ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(appCtx))
}
})
//Obsolete
routes.GET("renderMobileDesktop", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "finder/mobile-desktop.tmpl", gin.H{})
})
routes.POST("renderDesktop", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
@ -66,7 +77,13 @@ func (f *FinderApplication) PrivateRoutes(routes *gin.RouterGroup) {
})
return
}
ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(appCtx))
d := mobile.GetDevice(ctx)
switch {
case d.Mobile():
ctx.HTML(http.StatusOK, "finder/mobile-app.tmpl", f.Render(appCtx))
default:
ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(appCtx))
}
})
routes.GET("renderMobileDesktop", func(ctx *gin.Context) {

View File

@ -2,14 +2,17 @@ package imgviewer
import (
"net/http"
"personalwebsite/apps"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type ImgViewerApp struct {
fs *webfilesystem.WebFileSystem
appID string
fs *webfilesystem.WebFileSystem
appID string
path string
manifest apps.ApplicationManifest
}
func NewImgViewerApp(webFs *webfilesystem.WebFileSystem) *ImgViewerApp {
@ -22,6 +25,9 @@ func NewImgViewerApp(webFs *webfilesystem.WebFileSystem) *ImgViewerApp {
func (p *ImgViewerApp) PrivateRoutes(route *gin.RouterGroup) {
p.PublicRoutes(route)
}
func (i *ImgViewerApp) GetManifest() apps.ApplicationManifest {
return i.manifest
}
func (p *ImgViewerApp) PublicRoutes(route *gin.RouterGroup) {
route.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
@ -44,6 +50,10 @@ func (p *ImgViewerApp) PublicRoutes(route *gin.RouterGroup) {
})
}
func (p *ImgViewerApp) GetPath() string {
return p.path
}
func (p *ImgViewerApp) GetAppID() string {
return p.appID
}

86
apps/sunboard/sunboard.go Normal file
View File

@ -0,0 +1,86 @@
package sunboard
import (
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type SunboardApp struct {
fs *webfilesystem.WebFileSystem
wde *wde.WDE
appID string
appStorage *apps.ApplicationsStorage
path string
manifest apps.ApplicationManifest
}
func NewSunboardApp(webFs *webfilesystem.WebFileSystem, wde *wde.WDE, appStorage *apps.ApplicationsStorage) *SunboardApp {
manifest := apps.ApplicationManifest{}
_, err := webFs.Read(path.Join("/Applications/Sunboard.app", ".appmanifest"), &manifest)
if err != nil {
panic(err)
}
newApp := SunboardApp{
fs: webFs,
wde: wde,
appID: "Sunboard",
appStorage: appStorage,
path: "/Applications/Sunboard.app",
manifest: manifest,
}
return &newApp
}
func (a *SunboardApp) GetAppID() string {
return a.appID
}
func (a *SunboardApp) PublicRoutes(route *gin.RouterGroup) {
}
func (a *SunboardApp) GetPath() string {
return a.path
}
func (a *SunboardApp) GetManifest() apps.ApplicationManifest {
return a.manifest
}
func (a *SunboardApp) PrivateRoutes(router *gin.RouterGroup) {
router.POST("render", func(ctx *gin.Context) {
appIcons := []appIcon{}
for _, app := range a.appStorage.Apps {
if app.GetAppID() == "Sunboard" { //FIXME
continue
}
if app.GetManifest().Iconpath == "" {
continue
}
println(app.GetAppID() + " : " + app.GetPath())
// iconPath := path.Join(, "icon.icn")
appIcons = append(appIcons, appIcon{
Type: "Icon",
Icon: "/system/libs/img/icon/get?path=" + app.GetManifest().Iconpath + "&size=32",
Lable: app.GetAppID(),
AppId: app.GetAppID(),
Path: app.GetPath(),
})
}
ctx.HTML(http.StatusOK, "sunboard/sunboard.html", gin.H{
"AppsIcons": appIcons,
})
})
}
type appIcon struct {
AppId string
Type string
Icon string
Lable string
Path string
}

View File

@ -15,15 +15,17 @@ type WebDEApplication interface {
GetAppID() string
PublicRoutes(*gin.RouterGroup)
PrivateRoutes(*gin.RouterGroup)
// GetManifest() ApplicationManifest //TODO: Delete
GetPath() string
GetManifest() ApplicationManifest
// GEtHtml()
// GetId() string
}
type ApplicationManifest struct {
AppId string `bson:"appid" json:"appId"`
Js []string `bson:"js" json:"js"`
Css []string `bson:"css" json:"css"`
AppId string `bson:"appid" json:"appId"`
Js []string `bson:"js" json:"js"`
Css []string `bson:"css" json:"css"`
Iconpath string `bson:"iconpath" json:"iconpath"`
}
func NewApplicationsStorage(apps map[string]WebDEApplication, webfs *webfilesystem.WebFileSystem) *ApplicationsStorage {

BIN
front/dist/Charcoal.cb9045e5.woff2 vendored Normal file

Binary file not shown.

BIN
front/dist/Geneva.41461b69.woff2 vendored Normal file

Binary file not shown.

157
front/dist/apps/about-me/about-me.css vendored Normal file
View File

@ -0,0 +1,157 @@
@font-face {
font-family: Geneva;
src: url("../../Geneva.41461b69.woff2");
}
@font-face {
font-family: Charcoal;
src: url("../../Charcoal.cb9045e5.woff2");
}
.large-system-font, .ShortBio > .Text > .Name, .Island .Title, .Island .Key {
letter-spacing: .35px;
font-family: Charcoal;
font-size: 12px;
}
.small-system-font, .views-font {
font-family: Geneva;
}
.PersPropsContent {
flex-direction: row;
justify-content: center;
align-items: flex-start;
width: 100%;
height: 100%;
padding: 0;
display: flex;
}
.PersPropsContent .PropsView {
width: 100%;
height: auto;
}
.PropertiesList {
flex-direction: column;
flex-grow: 0;
order: 0;
align-self: flex-start;
align-items: flex-start;
gap: 16px;
padding: 12px;
display: flex;
}
.PropertiesList .ShortBio {
flex-direction: row;
align-items: center;
gap: 15px;
width: 100%;
display: flex;
}
.ShortBio .Image {
width: 48px;
height: 48px;
padding-left: 10px;
}
.ShortBio .Text {
align-self: stretch;
align-items: left;
flex-direction: column;
flex: 1 0 auto;
order: 0;
gap: 1px;
padding: 0;
display: flex;
}
.PropertiesList .Links {
flex-direction: column;
justify-content: center;
align-items: end;
width: auto;
height: auto;
padding: 0;
display: flex;
}
.Links > a {
flex-direction: row;
justify-content: center;
align-items: end;
gap: 2px;
padding: 0;
display: flex;
}
.PropertiesList .Links .Link {
width: 16px;
height: 16px;
}
.PropertiesList .Island {
border: 1px solid #888;
width: 100%;
height: auto;
padding-bottom: 10px;
box-shadow: 1px 1px #fff, inset 1px 1px #fff;
}
.Island .Title {
background-color: #ddd;
max-width: 100%;
display: inline-block;
position: relative;
top: -9px;
left: 12px;
}
.Island .Content {
flex-direction: column;
justify-content: center;
gap: 12px;
width: 100%;
padding: 0;
display: flex;
}
.Island .Row {
flex-direction: row;
justify-content: center;
gap: 5px;
margin-left: 12px;
margin-right: 12px;
padding: 0;
display: flex;
}
.Island .Key {
text-align: end;
white-space: nowrap;
width: 34%;
position: relative;
top: -1.5px;
}
.Island .KeyComment {
color: #646464;
text-align: end;
white-space: normal;
font-size: 9px;
font-style: italic;
}
.Island .Values {
flex-direction: column;
justify-content: left;
gap: 5px;
width: 55%;
padding: 0;
display: flex;
}
/*# sourceMappingURL=about-me.css.map */

View File

@ -0,0 +1 @@
{"mappings":"ACiBA;;;;;AAKA;;;;;AAKA;;;;;;AAMA;;;;AD/BA;;;;;;;;;;AAYA;;;;;AAKA;;;;;;;;;;;AAkBA;;;;;;;;AAsBA;;;;;;AAMA;;;;;;;;;;;AAuBA;;;;;;;;;;AAiBA;;;;;;;;;AAeA;;;;;AAMA;;;;;;;;AAeA;;;;;;;;;AAWA;;;;;;;;;AAWA;;;;;;;;;;AAUA;;;;;;;;AAcA;;;;;;;;AAUA","sources":["src/apps/about-me/about-me.less","src/theme.less"],"sourcesContent":["@import \"../../theme.less\";\n\n.PersPropsContent{\n width: 100%;\n height: 100%;\n\n /* Auto layout */\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: flex-start;\n padding: 0px;\n}\n\n.PersPropsContent .PropsView{\n /* background-color: rebeccapurple; */\n width: 100%;\n height: auto;\n}\n.PropertiesList{\n /* width: 100%;\n height: auto; */\n\n /* Inside auto layout */\n order: 0;\n align-self: flex-start;\n flex-grow: 0;\n\n /* Auto layout */\n display: flex;\n flex-direction: column;\n align-items: flex-start;\n padding: 12px;\n gap:16px;\n}\n\n\n.PropertiesList .ShortBio{\n /* width: 100%;\n height: auto; */\n /* margin-right: -20px; */\n\n // background-color: aquamarine;\n /* Inside auto layout */\n width: 100%;\n // flex: none;\n // order: 0;\n // align-self: stretch;\n // flex-grow: 1;\n\n /* Auto layout */\n display: flex;\n flex-direction: row;\n align-items: center;\n // padding: 0px;\n // margin-right: 20;\n gap:15px;\n}\n\n.ShortBio .Image{\n width: 48px;\n height: 48px;\n padding-left: 10px;\n}\n\n.ShortBio .Text{\n /* width: 100%;\n height: auto; */\n\n /* Inside auto layout */\n flex: none;\n order: 0;\n align-self: stretch;\n flex-grow: 1;\n \n /* Auto layout */\n display: flex;\n flex-direction: column;\n align-items: left;\n padding: 0px;\n gap:1px;\n}\n\n.ShortBio > .Text > .Name{\n &:extend(.large-system-font);\n // background-color: aqua;\n}\n\n.PropertiesList .Links {\n // position: absolute;\n // right: 14px;\n // top: 27px;\n // background-color: aqua;\n height: auto;\n width: auto;\n\n // background-color: aqua;\n /* Auto layout */\n display: flex;\n flex-direction: column;\n align-items: end;\n justify-content: center;\n padding: 0px;\n // gap:4px;\n}\n.Links > a{\n /* Auto layout */\n display: flex;\n flex-direction: row;\n align-items: end;\n justify-content: center;\n padding: 0px;\n gap: 2px;\n}\n.Links > a > .link-lable{\n // background-color: aqua;\n // line-height: 60px;\n // display:table\n}\n\n.PropertiesList .Links .Link {\n /* background-color:brown; */\n width: 16px;\n height: 16px;\n}\n\n.PropertiesList .Island{\n width: 100%;\n height: auto;\n border: 1px solid #888888;\n box-shadow: 1px 1px 0px #FFFFFF, inset 1px 1px 0px #FFFFFF;\n padding-bottom: 10px;\n\n /* Auto layout */\n /* display: flex;\n flex-direction: column;\n align-items: center;\n padding: 0px;\n gap:1px; */\n}\n\n.Island .Title {\n //FIXME\n &:extend(.large-system-font);\n position:relative;\n display: inline-block;\n max-width: 100%;\n background-color: #DDDDDD;\n left: 12px;\n top: -9px;\n}\n\n.Island .Content{\n width: 100%;\n /* top: 0px; */\n /* Auto layout */\n display: flex;\n flex-direction: column;\n justify-content: center;\n padding: 0px;\n gap: 12px;\n}\n\n.Island .Row{\n margin-left: 12px;\n margin-right: 12px;\n /* Auto layout */\n display: flex;\n flex-direction: row;\n justify-content: center;\n padding: 0px;\n gap: 5px;\n}\n.Island .Key{\n position: relative;\n &:extend(.large-system-font);\n // font-family: \"Virtue\";\n // font-size: 11px;\n // letter-spacing: 0.35px;\n text-align: end;\n width: 34%;\n white-space: nowrap;\n top: -1.5px;\n\n /* font-weight: bold; */\n}\n\n.Island .KeyComment{\n /* color: rgb(129, 129, 129); TODO*/\n color: #646464;\n font-size: 9px;\n font-style: italic;\n text-align: end;\n white-space:normal;\n /* filter: drop-shadow(-.5px -.5px 0px #616161); */\n}\n\n.Island .Values{\n width: 55%;\n display: flex;\n flex-direction: column;\n justify-content: left;\n padding: 0px;\n gap: 5px;\n\n}\n\n.Values .Value{\n /* width: 55%; */\n\n}",null],"names":[],"version":3,"file":"about-me.css.map","sourceRoot":"/__parcel_source_root/"}

81
front/dist/apps/finder/finder.css vendored Normal file
View File

@ -0,0 +1,81 @@
@font-face {
font-family: Geneva;
src: url("../../Geneva.41461b69.woff2");
}
@font-face {
font-family: Charcoal;
src: url("../../Charcoal.cb9045e5.woff2");
}
.large-system-font {
letter-spacing: .35px;
font-family: Charcoal;
font-size: 12px;
}
.small-system-font, .views-font {
font-family: Geneva;
}
.adjective {
border: 1px solid #555;
}
.convex {
box-shadow: 1px 1px #00000040, inset -1px -1px #00000045, inset 1px 1px #fff;
}
.border .grey {
border: 1px solid #555;
}
.border .black {
border: 1px solid #000;
}
.shadow .grey {
box-shadow: 1px 1px #555;
}
.shadow .black {
box-shadow: 1px 1px #000;
}
.rows-fill-shadowed {
filter: drop-shadow(1px 1px #777);
background: linear-gradient(#0000 0%, #fff 0% 50%, #0000 50%) 0 0 / 2px 2px;
}
.finder-content {
flex-direction: column;
justify-content: start;
align-items: flex-start;
width: 100%;
height: 100%;
padding: 0;
display: flex;
}
.finder-content > .tool-bar {
border-bottom: 1px solid #555;
width: 100%;
min-height: 20px;
}
.window-frame.Focused .tool-bar {
border-bottom: 1px solid #000;
box-shadow: inset -1px -1px #00000045, inset 1px 1px #fff;
}
.finder-content > .file-view-container {
flex-direction: row;
justify-content: center;
align-items: flex-start;
width: 100%;
height: 100%;
padding: 0;
display: flex;
}
/*# sourceMappingURL=finder.css.map */

1
front/dist/apps/finder/finder.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"mappings":"ACiBA;;;;;AAKA;;;;;AAKA;;;;;;AAMA;;;;ACjCA;;;;AAIA;;;;AAMA;;;;AAAA;;;;AAUA;;;;AAAA;;;;AAWA;;;;;AF5BA;;;;;;;;;;AAYA;;;;;;AAMA;;;;;AAKA","sources":["src/apps/finder/finder.less","src/theme.less","src/wde/effects.less"],"sourcesContent":["@import \"../../theme.less\";\n@import \"../../wde/effects.less\";\n\n.finder-content {\n width: 100%;\n height: 100%;\n\n /* Auto layout */\n display: flex;\n flex-direction: column;\n justify-content: start;\n align-items: flex-start;\n padding: 0px;\n}\n\n.finder-content > .tool-bar{\n width: 100%;\n min-height: 20px;\n border-bottom: @eff-border-grey;\n}\n\n.window-frame.Focused .tool-bar{\n border-bottom: 1px solid #000000;\n box-shadow: @eff-box-shadow-convex;\n}\n\n.finder-content > .file-view-container{\n width: 100%;\n height: 100%;\n\n // background-color: #FFFFFF;\n\n /* Auto layout */\n display: flex;\n flex-direction: row;\n justify-content: center;\n align-items: flex-start;\n padding: 0px;\n}",null,null],"names":[],"version":3,"file":"finder.css.map","sourceRoot":"/__parcel_source_root/"}

370
front/dist/desktop.css vendored Normal file
View File

@ -0,0 +1,370 @@
.WdePrimitives .adjective {
border: 1px solid #555;
}
.WdePrimitives .black-border {
border: 1px solid #000;
}
.FileTileView {
width: 100%;
height: 100%;
}
.FileTileView.DragDropBorder {
box-shadow: inset 0 0 0 4px #99c;
}
.FileTileView .FlexContainer {
scrollbar-width: none;
-ms-overflow-style: none;
flex-flow: wrap;
place-content: flex-start;
align-items: flex-start;
gap: 20px 50px;
width: 100%;
height: auto;
margin: 15px;
display: flex;
}
.FileTileView::-webkit-scrollbar {
width: 0;
height: 0;
}
.FileTileView .Tile {
flex-flow: column;
justify-content: flex-start;
align-items: center;
gap: 2px;
width: 50px;
height: 50px;
padding: 0;
display: flex;
}
.FileTileView .Icon {
background-size: cover;
width: 32px;
height: 32px;
}
.FileTileView .Selected .Icon {
filter: brightness(.4);
}
.FileTileView .Lable {
white-space: nowrap;
}
.FileTileView .Selected .Lable {
white-space: nowrap;
color: #fff;
background-color: #000;
}
.scrollbar-place {
border-left: 1px solid #555;
flex: 1 0 auto;
order: 0;
align-self: stretch;
width: 14px;
height: 100%;
bottom: 0;
right: 0;
overflow: hidden;
}
.Focused .active .scrollbar-place {
background-color: #aaa;
border-left: 1px solid #000;
box-shadow: inset -1px 0 #ffffff4a, inset -2px 0 #ffffff30, inset 1px 1px #00000024, inset 2px 2px #00000030;
}
.scroll-element {
visibility: hidden;
background: #99f;
flex-direction: row;
justify-content: space-around;
align-items: center;
gap: 5px;
width: 14px;
height: 31px;
padding: 0;
display: flex;
position: relative;
box-shadow: 0 -1px #000, 0 1px #000, 0 2px #00000021, 0 3px #00000030, inset 0 1px #ffffff80, inset 1px 0 #ffffff80, inset -1px -1px #6666cce8;
}
.Focused .active .scroll-element {
visibility: visible;
}
.drag-element {
pointer-events: none;
filter: drop-shadow(1px 1px #339);
background: linear-gradient(#0000 0%, #ccf 0% 50%, #0000 50%) 0 0 / 2px 2px;
width: 7px;
height: 7px;
margin-left: -1px;
}
.ScrollContent {
scrollbar-width: none;
-ms-overflow-style: none;
overflow-x: hidden;
overflow-y: scroll;
}
.ScrollContent::-webkit-scrollbar {
width: 0;
height: 0;
}
.adjective {
border: 1px solid #555;
}
.convex {
box-shadow: 1px 1px #00000040, inset -1px -1px #00000045, inset 1px 1px #fff;
}
.border .grey {
border: 1px solid #555;
}
.border .black {
border: 1px solid #000;
}
.shadow .grey {
box-shadow: 1px 1px #555;
}
.shadow .black {
box-shadow: 1px 1px #000;
}
.rows-fill-shadowed, .window-frame.Focused .title-bar .visual-drag-area {
filter: drop-shadow(1px 1px #777);
background: linear-gradient(#0000 0%, #fff 0% 50%, #0000 50%) 0 0 / 2px 2px;
}
.wde-button {
background-color: #ddd;
border: 1px solid #000;
border-radius: 3px;
width: auto;
height: 20px;
box-shadow: inset -1px -1px #00000045, inset 1px 1px #fff;
}
.wde-button:active {
background-color: #666;
box-shadow: inset 1px 1px #00000045, inset -1px -1px gray;
}
.ContentBorder {
width: 100%;
height: 100%;
overflow: hidden;
}
.ContextMenu {
background-color: #ddd;
border: 1px solid #000;
width: auto;
height: auto;
position: absolute;
}
.ContextMenu .Content {
flex-direction: column;
align-items: flex-start;
width: auto;
height: auto;
display: flex;
position: relative;
}
.ContextMenu .Row {
width: 100%;
height: 16px;
}
.ContextMenu .Row:hover {
color: #fff;
background-color: #339;
}
.ContextMenu .Row .Lable {
white-space: nowrap;
margin-left: 20px;
margin-right: 12px;
font-family: Virtue;
}
@font-face {
font-family: Geneva;
src: url("Geneva.41461b69.woff2");
}
@font-face {
font-family: Charcoal;
src: url("Charcoal.cb9045e5.woff2");
}
.large-system-font, .title-bar .lable {
letter-spacing: .35px;
font-family: Charcoal;
font-size: 12px;
}
.small-system-font, .views-font, body {
font-family: Geneva;
}
.window-frame {
background-color: #ddd;
border: 1px solid #555;
flex-direction: column;
flex: 1 0 auto;
order: 1;
align-self: stretch;
align-items: flex-start;
gap: 4px;
padding: 2px 6px 4px 4px;
display: flex;
position: absolute;
box-shadow: 1px 1px #555;
}
.window-frame.Focused {
background-color: #ccc;
border: 1px solid #000;
box-shadow: 1px 1px #555, inset -1px -1px #00000045, inset 1px 1px #fff;
}
.content-border {
background-color: #eee;
border: 1px solid #555;
width: 100%;
height: 100%;
overflow: hidden;
}
.Focused .content-border {
background-color: #ddd;
border: 1px solid #000;
box-shadow: -1px -1px #00000040, 1px 1px #fff;
}
.title-bar {
flex-direction: row;
flex: none;
order: 0;
justify-content: center;
align-self: stretch;
align-items: center;
gap: 5px;
width: 100%;
height: 13px;
padding: 0;
display: flex;
}
.title-bar .lable {
color: gray;
pointer-events: none;
white-space: nowrap;
position: relative;
top: 1px;
}
.window-frame.Focused .title-bar .lable {
color: #000;
}
.window-frame.Focused .title-bar .visual-drag-area {
pointer-events: none;
width: 100%;
height: 11px;
}
.title-bar > .icon {
width: 16px;
height: 16px;
}
.title-bar > .button {
visibility: hidden;
background: linear-gradient(135deg, #999 18.18%, #fff 81.82%);
border: 1px solid #222;
flex: none;
order: 0;
width: 11px;
height: 11px;
padding: 0%;
position: relative;
top: 1px;
box-shadow: .5px .5px 0 .5px #fff, -.5px -.5px 0 .5px #00000040, inset 1px 1px #ffffff80, inset -1px -1px #00000045;
}
.title-bar > .button:active {
background-color: #0006;
box-shadow: .5px .5px 0 .5px #fff, -.5px -.5px 0 .5px #00000040;
}
.window-frame.Focused .title-bar > .button {
visibility: visible;
}
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
::-webkit-scrollbar {
width: 0;
height: 0;
}
body {
src: url("Geneva.41461b69.woff2");
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-select: none;
touch-action: manipulation;
width: 100%;
height: 100%;
margin: 0;
font-size: 11px;
position: absolute;
}
#applications {
visibility: hidden;
width: 0;
height: 0;
position: static;
}
#windows-layer {
width: 0;
height: 0;
position: static;
}
#desktop-layer {
background-color: #99c;
width: 100%;
height: 100%;
position: fixed;
}
/*# sourceMappingURL=desktop.css.map */

1
front/dist/desktop.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"mappings":"ACAA;;;;AAAA;;;;ACCA;;;;;AAWA;;;;AAKA;;;;;;;;;;;;;AAqBA;;;;;AAKA;;;;;;;;;;;AAkBA;;;;;;AAeA;;;;AAIA;;;;AAIA;;;;;;ACrEA;;;;;;;;;;;;AAsBA;;;;;;AASA;;;;;;;;;;;;;;;AAyBA;;;;AAIA;;;;;;;;;AAeA;;;;;;;AAgBA;;;;;AC1GA;;;;AAIA;;;;AAMA;;;;AAAA;;;;AAUA;;;;AAAA;;;;AAWA;;;;;AE5BA;;;;;;;;;AACI;;;;;ACJJ;;;;;;AAUA;;;;;;;;AAUA;;;;;;;;;AAgBA;;;;;AAYA;;;;;AAKA;;;;;;;ACpCA;;;;;AAKA;;;;;AAKA;;;;;;AAMA;;;;AC9BA;;;;;;;;;;;;;;;AAyBA;;;;;;AAOA;;;;;;;;AAUA;;;;;;AJ1CA;;;;;;;;;;;;;;AAmBA;;;;;;;;AAcA;;;;AAIA;;;;;;AAOA;;;;;AAOA;;;;;;;;;;;;;;AAQI;;;;;AAmBJ;;;;ALvEA;;;;AAGA;;;;AAYA;;;;;AAKA;;;;;;;;;;;;;;AAwBA;;;;;;;AAOA;;;;;;AAOA","sources":["src/desktop.less","src/wde/primitives.less","src/wde/widgets/file-view/file-view.less","src/wde/widgets/scrollbar/scrollbar.less","src/wde/effects.less","src/wde/widgets/title-bar/title-bar.less","src/wde/widgets/button/button.less","src/wde/widgets/basic-widgets.less","src/theme.less","src/wde/window-frame.less"],"sourcesContent":["@import \"./wde/primitives.less\";\n@import \"./wde/widgets/file-view/file-view.less\";\n@import \"./wde/widgets/scrollbar/scrollbar.less\";\n@import \"./wde/widgets/button/button.less\";\n// @import \"./wde/legacy-ui.less\";\n@import \"./wde/widgets/basic-widgets.less\";\n@import \"./theme.less\";\n@import \"./wde/window-frame.less\";\n@import \"./wde/widgets/title-bar/title-bar.less\";\n\n.NoClick {\n pointer-events: none;\n}\n.Click {\n pointer-events: all;\n}\n// .DragArea\n\n// *{\n// font-family: Verdana, Geneva, sans-serif;\n// font-size: 11px;\n// font-style: normal;\n// font-weight:initial;\n// }\n\n*::-webkit-scrollbar { /* WebKit */\n width: 0;\n height: 0;\n}\n\nbody{\n &:extend(.views-font);\n // zoom: var(--zoom);\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0px;\n\n font-size: 11px;\n\n // font-family: \"Geneva\";\n src:url(\"./fonts/Geneva.woff2\");\n\n /* font: normal 14px Summer Pixel 22, \"res/SummerPixel22Regular.ttf\"; */\n -webkit-touch-callout: none; /* iOS Safari */\n -webkit-user-select: none; /* Safari */\n -khtml-user-select: none; /* Konqueror HTML */\n -moz-user-select: none; /* Old versions of Firefox */\n -ms-user-select: none; /* Internet Explorer/Edge */\n user-select: none; /* Non-prefixed version, currently\n supported by Chrome, Edge, Opera and Firefox */\n touch-action: manipulation;\n}\n\n#applications{\n position: static;\n width: 0px;\n height: 0px;\n visibility: hidden;\n}\n\n#windows-layer {\n width: 0px;\n height: 0px;\n /* position: fixed; */\n position: static;\n}\n\n#desktop-layer{\n position: fixed;\n /* margin: 0px; */\n width: 100%;\n height: 100%;\n background-color: @col-ceil;\n}",null,null,null,null,null,null,null,null,null],"names":[],"version":3,"file":"desktop.css.map","sourceRoot":"/__parcel_source_root/"}

168
front/dist/mobile.css vendored Normal file
View File

@ -0,0 +1,168 @@
.WdePrimitives .adjective {
border: 1px solid #555;
}
.WdePrimitives .black-border {
border: 1px solid #000;
}
#mobile-sunboard {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
width: 100%;
height: 100%;
display: flex;
}
#icons {
width: 100%;
height: 100%;
}
.apps-list {
flex-wrap: wrap;
flex: 1 0 0;
align-content: flex-start;
align-self: stretch;
align-items: flex-start;
gap: 64px 0;
padding: 64px 16px;
display: flex;
}
.app-icon {
flex-direction: column;
align-items: center;
gap: 10px;
width: 100px;
display: flex;
}
.app-icon .icon {
width: 32px;
height: 32px;
}
@font-face {
font-family: Geneva;
src: url("Geneva.41461b69.woff2");
}
@font-face {
font-family: Charcoal;
src: url("Charcoal.cb9045e5.woff2");
}
.large-system-font {
letter-spacing: .35px;
font-family: Charcoal;
font-size: 12px;
}
.small-system-font, .views-font, body {
font-family: Geneva;
}
.adjective {
border: 1px solid #555;
}
.convex {
box-shadow: 1px 1px #00000040, inset -1px -1px #00000045, inset 1px 1px #fff;
}
.border .grey {
border: 1px solid #555;
}
.border .black {
border: 1px solid #000;
}
.shadow .grey {
box-shadow: 1px 1px #555;
}
.shadow .black {
box-shadow: 1px 1px #000;
}
.rows-fill-shadowed {
filter: drop-shadow(1px 1px #777);
background: linear-gradient(#0000 0%, #fff 0% 50%, #0000 50%) 0 0 / 2px 2px;
}
.wde-button, .wde-mobile-button {
background-color: #ddd;
border: 1px solid #000;
border-radius: 3px;
width: auto;
height: 20px;
box-shadow: inset -1px -1px #00000045, inset 1px 1px #fff;
}
.wde-button:active, .wde-mobile-button:active {
background-color: #666;
box-shadow: inset 1px 1px #00000045, inset -1px -1px gray;
}
@font-face {
font-family: Geneva;
src: url("Geneva.41461b69.woff2");
}
body {
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-select: none;
touch-action: manipulation;
background-color: silver;
background-position: 0 0, 0 0, -5px -5px, 5px 5px;
background-size: 10px 10px;
width: 100%;
height: 100%;
margin: 0;
font-size: 12px;
position: absolute;
}
#mobile-app-views {
background: #ddd;
border: 1px solid #000;
border-radius: 5px;
position: absolute;
inset: 16px 16px 100px;
overflow: hidden;
box-shadow: 1px 1px #000;
}
#controls-bar {
justify-content: center;
align-self: stretch;
align-items: center;
gap: 53px;
width: 100%;
height: 100px;
display: flex;
position: absolute;
bottom: 0;
}
.mobile-app-view {
width: 100%;
height: 100%;
}
.wde-mobile-button {
flex-direction: row;
justify-content: center;
align-items: center;
width: 95px;
height: 35px;
padding-right: 5px;
display: flex;
}
/*# sourceMappingURL=mobile.css.map */

1
front/dist/mobile.css.map vendored Normal file
View File

@ -0,0 +1 @@
{"mappings":"ACAA;;;;AAAA;;;;ACGA;;;;;;;;;AAWA;;;;;AAaA;;;;;;;;;;;AAYA;;;;;;;;AAaA;;;;;ACnCA;;;;;AAKA;;;;;AAKA;;;;;;AAMA;;;;ACjCA;;;;AAIA;;;;AAMA;;;;AAAA;;;;AAUA;;;;AAAA;;;;AAWA;;;;;AC5BA;;;;;;;;;AACI;;;;;ALCJ;;;;;AAKA;;;;;;;;;;;;;;;;AAwCA;;;;;;;;;;AAaA;;;;;;;;;;;;AAiBA;;;;;AAOA","sources":["src/mobile.less","src/wde/primitives.less","src/wde/sunboard/sunboard-mobile.less","src/theme.less","src/wde/effects.less","src/wde/widgets/button/button.less"],"sourcesContent":["@import \"./wde/sunboard/sunboard-mobile.less\";\n@import \"./theme.less\";\n@import \"./wde/effects.less\";\n@import \"./wde/widgets/button/button.less\";\n\n@font-face{\n font-family: \"Geneva\";\n src:url(\"./fonts/Geneva.woff2\");\n} \n\nbody{\n &:extend(.views-font);\n // zoom: 2;\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0px;\n\n\n font-size: 12px;\n\n /* font: normal 14px Summer Pixel 22, \"res/SummerPixel22Regular.ttf\"; */\n -webkit-touch-callout: none; /* iOS Safari */\n -webkit-user-select: none; /* Safari */\n -khtml-user-select: none; /* Konqueror HTML */\n -moz-user-select: none; /* Old versions of Firefox */\n -ms-user-select: none; /* Internet Explorer/Edge */\n user-select: none; /* Non-prefixed version, currently\n supported by Chrome, Edge, Opera and Firefox */\n touch-action: manipulation;\n\n background-color: @col-argent;\n // /* Auto layout */\n // display: flex;\n // flex-direction: column;\n // align-items: flex-start;\n // justify-content: flex-start;\n // margin: 32px;\n\n // background-image:\n // linear-gradient(45deg, @col-argent 25%, transparent 25%),\n // linear-gradient(45deg, transparent 75%, @col-argent 75%),\n // linear-gradient(45deg, transparent 75%, @col-argent 75%),\n // linear-gradient(45deg, @col-argent 25%, #777777 25%); \n\n background-size:10px 10px; \n\n background-position:0 0, 0 0, -5px -5px, 5px 5px;\n}\n\n#mobile-app-views{\n position: absolute;\n // background-color: aqua;\n inset: 16px;\n bottom: 100px;\n \n border-radius: 5px;\n border: @eff-border-black;\n box-shadow: @eff-box-shadow-black;\n background: @col-gainsboro;\n overflow: hidden;\n}\n\n#controls-bar{\n position: absolute;\n\n width: 100%;\n height: 100px;\n // background-color: @col-argent;\n bottom: 0px;\n\n /* Auto layout */\n display: flex;\n // padding: 10px;\n justify-content: center;\n align-items: center;\n gap: 53px;\n align-self: stretch;\n}\n\n.mobile-app-view{\n // background-color: burlywood;\n width: 100%;\n height: 100%;\n // position: absolute;\n}\n\n.wde-mobile-button{\n &:extend(.wde-button);\n &:active{\n &:extend(.wde-button:active);\n }\n height: 35px;\n width: 95px;\n /* Auto layout */\n display: flex;\n // padding: 10px;\n flex-direction: row;\n justify-content: center;\n align-items: center;\n padding-right: 5px;\n // gap: 53px;\n // align-self: stretch;\n}\n\n.wde-mobile-button > .icon{\n \n // width: 8rem;\n // height: 8rem;\n}",null,null,null,null,null],"names":[],"version":3,"file":"mobile.css.map","sourceRoot":"/__parcel_source_root/"}

5873
front/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

6
front/package.json Normal file
View File

@ -0,0 +1,6 @@
{
"devDependencies": {
"@parcel/transformer-less": "^2.9.3",
"parcel": "^2.9.3"
}
}

View File

@ -0,0 +1,61 @@
import WDEApplication from "../../wde/application.js"
import AbstractWebDesktopEnvironment from "../../wde/wde.js"
export default class AboutMe extends WDEApplication{
/**
* @constructor
* @param {AbstractWebDesktopEnvironment} wde
*/
constructor(wde, appManifest){
super(wde, "AboutMe", appManifest)
}
/**
* @param {[]string} args
* @param {Object} runContext
*/
async NewWindow(args, runContext){
let html = await this.#renderView(runContext)
let newWindow = this.WDE().Decorat.CreateNewWindow(this.AppId, 360, document.body.clientHeight*0.8)
// console.log(html)
// return
newWindow.innerHTML = html
newWindow.style.height = 'auto'
newWindow.querySelector("#closeWindowButton").addEventListener('click', () => {
super.WDE().CloseWindow(newWindow)
})
}
/**
* @param {string[]} args
* @param {import("../../wde/wde.js").runContext} runContext
*/
async NewView(args, runContext){
let html = await this.#renderView(runContext)
let newView = super.WDE().Decorat.CreateNewView(this.AppId)
newView.innerHTML = html
}
/**
*
* @param {import("../../wde/wde.js").runContext} runContext
* @returns
*/
async #renderView(runContext){
const params = new URLSearchParams({
path: `:/aboutme.props`,
})
const response = await fetch(`/app/${this.AppId}/render?`+ params,{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
// super.WDE().Alert("Error TODO") //TODO
return
}
const html = await response.text() //Validate
return html
}
}

View File

@ -0,0 +1,211 @@
@import "../../theme.less";
.PersPropsContent{
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.PersPropsContent .PropsView{
/* background-color: rebeccapurple; */
width: 100%;
height: auto;
}
.PropertiesList{
/* width: 100%;
height: auto; */
/* Inside auto layout */
order: 0;
align-self: flex-start;
flex-grow: 0;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 12px;
gap:16px;
}
.PropertiesList .ShortBio{
/* width: 100%;
height: auto; */
/* margin-right: -20px; */
// background-color: aquamarine;
/* Inside auto layout */
width: 100%;
// flex: none;
// order: 0;
// align-self: stretch;
// flex-grow: 1;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: center;
// padding: 0px;
// margin-right: 20;
gap:15px;
}
.ShortBio .Image{
width: 48px;
height: 48px;
padding-left: 10px;
}
.ShortBio .Text{
/* width: 100%;
height: auto; */
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 1;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: left;
padding: 0px;
gap:1px;
}
.ShortBio > .Text > .Name{
&:extend(.large-system-font);
// background-color: aqua;
}
.PropertiesList .Links {
// position: absolute;
// right: 14px;
// top: 27px;
// background-color: aqua;
height: auto;
width: auto;
// background-color: aqua;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: end;
justify-content: center;
padding: 0px;
// gap:4px;
}
.Links > a{
/* Auto layout */
display: flex;
flex-direction: row;
align-items: end;
justify-content: center;
padding: 0px;
gap: 2px;
}
.Links > a > .link-lable{
// background-color: aqua;
// line-height: 60px;
// display:table
}
.PropertiesList .Links .Link {
/* background-color:brown; */
width: 16px;
height: 16px;
}
.PropertiesList .Island{
width: 100%;
height: auto;
border: 1px solid #888888;
box-shadow: 1px 1px 0px #FFFFFF, inset 1px 1px 0px #FFFFFF;
padding-bottom: 10px;
/* Auto layout */
/* display: flex;
flex-direction: column;
align-items: center;
padding: 0px;
gap:1px; */
}
.Island .Title {
//FIXME
&:extend(.large-system-font);
position:relative;
display: inline-block;
max-width: 100%;
background-color: #DDDDDD;
left: 12px;
top: -9px;
}
.Island .Content{
width: 100%;
/* top: 0px; */
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
padding: 0px;
gap: 12px;
}
.Island .Row{
margin-left: 12px;
margin-right: 12px;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
padding: 0px;
gap: 5px;
}
.Island .Key{
position: relative;
&:extend(.large-system-font);
// font-family: "Virtue";
// font-size: 11px;
// letter-spacing: 0.35px;
text-align: end;
width: 34%;
white-space: nowrap;
top: -1.5px;
/* font-weight: bold; */
}
.Island .KeyComment{
/* color: rgb(129, 129, 129); TODO*/
color: #646464;
font-size: 9px;
font-style: italic;
text-align: end;
white-space:normal;
/* filter: drop-shadow(-.5px -.5px 0px #616161); */
}
.Island .Values{
width: 55%;
display: flex;
flex-direction: column;
justify-content: left;
padding: 0px;
gap: 5px;
}
.Values .Value{
/* width: 55%; */
}

View File

@ -0,0 +1,380 @@
import AbstractWebDesktopEnvironment from "../../wde/wde.js"
import Finder from "./finder.js"
export default class FinderWindow{
#appId = "Finder" //FIXME
curPath = ""
fileView = undefined
windowElem = undefined
/** @type {Finder} */
#finder
/**
* @deprecated move to this.#finder.WDE()
* @type {AbstractWebDesktopEnvironment}
*/
#wde
/**
* @constructor
* @param {Finder}
* @param {AbstractWebDesktopEnvironment} wde
*/
constructor(finder, wde){
this.#finder = finder
this.#wde = wde
}
/**
* @param {Finder} finder
* @param {*} args
* @param {import("../../wde/wde.js").runContext} runContext
* @returns
*/
async Init(finder, args, runContext){
// console.log(args)
this.#finder = finder
if (runContext.isMobile){
console.log("Mobile Finder!")
this.CreateMobileView(args, runContext)
return
}
if (args[1] == "--desktop"){
let desktopNode = document.body.querySelector(`#${args[2]}`)
if (desktopNode == null){
this.#wde.Alert("Desktop node not found")
return
}
const params = new URLSearchParams({
path: args[0]
})
const response = await fetch(`/app/${this.#appId}/renderDesktop?` + params,
{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
console.log(response.status)
// this.#wde.Alert("Error in render desktop") //TODO
return
}
const html = await response.text()
desktopNode.innerHTML = html
// console.log(this.#wde)
this.fileView = new this.#wde.FileView(
desktopNode.querySelector(".FileTileView"), (event) =>{this.Click(event)},
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() },
this.#wde)
this.RenderDir(args[0])
return
}
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()
let newWindow = this.#wde.Decorat.CreateNewWindow(this.#appId, 500, 350 )
newWindow.innerHTML = html
//TODO change icons for every folder
// newWindow.querySelector(".title-bar").querySelector(".icon").setAttribute("src","/system/libs/img/icon/get?path=/Icons/GenericFolder.icn&size=16")
// console.log(newWindow.querySelector(".FileTileView"))
this.fileView = new this.#wde.FileView(
newWindow.querySelector(".FileTileView"),
(event) => { this.Click(event) },
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() },
this.#wde)
newWindow.querySelector("#closeWindowButton").addEventListener('click', () => {
this.#wde.Decorat.CloseWindow(newWindow)
})
// newWindow.querySelector("#RootButton").addEventListener('click', () =>{
// this.RenderDir('/')
// })
// newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
// this.RenderDir('/home/user')
// })
// let scrollBar = new this.#wde.ScrollBar(newWindow.querySelector(".scrollbar-place"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.RenderDir(args[0])
}
CreateDesktopWindow(){
}
/**
* @param {*} args
* @param {import("../../wde/wde-desktop.js").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.#finder.WDE().Alert(error.message)
return
}
const html = await response.text()
// console.log(html)
// console.log(this.#finder.WDE())
let newView = this.#finder.WDE().Decorat.CreateNewView(this.#appId)
newView.innerHTML = html
this.fileView = new this.#wde.FileView(
newView.querySelector(".FileTileView"),
(event) => { this.Click(event) },
(event) => { this.RightClick(event) },
(event, draggedElem) => { this.DropEvent(event, draggedElem)},
() => { this.ReRenderDir() },
this.#wde)
// newView.querySelector("#closeWindowButton").addEventListener('click', () => {
// this.#wde.Decorat.CloseWindow(newView)
// })
// newView.querySelector("#RootButton").addEventListener('click', () =>{
// this.RenderDir('/')
// })
// newView.querySelector("#HomeButton").addEventListener('click', () =>{
// this.RenderDir('/home/user')
// })
// let scrollBar = new this.#wde.ScrollBar(newView.querySelector(".scrollbar-place"), newView.querySelector(".FileTileView"))
this.windowElem = newView
this.RenderDir(args[0])
}
/**
* @param {string} path
*/
RenderDir(path){
this.curPath = path
this.fileView.OpenFolder(path)
}
ReRenderDir(){
this.RenderDir(this.curPath)
}
/**
* @param {DragEvent} event
* @param {HTMLElement} draggedElem
*/
async DropEvent(event){
// console.log(event.dataTransfer.getData("dropType"))
if (event.dataTransfer.getData("dropType") == "move"){
const sourcePath= event.dataTransfer.getData("filePath")
const targetPath = this.curPath + "/" + event.dataTransfer.getData("fileName")
const res = await this.#finder.WDE().WebFS().MoveFile(sourcePath, targetPath)
if (res){
this.ReRenderDir()
} else {
this.#wde.Alert("UWAGA TODO MOVE FILE ERROR") //TODO
}
} else {
console.log(event, this.curPath)
let files = event.dataTransfer.files
for (let i = 0; i < files.length; i++) {
const file = files[i];
console.log("file:" + file.name)
const res = await this.#finder.WDE().WebFS().UploadFile(file, this.curPath)
if (res){
this.ReRenderDir()
}
}
const params = new URLSearchParams({
parentPath: this.curPath,
})
const response = await fetch('/fs/upload/?' + params,
{
method: "POST", //TODO Change to PUT?
body: formData
})
if (response.status != 200){
this.#wde.Alert("ERROR IN UPLOADING FILE")//TODO
} else {
this.ReRenderDir()
}
}
}
/**
* @param {MouseEvent} event
*/
Click(event){
this.OpenFile(this.curPath, event.target.getAttribute("name"), event.target.getAttribute("filetype"))
}
/**
*
* @param {string} fileName
*/
getFileExtension(fileName){
return fileName.split(".")[fileName.split(".").length - 1] //FIXME
}
/**
* @param {string} filePath
*/
async OpenFile(parentPath, fileName, fileType){
// console.log(parentPath, fileName, fileType)
// const splittedPath = filePath.split("/")
// const fileName = splittedPath[splittedPath.length - 1]
const fileExtension = this.getFileExtension(fileName)
console.log(fileExtension)
switch (true) {
case fileType == "objectlink":
this.#finder.WDE().Alert("Links not supported yet")
break
case fileType == "pathlink":
let res = await WebFS.ReadPathLink(`${parentPath}/${fileName}`)
console.log(res)
this.OpenFile(res.parentPath, res.name, res.filetype)
break
case fileExtension == "app":
this.#finder.WDE().Open(`${parentPath}/${fileName}`, [])
break
case fileExtension == "blog":
this.#finder.WDE().Open(`/Applications/BlogViewer.app`, [`${parentPath}/${fileName}`])
break
case fileType == "directory":
this.#finder.WDE().Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
this.#finder.WDE().Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
this.#finder.WDE().Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
this.#finder.WDE().Alert("Unsupported file type")
break;
}
}
/**
* @param {MouseEvent} event
*/
RightClick(event){
this.CreateContextMenu(event.target, [event.clientY, event.clientX])
}
/**
* @param {HTMLElement} target
* @param {string[]} pos
*/
async CreateContextMenu(target, pos){
let context = ""
const fileName = target.getAttribute("name") //TODO check for null
const fileType = target.getAttribute("fileType")
if (target.classList.contains("FileTileView"))
{
context = "FileTileView"
} else {
context = fileType
}
let path = ""
if (fileName === null){
path = this.curPath
} else {
path = `${this.curPath}/${fileName}`
}
const params = new URLSearchParams({context: context, path: path})
const response = await fetch(`/app/${this.#appId}/contextMenu?` + params)
if (response.status != 200){
this.#wde.Alert("ERROR in Context menu TODO"); //TODO
return
}
const html = await response.text()
let overlay = document.createElement("div") //TODO Move to WDE.CreateOverlay()
overlay.setAttribute('id', 'finder-context-menu-overlay')
overlay.style.position = 'absolute'
overlay.style.width = "100%"
overlay.style.height = "100%"
let menu = document.createElement("div")
menu.setAttribute('class', 'ContextMenu WindowFrameShadow')
menu.style.position = 'absolute';
menu.style.top = pos[0] + "px";
menu.style.left = pos[1] + "px";
menu.innerHTML = html
// menu.children[0].firstElementChild.remove()
menu.children[0].lastElementChild.remove() //FIXME Can't ommit rendering of horLine in end of menu on backend
overlay.appendChild(menu)
document.body.appendChild(overlay)
overlay.addEventListener('click', async (event) => {
if (event.target.classList.contains("Row")){ //TODO add uuid id to rows to more accurate checks??
let res = false
switch (event.target.children[0].getAttribute("action")) {
case "createPathLink":
res = await this.#finder.WDE().WebFS().CreatePathLink(`${this.curPath}/${fileName}`, `${this.curPath}/Link to ${fileName}` )
if (res){
this.ReRenderDir()
}
break
case "createDir":
res = await this.#finder.WDE().WebFS().CreateDirectory(`${this.curPath}`)
// console.log(res)
if (res){
this.ReRenderDir()
}
break
case "deleteFile":
res = await this.#finder.WDE().WebFS().DeleteFile(`${this.curPath}/${fileName}`)
// console.log(res)
if (res){
this.ReRenderDir()
}
break
case "getInfo":
this.#finder.RenderProperites(path)
break
case "openAsDir":
this.#finder.WDE().Open(`/Applications/${this.#appId}.app`,[`${this.curPath}/${fileName}`])
break
default:
break;
}
}
overlay.remove()
})
overlay.addEventListener('contextmenu', (event) => {
event.preventDefault();
overlay.remove()
})
}
}

View File

@ -0,0 +1,63 @@
// require("./finder.less")
import WDEApplication from "../../wde/application.js"
import AbstractWebDesktopEnvironment from "../../wde/wde.js"
import FinderWindow from "./finder-window.js"
export default class Finder extends WDEApplication{
/** @deprecated */
static AppId = "Finder"
/**
* @constructor
* @param {AbstractWebDesktopEnvironment} wde
*/
constructor(wde){
super(wde, "Finder")
}
/**
* @param {string[]} args
* @param {import("../../wde/wde.js").runContext} runContext
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow(this, super.WDE())
await newFinder.Init(this, args, runContext)
}
/**
* @param {string[]} args
* @param {import("../../wde/wde.js").runContext} runContext
*/
async NewView(args, runContext){
let newFinderView = new FinderWindow(this, super.WDE())
await newFinderView.Init(this, args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
async RenderProperites(path){
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/${this.AppId}/renderProps?` + params)
if (response.status != 200){
this.WDE().Alert("Error in render properties widget") //TODO
return false
}
const html = await response.text()
let newWindow = this.WDE().Decorat.CreateNewWindow(this.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', () => {
// console.log(this.WDE().Decorat())
this.WDE().Decorat.CloseWindow(newWindow)
})
}
}

View File

@ -0,0 +1,39 @@
@import "../../theme.less";
@import "../../wde/effects.less";
.finder-content {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: start;
align-items: flex-start;
padding: 0px;
}
.finder-content > .tool-bar{
width: 100%;
min-height: 20px;
border-bottom: @eff-border-grey;
}
.window-frame.Focused .tool-bar{
border-bottom: 1px solid #000000;
box-shadow: @eff-box-shadow-convex;
}
.finder-content > .file-view-container{
width: 100%;
height: 100%;
// background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

75
front/src/desktop.less Normal file
View File

@ -0,0 +1,75 @@
@import "./wde/primitives.less";
@import "./wde/widgets/file-view/file-view.less";
@import "./wde/widgets/scrollbar/scrollbar.less";
@import "./wde/widgets/button/button.less";
// @import "./wde/legacy-ui.less";
@import "./wde/widgets/basic-widgets.less";
@import "./theme.less";
@import "./wde/window-frame.less";
@import "./wde/widgets/title-bar/title-bar.less";
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
// .DragArea
// *{
// font-family: Verdana, Geneva, sans-serif;
// font-size: 11px;
// font-style: normal;
// font-weight:initial;
// }
*::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}
body{
&:extend(.views-font);
// zoom: var(--zoom);
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
font-size: 11px;
// font-family: "Geneva";
src:url("./fonts/Geneva.woff2");
/* font: normal 14px Summer Pixel 22, "res/SummerPixel22Regular.ttf"; */
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
touch-action: manipulation;
}
#applications{
position: static;
width: 0px;
height: 0px;
visibility: hidden;
}
#windows-layer {
width: 0px;
height: 0px;
/* position: fixed; */
position: static;
}
#desktop-layer{
position: fixed;
/* margin: 0px; */
width: 100%;
height: 100%;
background-color: @col-ceil;
}

Binary file not shown.

Binary file not shown.

110
front/src/mobile.less Normal file
View File

@ -0,0 +1,110 @@
@import "./wde/sunboard/sunboard-mobile.less";
@import "./theme.less";
@import "./wde/effects.less";
@import "./wde/widgets/button/button.less";
@font-face{
font-family: "Geneva";
src:url("./fonts/Geneva.woff2");
}
body{
&:extend(.views-font);
// zoom: 2;
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
font-size: 12px;
/* font: normal 14px Summer Pixel 22, "res/SummerPixel22Regular.ttf"; */
-webkit-touch-callout: none; /* iOS Safari */
-webkit-user-select: none; /* Safari */
-khtml-user-select: none; /* Konqueror HTML */
-moz-user-select: none; /* Old versions of Firefox */
-ms-user-select: none; /* Internet Explorer/Edge */
user-select: none; /* Non-prefixed version, currently
supported by Chrome, Edge, Opera and Firefox */
touch-action: manipulation;
background-color: @col-argent;
// /* Auto layout */
// display: flex;
// flex-direction: column;
// align-items: flex-start;
// justify-content: flex-start;
// margin: 32px;
// background-image:
// linear-gradient(45deg, @col-argent 25%, transparent 25%),
// linear-gradient(45deg, transparent 75%, @col-argent 75%),
// linear-gradient(45deg, transparent 75%, @col-argent 75%),
// linear-gradient(45deg, @col-argent 25%, #777777 25%);
background-size:10px 10px;
background-position:0 0, 0 0, -5px -5px, 5px 5px;
}
#mobile-app-views{
position: absolute;
// background-color: aqua;
inset: 16px;
bottom: 100px;
border-radius: 5px;
border: @eff-border-black;
box-shadow: @eff-box-shadow-black;
background: @col-gainsboro;
overflow: hidden;
}
#controls-bar{
position: absolute;
width: 100%;
height: 100px;
// background-color: @col-argent;
bottom: 0px;
/* Auto layout */
display: flex;
// padding: 10px;
justify-content: center;
align-items: center;
gap: 53px;
align-self: stretch;
}
.mobile-app-view{
// background-color: burlywood;
width: 100%;
height: 100%;
// position: absolute;
}
.wde-mobile-button{
&:extend(.wde-button);
&:active{
&:extend(.wde-button:active);
}
height: 35px;
width: 95px;
/* Auto layout */
display: flex;
// padding: 10px;
flex-direction: row;
justify-content: center;
align-items: center;
padding-right: 5px;
// gap: 53px;
// align-self: stretch;
}
.wde-mobile-button > .icon{
// width: 8rem;
// height: 8rem;
}

39
front/src/theme.less Normal file
View File

@ -0,0 +1,39 @@
@col-ceil: #9999CC;
@col-argent: #C0C0C0;
@col-chinese-silver: #CCCCCC;
@col-gainsboro: #DDDDDD;
@col-bright-grey: #EEEEEE;
@col-davys-grey: #555555;
@col-granite-gray: #666666;
@col-grey: #808080;
@col-black: #000000;
@col-white: #FFFFFF;
@col-raisin-black: #222222;
@font-face{
font-family: "Geneva";
src:url("./fonts/Geneva.woff2");
}
@font-face {
font-family: "Charcoal";
src: url('./fonts/Charcoal.woff2');
}
.large-system-font{
font-family: "Charcoal";
// font-weight: bold;
letter-spacing: 0.35px;
font-size: 12px;
}
.small-system-font{
font-family: "Geneva";
}
.views-font{
font-family: "Geneva";
}

View File

@ -0,0 +1,35 @@
import AbstractWebDesktopEnvironment from "./wde.js"
export default class WDEApplication{
/** @type {AbstractWebDesktopEnvironment} */
#wde
/** @type {string} */
AppId
//TODO types
AppManifest
/**
* @constructor
* @param {AbstractWebDesktopEnvironment} wde
*/
constructor(wde, AppId, manifest){
this.#wde = wde //TODO: Vaidate
// console.log(wde)
this.AppId = AppId //TODO: Validate
this.AppManifest = manifest
}
/** @returns {AbstractWebDesktopEnvironment} */
WDE(){
return this.#wde
}
async NewWindow(){
}
/** @returns {Element} */
async NewView(){
return this.#wde.Decorat.CreateNewView(this.AppId)
}
}

View File

@ -0,0 +1,103 @@
export default class DesktopDecorat{
/** @type {Element} */
#windowsLayer
constructor(){
this.#windowsLayer = document.body.querySelector('#windows-layer') //TODO Validate if null
let startDrag = (event) => {
let window = event.target.closest('.window-frame')
this.bringWindowToFront(window)
if (event.target.classList.contains("DragArea")){
let xPosInit = event.offsetX
let yPosInit = event.offsetY
let dragWindow = function(event){
window.style.left = `${event.clientX - xPosInit}px`
window.style.top = `${event.clientY - yPosInit}px`
}
let stopDrag = function(){
removeEventListener('mousemove', dragWindow)
removeEventListener('mouseup', stopDrag)
}
addEventListener('mousemove', dragWindow)
addEventListener('mouseup', stopDrag)
}
}
this.#windowsLayer.addEventListener('mousedown', startDrag)
}
/**
* @param {HTMLElement} window
*/
bringWindowToFront(window){ //FIXME
let previousWindow = this.#windowsLayer.lastChild
if (window == null || window == undefined){
return
}
if (window != previousWindow){
this.#windowsLayer.insertBefore(window, previousWindow.nextSibling)
previousWindow.classList.remove("Focused")
window.classList.add("Focused")
} else {
window.classList.add("Focused")
}
return
}
/**
* @param {string} appId
* @param {number} width
* @param {number} height
* @returns {HTMLElement}
*/
CreateNewWindow(appId, width, height) {
let newWindow = document.createElement("div")
newWindow.setAttribute('appid', appId)
// newWindow.setAttribute("class", "WindowFrame ConvexElement")
newWindow.setAttribute("class", "window-frame")
newWindow.setAttribute("windowId", this.#makeid(4)) //TODO:
newWindow.style.width = width.toString() + "px"
newWindow.style.height = height.toString() + "px"
document.body.querySelector('#windows-layer').appendChild(newWindow)
return newWindow
}
/**
* @param {HTMLElement} window
*/
CloseWindow(window) {
window.remove()
}
CloseFocusedWindow() {
if (document.body.querySelector('#windows-layer').childElementCount > 1){
document.body.querySelector('#windows-layer').lastElementChild.remove()
}
}
static ChangeURL(appWindow){
let appId = appWindow.getAttribute('appid')
window.history.replaceState(null, "", `/${appId}/`);
}
/**
* @param {num} length
*/
#makeid(length) {
let result = '';
const characters = 'ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789';
const charactersLength = characters.length;
let counter = 0;
while (counter < length) {
result += characters.charAt(Math.floor(Math.random() * charactersLength));
counter += 1;
}
return result;
}
}

View File

@ -0,0 +1,37 @@
export default class MobileDecorat {
/** @type {Element} */
#applicationsNode
constructor(){
this.#applicationsNode = document.body.querySelector("#mobile-app-views") //TODO validate
this.#loadControlsBar()
}
#loadControlsBar(){
let bar = document.body.querySelector("#controls-bar") //TODO Validate
console.log(bar)
bar.querySelector("#back").addEventListener('click', () => {
this.BackAction()
})
}
/**
* @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)
this.#applicationsNode.insertBefore(newView, this.#applicationsNode.firstChild)
return newView
}
Open(){
}
BackAction(){
console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.firstChild.remove()
}
}

View File

@ -0,0 +1,45 @@
.adjective{
border: 1px solid #555555;
}
.convex{
box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.25),
inset -1px -1px 0px rgba(0, 0, 0, 0.27),
inset 1px 1px 0px #FFFFFF;
}
.border{
.grey{
border: 1px solid @col-davys-grey;
}
.black{
border: 1px solid @col-black;
}
}
.shadow{ //FIXME: shadow must be 2px offset from windows borders
.grey{
box-shadow: 1px 1px 0px @col-davys-grey;
}
.black{
box-shadow: 1px 1px 0px @col-black;
}
}
.rows-fill-shadowed{
background: linear-gradient(transparent 0%, white 0%, white 50%, transparent 50%);
background-size: 2px 2px;
filter: drop-shadow(1px 1px 0px #777777);
}
@eff-border-black: 1px solid @col-black;
@eff-border-grey: 1px solid @col-davys-grey;
@eff-box-shadow-grey: 1px 1px 0px @col-davys-grey;
@eff-box-shadow-black: 1px 1px 0px @col-black;
@eff-box-shadow-convex: inset -1px -1px 0px rgba(0, 0, 0, 0.27),inset 1px 1px 0px @col-white;
@eff-box-shadow-convex-inverted: inset 1px 1px 0px rgba(0, 0, 0, 0.27),inset -1px -1px 0px @col-grey;
@eff-box-shadow-adjective: -1px -1px 0px rgba(0, 0, 0, 0.25), 1px 1px 0px #FFFFFF;

View File

@ -0,0 +1,232 @@
// .WindowFrame {
// /* Auto layout */
// display: flex;
// flex-direction: column;
// align-items: flex-start;
// padding: 4px;
// padding-top: 2px;
// padding-right: 6px;
// gap: 4px;
// position: absolute;
// background: #DDDDDD;
// border: 1px solid #555555;
// /* Inside auto layout */
// flex: none;
// order: 1;
// align-self: stretch;
// flex-grow: 1;
// }
/* TODO Add shadows to windows */
.WindowFrame.Focused{
border: 1px solid #000000;
background-color: #CCCCCC;
}
.WindowFrameShadow {
box-shadow: 2px 2px 0px #555555;
}
/* FIXME Not work on context menu */
.WindowFrameShadow.Focused {
box-shadow: 2px 2px 0px #000000;
}
.ConvexElement.Focused {
box-shadow: 1px 1px 0px rgba(0, 0, 0, 0.25),
inset -1px -1px 0px rgba(0, 0, 0, 0.27),
inset 1px 1px 0px #FFFFFF;
}
.AdjectiveElement {
border: 1px solid #555555;
}
.Focused .AdjectiveElement {
border: 1px solid #000000;
box-shadow: -1px -1px 0px rgba(0, 0, 0, 0.25),
1px 1px 0px #FFFFFF;
/* inset -1px -1px 0px rgba(0, 0, 0, 0.27), */
/* inset 1px 1px 0px #FFFFFF;*/
}
.AdjectiveHorizontalLine {
border-top: 1px solid rgba(0, 0, 0, 0.25);
border-bottom: 1px solid #FFFFFF;
width: 100%;
height: 0px;
}
.AdjectiveHorizontalLine:last-child {
height: 0%;
visibility: hidden;
}
.WindowFrame .TitleBar {
width: 100%;
height: 13px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 5px;
padding: 0px;
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
}
.WindowFrame .TitleBar .Lable {
position: relative;
top: 1px;
/* font-size: 13px; */
color:#777777;
pointer-events: none;
white-space: nowrap;
font-family: "Virtue";
letter-spacing: 0.35px;
}
.WindowFrame.Focused .TitleBar .Lable {
color:#000000;
}
.WindowFrame .TitleBar .Button {
width: 11px;
height: 11px;
padding: 0%;
position: relative;
top: 1px;
visibility: hidden;
background: linear-gradient(135deg, #999999 18.18%, #FFFFFF 81.82%);
border: 1px solid #222222;
box-shadow: 0.5px 0.5px 0px 0.5px #FFFFFF,
-0.5px -0.5px 0px 0.5px rgba(0, 0, 0, 0.25),
inset 1px 1px 0px rgba(255, 255, 255, 0.5),
inset -1px -1px 0px rgba(0, 0, 0, 0.27);
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.WindowFrame.Focused .TitleBar .Button {
visibility: visible;
}
.WindowFrame .TitleBar .Button:active {
background-color: rgba(0, 0, 0, 0.4);
/* Green */
box-shadow: 0.5px 0.5px 0px 0.5px #FFFFFF,
-0.5px -0.5px 0px 0.5px rgba(0, 0, 0, 0.25);
}
.Focused .VisualDragArea {
pointer-events: none;
width: 100%;
height: 11px;
background: linear-gradient(transparent 0%, white 0%, white 50%, transparent 50%);
background-size: 2px 2px;
filter: drop-shadow(1px 1px 0px #777777);
}
.MobileContentBorder {
width: 100%;
height: 100%;
background-color: #DDDDDD;
/* border: 1px solid #000000; */
/* box-shadow: -1px -1px 0px rgba(0, 0, 0, 0.25),
1px 1px 0px #FFFFFF,
inset -1px -1px 0px rgba(0, 0, 0, 0.27),
inset 1px 1px 0px #FFFFFF; */
overflow: hidden;
overflow-x: hidden;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.MobileApplicationWindow {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
gap: 4px;
position: absolute;
top: 0px;
left: 0px;
}
.MobileWindowFrameBottomBar {
width: 100%;
height: 20px;
/*
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-between;
gap: 5px;
padding: 0px; */
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
}
.MobileWindowFrameBottomBarButton {
min-width: 11px;
width: auto;
height: 15px;
padding: 0px 4px 0px 4px;
position: absolute;
right: 4px;
background: linear-gradient(135deg, #999999 18.18%, #FFFFFF 81.82%);
border: 1px solid #222222;
box-shadow: 0.5px 0.5px 0px 0.5px #FFFFFF,
-0.5px -0.5px 0px 0.5px rgba(0, 0, 0, 0.25),
inset 1px 1px 0px rgba(255, 255, 255, 0.5),
inset -1px -1px 0px rgba(0, 0, 0, 0.27);
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.MobileWindowFrameBottomBar .MobileLable {
position: absolute;
/* top:1px; */
/* font-size: 13px; */
left: 50%;
pointer-events: none;
white-space: nowrap;
font-family: "Virtue";
letter-spacing: 0.35px;
}

View File

@ -0,0 +1,11 @@
.WdePrimitives {
.adjective{
border: 1px solid #555555;
}
.black-border{
border: 1px solid #000000;
}
}

View File

@ -0,0 +1,49 @@
import MobileWebDesktopEnvironment from "../wde-mobile.js"
export default class MobileDesktop{
/**@type {Element} */
#icons
/** @type {MobileWebDesktopEnvironment} */
#wde
constructor(wde){
this.#wde = wde
this.load()
}
async load(){
let view = this.#createDesktopView()
}
async #createDesktopView(){
let view = this.#wde.Decorat.CreateNewView("Sunboard") //FIXME
const params = new URLSearchParams({
// path: args[0] //FIXME
path: "/" //FIXME
})
const response = await fetch(`/app/Sunboard/render?` + params,
{
method: "POST",
// body: JSON.stringify(runContext)
})
if (response.status != 200){
console.log(response.status)
return
}
const html = await response.text()
view.innerHTML = html
let iconsList = view.querySelectorAll(".app-icon")
iconsList.forEach(element => {
let path = element.getAttribute('path') //TODO: Validate
element.addEventListener('click', () => {
this.#wde.Open(path, ["/"], "") //FIXME
})
});
}
async createFileView(){
}
}

View File

@ -0,0 +1,62 @@
@import "../../theme.less";
@import "../primitives.less";
#mobile-sunboard{
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
#icons{
width: 100%;
height: 100%;
// background-color: @col-ceil;
}
// #down-bar{
// &:extend(.WdePrimitives.AdjectiveElement);
// width: 100%;
// height: 150px;
// background-color: @col-argent;
// }
.apps-list{
/* Auto layout */
display: flex;
padding: 64px 16px;
align-items: flex-start;
align-content: flex-start;
gap: 64px 0px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon{
// background-color: rgba(0, 255, 255, 0.133);
width: 100px;
// height: 100px;
/* Auto layout */
display: flex;
// padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon{
width: 32px;
height: 32px;
// background-color: beige;
}
.app-icon .lable{
}

View File

@ -0,0 +1,144 @@
import DesktopDecorat from "./decorat/desktop-decorat.js";
import WDEScrollBar from "./widgets/scrollbar/scrollbar.js";
import WebFS from "../web-fs/web-fs.js";
import WDEApplication from "./application.js";
import WDEFileView from "./widgets/file-view/file-view.js";
import AbstractWebDesktopEnvironment from "./wde.js";
// import DesktopSunBoard from "./sunboard/sunboard-desktop.js";
export default class WebDesktopEnvironment extends AbstractWebDesktopEnvironment{
/** @type {string} */
test = ""
/** @type {WDEFileView} */
FileView = WDEFileView
/** @type {WDEScrollBar} */
ScrollBar = WDEScrollBar
/**@type {DesktopDecorat} */
Decorat
/** @type {Object<string, WDEApplication>} */
static Applications = {};
/** @deprecated */
static isMobile = false
// static decorat
static webFs
/** @deprecated */
basicWindow
constructor(){
super("localhost:8080")
super._SetWDE(this)
document.body.style.setProperty('--zoom', 1)
this.Decorat = new DesktopDecorat()
WebDesktopEnvironment.webFs = new WebFS()
this.FileView = WDEFileView
this.loadWDE()
// this.#devLoadSunboard()
}
async loadWDE(){
await this.Open("/Applications/Finder.app", ["/home/user/.Desktop","--desktop", "desktop-layer"])
await this.Open("/Applications/Finder.app", ["/", ""])
// await this.Open("/Applications/AboutMe.app", [])
return
let autoStart = document.body.querySelector("wde-autostart")
if (autoStart == null){
WebDesktopEnvironment.Alert("Error in loading DE: Autostart not presented")
return
}
for (const child of autoStart.children) {
if (child.nodeName != "APP") continue
let appPath = child.getAttribute("app-path")
if (appPath == null) continue
let args = []
let argsRaw = child.querySelector("args")
if (argsRaw == null) continue
for (const argRaw of argsRaw.children) {
let arg = argRaw.getAttribute("string")
if (arg == null) continue
args.push(arg)
}
// console.log(appPath, args)
await this.Open(appPath, args)
}
autoStart.remove()
}
/**
* @param {string} appPath
* @param {string[]} args
* @param {string} runPath
*/
async Open(appPath, args, runPath){
const runContext = {
isMobile: false,
bundlePath: appPath,
runPath: runPath
}
super._Open(appPath, args, runPath, (appManifest) =>{
super._GetApp(appManifest.appId).NewWindow(args, runContext)
})
}
/**
* @deprecated
* @param {string} html
*/
static SetBasicWindow(html){
this.basicWindow = html
}
/**
* @deprecated
* @returns {string}
*/
static GetBasicWindow(){
return this.basicWindow
}
/**
* @param {string} alertText
*/
Alert(alertText){
this.#createAlertWindow(alertText)
console.log(alertText)
}
/**
* @param {string} alertText
*/
#createAlertWindow(alertText){
let newWindow = document.createElement("div")
newWindow.setAttribute("class", "WindowFrameless")
newWindow.setAttribute("windowId", "SuperUniqUUID") //TODO:
newWindow.style.cssText = "position:absolute;width:450px;height:116px; margin-left: -225px; margin-top:-58px;left: 50%;top: 50%;background-color:#FFFFFF;border: 1px solid #000000;box-shadow: 2px 2px 0px #000000;"
let alertImage = document.createElement("img")
alertImage.setAttribute("src", "/res/sys/wde/icons/ohno.png")
alertImage.style.cssText = "position:absolute; width:64px;height:64px;top:15px;left:25px"
newWindow.appendChild(alertImage)
let errorText = document.createElement("div")
errorText.style.cssText = "position:absolute; width: 300px; left:128px; top:30px;font-family: 'Virtue';"
errorText.innerHTML = alertText
newWindow.appendChild(errorText)
let closeButton = document.createElement("button")
closeButton.style.cssText = "position:absolute; left: 382px; bottom: 10px; background-color:#FFFFFF; width: 55px; height:18px; font-family: 'Virtue'; border-radius:4px;border: 1px solid #000000;"
closeButton.innerHTML = "Close"
closeButton.addEventListener('click', () => { newWindow.remove()})
newWindow.appendChild(closeButton)
document.body.querySelector('#windows-layer').appendChild(newWindow)
}
}

View File

@ -0,0 +1,55 @@
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 extends AbstractWebDesktopEnvironment{
/** @type {MobileDecorat} */
Decorat
/** @type {WDEFileView} */
FileView
/** @type {MobileSunboard} */
#sunBoard
constructor(){
super()
super._SetWDE(this)
document.body.style.setProperty('--zoom', 3)
this.Decorat = new MobileDecorat()
this.FileView = WDEFileView
this.#sunBoard = new MobileSunboard(this)
// this.loadWDE()
document.addEventListener("touchstart", function(){}, true);//For working :active in css
}
loadWDE(){
this.#initControlsBar()
}
/**
* @param {string} appPath
* @param {string[]} args
* @param {string} runPath
*/
async Open(appPath, args, runPath){
const runContext = {
isMobile: true,
bundlePath: appPath,
runPath: runPath
}
super._Open(appPath, args, runPath, (appManifest) =>{
// console.log(super._GetApp(appManifest.appId))
super._GetApp(appManifest.appId).NewView(args, runContext)
}, this)
}
#initControlsBar(){
let barNode = document.body.querySelector("#controls-bar")//TODO Validate
barNode.querySelector("#back").addEventListener('click', () => {
this.Decorat.BackAction()
})
}
}

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

@ -0,0 +1,116 @@
import WDEApplication from "./application.js"
import WebFS from "../web-fs/web-fs.js"
export default class AbstractWebDesktopEnvironment{
/** @type {string} */
#apiAddress
/** @type {Object<string, WDEApplication>} */
_applications = {}
/** @type {AbstractWebDesktopEnvironment} */
#wde
/** @type {WebFS} */
#webFS
/** @constructor */
constructor(apiAddress){
this.#apiAddress = apiAddress
this.#webFS = WebFS
}
/**
* @deprecated
* @returns {string}
*/
GetApiAddress(){
return `${location.protocol}//${this.#apiAddress}`
}
/** @type {AbstractWebDesktopEnvironment} */
_SetWDE(wde){
this.#wde = wde
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
async _FetchAppManifest(path){
console.log(path)
// console.log(this.GetApiAddress())
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 {runContext} runContext
* @param {string} runPath
* @param {function} callback
*/
async _Open(appPath, runContext, runPath, callback){
const appManifest = await this._FetchAppManifest(appPath)
if (appManifest === undefined) return //TODO return err
if (this._applications[appManifest.appId] === undefined){
this.#loadApp(appManifest, () => {
callback(appManifest)
})
} else {
callback(appManifest)
}
}
/**
* @param {*} appManifest
* @param {function} onload callback after script loading
*/
async #loadApp(appManifest, onload){
let newApp
// console.log(appManifest)
await import(appManifest.js[0]).then((app) => {newApp = app}) //FIXME
let newAppClass = new newApp.default(this.#wde, appManifest)
this._applications[appManifest.appId] = newAppClass
let cssFile = document.createElement( "link" );
cssFile.rel = "stylesheet";
cssFile.type = "text/css";
cssFile.href = appManifest.css[0];
document.head.appendChild( cssFile );
onload()
return //TODO return result
}
_GetApp(appId){
// console.log(appId)
return this._applications[appId]
}
/** @returns {WebFS} */
WebFS(){
return this.#webFS
}
/**
* @param {string} alertText
*/
Alert(alertText){}
}
/**
* @typedef {Object} runContext
* @property {boolean} isMobile
* @property {string} appPath
* @property {string} runPath //TODO
*/
/** //TODO
* @typedef {Object} appManifest
*/

View File

@ -0,0 +1,60 @@
.ContentBorder { /*TODO Delete, deprecated*/
width: 100%;
height: 100%;
/* background-color: #DDDDDD;
border: 1px solid #000000; */
overflow: hidden;
overflow-x: hidden;
}
.ContextMenu {
position: absolute;
width: auto;
height: auto;
background-color: #DDDDDD;
border: 1px solid #000000;
}
.ContextMenu .Content{
position: relative;
width: auto;
height: auto;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
/* padding: 4px;
padding-top: 2px;
padding-right: 6px;
gap: 4px; */
}
.ContextMenu .Row {
width: 100%;
height: 16px;
}
.ContextMenu .SectionBreaker {
/* background-color: rebeccapurple; */
}
.ContextMenu .Row:hover{
background-color: #333399;
color: #FFFFFF;
}
.ContextMenu .Row .Lable{
margin-left: 20px;
margin-right: 12px;
font-family: "Virtue";
white-space: nowrap;
}

View File

@ -0,0 +1,27 @@
@import "../../effects.less";
@import "../../../theme.less";
.wde-button{
&:active{
background-color: @col-granite-gray;
box-shadow: @eff-box-shadow-convex-inverted;
// background-color: red;
}
background-color: @col-gainsboro;
box-shadow: @eff-box-shadow-convex;
border: @eff-border-black;
border-radius: 3px;
height: 20px;
width: auto;
}
// .wde-button:active{
// background-color: red;
// }
// .wde-button:hover{
// background-color: pink;
// }

View File

@ -0,0 +1,138 @@
import AbstractWebDesktopEnvironment from "../../wde.js"
export default class WDEFileView{
path = ""
parentElem = undefined
selected = []
/** @type {AbstractWebDesktopEnvironment} */
#wde
/**
* @param {HTMLElement} fileViewElem
* @param {Function} doubleClickCallback
* @param {Function} rightClickCallback
* @param {Function} updateFileViewCallback
*/
constructor(fileViewElem, doubleClickCallback, rightClickCallback, fileUploadCallback, updateFileViewCallback, wde){
this.#wde = wde
//TODO check all params
this.parentElem = fileViewElem
fileViewElem.addEventListener('click', (event) => {
if (event.target.classList[0] == 'file-view')
{
this.DeselectAll()
return
}
if (event.detail === 1){
this.DeselectAll()
this.Select([event.target])
} else if (event.detail === 2) {
doubleClickCallback(event)
}
})
fileViewElem.addEventListener('contextmenu', (event) => {
event.preventDefault();
if (event.target.classList.contains("Tile")){
this.DeselectAll()
this.Select([event.target])
}
this.Select([event.target])
rightClickCallback(event)
})
if (fileUploadCallback !== undefined) {
let counter = 0
let draggedElem = undefined
fileViewElem.addEventListener('dragstart', (event) => {
// console.log(event.target)
// console.log(this.path)
// draggedElem = event.target
event.dataTransfer.setData("fileName", event.target.getAttribute("name"))
event.dataTransfer.setData("filePath", this.path + "/" + event.target.getAttribute("name"))
event.dataTransfer.setData("dropType", "move")
// console.log(updateFileViewCallback)
// event.dataTransfer.setData("updateCallback", updateFileViewCallback)
// event.dataTransfer.setData("fileName", )
// console.log(draggedElem)
})
fileViewElem.addEventListener('dragenter', function(event) {
event.preventDefault();
counter++
fileViewElem.classList.add("DragDropBorder")
})
fileViewElem.addEventListener('dragend', function(event) {
// console.log(fileViewElem)
event.preventDefault();
counter--
if (counter === 0){
fileViewElem.classList.remove("DragDropBorder")
}
// updateFileViewCallback()
// draggedElem = undefined
})
fileViewElem.addEventListener('dragleave', function(event) {
// console.log(fileViewElem)
event.preventDefault();
counter--
if (counter === 0){
fileViewElem.classList.remove("DragDropBorder")
}
// draggedElem = undefined
})
fileViewElem.addEventListener('dragover', function(event) {
event.preventDefault();
})
fileViewElem.addEventListener("drop", (event) => {
event.preventDefault();
fileUploadCallback(event)
fileViewElem.classList.remove("DragDropBorder")
// updateFileViewCallback()
// this.OpenFolder(this.path)
// draggedElem = undefined
})
}
}
/**
* @param {[]Element} elements
*/
Select(elements){
elements.forEach(element => {
this.selected.push(element)
element.classList.add("Selected")
});
}
DeselectAll(){
this.selected.forEach(element => {
element.classList.remove("Selected")
});
this.selected = []
}
/** Get html of folder by path
* @param {string} path
*/
async OpenFolder(path){
this.path = path
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/system/wde/widgets/file-tile-view?` + params)
if (response.status != 200){
//TODO Error text message
this.#wde.Alert("Error in render folder view") //TODO
return
}
let html = await response.text()
this.parentElem.innerHTML = html
}
}

View File

@ -0,0 +1,89 @@
@import "../../../theme.less";
.FileTileView{
width: 100%;
height: 100%;
// background-color: @col-white;
/* FIXME Bug, on desktop mode top ~10 pixel are not active, like margin:10px */
}
.FileTileView.DragDropBorder{
box-shadow: inset 0px 0px 0px 4px #9999CC;
/* background-color: blue; */
}
.FileTileView .FlexContainer{
width: 100%;
height: auto;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
gap: 50px;
row-gap: 20px;
/* padding: 15px; Shit fix TODO: */
margin: 15px;
flex-wrap: wrap;
align-content: flex-start;
/* overflow: scroll; */
/* overflow-x: hidden; */
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */
}
.FileTileView::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}
.FileTileView .Tile{
width: 50px;
height: 50px;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: center;
justify-content: flex-start;
gap: 2px;
padding: 0px;
flex-wrap: nowrap;
}
.FileTileView .Selected{
/* inherits: ; */
/* background-color: black; */
}
.FileTileView .Icon{
width: 32px;
height: 32px;
/* background-image: url("./icons/folder.png"); */
background-size: cover;
// image-rendering: optimizeSpeed; /* STOP SMOOTHING, GIVE ME SPEED */
// image-rendering: -moz-crisp-edges; /* Firefox */
// image-rendering: -o-crisp-edges; /* Opera */
// image-rendering: -webkit-optimize-contrast; /* Chrome (and eventually Safari) */
// image-rendering: pixelated; /* Universal support since 2021 */
// image-rendering: optimize-contrast; /* CSS3 Proposed */
// -ms-interpolation-mode: nearest-neighbor; /* IE8+ */
}
.FileTileView .Selected .Icon{
filter: brightness(0.4);
}
.FileTileView .Lable{
white-space: nowrap;
}
.FileTileView .Selected .Lable{
white-space: nowrap;
color: white;
background-color: black;
}

View File

@ -0,0 +1,54 @@
export default class WdeScrollBar{
/**
* @param {HTMLElement} scrollBarContainer
* @param {HTMLElement} content
*/
constructor(scrollBarContainer, content){
let nonNativeScroll = false
console.log(scrollBarContainer, content)
// let handler = scrollBarContainer.children[0]
//TODO On scroll move focus on window?
let handler = scrollBarContainer.querySelector(".scroll-element") //TODO Refactor classes
// console.log(handler)
handler.style.height = (content.clientHeight /content.scrollHeight)* handler.parentElement.clientHeight + 'px'
let max = handler.parentElement.clientHeight - handler.clientHeight
let yPosInit = 0
handler.addEventListener('mousedown', (event) => {
nonNativeScroll = true
yPosInit = event.clientY - Number(handler.style.top.replace('px','' ))
document.addEventListener('mousemove', drag);
document.addEventListener('mouseup', stop)
})
content.addEventListener('scroll', (event) =>{
if (!this.nonNativeScroll){
let handlerPathLength = handler.parentElement.clientHeight - handler.clientHeight //TODO recalculate only on resize event
let coefficient = (content.scrollHeight - content.clientHeight) /handlerPathLength
handler.style.top = content.scrollTop/coefficient + 'px'
}
})
function drag() {
// console.log(event.clientY - yPosInit, Number(handler.style.top.replace('px','' )))
let pos = event.clientY - yPosInit
let clampPos = Math.min(Math.max(pos, 0), max)
handler.style.top = clampPos + "px";
let handlerPathLength = handler.parentElement.clientHeight - handler.clientHeight //TODO recalculate only on resize event
let coefficient = (content.scrollHeight - content.clientHeight) /handlerPathLength
// console.log(clampPos, coefficient, content.clientHeight, clampPos* coefficient)
content.scrollTop = clampPos* coefficient
}
function stop() {
// console.log("stop")
document.removeEventListener('mousemove', drag);
document.removeEventListener('mouseup', stop)
nonNativeScroll = false
}
}
}

View File

@ -0,0 +1,110 @@
// .scroller {
// overflow-y: scroll;
// scrollbar-color: #0A4C95 #C2D2E4;
// border-radius: 0px;
// }
// .scroll-content {
// position: relative;
// width: 400px;
// height: 414px;
// top: -17px;
// padding: 20px 10px 20px 10px;
// overflow-y: auto;
// }
.scrollbar-place{
overflow: hidden;
border-left: @eff-border-grey;
width: 14px;
height: 100%;
bottom: 0px;
right: 0px;
width: 14px;
height: 100%;
// background-color: #EEEEEE;
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 1;
}
.Focused .active .scrollbar-place{
border-left: @eff-border-black;
background-color: #AAAAAA;
box-shadow: inset -1px 0px 0px rgba(255, 255, 255, 0.29),
inset -2px 0px 0px rgba(255, 255, 255, 0.19),
inset 1px 1px 0px rgba(0, 0, 0, 0.14),
inset 2px 2px 0px rgba(0, 0, 0, 0.19);
}
.scroll-element{
position: relative;
visibility: hidden;
width: 14px;
height: 31px;
background: #9999FF;
box-shadow: 0px -1px 0px #000000,
0px 1px 0px #000000,
0px 2px 0px rgba(0, 0, 0, 0.13),
0px 3px 0px rgba(0, 0, 0, 0.19),
inset 0px 1px 0px rgba(255, 255, 255, 0.5),
inset 1px 0px 0px rgba(255, 255, 255, 0.5),
inset -1px -1px 0px rgba(102, 102, 204, 0.91);
/* Auto layout */
display: flex;
flex-direction: row;
align-items: center;
justify-content: space-around;
gap: 5px;
padding: 0px;
}
.Focused .active .scroll-element{
visibility: visible;
}
.drag-element{
pointer-events: none;
/* background-color: #0A4C95; */
width: 7px;
height: 7px;
margin-left: -1px;
background: linear-gradient(transparent 0%,#CCCCFF 0%, #CCCCFF 50%, transparent 50%);
background-size: 2px 2px;
/* TODO white pixels in rows start */
filter: drop-shadow(1px 1px 0px #333399);
}
/* TODO to wde css */
.ScrollContent {
/* width: 100%;
height: 100%; */
overflow: scroll;
overflow-x: hidden;
scrollbar-width: none; /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */
/* Auto layout */
/* display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px; */
}
.ScrollContent::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}

View File

@ -0,0 +1,88 @@
@import "../../effects.less";
@import "../../../theme.less";
.title-bar{
width: 100%;
height: 13px;
display: flex;
flex-direction: row;
align-items: center;
justify-content: center;
gap: 5px;
padding: 0px;
/* Inside auto layout */
flex: none;
order: 0;
align-self: stretch;
flex-grow: 0;
}
.title-bar .lable{
position: relative;
top: 1px;
/* font-size: 13px; */
color: @col-grey;
pointer-events: none;
white-space: nowrap;
&:extend(.large-system-font);
// font-family: "Virtue";
// letter-spacing: 0.35px;
}
.window-frame.Focused .title-bar .lable{
color: @col-black;
}
.window-frame.Focused .title-bar .visual-drag-area{
&:extend(.rows-fill-shadowed);
pointer-events: none;
width: 100%;
height: 11px;
}
.title-bar > .icon{
// background-color: aqua;
width: 16px;
height: 16px;
}
.title-bar > .button{
width: 11px;
height: 11px;
padding: 0%;
position: relative;
top: 1px;
visibility: hidden;
&:active{
background-color: rgba(0, 0, 0, 0.4);
/* Green */
box-shadow: 0.5px 0.5px 0px 0.5px #FFFFFF,
-0.5px -0.5px 0px 0.5px rgba(0, 0, 0, 0.25);
}
background: linear-gradient(135deg, #999999 18.18%, #FFFFFF 81.82%);
border: 1px solid @col-raisin-black;
box-shadow: 0.5px 0.5px 0px 0.5px #FFFFFF,
-0.5px -0.5px 0px 0.5px rgba(0, 0, 0, 0.25),
inset 1px 1px 0px rgba(255, 255, 255, 0.5),
inset -1px -1px 0px rgba(0, 0, 0, 0.27);
/* Inside auto layout */
flex: none;
order: 0;
flex-grow: 0;
}
.window-frame.Focused .title-bar > .button{
visibility:visible;
}
// .window-frame.Focused .title-bar > .button:active{
// background-color: aqua;
// }

View File

@ -0,0 +1,50 @@
@import "../theme.less";
@import "./effects.less";
.window-frame{
position: absolute;
border: @eff-border-grey;
box-shadow: @eff-box-shadow-grey;
position: absolute;
background-color: @col-gainsboro;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
padding: 4px;
padding-top: 2px;
padding-right: 6px;
gap: 4px;
/* Inside auto layout */
flex: none;
order: 1;
align-self: stretch;
flex-grow: 1;
}
.window-frame.Focused{
background-color: @col-chinese-silver;
border: @eff-border-black;
box-shadow: @eff-box-shadow-grey, @eff-box-shadow-convex;
}
.content-border{
border: @eff-border-grey;
width: 100%;
height: 100%;
background-color: @col-bright-grey;
overflow: hidden;
overflow-x: hidden;
}
.Focused .content-border{
background-color: @col-gainsboro;
border: @eff-border-black;
box-shadow: @eff-box-shadow-adjective;
}

131
front/src/web-fs/web-fs.js Normal file
View File

@ -0,0 +1,131 @@
export default class WebFS{
/**
* @param {string} path
* @returns {boolean}
*/
static async CreateDirectory(path){
if (path == undefined){
WebDesktopEnvironment.Alert("Path is undefined")
return false
}
const params = new URLSearchParams({
path: `${path}/New Directory`
})
const response = await fetch(`/system/fs/createDir?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DIRCTORY CREATION ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async DeleteFile(path){
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/system/fs/delete?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("DELETE ERROR") //TODO
return false
}
return true
}
/**
* @param {string} path
* @returns {boolean}
*/
static async MoveFile(sourcePath, targetPath){
const params = new URLSearchParams({
sourcePath: sourcePath,
targetPath: targetPath
})
const response = await fetch(`/system/fs/move?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Move ERROR") //TODO
return false
}
return true
}
/**
* @param {string} linkPath
* @returns {string}
*/
static async ReadObjectLink(linkPath){
const params = new URLSearchParams({
linkPath: linkPath,
})
const response = await fetch(`/system/fs/readObjectLink?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("TODO") //TODO
return ""
}
const path = await response.text()
//TODO Validate
return path
}
/**
* @param {string} sourcePath
* @param {string} linkPath
* @returns {string}
*/
static async CreatePathLink(sourcePath, linkPath){
const params = new URLSearchParams({
sourcePath: sourcePath,
linkPath: linkPath,
})
const response = await fetch(`/system/fs/createPathLink?` + params)
return response.status == 200
}
/**
* @param {string} linkPath
* @returns {string}
*/
static async ReadPathLink(linkPath){
const params = new URLSearchParams({
linkPath: linkPath,
})
const response = await fetch(`/system/fs/readPathLink?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("TODO") //TODO
return ""
}
// console.log(response)
const file = await response.json()
//TODO Validate
return file
}
/**
* @param {File} file
* @param {string} parentPath
* @returns {boolean}
*/
static async UploadFile(file, parentPath){
console.log('here')
let formData = new FormData()
formData.append("file", file) //FIXME Conn reset
const params = new URLSearchParams({
parentPath: parentPath,
})
const response = await fetch(`/system/fs/upload?` + params,
{
method: "POST", //TODO Change to PUT?
body: formData
})
console.log(response.status)
if (response.status != 201){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return false
}
return true
}
}

1
go.mod
View File

@ -21,6 +21,7 @@ require (
require (
github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5
github.com/gin-contrib/cors v1.4.0
github.com/gin-contrib/location v0.0.2
github.com/gin-contrib/sse v0.1.0 // indirect

2
go.sum
View File

@ -10,6 +10,8 @@ github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ3
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5 h1:e+OSfbvxkjub+bPlfDmqENiV9IEOnLUk9TU7fMhu2Ks=
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5/go.mod h1:2F+cddOTo8Rjp/98JPjMwZRCcCA1dP1VeNBvfk/tU6I=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=

BIN
icons/genericApp/color/16.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/genericApp/color/32.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/genericDocument/color/16.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/genericDocument/color/32.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/genericFolder/color/16.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/genericFolder/color/32.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

BIN
icons/github/color/github.png (Stored with Git LFS) Normal file

Binary file not shown.

BIN
icons/hand/color/8.png (Stored with Git LFS) Normal file

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
icons/twitter/color/twitter.png (Stored with Git LFS) Normal file

Binary file not shown.

View File

@ -2,6 +2,7 @@ package libs
import (
"net/http"
"path"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
@ -35,6 +36,22 @@ func (l *ImagLib) PublicRoutes(route *gin.RouterGroup) {
ctx.Data(http.StatusOK, "image/jpeg", imgData.Bin)
})
iconGroup := route.Group("icon")
iconGroup.GET("get", func(ctx *gin.Context) {
iconPath := ctx.Query("path")
iconType := ctx.Query("type")
_ = iconType
iconSize := ctx.Query("size")
imgData := Img{}
_, err := l.fs.Read(path.Join(iconPath, "color", iconSize+".png"), &imgData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.Data(http.StatusOK, "image/jpeg", imgData.Bin)
})
}
func GetBase64Image(img *Base64Img, min string) (string, error) {

View File

@ -12,6 +12,7 @@ import (
"personalwebsite/apps/blogviewer"
"personalwebsite/apps/finder"
imgviewer "personalwebsite/apps/img-viewer"
"personalwebsite/apps/sunboard"
"personalwebsite/routes"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
@ -72,16 +73,20 @@ func main() {
imgViewerApp := imgviewer.NewImgViewerApp(webfs)
blogViewerApp := blogviewer.NewBlogViewerApp(webfs)
blogWriterApp := blogwriter.NewBlogWriterApp(webfs)
sunBoardApp := sunboard.NewSunboardApp(webfs, webde, appsStorage)
appsStorage.Apps["personal-properties"] = persPropsApp
appsStorage.Apps["finder"] = finderApp
appsStorage.Apps["img-viewer"] = imgViewerApp
appsStorage.Apps[blogViewerApp.GetAppID()] = blogViewerApp
appsStorage.Apps["BlogWriter"] = blogWriterApp
appsStorage.Apps["Sunboard"] = sunBoardApp
go routes.PublicRoutes(publicPort, webfs, webde, appsStorage)
routes.PrivateRoutes(privatePort, webfs, webde, appsStorage)
}
// TODO to for loop with aal vars in slice
func FindEnv(parameter string) (string, error) {
path, exists := os.LookupEnv(parameter)

View File

@ -1,11 +0,0 @@
{
"folders": [
{
"path": "."
},
{
"path": "../personal-website-frontend"
}
],
"settings": {}
}

View File

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__);
/******/
/******/ })()
;

1
res/dev-fs/wde/mobile.js Normal file
View File

@ -0,0 +1 @@
(()=>{"use strict";function e(e,n){for(var t=0;t<n.length;t++){var r=n[t];r.enumerable=r.enumerable||!1,r.configurable=!0,"value"in r&&(r.writable=!0),Object.defineProperty(e,r.key,r)}}function n(n,t,r){return t&&e(n.prototype,t),r&&e(n,r),Object.defineProperty(n,"prototype",{writable:!1}),n}new(n((function e(){!function(e,n){if(!(e instanceof n))throw new TypeError("Cannot call a class as a function")}(this,e)})))})();

View File

@ -11,6 +11,7 @@ import (
"personalwebsite/webfilesystem"
"time"
mobile "github.com/floresj/go-contrib-mobile"
"github.com/gin-contrib/cors"
"github.com/gin-contrib/location"
"github.com/gin-gonic/gin"
@ -25,9 +26,22 @@ type AppString struct { //TODO temp
func PrivateRoutes(port string, webfs *webfilesystem.WebFileSystem, webde *wde.WDE, appsStorage *apps.ApplicationsStorage) {
router := gin.New()
router.Use(location.Default())
router.Use(mobile.Resolver())
router.Use(favicon.New("./res/dev-fs/wde/icons/ohno.png"))
router.LoadHTMLGlob("templates/**/*")
router.Static("/res", "res")
router.Static("/front", "./front/")
// router.Use(cors.New(cors.Config{
// AllowOrigins: []string{"http://localhost:1234"},
// AllowMethods: []string{"PUT", "PATCH"},
// AllowHeaders: []string{"Origin"},
// ExposeHeaders: []string{"Content-Length"},
// AllowCredentials: true,
// AllowOriginFunc: func(origin string) bool {
// return origin == "http://localhost:1234"
// },
// MaxAge: 12 * time.Hour,
// }))
// Set a lower memory limit for multipart forms (default is 32 MiB)
router.MaxMultipartMemory = 8 << 20 // 8 MiB
@ -41,21 +55,35 @@ func PrivateRoutes(port string, webfs *webfilesystem.WebFileSystem, webde *wde.W
AppPath: "/Applications/BlogViewer.app",
Args: []string{"/home/user/Blogs/blog1.blog"},
}
_ = appString
aboutMe := AppString{
AppPath: "/Applications/AboutMe.app",
Args: []string{},
}
_ = aboutMe
desktop := AppString{
AppPath: "/Applications/Finder.app",
Args: []string{"/home/user/.Desktop", "--desktop", "desktop-layer"},
Args: []string{"/", "--desktop", "desktop-layer"},
}
autostart := []AppString{desktop}
d := mobile.GetDevice(ctx)
switch {
// Hey I'm a desktop!... or laptop but not a mobile or tablet!
case d.Normal():
ctx.HTML(http.StatusOK, "index.html", gin.H{
"autostart": autostart,
})
// Hey I'm a mobile device!
case d.Mobile():
ctx.HTML(http.StatusOK, "mobile-desktop.html", gin.H{
// "autostart": autostart,
})
// Woa I'm a tablet!
case d.Tablet():
ctx.JSON(http.StatusOK, "Hello I'm a tablet device")
}
autostart := []AppString{desktop, appString, aboutMe}
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{
"autostart": autostart,
})
})
systemGroup := router.Group("system")
{

View File

@ -23,7 +23,7 @@ func PublicRoutes(port string, webfs *webfilesystem.WebFileSystem, webde *wde.WD
router.Static("/res", "res")
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
ctx.HTML(http.StatusOK, "index.html", gin.H{})
})
systemGroup := router.Group("system")

View File

@ -1,27 +1,38 @@
<!DOCTYPE html>
<!DOCTYPE HTML>
<html lang="en" dir="ltr">
<title>Greg Brzezinski</title>
<head>
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/base.css">
<!-- TODO: Move css init to js -->
<!-- <link rel="stylesheet" type="text/css" href="res/dev-fs/wde/base.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/wdeUI.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/basic-widgets.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/wde-scrollbar.css">
<link rel="stylesheet" type="text/css" href="res/dev-fs/wde/file-view.css">
<!-- TODO: Move css init to js -->
<link rel="stylesheet" href="res/dev-fs/apps/Finder/finder.css">
<link rel="stylesheet" href="/res/dev-fs/apps/AboutMe/about-me.css">
<link rel="stylesheet" href="/res/dev-fs/apps/ImgViewer/img-viewer.css">
<link rel="stylesheet" href="/res/dev-fs/apps/BlogViewer/blog-viewer.css">
<script src="res/dev-fs/wde/wde.js"></script>
<script src="res/dev-fs/wde/dist/desktop.js"></script>
<script src="res/dev-fs/wde/decorat.js"></script>
<script src="res/dev-fs/wde/webfs.js"></script>
<script src="/res/dev-fs/wde/wde-scrollbar.js"></script>
<script src="/res/dev-fs/wde/file-view.js"></script>
<script src="/res/dev-fs/wde/file-view.js"></script> -->
<!-- <script src="res/dev-fs/wde/dist/desktop.js"></script> -->
<!-- <link rel="stylesheet" type="text/css" href="/res/dev-fs/dist/desktop_style.css"> -->
<!-- <link rel="stylesheet" type="text/css" href="/res/dev-fs/dist/finder_style.css"> -->
<link rel="stylesheet" href="/front/dist/desktop.css">
<!-- <link rel="stylesheet" href="/front/dist/apps/finder/finder.css"> -->
</head>
<body>
<script type="module">
import * as WebDesktopEnvironment from "/front/src/wde/wde-desktop.js"
// console.log(WebDesktopEnvironment)
let kek = new WebDesktopEnvironment.default()
</script>
<wde-autostart>
{{ range $app := .autostart }}
<app app-path="{{ $app.AppPath }}">

View File

@ -0,0 +1,34 @@
<!DOCTYPE HTML>
<meta name="viewport" content="width=device-width, initial-scale=1">
<html lang="en" dir="ltr">
<title>Greg Brzezinski</title>
<head>
<!-- <script src="res/dev-fs/dist/mobile.js"></script> -->
<link rel="stylesheet" href="/front/dist/mobile.css">
<!-- <link rel="stylesheet" href="/front/dist/apps/finder/finder.css"> -->
</head>
<body>
<script type="module">
import * as wde from '/front/src/wde/wde-mobile.js';
// console.log(WebDesktopEnvironment)
let kek = new wde.default()
</script>
<!-- <div id="mobile-sunboard">
</div> -->
<div id="mobile-app-views"></div>
<div id="controls-bar">
<button id="back" class="wde-mobile-button Click" >
<img class="icon NoClick" src="/system/libs/img/get?path=/Icons/Hand.icn/color/8.png">
<div class="lable NoClick">Back</div>
</button>
<!-- <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>
</body>
</html>

View File

@ -1,26 +0,0 @@
{{ define "base/mobile-desktop.tmpl" }}
<div id="border" class="">
<div id="windows-layer" class="mobile-windows-layer ContentBorder">
<div class="FileTileView">
</div>
</div>
</div>
<div id="toolbar">
<div id="about-me" class="FileTile" >
<div class="Icon NoClick" style="background-image: url('./res/sys/wde/icons/about-me.png');"></div>
<div class="FileTileTitle NoClick">About Me</div>
</div>
<div id="mobile-desktop-blog" class="FileTile">
<div class="Icon NoClick" style="background-image: url('./res/sys/wde/icons/desktop.png');"></div>
<div class="FileTileTitle NoClick">Blog</div>
</div>
<div id="mobile-dekstop-close" class="FileTile">
<div class="Icon NoClick" style="background-image: url('./res/sys/wde/icons/trash.png');"></div>
<div class="FileTileTitle NoClick">Close</div>
</div>
</div>
{{ end }}

View File

@ -0,0 +1,23 @@
{{ define "finder/admin-app.tmpl" }}
{{template "wde-widgets/window-title-bar.tmpl" .TitleBarConfig}}
<div id="ContentBorder" class="content-border AdjectiveElement">
<div class="finder-content">
<div class="tool-bar">
<!-- <button id="BackButton">Back</button>
<button id="UpButton">Up</button>
<button id="RootButton">/</button>
<button id="HomeButton">Home</button>
<div class="AddressBar" contentEditable="true">You Favorite Movie</div> -->
</div>
<div class="file-view-container">
<div class="FileTileView">
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
</div>
</div>
{{ end }}

View File

@ -1,32 +0,0 @@
{{ define "finder/admin-app.tmpl" }}
<div class="TitleBar DragArea">
<button id="closeWindowButton" class="Button" title="Close Window"></button>
<div id="Drag" class="VisualDragArea"></div>
<div class="Lable">
Admin Finder
</div>
<div id="Drag" class="VisualDragArea"></div>
</div>
<div id="ContentBorder" class="ContentBorder AdjectiveElement">
<div class="FinderContent">
<!-- TODO Fix ConvexElement -->
<div class="ToolBar ConvexElement">
<button id="BackButton">Back</button>
<button id="UpButton">Up</button>
<button id="RootButton">/</button>
<button id="HomeButton">Home</button>
<div class="AddressBar" contentEditable="true">You Favorite Movie</div>
</div>
<div class="FinderFileView">
<div class="FileTileView">
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
</div>
</div>
{{ end }}

View File

@ -10,8 +10,7 @@
</div>
<div id="ContentBorder" class="ContentBorder AdjectiveElement">
<div class="FinderContent">
<!-- TODO Fix ConvexElement -->
<!-- <div class="FinderContent">
<div class="ToolBar ConvexElement">
Folder info
</div>
@ -20,7 +19,7 @@
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
</div>
</div> -->
</div>
{{ end }}

View File

@ -0,0 +1,22 @@
{{ define "finder/mobile-app.tmpl" }}
<div id="ContentBorder" class="content-border AdjectiveElement">
<div class="finder-content">
<div class="tool-bar">
<!-- <button id="BackButton">Back</button>
<button id="UpButton">Up</button>
<button id="RootButton">/</button>
<button id="HomeButton">Home</button>
<div class="AddressBar" contentEditable="true">You Favorite Movie</div> -->
</div>
<div class="file-view-container">
<div class="FileTileView">
</div>
{{template "wde-widgets/scrollbar.tmpl" .}}
</div>
</div>
</div>
{{ end }}

View File

@ -1,8 +0,0 @@
{{ define "finder/mobile-app.tmpl" }}
<div class="MobileContentBorder">
<div class="FileTileView">
</div>
</div>
{{ end }}

View File

@ -1,13 +1,13 @@
{{ define "finder/props.tmpl" }}
<div class="TitleBar DragArea">
<button id="closeWindowButton" class="Button" title="Close Window"></button>
<div id="Drag" class="VisualDragArea"></div>
<div class="Lable">
File Properties
<div class="title-bar DragArea">
<button id="closeWindowButton" class="button" title="Close Window"></button>
<div id="Drag" class="visual-drag-area"></div>
<div class="lable">
Properties
</div>
<div id="Drag" class="VisualDragArea"></div>
<div id="Drag" class="visual-drag-area"></div>
</div>
<div class="ContentBorder">
<div class="content-border">
<div class="PropertiesList">
<div class="Personal-properties-bio">
<!-- <img src="data:{{ .headerProps.Icon.Header }},{{ .headerProps.Icon.Base64 }}" alt="File Icon" style="width: 48px;height: 48px;"> -->

View File

@ -1,21 +1,10 @@
{{ define "personal-properties/app.tmpl" }}
<div class="TitleBar DragArea">
<button id="closeWindowButton" class="Button" title="Close Window"></button>
<div id="Drag" class="VisualDragArea"></div>
<div class="Lable">About me</div>
<div id="Drag" class="VisualDragArea"></div>
</div>
<div class="ContentBorder AdjectiveElement">
{{template "wde-widgets/window-title-bar.tmpl" .TitleBarConfig}}
<div class="content-border">
<div class="PersPropsContent">
<div class="PropsView">
<div class="PropertiesList">
<div class="Links">
{{ range $link := .Links }}
<a href="{{$link.Url}}" target="_blank">
<img class="Link" src="/system/libs/img/get?path={{$link.Icon}}" alt="{{$link.Text}}">
</a>
{{ end }}
</div>
<div class="ShortBio">
<img class="Image" src="/system/libs/img/get?path={{ .HeaderProps.IconPath }}" alt="My Photo">
<div class="Text">
@ -23,6 +12,14 @@
<div>{{ .HeaderProps.Value1 }}</div>
<div>{{ .HeaderProps.Value2 }}</div>
</div>
<div class="Links">
{{ range $link := .Links }}
<a href="{{$link.Url}}" target="_blank">
<div class="link-lable">{{$link.Text}}</div>
<img class="Link" src="/system/libs/img/get?path={{$link.Icon}}" >
</a>
{{ end }}
</div>
</div>
{{ range $island := .Islands }}
<!-- FIXME -->

View File

@ -0,0 +1,52 @@
{{ define "personal-properties/mobile-app.tmpl" }}
<div class="ContentBorder AdjectiveElement">
<div class="PersPropsContent">
<div class="PropsView">
<div class="PropertiesList">
<div class="Links">
{{ range $link := .Links }}
<a href="{{$link.Url}}" target="_blank">
<div class="link-lable">{{$link.Text}}</div>
<img class="Link" src="/system/libs/img/get?path={{$link.Icon}}" >
</a>
{{ end }}
</div>
<div class="ShortBio">
<img class="Image" src="/system/libs/img/get?path={{ .HeaderProps.IconPath }}" alt="My Photo">
<div class="Text">
<div class="Name">{{ .HeaderProps.Name }}</div>
<div>{{ .HeaderProps.Value1 }}</div>
<div>{{ .HeaderProps.Value2 }}</div>
</div>
</div>
{{ range $island := .Islands }}
<!-- FIXME -->
<div class="Island">
<div class="Title"> {{$island.Header}}:</div>
<div class="Content">
{{range $property := $island.Properties}}
<div class="Row">
<div class="Key">
{{$property.Key}}:
{{ range $keyComment := $property.KeyComments }}
<div class="KeyComment">{{ $keyComment }}</div>
{{ end }}
</div>
<div class="Values">
{{ range $value := $property.Values }}
<div class="Value">{{ $value }}</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
<!-- {{template "wde-widgets/scrollbar.tmpl" .}} -->
</div>
</div>
{{ end }}

View File

@ -1,45 +0,0 @@
{{ define "personal-properties/mobile-app.tmpl" }}
<div class="MobileContentBorder">
<div class="ScrollContent">
<div class="PropertiesList">
<div class="Personal-properties-bio">
<img src="res/img/default-avatar-photo-placeholder-profile-picture-vector.jpg" alt="My Photo" style="width: 48px;height: 48px;">
<div class="Personal-properties-textbio">
<div>{{ .Name }}</div>
<div>{{ .BasicBio }}</div>
</div>
</div>
{{ range $propIsland := .allprops }}
<div id="prop" class="Personal-properties-prop">
<div class="Personal-properties-prop-title">
{{$propIsland.Header}}:
</div>
<div class="Personal-properties-prop-content">
{{range $prop := $propIsland.Props}}
<div class="Personal-properties-prop-row">
<div class="Personal-properties-prop-key">
{{$prop.Key}}:
{{ range $value := $prop.KeyComments }}
<div class="Personal-properties-prop-key-comments">
{{ $value }}
</div>
{{ end }}
</div>
<div class="Personal-properties-prop-values">
{{ range $value := $prop.Values }}
<div class="Personal-properties-prop-value">
{{ $value }}
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
{{ end }}
</div>
</div>
</div>
{{ end }}

View File

@ -0,0 +1,15 @@
{{ define "sunboard/sunboard.html" }}
<div id="icons">
<div class="apps-list NoClick">
{{ range $appIcon := .AppsIcons }}
<div fileType="{{ $appIcon.Type }}" path="{{$appIcon.Path}}"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 }}

View File

@ -0,0 +1,8 @@
{{ define "wde-widgets/scrollbar.tmpl" }}
<div class="scrollbar-place">
<div class="scroll-element">
<div class="drag-element">
</div>
</div>
</div>
{{ end }}

View File

@ -1,8 +0,0 @@
{{ define "wde-widgets/scrollbar.tmpl" }}
<div class="ScrollbarPlace">
<div class="ScrollBarScrollElement">
<div class="ScrollBarScrollElementDrag">
</div>
</div>
</div>
{{ end }}

View File

@ -0,0 +1,16 @@
{{ define "wde-widgets/window-title-bar.tmpl" }}
<div class="title-bar DragArea">
{{if .CloseButton}}
<button id="closeWindowButton" class="button" title="Close Window"></button>
{{end}}
<div id="Drag" class="visual-drag-area"></div>
<!-- TODO:Disable dragging of icon -->
{{if .HasIcon}}
<img class="icon" src="/system/libs/img/icon/get?path={{.IconPath}}&size={{.IconSize}}">
{{ end }}
<div class="lable">
{{.Lable}}
</div>
<div id="Drag" class="visual-drag-area"></div>
</div>
{{ end }}

9
wde/titlebar.go Normal file
View File

@ -0,0 +1,9 @@
package wde
type TitleBarConfig struct {
Lable string
CloseButton bool
HasIcon bool
IconPath string
IconSize string
}

View File

@ -28,28 +28,32 @@ func (w *WDE) RenderFileTileView(directory string, host string) (gin.H, error) {
}
for _, file := range list {
file.Icon = w.GetIconPathForFile(file, directory)
file.Icon = w.GetIconPathForFile(file, directory, "32")
}
return gin.H{
"Files": list,
}, nil
}
func (w *WDE) GetIconPathForFile(fileHeader *webfilesystem.FileHeader, parentDir string) string {
func (w *WDE) GetIconPathForFile(fileHeader *webfilesystem.FileHeader, parentDir string, size string) string {
if fileHeader.Icon != "" {
return "/system/libs/img/get?path=" + fileHeader.Icon
return "/system/libs/img/icon/get?path=" + fileHeader.Icon + "&size=" + size
}
switch fileHeader.GetType() {
case "directory":
return "/system/libs/img/get?path=/wde/icons/macos9/folder.png"
case "jpeg":
extension := fileHeader.GetExtension()
switch true {
case extension == "app":
return "/system/libs/img/icon/get?path=/Icons/GenericApp.icn&size=" + size
case extension == "jpeg":
fallthrough
case "png":
case extension == "png":
fallthrough
case "jpg":
return "/system/libs/img/get?path=" + path.Join(parentDir, fileHeader.Name)
case extension == "jpg":
return "/system/libs/img/get?path=" + path.Join(parentDir, fileHeader.Name) //+ "&size=" + size
case fileHeader.GetType() == "directory":
return "/system/libs/img/icon/get?path=/Icons/GenericFolder.icn&size=" + size
default:
return "/system/libs/img/get?path=/wde/icons/macos9/folder.png"
return "/system/libs/img/icon/get?path=/Icons/GenericDocument.icn&size=" + size
}
}

View File

@ -41,6 +41,11 @@ func (fh *FileHeader) GetType() string {
return fh.Type
}
func (fh *FileHeader) GetExtension() string {
return strings.Split(fh.Name, ".")[len(strings.Split(fh.Name, "."))-1]
}
type BinaryFileData struct {
MongoId primitive.ObjectID `bson:"_id" json:"-"`
Bin []byte `bson:"bin" json:"-"`