Compare commits

...

3 Commits

Author SHA1 Message Date
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
95 changed files with 9979 additions and 12657 deletions

6
.gitignore vendored
View File

@ -24,4 +24,8 @@ go.work
/__debug_bin
/.env
front/node_modules/**
front/node_modules
.parcel-cache
**/node_modules/
front/node_modules/*

View File

@ -57,13 +57,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 +153,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 +186,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")

View File

@ -44,6 +44,7 @@ func (a *SunboardApp) PrivateRoutes(router *gin.RouterGroup) {
Icon: "",
Lable: app.GetAppID(),
AppId: app.GetAppID(),
Path: "/Applications/" + app.GetAppID() + ".app", //FIXME
})
}
ctx.HTML(http.StatusOK, "sunboard/sunboard.html", gin.H{
@ -57,4 +58,5 @@ type appIcon struct {
Type string
Icon string
Lable string
Path string
}

View File

@ -1,11 +0,0 @@
{
"plugins": ["@babel/syntax-dynamic-import"],
"presets": [
[
"@babel/preset-env",
{
"modules": false
}
]
]
}

View File

@ -1,15 +0,0 @@
# 🚀 Welcome to your new awesome project!
This project has been created using **webpack-cli**, you can now run
```
npm run build
```
or
```
yarn build
```
to bundle your application

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

@ -0,0 +1,149 @@
.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;
flex: 1 0 auto;
order: 0;
align-self: stretch;
align-items: center;
gap: 15px;
margin-right: 20px;
padding: 0;
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;
}
.ShortBio .Name {
letter-spacing: .35px;
font-family: Virtue;
}
.PropertiesList .Links {
align-items: left;
flex-direction: row;
gap: 4px;
width: auto;
height: auto;
padding: 0;
display: flex;
position: absolute;
top: 27px;
right: 14px;
}
.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 {
letter-spacing: .35px;
background-color: #ddd;
max-width: 100%;
font-family: Virtue;
display: inline-block;
position: relative;
top: -9px;
left: 12px;
}
.Focused .Island .Title {
background-color: #ccc;
}
.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 {
letter-spacing: .35px;
text-align: end;
white-space: nowrap;
width: 34%;
font-family: Virtue;
font-size: 11px;
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":"AAwBA;;;;;;;;;;AAYA;;;;;AAKA;;;;;;;;;;;AAkBA;;;;;;;;;;;;AAoBA;;;;;;AAMA;;;;;;;;;;;AAkBA;;;;;AAMA;;;;;;;;;;;;;AAgBA;;;;;AAMA;;;;;;;;AAeA;;;;;;;;;;;AAYA;;;;AAIA;;;;;;;;;AAWA;;;;;;;;;;AAUA;;;;;;;;;;;AAaA;;;;;;;;AAUA","sources":["src/apps/about-me/about-me.less"],"sourcesContent":["/* TODO Move this to body? */\n/*.ScrollContent {\n width: 100%;\n height: 100%;\n overflow: scroll;\n overflow-x: hidden;\n /* Firefox */\n /* scrollbar-width: none; */\n /* Internet Explorer 10+ */\n /* -ms-overflow-style: none; */\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/* WebKit */\n/* .ScrollContent::-webkit-scrollbar { \n width: 0;\n height: 0;\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 /* 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: 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 .Name{\n font-family: \"Virtue\";\n /* FIXME */\n letter-spacing: 0.35px; \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 /* Auto layout */\n display: flex;\n flex-direction: row;\n align-items: left;\n padding: 0px;\n gap:4px;\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 font-family: \"Virtue\";\n /* FIXME */\n letter-spacing: 0.35px; \n position:relative;\n display: inline-block;\n max-width: 100%;\n background-color: #DDDDDD;\n left: 12px;\n top: -9px;\n}\n\n.Focused .Island .Title{\n background-color: #CCCCCC;\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 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}"],"names":[],"version":3,"file":"about-me.css.map","sourceRoot":"/__parcel_source_root/"}

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

@ -0,0 +1,34 @@
.FinderContent {
flex-direction: column;
justify-content: center;
align-items: flex-start;
width: 100%;
height: 100%;
padding: 0;
display: flex;
}
.FinderContent .ToolBar {
background-color: #eee;
border-bottom: 1px solid #555;
width: 100%;
height: 20px;
}
.Focused .FinderContent .ToolBar {
background-color: #ddd;
border-bottom: 1px solid #000;
}
.FinderContent .FinderFileView {
background-color: #fff;
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":"AAAA;;;;;;;;;;AAYA;;;;;;;AAOA;;;;;AAOA","sources":["src/apps/finder/finder.less"],"sourcesContent":[".FinderContent {\n width: 100%;\n height: 100%;\n\n /* Auto layout */\n display: flex;\n flex-direction: column;\n justify-content: center;\n align-items: flex-start;\n padding: 0px;\n}\n\n.FinderContent .ToolBar{\n width: 100%;\n height: 20px;\n border-bottom: 1px solid #555555;\n background-color: #EEEEEE;\n}\n\n.Focused .FinderContent .ToolBar{\n border-bottom: 1px solid #000000;\n background-color: #DDDDDD;\n}\n\n\n\n.FinderContent .FinderFileView{\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}"],"names":[],"version":3,"file":"finder.css.map","sourceRoot":"/__parcel_source_root/"}

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

@ -0,0 +1,329 @@
.WdePrimitives.AdjectiveElement {
border: 1px solid #555;
}
.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 {
image-rendering: optimizespeed;
image-rendering: -moz-crisp-edges;
image-rendering: -o-crisp-edges;
image-rendering: -webkit-optimize-contrast;
image-rendering: pixelated;
image-rendering: optimize-contrast;
-ms-interpolation-mode: nearest-neighbor;
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;
}
.WindowFrame {
background: #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;
}
.WindowFrame.Focused {
background-color: #ccc;
border: 1px solid #000;
}
.WindowFrameShadow {
box-shadow: 2px 2px #555;
}
.WindowFrameShadow.Focused {
box-shadow: 2px 2px #000;
}
.ConvexElement.Focused {
box-shadow: 1px 1px #00000040, inset -1px -1px #00000045, inset 1px 1px #fff;
}
.AdjectiveElement {
border: 1px solid #555;
}
.Focused .AdjectiveElement {
border: 1px solid #000;
box-shadow: -1px -1px #00000040, 1px 1px #fff;
}
.AdjectiveHorizontalLine {
border-top: 1px solid #00000040;
border-bottom: 1px solid #fff;
width: 100%;
height: 0;
}
.AdjectiveHorizontalLine:last-child {
visibility: hidden;
height: 0%;
}
.WindowFrame .TitleBar {
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;
}
.WindowFrame .TitleBar .Lable {
color: #777;
pointer-events: none;
white-space: nowrap;
letter-spacing: .35px;
font-family: Virtue;
position: relative;
top: 1px;
}
.WindowFrame.Focused .TitleBar .Lable {
color: #000;
}
.WindowFrame .TitleBar .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;
}
.WindowFrame.Focused .TitleBar .Button {
visibility: visible;
}
.WindowFrame .TitleBar .Button:active {
background-color: #0006;
box-shadow: .5px .5px 0 .5px #fff, -.5px -.5px 0 .5px #00000040;
}
.Focused .VisualDragArea {
pointer-events: none;
filter: drop-shadow(1px 1px #777);
background: linear-gradient(#0000 0%, #fff 0% 50%, #0000 50%) 0 0 / 2px 2px;
width: 100%;
height: 11px;
}
.MobileContentBorder {
background-color: #ddd;
flex-direction: row;
justify-content: center;
align-items: flex-start;
width: 100%;
height: 100%;
padding: 0;
display: flex;
overflow: hidden;
}
.MobileApplicationWindow {
flex-direction: column;
align-items: flex-start;
gap: 4px;
width: 100%;
height: 100%;
display: flex;
position: absolute;
top: 0;
left: 0;
}
.MobileWindowFrameBottomBar {
flex: none;
order: 0;
align-self: stretch;
width: 100%;
height: 20px;
}
.MobileWindowFrameBottomBarButton {
background: linear-gradient(135deg, #999 18.18%, #fff 81.82%);
border: 1px solid #222;
flex: none;
order: 0;
width: auto;
min-width: 11px;
height: 15px;
padding: 0 4px;
position: absolute;
right: 4px;
box-shadow: .5px .5px 0 .5px #fff, -.5px -.5px 0 .5px #00000040, inset 1px 1px #ffffff80, inset -1px -1px #00000045;
}
.MobileWindowFrameBottomBar .MobileLable {
pointer-events: none;
white-space: nowrap;
letter-spacing: .35px;
font-family: Virtue;
position: absolute;
left: 50%;
}
.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;
}
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
* {
font-family: Verdana, Geneva, sans-serif;
font-size: 11px;
font-style: normal;
font-weight: initial;
}
::-webkit-scrollbar {
width: 0;
height: 0;
}
body {
zoom: var(--zoom);
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-select: none;
touch-action: manipulation;
width: 100%;
height: 100%;
margin: 0;
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;;;;ACAA;;;;;AASA;;;;AAKA;;;;;;;;;;;;;AAqBA;;;;;AAKA;;;;;;;;;;;AAkBA;;;;;;;;;;;;;AAeA;;;;AAIA;;;;AAIA;;;;;;ACjFA;;;;;;;;;;;;;;AAwBA;;;;;AAKA;;;;AAKA;;;;AAIA;;;;AAMA;;;;AAIA;;;;;AAQA;;;;;;;AAOA;;;;;AAMA;;;;;;;;;;;;;;AAmBA;;;;;;;;;;AAYA;;;;AAKA;;;;;;;;;;;;;;AAoBA;;;;AAIA;;;;;AAOA;;;;;;;;AASA;;;;;;;;;;;;AAsBA;;;;;;;;;;;;AAcA;;;;;;;;AAkBA;;;;;;;;;;;;;;AAqBA;;;;;;;;;AC5NA;;;;;;AAUA;;;;;;;;AAUA;;;;;;;;;AAgBA;;;;;AAYA;;;;;AAKA;;;;;;;AJ/BA;;;;AAGA;;;;AAGA;;;;;;;AAOA;;;;;AAKA;;;;;;;;;;;;;AAkBA;;;;;;;AAOA;;;;;;AAOA","sources":["src/desktop.less","src/wde/primitives.less","src/wde/widgets/file-view/file-view.less","src/wde/legacy-ui.less","src/wde/widgets/basic-widgets.less"],"sourcesContent":["@import \"./wde/primitives.less\";\n@import \"./wde/widgets/file-view/file-view.less\";\n@import \"./wde/legacy-ui.less\";\n@import \"./wde/widgets/basic-widgets.less\";\n@import \"./theme.less\";\n\n// @font-face{\n// font-family: \"Virtue\";\n// src:url(\"/res/dev-fs/fonts/virtue.ttf\");\n// }\n\n/* @font-face{\n font-family: \"Virtue\";\n src:url(\"/res/dev-fs/fonts/virtue.ttf\")\n} */\n\n/* @media screen and (max-device-width: 2048px) and (max-device-height: 2048px) {\n html {\n zoom: 3\n }\n } */\n\n.NoClick {\n pointer-events: none;\n}\n.Click {\n pointer-events: all;\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 zoom: var(--zoom);\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0px;\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],"names":[],"version":3,"file":"desktop.css.map","sourceRoot":"/__parcel_source_root/"}

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

@ -0,0 +1,89 @@
.WdePrimitives.AdjectiveElement {
border: 1px solid #555;
}
#mobile-sunboard {
flex-direction: column;
justify-content: flex-start;
align-items: flex-start;
width: 100%;
height: 100%;
display: flex;
}
#icons {
background-color: #99c;
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: 103px 18px;
padding: 64px 32px;
display: flex;
}
.app-icon {
flex-direction: column;
align-items: center;
gap: 10px;
width: 100px;
height: 100px;
padding: 4px 8px;
display: flex;
}
.app-icon .icon {
background-color: beige;
width: 64px;
height: 64px;
}
body {
zoom: 2;
-webkit-touch-callout: none;
-webkit-user-select: none;
user-select: none;
-khtml-user-select: none;
touch-action: manipulation;
background-image: linear-gradient(45deg, silver 25%, #0000 25%), linear-gradient(45deg, #0000 75%, silver 75%), linear-gradient(45deg, #0000 75%, silver 75%), linear-gradient(45deg, silver 25%, #777 25%);
background-position: 0 0, 0 0, -5px -5px, 5px 5px;
background-size: 10px 10px;
width: 100%;
height: 100%;
margin: 0;
position: absolute;
}
#mobile-app-views {
background: #99c;
border: 1px solid #000;
border-radius: 15px;
position: absolute;
inset: 16px 16px 128px;
overflow: hidden;
}
#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%;
}
/*# sourceMappingURL=mobile.css.map */

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

@ -0,0 +1 @@
{"mappings":"ACAA;;;;ACGA;;;;;;;;;AAWA;;;;;;AAaA;;;;;;;;;;;AAYA;;;;;;;;;;AAYA;;;;;;AFjDA;;;;;;;;;;;;;;;;AAmCA;;;;;;;;;AAYA;;;;;;;;;;;;AAiBA","sources":["src/mobile.less","src/wde/primitives.less","src/wde/sunboard/sunboard-mobile.less"],"sourcesContent":["@import \"./wde/sunboard/sunboard-mobile.less\";\n\nbody{\n zoom: 2;\n position: absolute;\n width: 100%;\n height: 100%;\n margin: 0px;\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 // /* 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: 128px;\n \n border-radius: 15px;\n border: 1px solid #000;\n background: #99C;\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}",null,null],"names":[],"version":3,"file":"mobile.css.map","sourceRoot":"/__parcel_source_root/"}

View File

@ -1,12 +0,0 @@
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Webpack App</title>
</head>
<body>
<h1>Hello world!</h1>
<h2>Tip: Check your console</h2>
</body>
</html>

15830
front/package-lock.json generated

File diff suppressed because it is too large Load Diff

View File

@ -1,31 +1,6 @@
{
"devDependencies": {
"@babel/core": "^7.20.2",
"@babel/preset-env": "^7.20.2",
"@webpack-cli/generators": "^3.0.7",
"babel-loader": "^9.1.0",
"css-loader": "^6.7.2",
"less": "^4.1.3",
"less-loader": "^11.1.0",
"mini-css-extract-plugin": "^2.7.6",
"style-loader": "^3.3.1",
"webpack": "^5.88.2",
"webpack-cli": "^5.1.4",
"webpack-dev-server": "^4.11.1"
},
"type": "module",
"version": "1.0.0",
"description": "My webpack project",
"name": "my-webpack-project",
"scripts": {
"build": "webpack --mode=production --node-env=production",
"build:dev": "webpack --mode=development",
"build:prod": "webpack --mode=production --node-env=production",
"watch": "webpack --watch",
"watch:prod": "webpack --watch --mode=production --node-env=production",
"serve": "webpack serve"
},
"dependencies": {
"request": "^2.79.0"
"@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,220 @@
/* TODO Move this to body? */
/*.ScrollContent {
width: 100%;
height: 100%;
overflow: scroll;
overflow-x: hidden;
/* Firefox */
/* scrollbar-width: none; */
/* Internet Explorer 10+ */
/* -ms-overflow-style: none; */
/* Auto layout */
/*display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}*/
/* WebKit */
/* .ScrollContent::-webkit-scrollbar {
width: 0;
height: 0;
} */
.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; */
/* Inside auto layout */
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 .Name{
font-family: "Virtue";
/* FIXME */
letter-spacing: 0.35px;
}
.PropertiesList .Links {
position: absolute;
right: 14px;
top: 27px;
/* background-color: aqua; */
height: auto;
width: auto;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: left;
padding: 0px;
gap:4px;
}
.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 {
font-family: "Virtue";
/* FIXME */
letter-spacing: 0.35px;
position:relative;
display: inline-block;
max-width: 100%;
background-color: #DDDDDD;
left: 12px;
top: -9px;
}
.Focused .Island .Title{
background-color: #CCCCCC;
}
.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;
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

@ -1,28 +1,40 @@
// import WebDesktopEnvironment from "../../wde/wde-desktop"
import AbstractWebDesktopEnvironment from "../../wde/wde.js"
import Finder from "./finder.js"
// import Finder from "./finder"
// import WebDesktopEnvironment from "../../wde/wde-desktop"
export default class FinderWindow{
#appId = "Finder" //FIXME
curPath = ""
fileView = undefined
windowElem = undefined
/** @type {WebDesktopEnvironment} */
#wde
/** @type {Finder} */
#finder
/**
* @deprecated
* @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-desktop").runContext} runContext
* @param {import("../../wde/wde.js").runContext} runContext
* @returns
*/
async Init(finder, args, runContext){
console.log(args)
this.#finder = finder
this.#wde = runContext.WDE
if (runContext.isMobile){
console.log("Mobile Finder!")
this.CreateMobileView(args, runContext)
return
}
@ -43,18 +55,20 @@ export default class FinderWindow{
})
if (response.status != 200){
console.log(response.status)
this.#wde.Alert("Error in render desktop") //TODO
// this.#wde.Alert("Error in render desktop") //TODO
return
}
const html = await response.text()
desktopNode.innerHTML = html
this.fileView = new runContext.WDE.FileView(
// 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.ReRenderDir() },
this.#wde)
this.RenderDir(args[0])
return
}
@ -76,13 +90,13 @@ export default class FinderWindow{
// console.log(this.#wde)
this.fileView = new runContext.WDE.FileView(
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.ReRenderDir() },
this.#wde)
newWindow.querySelector("#closeWindowButton").addEventListener('click', () => {
this.#wde.Decorat.CloseWindow(newWindow)
@ -108,7 +122,7 @@ export default class FinderWindow{
/**
* @param {*} args
* @param {import("../../wde/wde-desktop").runContext} runContext
* @param {import("../../wde/wde-desktop.js").runContext} runContext
* @returns
*/
async CreateMobileView(args, runContext){
@ -126,7 +140,7 @@ export default class FinderWindow{
}
const html = await response.text()
console.log(this.#wde)
let newView = this.#wde.Decorat.CreateNewView(this.#appId,)
let newView = this.#wde.Decorat.CreateNewView(this.#appId)
newView.innerHTML = html
}
/**

View File

@ -1,37 +1,38 @@
// require("./finder.less")
import WDEApplication from "../../wde/application.js"
import WebDesktopEnvironment from "../../wde/wde-desktop.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 {WebDesktopEnvironment} wde
* @param {AbstractWebDesktopEnvironment} wde
*/
constructor(wde){
/** @type {WDEApplication} */
super(wde)
super(wde, "Finder")
}
/**
* @param {string[]} args
* @param {import("../../wde/wde-desktop.js").runContext} runContext
* @param {import("../../wde/wde.js").runContext} runContext
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
await newFinder.Init(this, args, runContext)
let newFinder = new FinderWindow(this, super.WDE())
await newFinder.Init(this, args, runContext)
}
/**
/**
* @param {string[]} args
* @param {import("../../wde/wde-desktop.js").runContext} runContext
* @param {import("../../wde/wde.js").runContext} runContext
*/
async NewView(args, runContext){
let newFinderView = new FinderWindow(this, args, runContext)
// console.log(super.WDE())
let newFinderView = new FinderWindow(this, super.WDE())
await newFinderView.Init(this, args, runContext)
}
@ -40,7 +41,6 @@ export default class Finder extends WDEApplication{
* @returns {boolean}
*/
async RenderProperites(path){
// return
if (path == null || path ==""){
return
@ -48,6 +48,7 @@ export default class Finder extends WDEApplication{
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/${Finder.AppId}/renderProps?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Error in properties render") //TODO
@ -55,7 +56,7 @@ export default class Finder extends WDEApplication{
}
const html = await response.text()
let newWindow = super.getWde().Decorat.CreateNewWindow(Finder.AppId, 350, 500 )
let newWindow = super.WDE().Decorat.CreateNewWindow(Finder.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
// WebDesktopEnvironment.CloseWindow(newWindow)

View File

@ -1,4 +0,0 @@
import WebDesktopEnvironment from "./wde/wde-desktop.js";
document.addEventListener('DOMContentLoaded', function() {
let wde = new WebDesktopEnvironment()
}, false);

View File

@ -1,5 +0,0 @@
import MobileWebDesktopEnvironment from "./wde/wde-mobile";
require("./mobile.less")
document.addEventListener('DOMContentLoaded', function() {
let wde = new MobileWebDesktopEnvironment()
}, false);

View File

@ -1,7 +1,7 @@
@import "./wde/sunboard/sunboard-mobile.less";
body{
zoom: var(--zoom);
zoom: 2;
position: absolute;
width: 100%;
height: 100%;
@ -17,30 +17,51 @@ body{
supported by Chrome, Edge, Opera and Firefox */
touch-action: manipulation;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
// /* 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{
width: 100%;
height: 100%;
// background-color: @col-ceil;
position: absolute;
// background-color: aqua;
inset: 16px;
bottom: 128px;
border-radius: 15px;
border: 1px solid #000;
background: #99C;
overflow: hidden;
}
#controls-bar{
&:extend(.WdePrimitives.AdjectiveElement);
position: absolute;
width: 100%;
height: 150px;
background-color: @col-argent;
height: 100px;
// background-color: @col-argent;
bottom: 0px;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
// padding: 10px;
justify-content: center;
align-items: center;
gap: 53px;
align-self: stretch;
}
.mobile-app-view{

View File

@ -0,0 +1,339 @@
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
/** @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){
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.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
// console.log(this.#wde)
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() }
)
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(".ScrollbarPlace"), 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.#wde.Alert(error.message)
return
}
const html = await response.text()
console.log(this.#wde)
let newView = this.#wde.Decorat.CreateNewView(this.#appId,)
newView.innerHTML = html
}
/**
* @param {string} path
*/
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 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 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} filePath
*/
async OpenFile(parentPath, fileName, fileType){
// console.log(parentPath, fileName, fileType)
// const splittedPath = filePath.split("/")
// const fileName = splittedPath[splittedPath.length - 1]
const fileExtension = fileName.split(".")[fileName.split(".").length - 1] //FIXME
switch (true) {
case fileType == "objectlink":
this.#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.#wde.Open(`${parentPath}/${fileName}`, [])
break
case fileExtension == "blog":
this.#wde.Open(`/Applications/BlogViewer.app`, [`${parentPath}/${fileName}`])
break
case fileType == "directory":
this.#wde.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
this.#wde.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
this.#wde.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
this.#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 WebFS.CreatePathLink(`${this.curPath}/${fileName}`, `${this.curPath}/Link to ${fileName}` )
if (res){
this.ReRenderDir()
}
break
case "createDir":
res = await WebFS.CreateDirectory(`${this.curPath}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "deleteFile":
res = await WebFS.DeleteFile(`${this.curPath}/${fileName}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "getInfo":
Finder.RenderProperites(path)
break
case "openAsDir":
this.#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,64 @@
// 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){
// console.log(super.WDE())
let newFinderView = new FinderWindow(this, super.WDE())
await newFinderView.Init(this, args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
async RenderProperites(path){
// return
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/${Finder.AppId}/renderProps?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Error in properties render") //TODO
return false
}
const html = await response.text()
let newWindow = super.WDE().Decorat.CreateNewWindow(Finder.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
// WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}

View File

@ -0,0 +1,39 @@
.FinderContent {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.FinderContent .ToolBar{
width: 100%;
height: 20px;
border-bottom: 1px solid #555555;
background-color: #EEEEEE;
}
.Focused .FinderContent .ToolBar{
border-bottom: 1px solid #000000;
background-color: #DDDDDD;
}
.FinderContent .FinderFileView{
width: 100%;
height: 100%;
background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

View File

@ -0,0 +1,79 @@
@import "./wde/primitives.less";
@import "./wde/widgets/file-view/file-view.less";
@import "./wde/legacy-ui.less";
@import "./wde/widgets/basic-widgets.less";
@import "./theme.less";
// @font-face{
// font-family: "Virtue";
// src:url("/res/dev-fs/fonts/virtue.ttf");
// }
/* @font-face{
font-family: "Virtue";
src:url("/res/dev-fs/fonts/virtue.ttf")
} */
/* @media screen and (max-device-width: 2048px) and (max-device-height: 2048px) {
html {
zoom: 3
}
} */
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
*{
font-family: Verdana, Geneva, sans-serif;
font-size: 11px;
font-style: normal;
font-weight:initial;
}
*::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}
body{
zoom: var(--zoom);
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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;
}

View File

@ -0,0 +1,339 @@
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
/** @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){
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.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
// console.log(this.#wde)
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() }
)
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(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.RenderDir(args[0])
}
CreateDesktopWindow(){
}
/**
* @param {*} args
* @param {import("../../wde/wde-desktop").runContext} runContext
* @returns
*/
async CreateMobileView(args, runContext){
const params = new URLSearchParams({isMobile: false}) //FIXME
const response = await fetch(`/app/${this.#appId}/render?` + params,
{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
const error = await response.json()
this.#wde.Alert(error.message)
return
}
const html = await response.text()
console.log(this.#wde)
let newView = this.#wde.Decorat.CreateNewView(this.#appId,)
newView.innerHTML = html
}
/**
* @param {string} path
*/
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 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 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} filePath
*/
async OpenFile(parentPath, fileName, fileType){
// console.log(parentPath, fileName, fileType)
// const splittedPath = filePath.split("/")
// const fileName = splittedPath[splittedPath.length - 1]
const fileExtension = fileName.split(".")[fileName.split(".").length - 1] //FIXME
switch (true) {
case fileType == "objectlink":
this.#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.#wde.Open(`${parentPath}/${fileName}`, [])
break
case fileExtension == "blog":
this.#wde.Open(`/Applications/BlogViewer.app`, [`${parentPath}/${fileName}`])
break
case fileType == "directory":
this.#wde.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
this.#wde.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
this.#wde.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
this.#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 WebFS.CreatePathLink(`${this.curPath}/${fileName}`, `${this.curPath}/Link to ${fileName}` )
if (res){
this.ReRenderDir()
}
break
case "createDir":
res = await WebFS.CreateDirectory(`${this.curPath}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "deleteFile":
res = await WebFS.DeleteFile(`${this.curPath}/${fileName}`)
console.log(res)
if (res){
this.ReRenderDir()
}
break
case "getInfo":
Finder.RenderProperites(path)
break
case "openAsDir":
this.#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,64 @@
// 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){
// console.log(super.WDE())
let newFinderView = new FinderWindow(this, super.WDE())
await newFinderView.Init(this, args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
async RenderProperites(path){
// return
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/${Finder.AppId}/renderProps?` + params)
if (response.status != 200){
// WebDesktopEnvironment.Alert("Error in properties render") //TODO
return false
}
const html = await response.text()
let newWindow = super.WDE().Decorat.CreateNewWindow(Finder.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
// WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}

View File

@ -0,0 +1,39 @@
.FinderContent {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.FinderContent .ToolBar{
width: 100%;
height: 20px;
border-bottom: 1px solid #555555;
background-color: #EEEEEE;
}
.Focused .FinderContent .ToolBar{
border-bottom: 1px solid #000000;
background-color: #DDDDDD;
}
.FinderContent .FinderFileView{
width: 100%;
height: 100%;
background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

View File

@ -0,0 +1,54 @@
@import "./wde/sunboard/sunboard-mobile.less";
body{
zoom: 2;
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
#mobile-app-views{
width: 100%;
height: 100%;
// padding: 64px;
// border-radius: 50px;
// overflow:hidden
// background-color: @col-ceil;
}
#controls-bar{
&:extend(.WdePrimitives.AdjectiveElement);
width: 100%;
height: 150px;
background-color: @col-argent;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.mobile-app-view{
// background-color: burlywood;
width: 100%;
height: 100%;
// position: absolute;
}

View File

@ -0,0 +1,2 @@
@col-ceil: #9999CC;
@col-argent: #C0C0C0;

View File

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

View File

@ -0,0 +1,104 @@
export default class DesktopDecorat{
/** @type {Element} */
#windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
// this.#windowsLayer = document.body.querySelector('#windows-layer')
this.#windowsLayer = document.body.querySelector('#windows-layer')
let startDrag = (event) => {
let window = event.target.closest('.WindowFrame')
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("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,27 @@
export default class MobileDecorat {
/** @type {Element} */
#applicationsNode
constructor(){
this.#applicationsNode = document.body.querySelector("#mobile-app-views") //TODO validate
}
/**
* @param {string} appId
* @returns {Element}
*/
CreateNewView(appId){
let newView = document.createElement("div")
newView.setAttribute("class", "mobile-app-view")
newView.setAttribute("appId", appId)
this.#applicationsNode.appendChild(newView)
return newView
}
Open(){
}
BackAction(){
// console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.lastChild.remove()
}
}

View File

@ -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,3 @@
.WdePrimitives.AdjectiveElement {
border: 1px solid #555555;
}

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(".ScrollBarScrollElement") //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;
}
.ScrollbarPlace{
overflow: hidden;
border-left: 1px solid #555555;
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 .ScrollbarPlace{
border-left: 1px solid #000000;
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);
}
.ScrollBarScrollElement{
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 .ScrollBarScrollElement{
visibility: visible;
}
.ScrollBarScrollElementDrag{
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,50 @@
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 = await 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 appId = element.getAttribute('appId')
element.addEventListener('click', () => {
// console.log(appId)
// this.#wde.Decorat.CreateNewView(appId)
this.#wde.Open("/Applications/Finder.app", [""], "")
})
});
}
async createFileView(){
}
}

View File

@ -0,0 +1,61 @@
@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 32px;
align-items: flex-start;
align-content: flex-start;
gap: 103px 18px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon{
width: 100px;
height: 100px;
/* Auto layout */
display: flex;
padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon{
width: 64px;
height: 64px;
background-color: beige;
}
.app-icon .lable{
}

View File

@ -0,0 +1,173 @@
import DesktopDecorat from "./decorat/desktop-decorat.js";
import WDEScrollBar from "./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
constructor(){
super()
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(){
let autoStart = document.body.querySelector("wde-autostart")
if (autoStart == null){
WebDesktopEnvironment.Alert("Error in loading DE")
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)
})
}
/**
* @param {string} appManifest
* @param {function} onload callback after script loading
*/
static async load2(appManifest, onload){
// import(window.location.origin + appManifest.js[0]).then((app) => {
// console.log(window.location.origin + appManifest.js[0] == 'http://localhost:8080/res/dev-fs/wde/dist/finder.js')
// let kek = 'http://localhost:8080/res/dev-fs/wde/dist/finder.js'
import('http://localhost:8080/res/dev-fs/dist/finder.js').then((app) => {
let newApp = new app.default()
// if newApp //TODO Validate
WebDesktopEnvironment.Applications[appManifest.appId] = newApp;
onload()
})
return //TODO return result
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
static async fetchApp(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} html
*/
static SetBasicWindow(html){
this.basicWindow = html
}
/**
* @returns {string}
*/
static GetBasicWindow(){
return this.basicWindow
}
/**
* @param {string} alertText
*/
static Alert(alertText){
WebDesktopEnvironment.CreateAlertWindow(alertText)
console.log(alertText)
}
/**
* @param {string} alertText
*/
static 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,52 @@
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()
}
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) =>{
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()
})
}
}

View File

@ -0,0 +1,94 @@
import WDEApplication from "./application.js"
export default class AbstractWebDesktopEnvironment{
/** @type {Object<string, WDEApplication>} */
_applications = {}
/** @type {AbstractWebDesktopEnvironment} */
#wde
/** @type {AbstractWebDesktopEnvironment} */
_SetWDE(wde){
this.#wde = wde
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
async _FetchAppManifest(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
// WebDesktopEnvironment.Alert(error.message) //FIXME
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} appPath
* @param {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
await import(/* webpackMode: "eager" */ `${window.location.origin}/res/dev-fs/dist/finder.js`).then((app) => {newApp = app})
// let newApp
// switch (appManifest.appId) { //FIXME Can't dynamicly load es6 modules withou static pathes
// case 'Finder':
// break;
// }
let newAppClass = new newApp.default(this.#wde)
this._applications[appManifest.appId] = newAppClass
onload()
return //TODO return result
}
_GetApp(appId){
// console.log(appId)
return this._applications[appId]
}
_fetchComp(res) {
import(`${window.location.origin}${res}`).then(() => {
console.log("Loaded")
}, (err)=>{
console.log("Error", err)
})
}
}
/**
* @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,134 @@
export default class WDEFileView{
path = ""
parentElem = undefined
selected = []
/**
* @param {HTMLElement} fileViewElem
* @param {Function} doubleClickCallback
* @param {Function} rightClickCallback
* @param {Function} updateFileViewCallback
*/
constructor(fileViewElem, doubleClickCallback, rightClickCallback, fileUploadCallback, updateFileViewCallback){
//TODO check all params
this.parentElem = fileViewElem
fileViewElem.addEventListener('click', (event) => {
if (event.target.classList[0] == 'FileTileView')
{
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
WebDesktopEnvironment.Alert("TODO")
return
}
let html = await response.text()
this.parentElem.innerHTML = html
}
}

View File

@ -0,0 +1,86 @@
.FileTileView{
width: 100%;
height: 100%;
/* 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,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
}
}

View File

@ -0,0 +1,79 @@
@import "./wde/primitives.less";
@import "./wde/widgets/file-view/file-view.less";
@import "./wde/legacy-ui.less";
@import "./wde/widgets/basic-widgets.less";
@import "./theme.less";
// @font-face{
// font-family: "Virtue";
// src:url("/res/dev-fs/fonts/virtue.ttf");
// }
/* @font-face{
font-family: "Virtue";
src:url("/res/dev-fs/fonts/virtue.ttf")
} */
/* @media screen and (max-device-width: 2048px) and (max-device-height: 2048px) {
html {
zoom: 3
}
} */
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
*{
font-family: Verdana, Geneva, sans-serif;
font-size: 11px;
font-style: normal;
font-weight:initial;
}
*::-webkit-scrollbar { /* WebKit */
width: 0;
height: 0;
}
body{
zoom: var(--zoom);
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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;
}

3
front/src/src/init.mjs Normal file
View File

@ -0,0 +1,3 @@
export default class Kek{
}

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

@ -0,0 +1,54 @@
@import "./wde/sunboard/sunboard-mobile.less";
body{
zoom: 2;
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
#mobile-app-views{
width: 100%;
height: 100%;
// padding: 64px;
// border-radius: 50px;
// overflow:hidden
// background-color: @col-ceil;
}
#controls-bar{
&:extend(.WdePrimitives.AdjectiveElement);
width: 100%;
height: 150px;
background-color: @col-argent;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.mobile-app-view{
// background-color: burlywood;
width: 100%;
height: 100%;
// position: absolute;
}

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

@ -0,0 +1,2 @@
@col-ceil: #9999CC;
@col-argent: #C0C0C0;

View File

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

View File

@ -0,0 +1,104 @@
export default class DesktopDecorat{
/** @type {Element} */
#windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
// this.#windowsLayer = document.body.querySelector('#windows-layer')
this.#windowsLayer = document.body.querySelector('#windows-layer')
let startDrag = (event) => {
let window = event.target.closest('.WindowFrame')
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("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,27 @@
export default class MobileDecorat {
/** @type {Element} */
#applicationsNode
constructor(){
this.#applicationsNode = document.body.querySelector("#mobile-app-views") //TODO validate
}
/**
* @param {string} appId
* @returns {Element}
*/
CreateNewView(appId){
let newView = document.createElement("div")
newView.setAttribute("class", "mobile-app-view")
newView.setAttribute("appId", appId)
this.#applicationsNode.appendChild(newView)
return newView
}
Open(){
}
BackAction(){
// console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.lastChild.remove()
}
}

View File

@ -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,3 @@
.WdePrimitives.AdjectiveElement {
border: 1px solid #555555;
}

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(".ScrollBarScrollElement") //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;
}
.ScrollbarPlace{
overflow: hidden;
border-left: 1px solid #555555;
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 .ScrollbarPlace{
border-left: 1px solid #000000;
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);
}
.ScrollBarScrollElement{
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 .ScrollBarScrollElement{
visibility: visible;
}
.ScrollBarScrollElementDrag{
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,50 @@
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 = await 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 appId = element.getAttribute('appId')
element.addEventListener('click', () => {
// console.log(appId)
// this.#wde.Decorat.CreateNewView(appId)
this.#wde.Open("/Applications/Finder.app", [""], "")
})
});
}
async createFileView(){
}
}

View File

@ -0,0 +1,61 @@
@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 32px;
align-items: flex-start;
align-content: flex-start;
gap: 103px 18px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon{
width: 100px;
height: 100px;
/* Auto layout */
display: flex;
padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon{
width: 64px;
height: 64px;
background-color: beige;
}
.app-icon .lable{
}

View File

@ -0,0 +1,173 @@
import DesktopDecorat from "./decorat/desktop-decorat.js";
import WDEScrollBar from "./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
constructor(){
super()
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(){
let autoStart = document.body.querySelector("wde-autostart")
if (autoStart == null){
WebDesktopEnvironment.Alert("Error in loading DE")
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)
})
}
/**
* @param {string} appManifest
* @param {function} onload callback after script loading
*/
static async load2(appManifest, onload){
// import(window.location.origin + appManifest.js[0]).then((app) => {
// console.log(window.location.origin + appManifest.js[0] == 'http://localhost:8080/res/dev-fs/wde/dist/finder.js')
// let kek = 'http://localhost:8080/res/dev-fs/wde/dist/finder.js'
import('http://localhost:8080/res/dev-fs/dist/finder.js').then((app) => {
let newApp = new app.default()
// if newApp //TODO Validate
WebDesktopEnvironment.Applications[appManifest.appId] = newApp;
onload()
})
return //TODO return result
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
static async fetchApp(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} html
*/
static SetBasicWindow(html){
this.basicWindow = html
}
/**
* @returns {string}
*/
static GetBasicWindow(){
return this.basicWindow
}
/**
* @param {string} alertText
*/
static Alert(alertText){
WebDesktopEnvironment.CreateAlertWindow(alertText)
console.log(alertText)
}
/**
* @param {string} alertText
*/
static 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,52 @@
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()
}
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) =>{
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()
})
}
}

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

@ -0,0 +1,94 @@
import WDEApplication from "./application.js"
export default class AbstractWebDesktopEnvironment{
/** @type {Object<string, WDEApplication>} */
_applications = {}
/** @type {AbstractWebDesktopEnvironment} */
#wde
/** @type {AbstractWebDesktopEnvironment} */
_SetWDE(wde){
this.#wde = wde
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
async _FetchAppManifest(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
// WebDesktopEnvironment.Alert(error.message) //FIXME
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} appPath
* @param {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
await import(/* webpackMode: "eager" */ `${window.location.origin}/res/dev-fs/dist/finder.js`).then((app) => {newApp = app})
// let newApp
// switch (appManifest.appId) { //FIXME Can't dynamicly load es6 modules withou static pathes
// case 'Finder':
// break;
// }
let newAppClass = new newApp.default(this.#wde)
this._applications[appManifest.appId] = newAppClass
onload()
return //TODO return result
}
_GetApp(appId){
// console.log(appId)
return this._applications[appId]
}
_fetchComp(res) {
import(`${window.location.origin}${res}`).then(() => {
console.log("Loaded")
}, (err)=>{
console.log("Error", err)
})
}
}
/**
* @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,134 @@
export default class WDEFileView{
path = ""
parentElem = undefined
selected = []
/**
* @param {HTMLElement} fileViewElem
* @param {Function} doubleClickCallback
* @param {Function} rightClickCallback
* @param {Function} updateFileViewCallback
*/
constructor(fileViewElem, doubleClickCallback, rightClickCallback, fileUploadCallback, updateFileViewCallback){
//TODO check all params
this.parentElem = fileViewElem
fileViewElem.addEventListener('click', (event) => {
if (event.target.classList[0] == 'FileTileView')
{
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
WebDesktopEnvironment.Alert("TODO")
return
}
let html = await response.text()
this.parentElem.innerHTML = html
}
}

View File

@ -0,0 +1,86 @@
.FileTileView{
width: 100%;
height: 100%;
/* 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,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
}
}

View File

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

View File

@ -3,9 +3,8 @@ export default class DesktopDecorat{
#windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
// this.#windowsLayer = document.body.querySelector('#windows-layer')
this.#windowsLayer = document.body.querySelector('#windows-layer')
this.#windowsLayer = document.body.querySelector('#windows-layer') //TODO Validate if null
let startDrag = (event) => {
let window = event.target.closest('.WindowFrame')
this.bringWindowToFront(window)
@ -65,7 +64,6 @@ export default class DesktopDecorat{
document.body.querySelector('#windows-layer').appendChild(newWindow)
return newWindow
}
/**

View File

@ -3,8 +3,16 @@ export default class MobileDecorat {
#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}
@ -13,15 +21,17 @@ export default class MobileDecorat {
let newView = document.createElement("div")
newView.setAttribute("class", "mobile-app-view")
newView.setAttribute("appId", appId)
this.#applicationsNode.appendChild(newView)
// this.#applicationsNode.appendChild(newView)
this.#applicationsNode.insertBefore(newView, this.#applicationsNode.firstChild)
return newView
}
Open(){
}
BackAction(){
// console.log(this.#applicationsNode.childNodes.length)
console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.lastChild.remove()
this.#applicationsNode.firstChild.remove()
}
}

View File

@ -15,7 +15,7 @@ export default class MobileDesktop{
}
async #createDesktopView(){
let view = await this.#wde.Decorat.CreateNewView("Sunboard") //FIXME
let view = this.#wde.Decorat.CreateNewView("Sunboard") //FIXME
const params = new URLSearchParams({
// path: args[0] //FIXME
@ -28,7 +28,6 @@ export default class MobileDesktop{
})
if (response.status != 200){
console.log(response.status)
// this.#wde.Alert("Error in render desktop") //TODO
return
}
const html = await response.text()
@ -36,11 +35,10 @@ export default class MobileDesktop{
let iconsList = view.querySelectorAll(".app-icon")
iconsList.forEach(element => {
let appId = element.getAttribute('appId')
let path = element.getAttribute('path') //TODO: Validate
element.addEventListener('click', () => {
// console.log(appId)
// this.#wde.Decorat.CreateNewView(appId)
this.#wde.Open("/Applications/Finder.app", [""], "")
this.#wde.Open(path, [""], "") //FIXME
})
});
}

View File

@ -3,9 +3,10 @@ import WDEScrollBar from "./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{
export default class WebDesktopEnvironment extends AbstractWebDesktopEnvironment{
/** @type {string} */
test = ""
/** @type {WDEFileView} */
@ -20,7 +21,10 @@ export default class WebDesktopEnvironment{
static isMobile = false
// static decorat
static webFs
constructor(){
super("localhost:8080")
super._SetWDE(this)
document.body.style.setProperty('--zoom', 1)
this.Decorat = new DesktopDecorat()
@ -31,10 +35,12 @@ export default class WebDesktopEnvironment{
}
async loadWDE(){
await this.Open("/Applications/Finder.app", ["/","--desktop", "desktop-layer"])
return
let autoStart = document.body.querySelector("wde-autostart")
if (autoStart == null){
WebDesktopEnvironment.Alert("Error in loading DE")
WebDesktopEnvironment.Alert("Error in loading DE: Autostart not presented")
return
}
for (const child of autoStart.children) {
@ -64,66 +70,17 @@ export default class WebDesktopEnvironment{
* @param {string} runPath
*/
async Open(appPath, args, runPath){
const appManifest = await WebDesktopEnvironment.fetchApp(appPath)
if (appManifest === undefined) return //TODO return err
/**@type {runContext} */
const runContext = {
WDE: this,
isMobile: false,
bundlePath: appPath,
runPath: runPath
}
if (WebDesktopEnvironment.Applications[appManifest.appId] === undefined){
WebDesktopEnvironment.load2(appManifest, () =>{
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
})
} else {
WebDesktopEnvironment.Applications[appManifest.appId].NewWindow(args, runContext)
}
}
/**
* @param {string} appManifest
* @param {function} onload callback after script loading
*/
static async load2(appManifest, onload){
// import(window.location.origin + appManifest.js[0]).then((app) => {
// console.log(window.location.origin + appManifest.js[0] == 'http://localhost:8080/res/dev-fs/wde/dist/finder.js')
// let kek = 'http://localhost:8080/res/dev-fs/wde/dist/finder.js'
import('http://localhost:8080/res/dev-fs/dist/finder.js').then((app) => {
let newApp = new app.default()
// if newApp //TODO Validate
WebDesktopEnvironment.Applications[appManifest.appId] = newApp;
onload()
super._Open(appPath, args, runPath, (appManifest) =>{
super._GetApp(appManifest.appId).NewWindow(args, runContext)
})
return //TODO return result
}
/**
* @param {string} path
* @returns {Object | undefined} //FIXME
*/
static async fetchApp(path){
// console.log("path: " + path )
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return undefined
}
//TODO Validate manifest
const appManifest = response.json()
return appManifest
}
/**
* @param {string} html
*/
@ -178,10 +135,3 @@ export default class WebDesktopEnvironment{
}
/**
* @typedef {Object} runContext
* @property {WebDesktopEnvironment} WDE
* @property {boolean} isMobile
* @property {string} appPath
* @property {string} runPath //TODO
*/

View File

@ -10,13 +10,14 @@ export default class MobileWebDesktopEnvironment extends AbstractWebDesktopEnvir
/** @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()
// this.loadWDE()
}
loadWDE(){
@ -29,17 +30,19 @@ export default class MobileWebDesktopEnvironment extends AbstractWebDesktopEnvir
* @param {string} runPath
*/
async Open(appPath, args, runPath){
super._Open(appPath, args, runPath, async (appManifest, runContext) => {
console.log(super._GetApp(appManifest.appId))
// console.log(super())
let contentView = await super._GetApp(appManifest.appId).NewWindow(args, runContext)
let view = this.Decorat.CreateNewView()
console.log(view)
view.appendChild(contentView)
// super._GetApp
})
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

View File

@ -1,10 +1,24 @@
import WDEApplication from "./application.js"
export default class AbstractWebDesktopEnvironment{
/** @type {Object<string, WDEApplication>} */
/** @type {string} */
#apiAddress
/** @type {Object<string, WDEApplication>} */
_applications = {}
constructor(){
/** @type {AbstractWebDesktopEnvironment} */
#wde
/** @constructor */
constructor(apiAddress){
this.#apiAddress = apiAddress
}
/** @returns {string} */
GetApiAddress(){
return `${location.protocol}//${this.#apiAddress}`
}
/** @type {AbstractWebDesktopEnvironment} */
_SetWDE(wde){
this.#wde = wde
}
/**
@ -12,7 +26,8 @@ export default class AbstractWebDesktopEnvironment{
* @returns {Object | undefined} //FIXME
*/
async _FetchAppManifest(path){
console.log("path: " + path )
// console.log(location)
// console.log(this.GetApiAddress())
const params = new URLSearchParams({path: path, mode: "json"})
const response = await fetch(`/system/loadApp?` + params)
if (response.status != 200){
@ -27,28 +42,21 @@ export default class AbstractWebDesktopEnvironment{
/**
* @param {string} appPath
* @param {string[]} args
* @param {runContext} runContext
* @param {string} runPath
* @param {callback} function
* @param {function} callback
*/
async _Open(appPath, args, runPath, callback){
async _Open(appPath, runContext, runPath, callback){
const appManifest = await this._FetchAppManifest(appPath)
if (appManifest === undefined) return //TODO return err
/**@type {runContext} */
const runContext = {
WDE: this,
isMobile: true,
bundlePath: appPath,
runPath: runPath
}
if (this._applications[appManifest.appId] === undefined){
this.#loadApp(appManifest, () => {
callback(appManifest, runContext)
callback(appManifest)
})
} else {
callback(appManifest, runContext)
callback(appManifest)
}
}
@ -57,22 +65,35 @@ export default class AbstractWebDesktopEnvironment{
* @param {function} onload callback after script loading
*/
async #loadApp(appManifest, onload){
let newApp
// console.log(appManifest)
// import(window.location.origin + appManifest.js[0]).then((app) => {
// console.log(window.location.origin + appManifest.js[0] == 'http://localhost:8080/res/dev-fs/wde/dist/finder.js')
// let kek = 'http://localhost:8080/res/dev-fs/wde/dist/finder.js'
import('http://localhost:8080/res/dev-fs/dist/finder.js').then((app) => {
let newApp = new app.default()
// if newApp //TODO Validate
this._applications[appManifest.appId] = newApp;
onload()
})
await import(appManifest.js[0]).then((app) => {newApp = app})
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)
// console.log(appId)
return this._applications[appId]
}
}
/**
* @typedef {Object} runContext
* @property {boolean} isMobile
* @property {string} appPath
* @property {string} runPath //TODO
*/
/** //TODO
* @typedef {Object} appManifest
*/

View File

@ -1,16 +1,20 @@
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){
constructor(fileViewElem, doubleClickCallback, rightClickCallback, fileUploadCallback, updateFileViewCallback, wde){
this.#wde = wde
//TODO check all params
this.parentElem = fileViewElem
@ -122,7 +126,7 @@ export default class WDEFileView{
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/system/wde/widgets/file-tile-view?` + params)
const response = await fetch(`${this.#wde.GetApiAddress()}/system/wde/widgets/file-tile-view?` + params)
if (response.status != 200){
//TODO Error text message
WebDesktopEnvironment.Alert("TODO")

View File

@ -1,85 +0,0 @@
// Generated using webpack-cli https://github.com/webpack/webpack-cli
const path = require('path');
const isProduction = process.env.NODE_ENV == 'production';
const stylesHandler = 'style-loader';
const MiniCssExtractPlugin = require("mini-css-extract-plugin");
const { experiments } = require('webpack');
const config = {
// entry: [ './src/wde-mobile.js'],
entry: {
desktop:[
'./src/wde/wde-desktop.js',
],
desktop_style: [
"./src/desktop.less",
],
mobile: [
'./src/wde/wde-mobile.js',
],
mobile_style: [
"./src/mobile.less",
],
finder : [
'./src/apps/finder/finder.js',
],
finder_style:[
'./src/apps/finder/finder.less',
]
},
output: {
// path: path.resolve(__dirname, 'dist'),
path: path.resolve('../res/dev-fs/dist'),
filename: '[name].js',
library: {
type: "module",
},
},
experiments: {
outputModule: true,
},
devServer: {
open: true,
host: 'localhost',
},
plugins: [new MiniCssExtractPlugin()],
module: {
rules: [
{
test: /\.(js|jsx)$/i,
loader: 'babel-loader',
},
{
test: /\.css$/i,
use: [stylesHandler,'css-loader'],
},
{
test: /\.less$/i,
// use: [stylesHandler, 'css-loader', 'less-loader'],
use: [MiniCssExtractPlugin.loader, 'css-loader', 'less-loader'],
},
{
test: /\.(eot|svg|ttf|woff|woff2|png|jpg|gif)$/i,
type: 'asset',
},
// Add your rules for custom modules here
// Learn more about loaders from https://webpack.js.org/loaders/
],
},
};
module.exports = () => {
if (isProduction) {
config.mode = 'production';
} else {
config.mode = 'development';
}
return config;
};

File diff suppressed because one or more lines are too long

View File

@ -1,384 +0,0 @@
/*!***********************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/desktop.less ***!
\***********************************************************************************************************/
.WdePrimitives.AdjectiveElement {
border: 1px solid #555555;
}
.FileTileView {
width: 100%;
height: 100%;
/* 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;
}
.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;
}
.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;
}
/* @font-face{
font-family: "Virtue";
src:url("/res/dev-fs/fonts/virtue.ttf")
} */
/* @media screen and (max-device-width: 2048px) and (max-device-height: 2048px) {
html {
zoom: 3
}
} */
.NoClick {
pointer-events: none;
}
.Click {
pointer-events: all;
}
* {
font-family: Verdana, Geneva, sans-serif;
font-size: 11px;
font-style: normal;
font-weight: initial;
}
*::-webkit-scrollbar {
/* WebKit */
width: 0;
height: 0;
}
body {
zoom: var(--zoom);
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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: #9999CC;
}

View File

@ -1,45 +0,0 @@
/*
* 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/).
*/
/******/ var __webpack_modules__ = ({
/***/ "./src/desktop.less":
/*!**************************!*\
!*** ./src/desktop.less ***!
\**************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://my-webpack-project/./src/desktop.less?");
/***/ })
/******/ });
/************************************************************************/
/******/ // 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/desktop.less"](0, __webpack_exports__, __webpack_require__);
/******/

View File

@ -1,35 +0,0 @@
/*!**********************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/apps/finder/finder.less ***!
\**********************************************************************************************************************/
.FinderContent {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.FinderContent .ToolBar {
width: 100%;
height: 20px;
border-bottom: 1px solid #555555;
background-color: #EEEEEE;
}
.Focused .FinderContent .ToolBar {
border-bottom: 1px solid #000000;
background-color: #DDDDDD;
}
.FinderContent .FinderFileView {
width: 100%;
height: 100%;
background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

File diff suppressed because one or more lines are too long

View File

@ -1,35 +0,0 @@
/*!**********************************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/apps/finder/finder.less ***!
\**********************************************************************************************************************/
.FinderContent {
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
justify-content: center;
align-items: flex-start;
padding: 0px;
}
.FinderContent .ToolBar {
width: 100%;
height: 20px;
border-bottom: 1px solid #555555;
background-color: #EEEEEE;
}
.Focused .FinderContent .ToolBar {
border-bottom: 1px solid #000000;
background-color: #DDDDDD;
}
.FinderContent .FinderFileView {
width: 100%;
height: 100%;
background-color: #FFFFFF;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content: center;
align-items: flex-start;
padding: 0px;
}

View File

@ -1,45 +0,0 @@
/*
* 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/).
*/
/******/ var __webpack_modules__ = ({
/***/ "./src/apps/finder/finder.less":
/*!*************************************!*\
!*** ./src/apps/finder/finder.less ***!
\*************************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://my-webpack-project/./src/apps/finder/finder.less?");
/***/ })
/******/ });
/************************************************************************/
/******/ // 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/apps/finder/finder.less"](0, __webpack_exports__, __webpack_require__);
/******/

File diff suppressed because one or more lines are too long

View File

@ -1,93 +0,0 @@
/*!**********************************************************************************************************!*\
!*** css ./node_modules/css-loader/dist/cjs.js!./node_modules/less-loader/dist/cjs.js!./src/mobile.less ***!
\**********************************************************************************************************/
.WdePrimitives.AdjectiveElement,
#controls-bar {
border: 1px solid #555555;
}
#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: #9999CC;
}
.apps-list {
/* Auto layout */
display: flex;
padding: 64px 32px;
align-items: flex-start;
align-content: flex-start;
gap: 103px 18px;
flex: 1 0 0;
align-self: stretch;
flex-wrap: wrap;
}
.app-icon {
width: 100px;
height: 100px;
/* Auto layout */
display: flex;
padding: 4px 8px;
flex-direction: column;
align-items: center;
gap: 10px;
}
.app-icon .icon {
width: 64px;
height: 64px;
background-color: beige;
}
body {
zoom: var(--zoom);
position: absolute;
width: 100%;
height: 100%;
margin: 0px;
/* 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;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
}
#mobile-app-views {
width: 100%;
height: 100%;
}
#controls-bar {
width: 100%;
height: 150px;
background-color: #C0C0C0;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
}
.mobile-app-view {
width: 100%;
height: 100%;
}

View File

@ -1,45 +0,0 @@
/*
* 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/).
*/
/******/ var __webpack_modules__ = ({
/***/ "./src/mobile.less":
/*!*************************!*\
!*** ./src/mobile.less ***!
\*************************/
/***/ ((__unused_webpack_module, __webpack_exports__, __webpack_require__) => {
eval("__webpack_require__.r(__webpack_exports__);\n// extracted by mini-css-extract-plugin\n\n\n//# sourceURL=webpack://my-webpack-project/./src/mobile.less?");
/***/ })
/******/ });
/************************************************************************/
/******/ // 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.less"](0, __webpack_exports__, __webpack_require__);
/******/

View File

@ -30,6 +30,18 @@ func PrivateRoutes(port string, webfs *webfilesystem.WebFileSystem, webde *wde.W
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

View File

@ -21,12 +21,15 @@
<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/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" 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 '/res/dev-fs/dist/desktop.js';
import * as WebDesktopEnvironment from "/front/src/wde/wde-desktop.js"
// console.log(WebDesktopEnvironment)
let kek = new WebDesktopEnvironment.default()
</script>

View File

@ -3,13 +3,14 @@
<title>Greg Brzezinski</title>
<head>
<!-- <script src="res/dev-fs/dist/mobile.js"></script> -->
<link rel="stylesheet" type="text/css" href="res/dev-fs/dist/mobile_style.css">
<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 WebDesktopEnvironment from '/res/dev-fs/dist/mobile.js';
import * as wde from '/front/src/wde/wde-mobile.js';
// console.log(WebDesktopEnvironment)
let kek = new WebDesktopEnvironment.default()
let kek = new wde.default()
</script>
<!-- <div id="mobile-sunboard">
</div> -->
@ -17,16 +18,16 @@
<div id="controls-bar">
<div id="back" class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
<div class="lable NoClick">Back</div>
</div>
<div class="app-icon Click" >
<!-- <div class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
</div>
<div class="app-icon Click" >
<img class="icon NoClick" src="">
<div class="lable NoClick">Test</div>
</div>
</div> -->
</div>
</body>
</html>

View File

@ -0,0 +1,51 @@
{{ 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">
<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">
<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

@ -2,7 +2,7 @@
<div id="icons">
<div class="apps-list NoClick">
{{ range $appIcon := .AppsIcons }}
<div fileType="{{ $appIcon.Type }}" class="app-icon Click" appId="{{$appIcon.AppId}}" name="{{$appIcon.Lable}}">
<div 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>