Compare commits

..

145 Commits

Author SHA1 Message Date
264a8d38d6 update ignore 2023-07-24 03:31:56 +03:00
38c1d03755 delete build files 2023-07-24 03:31:25 +03:00
71d5e34e49 update gitignore 2023-07-24 03:29:37 +03:00
5ff8696ea4 Delete files 2023-07-24 03:29:27 +03:00
74cb1ced32 add .env to ignore 2023-07-24 03:28:32 +03:00
e76c55f2c3 fixes 2023-07-24 03:27:53 +03:00
3b5b00f5b0 more work 2023-07-23 06:12:17 +03:00
b79b65868c icons and title-bar as widget 2023-07-23 02:55:08 +03:00
766b7ac4bf Merge branch 'webpack' of http://192.168.88.228:9101/cyber-dream/personal-website into webpack 2023-07-23 01:01:03 +03:00
d1c5e8ea15 mobile finder 2023-07-23 01:00:51 +03:00
559c22f626 Fix wde fs import 2023-07-22 21:16:00 +03:00
265f57e2de rename finder template 2023-07-22 21:15:42 +03:00
46e3bcf865 Add obsolete notation 2023-07-22 21:15:17 +03:00
68664c1bf3 Add todo 2023-07-22 18:56:51 +03:00
3636cb86e2 New icons format 2023-07-22 18:55:23 +03:00
9f60c185ad fixes 2023-07-22 04:10:00 +03:00
ec9ef532f6 delete duplicates 2023-07-22 04:05:34 +03:00
71431790b5 quick fix aboutme 2023-07-22 03:50:58 +03:00
41bd2a43b8 finder rework 2023-07-22 03:48:45 +03:00
bd0f77b1b6 Add todo to line in wde 2023-07-21 17:44:01 +03:00
bc71ca9682 Fix deprecated variable use 2023-07-21 17:43:37 +03:00
c5c277f516 working mobile and desktop 2023-07-21 04:42:12 +03:00
d018477fe3 trys 2023-07-21 01:05:06 +03:00
d61fa2bd4b Working mobile and desktop views 2023-07-20 02:11:53 +03:00
edf011fccd Working mobile wde 2023-07-19 19:38:28 +03:00
186ea27db8 Trys with mobile wde 2023-07-19 04:35:17 +03:00
cb1dfce2a9 Working desktop 2023-07-19 04:06:13 +03:00
0e9720d295 Merge branch 'refs/heads/main' into webpack 2023-07-19 01:23:06 +03:00
96f8be759e fix autostart arg 2023-07-19 01:22:58 +03:00
de0ad81615 Update apps 2023-07-18 23:47:12 +03:00
488f3a56b9 test webpack 2023-07-18 20:15:06 +03:00
fb6b310a49 Links in about-me app 2023-06-07 04:22:25 +03:00
86552cb22f Add json reflections to aboutme structs 2023-06-07 03:45:56 +03:00
2ba61f10ff Markdown with supress <p> 2023-06-07 03:42:50 +03:00
b0c7b6a690 Working markdown in blog 2023-06-07 02:17:29 +03:00
81af984d96 delete temp files 2023-06-07 01:49:33 +03:00
651e219b09 integrate markdown 2023-06-07 01:49:26 +03:00
e6138cba1e Autostart list from backend 2023-05-28 04:28:48 +03:00
a921646f4c Rename persprops to AboutMe 2023-05-25 01:51:37 +03:00
c1ba99bb77 Routes now get ports number from .env 2023-05-24 02:19:21 +03:00
5aaea9c1be Add blog editing api 2023-05-24 02:09:16 +03:00
55bb4c17fc Select admin finder template for private route 2023-05-24 02:09:02 +03:00
b975dd958a Disable buttons in public finder 2023-05-24 02:08:39 +03:00
0599e35a92 Fix dockerfile 2023-05-24 02:08:25 +03:00
641e58984b Rename and scrub resources 2023-05-24 02:08:01 +03:00
4cb31d2e19 Fix decorat window bringToTop logic 2023-05-23 02:58:41 +03:00
9ec954ceb3 Massive rework in blog viewer 2023-05-18 04:57:44 +03:00
5d160bddd9 Relatives patches, appContext in backend and temp favicon 2023-05-18 01:45:39 +03:00
9cc2dc5a42 Fix run of AboutMe.app 2023-05-17 16:57:55 +03:00
56038cc284 Fixes 2023-05-17 16:09:22 +03:00
f363ebbe10 Create pathlinks 2023-05-16 15:12:55 +03:00
2a5f0bb3f4 Disable console log 2023-05-16 13:52:11 +03:00
6a93f418d5 Create public and private modes for website 2023-05-16 13:51:28 +03:00
d2ea95a182 Fixes for frontend 2023-05-16 02:04:16 +03:00
1b3f17777e Fix finder context menu in desktop mode and add error on link giletype 2023-05-11 04:56:56 +03:00
8facac5d19 Fix margin of error window 2023-05-11 04:56:17 +03:00
435e98dac0 Start work on links support 2023-05-11 04:45:57 +03:00
5b03a465fc Add initial support for stateUrls 2023-05-11 02:56:40 +03:00
08473aab11 Fix desktop mode in finder 2023-05-11 02:45:38 +03:00
6dc162f3ff Fix blog after refactoring 2023-05-11 02:26:57 +03:00
3702495714 Refactor AboutMe app 2023-05-11 02:17:59 +03:00
50d7924728 Delete empty strings 2023-05-11 02:17:50 +03:00
7f2c7f065c Fix error window 2023-05-11 02:06:45 +03:00
4426d30342 Finder refactoring 2023-05-11 01:56:28 +03:00
9c0cc8d709 Start finder refactoring 2023-05-10 15:39:49 +03:00
f81e15f1b8 Add cat lib with route 2023-05-10 01:19:06 +03:00
da8af8222d move from comments init css zoom and finder desktop 2023-05-10 01:18:54 +03:00
61cbf717c3 Add todo 2023-05-10 01:18:02 +03:00
46ad190b2a New applications load method 2023-05-09 06:17:34 +03:00
ade7b9b021 change app manifest creation 2023-05-09 03:57:53 +03:00
5b0830de4d Add empty strings init on App Creation 2023-05-09 03:51:33 +03:00
5fe693f664 Increase myPhoto size 2023-05-08 00:31:12 +03:00
5c6d1d65a6 Add todo 2023-05-08 00:31:03 +03:00
c9e846e2cf Start loading apps by manifest 2023-05-08 00:20:40 +03:00
113b7ebc37 custom icons support 2023-05-07 23:20:16 +03:00
ea65976d01 Frontend apps fixes 2023-05-07 22:56:40 +03:00
fa50328474 Fixes for apps 2023-05-07 15:14:42 +03:00
b5cde34178 Add support file open to blog and pers-prpps 2023-05-07 04:28:58 +03:00
b8eda48aa7 pers props app update 2023-05-07 04:24:46 +03:00
9b88db9289 temp default icon 2023-05-07 04:24:33 +03:00
0ceae10530 Port code base to new fs version 2023-05-07 04:00:22 +03:00
6c3bc32b59 massive commit for safe refactoring 2023-05-07 03:14:30 +03:00
1beba0f0ee Personal props 2023-05-06 01:50:57 +03:00
405f45e788 Initial file props window 2023-05-06 01:07:09 +03:00
c95501dbb7 Working img viewer 2023-05-05 23:31:42 +03:00
5736b8de31 File Deleting and new decoding 2023-05-05 21:32:41 +03:00
2197356dcc assive commit 2023-05-05 17:44:03 +03:00
ccaebdc667 Add file deletion (not work) 2023-05-05 01:11:11 +03:00
70a163c4aa Revert "update imports"
This reverts commit 71dc0c519b.
2023-05-05 00:20:36 +03:00
71dc0c519b update imports 2023-05-05 00:20:17 +03:00
00750280df Change context menu action data to string 2023-05-04 22:50:12 +03:00
1e93568f9b Move upload func to fs pacakge 2023-05-04 22:49:59 +03:00
ccc24b93ad Add callback to fileUploading drag-n-drop 2023-05-04 22:49:42 +03:00
b496ce2ab2 Add file uploading 2023-05-04 22:49:22 +03:00
313be711a9 Mongo directories validation 2023-05-04 18:55:08 +03:00
bea6859457 Improve contex menu in finder, small fixes 2023-05-04 17:58:38 +03:00
4382b57e9e new attempt to create focus algorithm 2023-05-04 13:46:48 +03:00
2f3cb85d22 Fix focus logic in css 2023-05-04 13:46:28 +03:00
0b6507e52a Fix bug top padding in desktop 2023-05-04 05:04:07 +03:00
8b7dac3c60 Create focus mode for windows 2023-05-04 05:00:09 +03:00
6bc3b0d79b Disable debug black color in context menu 2023-05-04 04:59:56 +03:00
e1635f5e27 Add context menu 2023-05-04 03:38:24 +03:00
809b7aa901 Add new class to windows generation 2023-05-04 01:47:58 +03:00
41ca6ba346 make different classes for visual and markup 2023-05-04 01:47:23 +03:00
7fe9660923 add admin finder render 2023-05-04 01:47:00 +03:00
be13dcd525 Change libs routes 2023-05-04 01:04:29 +03:00
139831365a Move apps to classes 2023-05-04 00:50:08 +03:00
0ae5eb4325 fix files uploading 2023-05-03 22:50:43 +03:00
7e65712103 fix css in alert window 2023-05-02 15:12:04 +03:00
70bcc60edd Add initial alert ui window 2023-05-02 14:32:56 +03:00
17dbd6249b Add deselection by clicking on black space of tileview 2023-05-02 13:50:56 +03:00
93dcea8b21 Fix bringToFront function 2023-05-02 13:38:28 +03:00
624bd3255c Add hostname catching on backend 2023-05-02 03:59:11 +03:00
c77dc479db Create one file select and doubleclick/click events 2023-05-02 03:48:12 +03:00
8e2d014317 fix uploading and img rendering 2023-05-02 03:12:43 +03:00
a0ccc5e120 delete test images 2023-05-02 02:06:04 +03:00
0d1dcde727 fix finder header 2023-05-02 02:05:54 +03:00
3b8bc166cb working binary images in mongo 2023-05-01 15:32:41 +03:00
d549c96492 css refactoring 2023-04-30 14:32:35 +03:00
6c5d804ae0 Add todos 2023-04-30 00:16:37 +03:00
2f2ad23fd6 Desktop with files and background 2023-04-30 00:01:23 +03:00
e9422f797b props markup fixes + shared lib to read images 2023-04-29 23:17:34 +03:00
f736033ce3 basic islands from db 2023-04-29 22:37:08 +03:00
4c0bea4f89 fixes in img viewer 2023-04-29 20:02:00 +03:00
5f6d5e7a48 Fix class name 2023-04-29 19:57:02 +03:00
326e150780 fix in img-viewer 2023-04-29 19:56:30 +03:00
5f07c9a52c base64 images 2023-04-29 19:47:12 +03:00
0a8e438d4d Fix windows dragging 2023-04-29 18:34:25 +03:00
06a87af35b Working blog markup 2023-04-29 17:26:07 +03:00
471350ead1 Working blog files opening 2023-04-29 16:58:39 +03:00
b6b3cf9ca1 Fix name in FinderApplication 2023-04-29 15:03:03 +03:00
21b201fd9d init blog render via files 2023-04-29 15:02:25 +03:00
8d424398dd Add work with directories and files 2023-04-29 13:17:25 +03:00
38e4058840 Merge branch 'webfs/init' of https://git.gregbrzezinski.com/cyber-dream/personal-website into webfs/init 2023-04-29 12:04:02 +03:00
58eabd1af9 Add .env to gitignore 2023-04-29 12:03:56 +03:00
e1e62a0373 Add file data structure 2023-04-29 12:02:55 +03:00
451486f44b Add real webfs code 2023-04-25 12:37:42 +03:00
fdf2228c3e new imports 2023-04-25 12:37:17 +03:00
8701baab7a Init blog-viewer 2023-04-14 18:53:23 +03:00
c1bed6e2cd Working close button 2023-04-13 21:28:37 +03:00
10a7cf9301 fix close buttons 2023-04-13 21:28:28 +03:00
6ef9ac2df1 Remove obsolete code + fix window moving and add focus 2023-04-13 20:09:49 +03:00
eaa3ce9d5d change to query selector 2023-04-13 20:09:14 +03:00
9478c6c8dd Change to query selector 2023-04-13 20:09:01 +03:00
dc7bf44576 Add todo to old scrollbar 2023-04-13 19:33:29 +03:00
175 changed files with 15529 additions and 1642 deletions

8
.gitignore vendored
View File

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

View File

@ -10,7 +10,7 @@ FROM golang:1.18-alpine
WORKDIR /usr/app WORKDIR /usr/app
COPY --from=build /usr/app/personalwebsite /usr/app/personalwebsite COPY --from=build /usr/app/personalwebsite /usr/app/personalwebsite
COPY ./templates /usr/app/templates COPY ./templates /usr/app/templates
COPY ./resources /usr/app/resources COPY ./res /usr/app/res
EXPOSE 8080 EXPOSE 8080

View File

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

View File

@ -0,0 +1,335 @@
package aboutme
import (
"errors"
"html/template"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"personalwebsite/libs"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type AboutMeApp struct {
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
titleBarConfig wde.TitleBarConfig //TODO to app manifest?
path string
manifest apps.ApplicationManifest
}
func NewAboutMeApp(webFs *webfilesystem.WebFileSystem) *AboutMeApp {
manifest := apps.ApplicationManifest{}
_, err := webFs.Read(path.Join("/Applications/AboutMe.app", ".appmanifest"), &manifest)
if err != nil {
panic(err)
}
newApp := AboutMeApp{
fs: webFs,
appID: "AboutMe",
path: "/Applications/AboutMe.app",
titleBarConfig: wde.TitleBarConfig{
Lable: "About Me",
CloseButton: true,
HasIcon: true,
IconPath: "/Icons/GenericApp.icn",
IconSize: "16",
},
manifest: manifest,
}
return &newApp
}
func (p *AboutMeApp) GetPath() string {
return p.path
}
func (p *AboutMeApp) GetManifest() apps.ApplicationManifest {
return p.manifest
}
func (p *AboutMeApp) PublicRoutes(route *gin.RouterGroup) {
route.POST("render", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
ginH, err := p.Render(appCtx, filePath)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "TODO") //TODO
return
}
if appCtx.IsMobile {
ctx.HTML(http.StatusOK, "personal-properties/mobile-app.tmpl", ginH)
} else {
ctx.HTML(http.StatusOK, "personal-properties/app.tmpl", ginH)
}
})
}
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("getMock", func(ctx *gin.Context) {
ctx.JSON(http.StatusOK, PropertiesFileData{
Header: HeaderIsland{
Name: "",
IconPath: "",
Value1: "",
Value2: "",
},
Links: []HeaderLink{
{
Text: "",
Url: "",
Icon: "",
},
},
Islands: []Island{
{
Header: "qq",
Properties: []IslandProperty{
{
Key: "22",
KeyComments: []string{
"45",
"12",
},
Values: []string{
"aaaa",
},
},
},
},
},
})
})
router.GET("read", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
return
}
propData, err := p.Read(filePath)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.JSON(http.StatusOK, propData)
})
router.POST("edit", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
return
}
propsData := PropertiesFileData{}
err := ctx.BindJSON(&propsData)
if err != nil {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
err = p.Edit(filePath, propsData)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.Status(http.StatusOK)
})
}
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",
},
}
_, _, err := p.fs.Write("/Applications/AboutMe.app/aboutme.props", &fileHeader, fileData)
return err
}
func (p *AboutMeApp) Read(filePath string) (*PropertiesFileData, error) {
propData := PropertiesFileData{}
fileHeader, err := p.fs.Read(path.Join(filePath, "aboutme.props"), &propData)
if err != nil {
return nil, err
}
if fileHeader.Type != "personal-properties" {
return nil, errors.New("wrong file type")
}
return &propData, nil
}
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 {
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")
}
err = p.fs.Remove(propsPath)
if err != nil {
return err
}
fileHeader.MongoId = primitive.NewObjectID()
_, _, err = p.fs.Write(propsPath, fileHeader, blogData)
if err != nil {
return err
}
return nil
}
func (p *AboutMeApp) Render(appCtx appCtx.AppContext, filePath string) (gin.H, error) {
//Read file from WebFS
propsData := &PropertiesFileData{}
filePath = p.fs.RelativeToAbsolute(appCtx, filePath)
_, err := p.fs.Read(filePath, &propsData)
if err != nil {
return nil, err
}
//Render Markdown strings
renderedIslands := []RenderedIsland{}
for _, island := range propsData.Islands {
newRenderedIsland := RenderedIsland{
Header: island.Header,
Properties: []RenderedIslandProperty{},
}
for _, property := range island.Properties {
newRenderedIslandProperty := RenderedIslandProperty{
Key: property.Key,
KeyComments: property.KeyComments,
Values: []template.HTML{},
}
for _, value := range property.Values {
renderedValue := p.mLib.Render([]byte(value), true)
newRenderedIslandProperty.Values = append(newRenderedIslandProperty.Values, renderedValue)
}
newRenderedIsland.Properties = append(newRenderedIsland.Properties, newRenderedIslandProperty)
}
renderedIslands = append(renderedIslands, newRenderedIsland)
}
//Make icon path absolute
propsData.Header.IconPath = p.fs.RelativeToAbsolute(appCtx, propsData.Header.IconPath)
absoluteLinks := []HeaderLink{}
for _, link := range propsData.Links {
absoluteLinks = append(absoluteLinks, HeaderLink{
Text: link.Text,
Url: link.Url,
Icon: p.fs.RelativeToAbsolute(appCtx, link.Icon),
})
}
return gin.H{
"TitleBarConfig": p.titleBarConfig,
"HeaderProps": propsData.Header,
"Links": absoluteLinks,
"Islands": renderedIslands,
}, nil
}
type PropertiesFileData struct {
Header HeaderIsland `bson:"header" json:"header"`
Links []HeaderLink `bson:"links" json:"links"`
Islands []Island `bson:"islands" json:"islands"` //TODO rename
}
type HeaderIsland struct {
Name string `bson:"name" json:"name"`
IconPath string `bson:"iconpath" json:"iconpath"`
Value1 string `bson:"value1" json:"value1"` //TODO Rename to value
Value2 string `bson:"value2" json:"value2"`
}
type HeaderLink struct {
Text string `bson:"text" json:"text"`
Url string `bson:"url" json:"url"`
Icon string `bson:"icon" json:"icon"`
}
type Island struct {
Header string `bson:"header" json:"header"`
Properties []IslandProperty `bson:"properties" json:"properties"`
}
type IslandProperty struct {
Key string `bson:"key" json:"key"`
KeyComments []string `bson:"keycomment" json:"keycomment"`
Values []string `bson:"values" json:"values"`
}
type RenderedIsland struct {
Header string
Properties []RenderedIslandProperty
}
type RenderedIslandProperty struct {
Key string
KeyComments []string
Values []template.HTML
}
// type Value struct {
// Blocks []ValueBlock
// }
// type ValueBlock struct {
// Type string
// Data string
// }

View File

@ -0,0 +1,8 @@
package appCtx
//TODO to websiteapp package
type AppContext struct {
IsMobile bool `json:"isMobile"`
BundlePath string `json:"bundlePath"`
RunPath string `json:"runPath"`
}

View File

@ -0,0 +1,18 @@
package blogviewer
import "html/template"
type BlogFileData struct {
Header string `bson:"header"`
Blocks []*Block `bson:"blocks"`
}
type Block struct {
Type string `bson:"type"`
Data []string `bson:"data"`
}
type RenderedBlock struct {
Type string `bson:"type"`
Data []template.HTML `bson:"data"`
}

View File

@ -0,0 +1,266 @@
package blogviewer
import (
"errors"
"net/http"
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
"personalwebsite/libs"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
type BlogViewerApplication struct {
fs *webfilesystem.WebFileSystem
appID string
mLib libs.MarkdownLib
path string
manifest apps.ApplicationManifest
}
func NewBlogViewerApp(webFs *webfilesystem.WebFileSystem) *BlogViewerApplication {
return &BlogViewerApplication{
fs: webFs,
appID: "BlogViewer",
mLib: libs.MarkdownLib{},
}
}
func (b *BlogViewerApplication) GetManifest() apps.ApplicationManifest {
return b.manifest
}
func (b *BlogViewerApplication) GetAppID() string {
return b.appID
}
func (b *BlogViewerApplication) GetPath() string {
return b.path
}
func (b *BlogViewerApplication) PrivateRoutes(route *gin.RouterGroup) {
b.PublicRoutes(route)
route.POST("test", func(ctx *gin.Context) {
blogData := BlogFileData{}
err := ctx.BindJSON(&blogData)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
mLib := libs.MarkdownLib{}
for _, block := range blogData.Blocks {
for _, str := range block.Data {
test := []byte(str)
mLib.Render(test, true)
}
}
})
route.GET("writeMockBlog", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
err := b.WriteMock(path)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.JSON(http.StatusOK, "OK")
})
route.POST("edit", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
}
blogData := BlogFileData{}
err := ctx.BindJSON(&blogData)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
err = b.Edit(filePath, blogData)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.Status(http.StatusOK)
})
route.GET("read", func(ctx *gin.Context) {
filePath := ctx.Query("path")
if filePath == "" {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "File path is empty",
})
}
blogData, err := b.Read(filePath)
if err != nil {
ctx.JSON(http.StatusInternalServerError, errormessage.ErrorMessage{
Message: err.Error(),
})
return
}
ctx.JSON(http.StatusOK, blogData)
})
}
func (b *BlogViewerApplication) PublicRoutes(route *gin.RouterGroup) {
route.POST("render", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.Status(http.StatusBadRequest)
return
}
ginH, err := b.Render(path, appCtx)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "TODO")
return
}
if appCtx.IsMobile {
ctx.HTML(http.StatusOK, "blog-viewer/mobile-app.tmpl", ginH)
} else {
ctx.HTML(http.StatusOK, "blog-viewer/app.tmpl", ginH)
}
})
}
func (b *BlogViewerApplication) WriteMock(path string) error {
blogFileHeader := webfilesystem.FileHeader{ //TODO to fs.CreateDirectory()
MongoId: primitive.NewObjectID(),
Name: "blog1.blog",
Type: "directory",
Icon: "",
Data: [12]byte{},
}
blogFileData := webfilesystem.DirectoryData{
MongoId: primitive.NewObjectID(),
Parent: [12]byte{},
Children: []primitive.ObjectID{},
}
_, _, err := b.fs.Write("/home/user/blog1.blog", &blogFileHeader, blogFileData)
if err != nil {
println(err.Error())
return err
}
blogContentFileHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: ".content",
Type: "blog-content",
Icon: "",
Data: [12]byte{},
}
blogContentFileData := BlogFileData{
Header: "OMG THIS IS BLOG",
}
blogContentFileData.Blocks = append(blogContentFileData.Blocks, &Block{
Type: "plain-text",
Data: []string{
"Apoqiwepoqiwepo",
".,mas;dakls;d",
"q[poqwieqpipoi]",
},
})
_, _, err = b.fs.Write("/home/user/blog1.blog/.content", &blogContentFileHeader, blogContentFileData)
if err != nil {
println(err.Error())
return err
}
return nil
}
func (b *BlogViewerApplication) Read(filePath string) (*BlogFileData, error) {
fileData := BlogFileData{}
fileHeader, err := b.fs.Read(path.Join(filePath, ".content"), &fileData)
if err != nil {
return nil, err
}
if fileHeader.Type != "blog-content" {
return nil, errors.New("wrong file type")
}
return &fileData, nil
}
func (b *BlogViewerApplication) Edit(filePath string, blogData BlogFileData) error {
contentPath := path.Join(filePath, ".content")
fileHeader, err := b.fs.Read(contentPath, nil)
if err != nil {
return err
}
if fileHeader.Type != "blog-content" {
return errors.New("wrong file type")
}
err = b.fs.Remove(contentPath)
if err != nil {
return err
}
fileHeader.MongoId = primitive.NewObjectID()
_, _, err = b.fs.Write(contentPath, fileHeader, blogData)
if err != nil {
return err
}
return nil
}
func (b *BlogViewerApplication) Render(filePath string, appCtx appCtx.AppContext) (gin.H, error) {
data := &BlogFileData{}
_, err := b.fs.Read(path.Join(filePath, ".content"), &data)
if err != nil {
return nil, err
}
newData := []RenderedBlock{}
for _, block := range data.Blocks {
newBlock := RenderedBlock{}
switch block.Type {
case "image":
// for _, image := range block.Data {
// newData = append(newData, b.fs.RelativeToAbsolute(appCtx, image))
// }
case "markdown":
for _, data := range block.Data {
renderedMD := b.mLib.Render([]byte(data), true)
newBlock.Data = append(newBlock.Data, renderedMD)
}
newData = append(newData, newBlock)
}
// block.Data = newData
}
return gin.H{
"header": data.Header,
"blocks": newData,
// "html": html,
}, nil
}

91
apps/finder/finder.go Normal file
View File

@ -0,0 +1,91 @@
package finder
import (
"path"
"personalwebsite/apps"
"personalwebsite/apps/appCtx"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type FinderApplication struct {
fs *webfilesystem.WebFileSystem
appID string
titleBarConfig wde.TitleBarConfig
path string
manifest apps.ApplicationManifest
// manifest apps.ApplicationManifest
}
func NewFinderApplication(webFs *webfilesystem.WebFileSystem) *FinderApplication {
manifest := apps.ApplicationManifest{}
_, err := webFs.Read(path.Join("/Applications/Finder.app", ".appmanifest"), &manifest)
if err != nil {
panic(err)
}
return &FinderApplication{
fs: webFs,
path: "/Applications/Finder.app",
appID: "Finder",
titleBarConfig: wde.TitleBarConfig{
Lable: "Finder",
CloseButton: true,
HasIcon: true,
IconPath: "/Icons/GenericFolder.icn",
IconSize: "16",
},
manifest: manifest,
}
}
func (f *FinderApplication) GetManifest() apps.ApplicationManifest {
return f.manifest
}
func (f *FinderApplication) GetAppID() string {
return f.appID
}
func (f *FinderApplication) GetPath() string {
return f.path
}
func (f *FinderApplication) Render(appCtx appCtx.AppContext) gin.H {
return gin.H{
"TitleBarConfig": f.titleBarConfig,
}
}
func (f *FinderApplication) RenderPublicContextMenu(context string, filePath string, data string) gin.H {
islands := [][]wde.ContexMenuRow{}
islands = append(islands, []wde.ContexMenuRow{})
//TODO: Links read as source files in props info
islands = append(islands, []wde.ContexMenuRow{
{Label: "Get Info", Action: "getInfo"},
})
if context == "FileTileView" {
return gin.H{
"Islands": islands,
}
}
switch context {
default:
}
return gin.H{
"Islands": islands,
}
}
func (f *FinderApplication) RenderProps(filePath string) (gin.H, error) {
fileHeader, err := f.fs.Read(filePath, nil)
if err != nil {
return nil, err
}
return gin.H{
"file": fileHeader,
}, nil
}

View File

@ -0,0 +1,61 @@
package finder
import (
"personalwebsite/apps/appCtx"
"personalwebsite/wde"
"github.com/gin-gonic/gin"
)
func (f *FinderApplication) RenderAdminWindow(appCtx appCtx.AppContext) gin.H {
return gin.H{}
}
func (f *FinderApplication) RenderPrivateContextMenu(context string, filePath string, data string) gin.H {
islands := [][]wde.ContexMenuRow{}
// islands = append(islands, []wde.ContexMenuRow{})
islands = append(islands, []wde.ContexMenuRow{
{Label: "Get Info", Action: "getInfo"},
})
if context == "FileTileView" {
islands = append(islands, []wde.ContexMenuRow{
{Label: "New Directory", Action: "createDir"},
})
return gin.H{
"Islands": islands,
}
}
islands = append(islands, []wde.ContexMenuRow{
{Label: "Create path link", Action: "createPathLink"},
})
switch context {
case "directory":
switch f.fs.GetExtension(filePath) {
case "app":
islands = append(islands, []wde.ContexMenuRow{
{Label: "Open as Directory", Action: "openAsDir"},
})
case "blog":
islands = append(islands, []wde.ContexMenuRow{
{Label: "Open as Directory", Action: "openAsDir"},
})
}
default:
islands = append(islands, []wde.ContexMenuRow{
{Label: "temp Menu 1", Action: ""},
{Label: "temp Menu 2", Action: ""},
})
}
islands = append(islands, []wde.ContexMenuRow{
{Label: "Delete File", Action: "deleteFile"},
})
return gin.H{
"Islands": islands,
}
}

122
apps/finder/routes.go Normal file
View File

@ -0,0 +1,122 @@
package finder
import (
"net/http"
"personalwebsite/apps/appCtx"
"personalwebsite/errormessage"
mobile "github.com/floresj/go-contrib-mobile"
"github.com/gin-gonic/gin"
)
func (f *FinderApplication) PublicRoutes(routes *gin.RouterGroup) {
routes.POST("render", func(ctx *gin.Context) {
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "Error in decoding app bundle",
})
return
}
d := mobile.GetDevice(ctx)
switch {
case d.Mobile():
ctx.HTML(http.StatusOK, "templates/finder/mobile-app.tmpl", gin.H{
// "autostart": autostart,
})
default:
ctx.HTML(http.StatusOK, "finder/app.tmpl", f.Render(appCtx))
}
})
//Obsolete
routes.GET("renderMobileDesktop", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "finder/mobile-desktop.tmpl", gin.H{})
})
routes.POST("renderDesktop", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
ctx.HTML(http.StatusOK, "finder/desktop.tmpl", gin.H{})
})
routes.GET("contextMenu", func(ctx *gin.Context) {
context := ctx.Query("context")
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
data := ctx.Query("data")
ginH := f.RenderPublicContextMenu(context, filePath, data)
ctx.HTML(http.StatusOK, "wde-widgets/context-menu.tmpl", ginH)
})
routes.GET("renderProps", func(ctx *gin.Context) {
filePath := ctx.Query("path")
ginH, err := f.RenderProps(filePath)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.HTML(http.StatusOK, "finder/props.tmpl", ginH)
})
}
func (f *FinderApplication) PrivateRoutes(routes *gin.RouterGroup) {
routes.POST("render", func(ctx *gin.Context) {
appCtx := appCtx.AppContext{}
err := ctx.BindJSON(&appCtx)
if err != nil {
ctx.JSON(http.StatusBadRequest, errormessage.ErrorMessage{
Message: "Error in decoding app bundle",
})
return
}
d := mobile.GetDevice(ctx)
switch {
case d.Mobile():
ctx.HTML(http.StatusOK, "finder/mobile-app.tmpl", f.Render(appCtx))
default:
ctx.HTML(http.StatusOK, "finder/admin-app.tmpl", f.Render(appCtx))
}
})
routes.GET("renderMobileDesktop", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "finder/mobile-desktop.tmpl", gin.H{})
})
routes.POST("renderDesktop", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
ctx.HTML(http.StatusOK, "finder/desktop.tmpl", gin.H{})
})
routes.GET("contextMenu", func(ctx *gin.Context) {
context := ctx.Query("context")
filePath := ctx.Query("path")
if filePath == "" {
ctx.Status(http.StatusBadRequest)
return
}
data := ctx.Query("data")
ginH := f.RenderPrivateContextMenu(context, filePath, data)
ctx.HTML(http.StatusOK, "wde-widgets/context-menu.tmpl", ginH)
})
routes.GET("renderProps", func(ctx *gin.Context) {
filePath := ctx.Query("path")
ginH, err := f.RenderProps(filePath)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.HTML(http.StatusOK, "finder/props.tmpl", ginH)
})
}

View File

@ -0,0 +1,82 @@
package imgviewer
import (
"net/http"
"personalwebsite/apps"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type ImgViewerApp struct {
fs *webfilesystem.WebFileSystem
appID string
path string
manifest apps.ApplicationManifest
}
func NewImgViewerApp(webFs *webfilesystem.WebFileSystem) *ImgViewerApp {
newApp := ImgViewerApp{
fs: webFs,
appID: "ImgViewer",
}
return &newApp
}
func (p *ImgViewerApp) PrivateRoutes(route *gin.RouterGroup) {
p.PublicRoutes(route)
}
func (i *ImgViewerApp) GetManifest() apps.ApplicationManifest {
return i.manifest
}
func (p *ImgViewerApp) PublicRoutes(route *gin.RouterGroup) {
route.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
path := ctx.Query("path")
if path == "" {
ctx.JSON(http.StatusBadRequest, "no path provided")
return
}
ginH, err := p.Render(path, isMobile)
if err != nil {
ctx.JSON(http.StatusInternalServerError, "TODO")
return
}
if isMobile {
ctx.HTML(http.StatusOK, "img-viewer/mobile-app.tmpl", ginH)
} else {
ctx.HTML(http.StatusOK, "img-viewer/app.tmpl", ginH)
}
})
}
func (p *ImgViewerApp) GetPath() string {
return p.path
}
func (p *ImgViewerApp) GetAppID() string {
return p.appID
}
func (p *ImgViewerApp) Render(filePath string, isMobile bool) (gin.H, error) {
// file, err := p.fs.NewRead(filePath)
// if err != nil {
// return nil, err
// }
// println(file.Data.(primitive.Binary).Data)
// img, err := p.fs.NewRead(path)
// if err != nil {
// return nil, err
// }
// data, err := libs.ReadImage(img)
// if err != nil {
// return nil, err
// }
// url := location.Get(ctx)
return gin.H{
"imgUrl": "/system/libs/img/get?path=" + filePath,
// "header": data.Header,
// "base64": data.Base64,
}, nil
}

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

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

145
apps/websiteapp.go Normal file
View File

@ -0,0 +1,145 @@
package apps
import (
"net/http"
"path"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
"go.mongodb.org/mongo-driver/bson/primitive"
)
//TODO to libs
type WebDEApplication interface {
// Render()
GetAppID() string
PublicRoutes(*gin.RouterGroup)
PrivateRoutes(*gin.RouterGroup)
GetPath() string
GetManifest() ApplicationManifest
// GEtHtml()
// GetId() string
}
type ApplicationManifest struct {
AppId string `bson:"appid" json:"appId"`
Js []string `bson:"js" json:"js"`
Css []string `bson:"css" json:"css"`
Iconpath string `bson:"iconpath" json:"iconpath"`
}
func NewApplicationsStorage(apps map[string]WebDEApplication, webfs *webfilesystem.WebFileSystem) *ApplicationsStorage {
return &ApplicationsStorage{
Apps: apps,
fs: webfs,
}
}
type ApplicationsStorage struct {
Apps map[string]WebDEApplication
fs *webfilesystem.WebFileSystem
}
func (as *ApplicationsStorage) createApp(appName string, appId string, appPath string) error {
appBundleName := appName + ".app"
newAppBundleHeader := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: appBundleName,
Type: "directory",
Icon: "",
Data: primitive.NewObjectID(),
}
newAppBundleData := webfilesystem.DirectoryData{
MongoId: primitive.NewObjectID(),
Parent: primitive.NewObjectID(),
Children: []primitive.ObjectID{},
}
_, _, err := as.fs.Write(appPath+"/"+appBundleName, &newAppBundleHeader, &newAppBundleData)
if err != nil {
return err
}
newAppData := ApplicationManifest{
AppId: appId,
Js: []string{},
Css: []string{},
}
newAppFile := webfilesystem.FileHeader{
MongoId: primitive.NewObjectID(),
Name: ".appmanifest",
Type: "application-manifest",
Icon: "",
Data: primitive.NewObjectID(),
}
_, _, err = as.fs.Write(appPath+"/"+appBundleName+"/"+newAppFile.Name, &newAppFile, newAppData)
if err != nil {
return err
}
return nil
}
func (aStorage *ApplicationsStorage) PrivateRoute(route *gin.RouterGroup) {
route.GET("/get", func(ctx *gin.Context) {
appId := ctx.Query("appid")
if appId == "" {
ctx.Status(http.StatusBadRequest)
return
}
// app, isExist := aStorage.Apps[appId]
// if !isExist {
// ctx.Status(http.StatusNoContent)
// return
// }
// ctx.JSON(http.StatusOK, app.GetManifest())
ctx.String(http.StatusMovedPermanently, "Obsolete")
})
route.GET("/loadApp", func(ctx *gin.Context) {
appPath := ctx.Query("path")
if appPath == "" {
ctx.Status(http.StatusBadRequest)
return
}
appManifestData := ApplicationManifest{}
fileHeader, err := aStorage.fs.Read(path.Join(appPath, ".appmanifest"), &appManifestData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
if fileHeader.Type != "application-manifest" {
ctx.Status(http.StatusBadRequest)
return
}
ctx.JSON(http.StatusOK, appManifestData)
})
route.GET("/createApp", func(ctx *gin.Context) {
appId := ctx.Query("appId")
if appId == "" {
ctx.Status(http.StatusBadRequest)
return
}
appName := ctx.Query("appName")
if appName == "" {
ctx.Status(http.StatusBadRequest)
return
}
appPath := ctx.Query("path")
if appPath == "" {
ctx.Status(http.StatusBadRequest)
return
}
err := aStorage.createApp(appId, appName, appPath)
if err != nil {
ctx.String(http.StatusInternalServerError, err.Error())
return
}
ctx.Status(http.StatusOK)
})
}

View File

@ -0,0 +1,5 @@
package errormessage
type ErrorMessage struct {
Message string `json:"message"`
}

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

Binary file not shown.

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

Binary file not shown.

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

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

View File

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

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

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

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

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

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

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

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

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

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

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

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

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

5873
front/package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

6
front/package.json Normal file
View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

Binary file not shown.

Binary file not shown.

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

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

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

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

View File

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

View File

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

View File

@ -0,0 +1,37 @@
export default class MobileDecorat {
/** @type {Element} */
#applicationsNode
constructor(){
this.#applicationsNode = document.body.querySelector("#mobile-app-views") //TODO validate
this.#loadControlsBar()
}
#loadControlsBar(){
let bar = document.body.querySelector("#controls-bar") //TODO Validate
console.log(bar)
bar.querySelector("#back").addEventListener('click', () => {
this.BackAction()
})
}
/**
* @param {string} appId
* @returns {Element}
*/
CreateNewView(appId){
let newView = document.createElement("div")
newView.setAttribute("class", "mobile-app-view")
newView.setAttribute("appId", appId)
// this.#applicationsNode.appendChild(newView)
this.#applicationsNode.insertBefore(newView, this.#applicationsNode.firstChild)
return newView
}
Open(){
}
BackAction(){
console.log(this.#applicationsNode.childNodes.length)
if (this.#applicationsNode.childNodes.length <= 1) return
this.#applicationsNode.firstChild.remove()
}
}

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

View File

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

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

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

30
go.mod
View File

@ -4,29 +4,51 @@ go 1.18
require github.com/gin-gonic/gin v1.9.0 require github.com/gin-gonic/gin v1.9.0
require (
github.com/aymerick/douceur v0.2.0 // indirect
github.com/golang/snappy v0.0.1 // indirect
github.com/gorilla/css v1.0.0 // indirect
github.com/klauspost/compress v1.13.6 // indirect
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe // indirect
github.com/pkg/errors v0.9.1 // indirect
github.com/xdg-go/pbkdf2 v1.0.0 // indirect
github.com/xdg-go/scram v1.1.1 // indirect
github.com/xdg-go/stringprep v1.0.3 // indirect
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d // indirect
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c // indirect
)
require ( require (
github.com/bytedance/sonic v1.8.0 // indirect github.com/bytedance/sonic v1.8.0 // indirect
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 // indirect
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5
github.com/gin-contrib/cors v1.4.0
github.com/gin-contrib/location v0.0.2
github.com/gin-contrib/sse v0.1.0 // indirect github.com/gin-contrib/sse v0.1.0 // indirect
github.com/go-playground/locales v0.14.1 // indirect github.com/go-playground/locales v0.14.1 // indirect
github.com/go-playground/universal-translator v0.18.1 // indirect github.com/go-playground/universal-translator v0.18.1 // indirect
github.com/go-playground/validator/v10 v10.11.2 // indirect github.com/go-playground/validator/v10 v10.11.2 // indirect
github.com/goccy/go-json v0.10.0 // indirect github.com/goccy/go-json v0.10.0 // indirect
github.com/google/uuid v1.3.0 github.com/joho/godotenv v1.5.1
github.com/json-iterator/go v1.1.12 // indirect github.com/json-iterator/go v1.1.12 // indirect
github.com/klauspost/cpuid/v2 v2.0.9 // indirect github.com/klauspost/cpuid/v2 v2.0.9 // indirect
github.com/leodido/go-urn v1.2.1 // indirect github.com/leodido/go-urn v1.2.1 // indirect
github.com/mattn/go-isatty v0.0.17 // indirect github.com/mattn/go-isatty v0.0.17 // indirect
github.com/microcosm-cc/bluemonday v1.0.24
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 // indirect
github.com/modern-go/reflect2 v1.0.2 // indirect github.com/modern-go/reflect2 v1.0.2 // indirect
github.com/pelletier/go-toml/v2 v2.0.6 // indirect github.com/pelletier/go-toml/v2 v2.0.6 // indirect
github.com/russross/blackfriday v1.6.0
github.com/russross/blackfriday/v2 v2.1.0
github.com/thinkerou/favicon v0.2.0
github.com/twitchyliquid64/golang-asm v0.15.1 // indirect github.com/twitchyliquid64/golang-asm v0.15.1 // indirect
github.com/ugorji/go/codec v1.2.9 // indirect github.com/ugorji/go/codec v1.2.9 // indirect
go.mongodb.org/mongo-driver v1.11.6
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect golang.org/x/arch v0.0.0-20210923205945-b76863e36670 // indirect
golang.org/x/crypto v0.5.0 // indirect golang.org/x/crypto v0.5.0 // indirect
golang.org/x/net v0.7.0 // indirect golang.org/x/net v0.10.0 // indirect
golang.org/x/sys v0.5.0 // indirect golang.org/x/sys v0.8.0 // indirect
golang.org/x/text v0.7.0 // indirect golang.org/x/text v0.9.0 // indirect
google.golang.org/protobuf v1.28.1 // indirect google.golang.org/protobuf v1.28.1 // indirect
gopkg.in/yaml.v3 v3.0.1 // indirect gopkg.in/yaml.v3 v3.0.1 // indirect
) )

123
go.sum
View File

@ -1,73 +1,180 @@
github.com/aymerick/douceur v0.2.0 h1:Mv+mAeH1Q+n9Fr+oyamOlAkUNPWPlA8PPGR0QAaYuPk=
github.com/aymerick/douceur v0.2.0/go.mod h1:wlT5vV2O3h55X9m7iVYN0TBM0NH/MmbLnd30/FjWUq4=
github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM= github.com/bytedance/sonic v1.5.0/go.mod h1:ED5hyg4y6t3/9Ku1R6dU/4KyJ48DZ4jPhfY1O2AihPM=
github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA= github.com/bytedance/sonic v1.8.0 h1:ea0Xadu+sHlu7x5O3gKhRpQ1IKiMrSiHttPF0ybECuA=
github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U= github.com/bytedance/sonic v1.8.0/go.mod h1:i736AoUSYt75HyZLoJW9ERYxcy6eaN6h4BZXU064P/U=
github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY= github.com/chenzhuoyu/base64x v0.0.0-20211019084208-fb5309c8db06/go.mod h1:DH46F32mSOjUmXrMHnKwZdA8wcEefY7UVqBKYGjpdQY=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311 h1:qSGYFH7+jGhDF8vLC+iwCD4WpbV1EBDSzWkJODFLams=
github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk= github.com/chenzhuoyu/base64x v0.0.0-20221115062448-fe3a3abad311/go.mod h1:b583jCggY9gE99b6G5LEC39OIiVsWj+R97kbl5odCEk=
github.com/creack/pty v1.1.9/go.mod h1:oKZEueFk5CKHvIhNR5MUki03XCEU+Q6VDXinZuGJ33E=
github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.0/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/davecgh/go-spew v1.1.1 h1:vj9j/u1bqnvCEfJOwUhtlOARqs3+rkHYY13jYWTU97c=
github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38= github.com/davecgh/go-spew v1.1.1/go.mod h1:J7Y8YcW2NihsgmVo/mv3lAwl/skON4iLHjSsI+c5H38=
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5 h1:e+OSfbvxkjub+bPlfDmqENiV9IEOnLUk9TU7fMhu2Ks=
github.com/floresj/go-contrib-mobile v0.0.0-20150714204826-47557cfa26f5/go.mod h1:2F+cddOTo8Rjp/98JPjMwZRCcCA1dP1VeNBvfk/tU6I=
github.com/gin-contrib/cors v1.4.0 h1:oJ6gwtUl3lqV0WEIwM/LxPF1QZ5qe2lGWdY2+bz7y0g=
github.com/gin-contrib/cors v1.4.0/go.mod h1:bs9pNM0x/UsmHPBWT2xZz9ROh8xYjYkiURUfmBoMlcs=
github.com/gin-contrib/location v0.0.2 h1:QZKh1+K/LLR4KG/61eIO3b7MLuKi8tytQhV6texLgP4=
github.com/gin-contrib/location v0.0.2/go.mod h1:NGoidiRlf0BlA/VKSVp+g3cuSMeTmip/63PhEjRhUAc=
github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE= github.com/gin-contrib/sse v0.1.0 h1:Y/yl/+YNO8GZSjAhjMsSuLt29uWRFHdHYUb5lYOV9qE=
github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI= github.com/gin-contrib/sse v0.1.0/go.mod h1:RHrZQHXnP2xjPF+u1gW/2HnVO7nvIa9PG3Gm+fLHvGI=
github.com/gin-gonic/gin v1.6.3/go.mod h1:75u5sXoLsGZoRN5Sgbi1eraJ4GU3++wFwWzhwvtwp4M=
github.com/gin-gonic/gin v1.8.1/go.mod h1:ji8BvRH1azfM+SYow9zQ6SZMvR8qOMZHmsCuWR9tTTk=
github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8= github.com/gin-gonic/gin v1.9.0 h1:OjyFBKICoexlu99ctXNR2gg+c5pKrKMuyjgARg9qeY8=
github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k= github.com/gin-gonic/gin v1.9.0/go.mod h1:W1Me9+hsUSyj3CePGrd1/QrKJMSJ1Tu/0hFEH89961k=
github.com/go-playground/assert/v2 v2.0.1/go.mod h1:VDjEfimB/XKnb+ZQfWdccd7VUvScMdVu0Titje2rxJ4=
github.com/go-playground/assert/v2 v2.2.0 h1:JvknZsQTYeFEAhQwI4qEt9cyV5ONwRHC+lYKSsYSR8s=
github.com/go-playground/locales v0.13.0/go.mod h1:taPMhCMXrRLJO55olJkUXHZBHCxTMfnGwq/HNwmWNS8=
github.com/go-playground/locales v0.14.0/go.mod h1:sawfccIbzZTqEDETgFXqTho0QybSa7l++s0DH+LDiLs=
github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA= github.com/go-playground/locales v0.14.1 h1:EWaQ/wswjilfKLTECiXz7Rh+3BjFhfDFKv/oXslEjJA=
github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY= github.com/go-playground/locales v0.14.1/go.mod h1:hxrqLVvrK65+Rwrd5Fc6F2O76J/NuW9t0sjnWqG1slY=
github.com/go-playground/universal-translator v0.17.0/go.mod h1:UkSxE5sNxxRwHyU+Scu5vgOQjsIJAF8j9muTVoKLVtA=
github.com/go-playground/universal-translator v0.18.0/go.mod h1:UvRDBj+xPUEGrFYl+lu/H90nyDXpg0fqeB/AQUGNTVA=
github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY= github.com/go-playground/universal-translator v0.18.1 h1:Bcnm0ZwsGyWbCzImXv+pAJnYK9S473LQFuzCbDbfSFY=
github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY= github.com/go-playground/universal-translator v0.18.1/go.mod h1:xekY+UJKNuX9WP91TpwSH2VMlDf28Uj24BCp08ZFTUY=
github.com/go-playground/validator/v10 v10.2.0/go.mod h1:uOYAAleCW8F/7oMFd6aG0GOhaH6EGOAJShg8Id5JGkI=
github.com/go-playground/validator/v10 v10.10.0/go.mod h1:74x4gJWsvQexRdW8Pn3dXSGrTK4nAUsbPlLADvpJkos=
github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU= github.com/go-playground/validator/v10 v10.11.2 h1:q3SHpufmypg+erIExEKUmsgmhDTyhcJ38oeKGACXohU=
github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s= github.com/go-playground/validator/v10 v10.11.2/go.mod h1:NieE624vt4SCTJtD87arVLvdmjPAeV8BQlHtMnw9D7s=
github.com/goccy/go-json v0.9.7/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA= github.com/goccy/go-json v0.10.0 h1:mXKd9Qw4NuzShiRlOXKews24ufknHO7gx30lsDyokKA=
github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I= github.com/goccy/go-json v0.10.0/go.mod h1:6MelG93GURQebXPDq3khkgXZkazVtN9CRI+MGFi0w8I=
github.com/golang/protobuf v1.3.3/go.mod h1:vzj43D7+SQXF/4pzW/hwtAqwc6iTitCiVSaWz5lYuqw=
github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk= github.com/golang/protobuf v1.5.0/go.mod h1:FsONVRAS9T7sI+LIUmWTfcYkHO4aIWwzhcaSAoJOfIk=
github.com/golang/snappy v0.0.1 h1:Qgr9rKW7uDUkrbSmQeiDsGa8SjGyCOGtuasMWwvp2P4=
github.com/golang/snappy v0.0.1/go.mod h1:/XxbfmMg8lxefKM7IXC3fBNl/7bRcc72aCRzEWrmP2Q=
github.com/google/go-cmp v0.5.2/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/go-cmp v0.5.5 h1:Khx7svrCpmxxtHBq5j2mp/xVjsi8hQMfNLvJFAlrGgU=
github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE= github.com/google/go-cmp v0.5.5/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg= github.com/google/gofuzz v1.0.0/go.mod h1:dBl0BpW6vV/+mYPU4Po3pmUjxk6FQPldtuIdl/M65Eg=
github.com/google/uuid v1.3.0 h1:t6JiXgmwXMjEs8VusXIJk2BXHsn+wx8BZdTaoZ5fu7I= github.com/gorilla/css v1.0.0 h1:BQqNyPTi50JCFMTw/b67hByjMVXZRwGha6wxVGkeihY=
github.com/google/uuid v1.3.0/go.mod h1:TIyPZe4MgqvfeYDBFedMoGGpEw/LqOeaOT+nhxU+yHo= github.com/gorilla/css v1.0.0/go.mod h1:Dn721qIggHpt4+EFCcTLTU/vk5ySda2ReITrtgBl60c=
github.com/joho/godotenv v1.5.1 h1:7eLL/+HRGLY0ldzfGMeQkb7vMd0as4CfYvUVzLqw0N0=
github.com/joho/godotenv v1.5.1/go.mod h1:f4LDr5Voq0i2e/R5DDNOoa2zzDfwtkZa6DnEwAbqwq4=
github.com/json-iterator/go v1.1.9/go.mod h1:KdQUCv79m/52Kvf8AW2vK1V8akMuk1QjK/uOdHXbAo4=
github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM= github.com/json-iterator/go v1.1.12 h1:PV8peI4a0ysnczrg+LtxykD8LfKY9ML6u2jnxaEnrnM=
github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo= github.com/json-iterator/go v1.1.12/go.mod h1:e30LSqwooZae/UwlEbR2852Gd8hjQvJoHmT4TnhNGBo=
github.com/klauspost/compress v1.13.6 h1:P76CopJELS0TiO2mebmnzgWaajssP/EszplttgQxcgc=
github.com/klauspost/compress v1.13.6/go.mod h1:/3/Vjq9QcHkK5uEr5lBEmyoZ1iFhe47etQ6QUkpK6sk=
github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4= github.com/klauspost/cpuid/v2 v2.0.9 h1:lgaqFMSdTdQYdZ04uHyN2d/eKdOMyi2YLSvlQIBFYa4=
github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg= github.com/klauspost/cpuid/v2 v2.0.9/go.mod h1:FInQzS24/EEf25PyTYn52gqo7WaD8xa0213Md/qVLRg=
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
github.com/kr/pretty v0.2.1/go.mod h1:ipq/a2n7PKx3OHsz4KJII5eveXtPO4qwEXGdVfWzfnI=
github.com/kr/pretty v0.3.0 h1:WgNl7dwNpEZ6jJ9k1snq4pZsg7DOEN8hP9Xw0Tsjwk0=
github.com/kr/pretty v0.3.0/go.mod h1:640gp4NfQd8pI5XOwp5fnNeVWj67G7CFk/SaSQn7NBk=
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
github.com/kr/text v0.2.0 h1:5Nx0Ya0ZqY2ygV366QzturHI13Jq95ApcVaJBhpS+AY=
github.com/kr/text v0.2.0/go.mod h1:eLer722TekiGuMkidMxC/pM04lWEeraHUUmBw8l2grE=
github.com/leodido/go-urn v1.2.0/go.mod h1:+8+nEpDfqqsY+g338gtMEUOtuK+4dEMhiQEgxpxOKII=
github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w= github.com/leodido/go-urn v1.2.1 h1:BqpAaACuzVSgi/VLzGZIobT2z4v53pjosyNd9Yv6n/w=
github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY= github.com/leodido/go-urn v1.2.1/go.mod h1:zt4jvISO2HfUBqxjfIshjdMTYS56ZS/qv49ictyFfxY=
github.com/mattn/go-isatty v0.0.12/go.mod h1:cbi8OIDigv2wuxKPP5vlRcQ1OAZbq2CE4Kysco4FUpU=
github.com/mattn/go-isatty v0.0.14/go.mod h1:7GGIvUiUoEMVVmxf/4nioHXj79iQHKdU27kJ6hsGG94=
github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng= github.com/mattn/go-isatty v0.0.17 h1:BTarxUcIeDqL27Mc+vyvdWYSL28zpIhv3RoTdsLMPng=
github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM= github.com/mattn/go-isatty v0.0.17/go.mod h1:kYGgaQfpe5nmfYZH+SKPsOc2e4SrIfOl2e/yFXSvRLM=
github.com/microcosm-cc/bluemonday v1.0.24 h1:NGQoPtwGVcbGkKfvyYk1yRqknzBuoMiUrO6R7uFTPlw=
github.com/microcosm-cc/bluemonday v1.0.24/go.mod h1:ArQySAMps0790cHSkdPEJ7bGkF2VePWH773hsJNSHf8=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421 h1:ZqeYNhU3OHLH3mGKHDcjJRFFRrJa6eAM5H+CtDdOsPc=
github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q= github.com/modern-go/concurrent v0.0.0-20180228061459-e0a39a4cb421/go.mod h1:6dJC0mAP4ikYIbvyc7fijjWJddQyLn8Ig3JB5CqoB9Q=
github.com/modern-go/reflect2 v0.0.0-20180701023420-4b7aa43c6742/go.mod h1:bx2lNnkwVCuqBIxFjflWJWanXIb3RllmbCylyMrvgv0=
github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M= github.com/modern-go/reflect2 v1.0.2 h1:xBagoLtFs94CBntxluKeaWgTMpvLxC4ur3nMaC9Gz0M=
github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk= github.com/modern-go/reflect2 v1.0.2/go.mod h1:yWuevngMOJpCy52FWWMvUC8ws7m/LJsjYzDa0/r8luk=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe h1:iruDEfMl2E6fbMZ9s0scYfZQ84/6SPL6zC8ACM2oIL0=
github.com/montanaflynn/stats v0.0.0-20171201202039-1bf9dbcd8cbe/go.mod h1:wL8QJuTMNUDYhXwkmfOly8iTdp5TEcJFWZD2D7SIkUc=
github.com/pelletier/go-toml/v2 v2.0.1/go.mod h1:r9LEWfGN8R5k0VXJ+0BkIe7MYkRdwZOjgMj2KwnJFUo=
github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU= github.com/pelletier/go-toml/v2 v2.0.6 h1:nrzqCb7j9cDFj2coyLNLaZuJTLjWjlaz6nvTvIwycIU=
github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek= github.com/pelletier/go-toml/v2 v2.0.6/go.mod h1:eumQOmlWiOPt5WriQQqoM5y18pDHwha2N+QD+EUNTek=
github.com/pkg/diff v0.0.0-20210226163009-20ebb0f2a09e/go.mod h1:pJLUxLENpZxwdsKMEsNbx1VGcRFpLqf3715MtcvvzbA=
github.com/pkg/errors v0.9.1 h1:FEBLx1zS214owpjy7qsBeixbURkuhQAwrK5UwLGTwt4=
github.com/pkg/errors v0.9.1/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
github.com/pmezard/go-difflib v1.0.0 h1:4DBwDE0NGyQoBHbLQYPwSUPoCMWR5BEzIk/f1lZbAQM=
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4= github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
github.com/rogpeppe/go-internal v1.6.1/go.mod h1:xXDCJY+GAPziupqXw64V24skbSoqbTEfhy4qGm1nDQc=
github.com/rogpeppe/go-internal v1.8.0 h1:FCbCCtXNOY3UtUuHUYaghJg4y7Fd14rXifAYUAtL9R8=
github.com/rogpeppe/go-internal v1.8.0/go.mod h1:WmiCO8CzOY8rg0OYDC4/i/2WRWAB6poM+XZ2dLUbcbE=
github.com/russross/blackfriday v1.6.0 h1:KqfZb0pUVN2lYqZUYRddxF4OR8ZMURnJIG5Y3VRLtww=
github.com/russross/blackfriday v1.6.0/go.mod h1:ti0ldHuxg49ri4ksnFxlkCfN+hvslNlmVHqNRXXJNAY=
github.com/russross/blackfriday/v2 v2.1.0 h1:JIOH55/0cWyOuilr9/qlrm0BSXldqnqwMsf35Ld67mk=
github.com/russross/blackfriday/v2 v2.1.0/go.mod h1:+Rmxgy9KzJVeS9/2gXHxylqXiyQDYRxCVz55jmeOWTM=
github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME= github.com/stretchr/objx v0.1.0/go.mod h1:HFkY916IF+rwdDfMAkV7OtwuqBVzrE8GR6GFx+wExME=
github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw= github.com/stretchr/objx v0.4.0/go.mod h1:YvHI0jy2hoMjB+UWwv71VJQ9isScKT/TqJzVSSt89Yw=
github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo= github.com/stretchr/objx v0.5.0/go.mod h1:Yh+to48EsGEfYuaHDzXPcE3xhTkx73EhmCGUpEOglKo=
github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI= github.com/stretchr/testify v1.3.0/go.mod h1:M5WIy9Dh21IEIfnGCwXGc5bZfKNJtfHm1UVUgZn+9EI=
github.com/stretchr/testify v1.4.0/go.mod h1:j7eGeouHqKxXV5pUuKE4zz7dFj8WfuZ+81PSLYec5m4=
github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.6.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.0/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg= github.com/stretchr/testify v1.7.1/go.mod h1:6Fq8oRcR53rry900zMqJjRRixrwX3KX962/h/Wwjteg=
github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU= github.com/stretchr/testify v1.8.0/go.mod h1:yNjHg4UonilssWZ8iaSj1OCr/vHnekPRkoO+kdMU+MU=
github.com/stretchr/testify v1.8.1 h1:w7B6lhMri9wdJUVmEZPGGhZzrYTPvgJArz7wNPgYKsk=
github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4= github.com/stretchr/testify v1.8.1/go.mod h1:w2LPCIKwWwSfY2zedu0+kehJoqGctiVI29o6fzry7u4=
github.com/thinkerou/favicon v0.2.0 h1:/qO//fFevzhx68pAAPjuiOwB2ykoKwLcZW9luMZ8PEU=
github.com/thinkerou/favicon v0.2.0/go.mod h1:PM31DMRkXDVi9/sGwb/a/evMB536N9VfVNC+Dtf4iDQ=
github.com/tidwall/pretty v1.0.0 h1:HsD+QiTn7sK6flMKIvNmpqz1qrpP3Ps6jOKIKMooyg4=
github.com/tidwall/pretty v1.0.0/go.mod h1:XNkn88O1ChpSDQmQeStsy+sBenx6DDtFZJxhVysOjyk=
github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI= github.com/twitchyliquid64/golang-asm v0.15.1 h1:SU5vSMR7hnwNxj24w34ZyCi/FmDZTkS4MhqMhdFk5YI=
github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08= github.com/twitchyliquid64/golang-asm v0.15.1/go.mod h1:a1lVb/DtPvCB8fslRZhAngC2+aY1QWCk3Cedj/Gdt08=
github.com/ugorji/go v1.1.7/go.mod h1:kZn38zHttfInRq0xu/PH0az30d+z6vm202qpg1oXVMw=
github.com/ugorji/go v1.2.7/go.mod h1:nF9osbDWLy6bDVv/Rtoh6QgnvNDpmCalQV5urGCCS6M=
github.com/ugorji/go/codec v1.1.7/go.mod h1:Ax+UKWsSmolVDwsd+7N3ZtXu+yMGCf907BLYF3GoBXY=
github.com/ugorji/go/codec v1.2.7/go.mod h1:WGN1fab3R1fzQlVQTkfxVtIBhWDRqOviHU95kRgeqEY=
github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU= github.com/ugorji/go/codec v1.2.9 h1:rmenucSohSTiyL09Y+l2OCk+FrMxGMzho2+tjr5ticU=
github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg= github.com/ugorji/go/codec v1.2.9/go.mod h1:UNopzCgEMSXjBc6AOMqYvWC1ktqTAfzJZUZgYf6w6lg=
github.com/xdg-go/pbkdf2 v1.0.0 h1:Su7DPu48wXMwC3bs7MCNG+z4FhcyEuz5dlvchbq0B0c=
github.com/xdg-go/pbkdf2 v1.0.0/go.mod h1:jrpuAogTd400dnrH08LKmI/xc1MbPOebTwRqcT5RDeI=
github.com/xdg-go/scram v1.1.1 h1:VOMT+81stJgXW3CpHyqHN3AXDYIMsx56mEFrB37Mb/E=
github.com/xdg-go/scram v1.1.1/go.mod h1:RaEWvsqvNKKvBPvcKeFjrG2cJqOkHTiyTpzz23ni57g=
github.com/xdg-go/stringprep v1.0.3 h1:kdwGpVNwPFtjs98xCGkHjQtGKh86rDcRZN17QEMCOIs=
github.com/xdg-go/stringprep v1.0.3/go.mod h1:W3f5j4i+9rC0kuIEJL0ky1VpHXQU3ocBgklLGvcBnW8=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d h1:splanxYIlg+5LfHAM6xpdFEAYOk8iySO56hMFq6uLyA=
github.com/youmark/pkcs8 v0.0.0-20181117223130-1be2e3e5546d/go.mod h1:rHwXgn7JulP+udvsHwJoVG1YGAP6VLg4y9I5dyZdqmA=
go.mongodb.org/mongo-driver v1.11.6 h1:XM7G6PjiGAO5betLF13BIa5TlLUUE3uJ/2Ox3Lz1K+o=
go.mongodb.org/mongo-driver v1.11.6/go.mod h1:G9TgswdsWjX4tmDA5zfs2+6AEPpYJwqblyjsfuh8oXY=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU=
golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8=
golang.org/x/crypto v0.0.0-20210711020723-a769d52b0f97/go.mod h1:GvvjBRRGRdwPK5ydBHafDWAxML/pGHZbMvKqRZ5+Abc=
golang.org/x/crypto v0.0.0-20220622213112-05595931fe9d/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4=
golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE= golang.org/x/crypto v0.5.0 h1:U/0M97KRkSFvyD/3FSmdP5W5swImpNgle/EHFhOsQPE=
golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU= golang.org/x/crypto v0.5.0/go.mod h1:NK/OQwhpMQP3MwtdjgLlYHnH9ebylxKWv3e0fK+mkQU=
golang.org/x/net v0.7.0 h1:rJrUqqhjsgNp7KqAIc25s9pZnjU7TUcSY7HcVZjdn1g= golang.org/x/net v0.0.0-20210226172049-e18ecbb05110/go.mod h1:m0MpNAwzfU5UDzcl9v0D8zg8gWTRqZa9RBIspLL5mdg=
golang.org/x/net v0.7.0/go.mod h1:2Tu9+aMcznHK/AK1HMvgo6xiTLG5rD5rZLDS+rp2Bjs= golang.org/x/net v0.0.0-20211112202133-69e39bad7dc2/go.mod h1:9nx3DQGgdP8bBQD5qxJ1jj9UTztislL4KSBs9R2vV5Y=
golang.org/x/net v0.10.0 h1:X2//UzNDwYmtCLn7To6G58Wr6f5ahEAQgKNzv9Y951M=
golang.org/x/net v0.10.0/go.mod h1:0qNGK6F8kojg2nk9dLZ2mShWaEBan6FAoqfSigmmuDg=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ=
golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
golang.org/x/sys v0.0.0-20200116001909-b77594299b42/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20201119102817-f84b799fce68/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210423082822-04245dca01da/go.mod h1:h1NjWce9XRLGQEsW7wpKNCjG9DtNlClVuFLEZdDNbEs=
golang.org/x/sys v0.0.0-20210615035016-665e8c7367d1/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210630005230-0f9fa26af87c/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20210806184541-e5e7981a1069/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.0.0-20220811171246-fbc7d0a398ab/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/sys v0.5.0 h1:MUK/U/4lj1t1oPg0HfuXDN/Z1wv31ZJ/YcPiGccS4DU= golang.org/x/sys v0.8.0 h1:EBmGv8NaZBZTWvrbjNoL6HVt+IVy3QDQpJs7VRIw3tU=
golang.org/x/sys v0.5.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/sys v0.8.0/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg=
golang.org/x/text v0.7.0 h1:4BRB4x83lYWy72KwLD/qYDuTu7q9PjSagHvijDw7cLo= golang.org/x/term v0.0.0-20201126162022-7de9c90e9dd1/go.mod h1:bj7SfCRtBDWHUb9snDiAeCFNEtKQo2Wmx5Cou7ajbmo=
golang.org/x/text v0.7.0/go.mod h1:mrYo+phRRbMaCq/xk9113O4dZlRixOauAjOtrjsXDZ8= golang.org/x/text v0.3.2/go.mod h1:bEr9sfX3Q8Zfm5fL9x+3itogRgK3+ptLWKqgva+5dAk=
golang.org/x/text v0.3.3/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.6/go.mod h1:5Zoc/QRtKVWzQhOtBMvqHzDpF6irO9z98xDceosuGiQ=
golang.org/x/text v0.3.7/go.mod h1:u+2+/6zg+i71rQMx5EYifcz6MCKuco9NR6JIITiCfzQ=
golang.org/x/text v0.9.0 h1:2sjJmO8cDvYveuX97RDLsxlyUxLl+GHoLxBiRdHllBE=
golang.org/x/text v0.9.0/go.mod h1:e1OnstbJyHTd6l/uOt8jFFHp6TRDWZR/bV3emEE/zU8=
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543 h1:E7g+9GITq07hpfrRu66IVDexMakfv52eLZ2CXBWiKr4=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw= google.golang.org/protobuf v1.26.0-rc.1/go.mod h1:jlhhOSvTdKEhbULTjvd4ARK9grFBp09yW+WbY/TyQbw=
google.golang.org/protobuf v1.28.0/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w= google.golang.org/protobuf v1.28.1 h1:d0NfwRgPtno5B1Wa6L2DAG+KivqkdutMf1UhdNx175w=
google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I= google.golang.org/protobuf v1.28.1/go.mod h1:HV8QOd/L58Z+nl8r43ehVNZIU/HEI6OcFqwMG9pJV4I=
gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0= gopkg.in/check.v1 v0.0.0-20161208181325-20d25e280405/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20180628173108-788fd7840127/go.mod h1:Co6ibVJAznAaIkqp8huTwlJQCZ016jof/cbN4VW5Yz0=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c h1:Hei/4ADfdWqJk1ZMxUNpqntNwaWcugrBjAiHlqqRiVk=
gopkg.in/check.v1 v1.0.0-20201130134442-10cb98267c6c/go.mod h1:JHkPIbrfpd72SG/EVd6muEfDQjcINNoR0C8j2r3qZ4Q=
gopkg.in/errgo.v2 v2.1.0/go.mod h1:hNsd1EY+bozCKY1Ytp96fpM3vjJbqLJn88ws8XvfDNI=
gopkg.in/yaml.v2 v2.2.2/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.2.8/go.mod h1:hI93XBmqTisBFMUTm0b8Fm+jr3Dg1NNxqwp+5A1VGuI=
gopkg.in/yaml.v2 v2.4.0/go.mod h1:RDklbk79AGWmwhnvt/jBztapEOGDOx6ZbXqjP6csGnQ=
gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.0-20200313102051-9f266ea9e77c/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.0-20210107192922-496545a6307b/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA= gopkg.in/yaml.v3 v3.0.1 h1:fxVm/GzAzEWqLHuvctI91KS9hhNmmWOoWu0XTYJS7CA=
gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM= gopkg.in/yaml.v3 v3.0.1/go.mod h1:K4uyk7z7BCEPqu6E+C64Yfv1cQ7kz7rIZviUmN+EgEM=
rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4= rsc.io/pdf v0.1.1/go.mod h1:n8OzWcQ6Sp37PL01nO98y4iUCRdTGarVfzxY20ICaU4=

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 6.4 KiB

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

Binary file not shown.

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

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

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

Binary file not shown.

64
libs/cat.go Normal file
View File

@ -0,0 +1,64 @@
package libs
import (
"errors"
"net/http"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
//TODO Use this to get json from back
type Cat struct {
fs *webfilesystem.WebFileSystem
}
func NewCatLib(webfs *webfilesystem.WebFileSystem) *Cat {
return &Cat{
fs: webfs,
}
}
func (c *Cat) Get(filePath string) (string, error) {
file, err := c.fs.Read(filePath, nil)
if err != nil {
return "", err
}
if file.Type != "plaintext" {
return "", errors.New("todo")
}
fileData := webfilesystem.PlainTextFileData{}
_, err = c.fs.Read(filePath, &fileData)
if err != nil {
return "", err
}
return fileData.Data, nil
}
func (c *Cat) PublicRoutes(route *gin.RouterGroup) {
route.GET("get", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.String(http.StatusBadRequest, "TODO") //TODO json error struct
return
}
data, err := c.Get(path)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
mode := ctx.Query("mode")
switch mode {
case "json":
ctx.JSON(http.StatusOK, data)
default:
ctx.String(http.StatusOK, "plaintext", data)
}
})
}

79
libs/imglib.go Normal file
View File

@ -0,0 +1,79 @@
package libs
import (
"net/http"
"path"
"personalwebsite/webfilesystem"
"github.com/gin-gonic/gin"
)
type ImagLib struct {
fs *webfilesystem.WebFileSystem
}
func NewImgLib(webfs *webfilesystem.WebFileSystem) *ImagLib {
return &ImagLib{
fs: webfs,
}
}
func (l *ImagLib) PublicRoutes(route *gin.RouterGroup) {
route.GET("get", func(ctx *gin.Context) {
path := ctx.Query("path")
if path == "" {
ctx.String(http.StatusBadRequest, "TODO") //TODO json error struct
return
}
imgData := Img{}
_, err := l.fs.Read(path, &imgData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.Data(http.StatusOK, "image/jpeg", imgData.Bin)
})
iconGroup := route.Group("icon")
iconGroup.GET("get", func(ctx *gin.Context) {
iconPath := ctx.Query("path")
iconType := ctx.Query("type")
_ = iconType
iconSize := ctx.Query("size")
imgData := Img{}
_, err := l.fs.Read(path.Join(iconPath, "color", iconSize+".png"), &imgData)
if err != nil {
ctx.Status(http.StatusInternalServerError)
return
}
ctx.Data(http.StatusOK, "image/jpeg", imgData.Bin)
})
}
func GetBase64Image(img *Base64Img, min string) (string, error) {
imgString := ""
switch min {
case "min32":
imgString = "data:" + img.Header + ", " + img.Base64Miniature32
default:
imgString = "data:" + img.Header + ", " + img.Base64
}
return imgString, nil
}
type Base64Img struct {
Header string `bson:"header"`
Base64 string `bson:"base64"`
Base64Miniature32 string `bson:"base64min32"`
}
type Img struct {
Header string `bson:"header"`
Bin []byte `bson:"bin"`
// BinMin32 []byte `bson:"binmin32"`
}

17
libs/libs.go Normal file
View File

@ -0,0 +1,17 @@
package libs
import (
"personalwebsite/webfilesystem"
)
type Libs struct {
Imglib *ImagLib
Cat *Cat
}
func NewLibs(webfs *webfilesystem.WebFileSystem) Libs {
return Libs{
Imglib: NewImgLib(webfs),
Cat: NewCatLib(webfs),
}
}

31
libs/markdown.go Normal file
View File

@ -0,0 +1,31 @@
package libs
import (
"html/template"
"strings"
"github.com/microcosm-cc/bluemonday"
"github.com/russross/blackfriday/v2"
)
type MarkdownLib struct {
}
func (ml *MarkdownLib) Render(md []byte, supressParagraph bool) template.HTML {
output := blackfriday.Run(md)
if supressParagraph {
output = []byte(strings.ReplaceAll(string(output), "<p>", ""))
output = []byte(strings.ReplaceAll(string(output), "</p>", ""))
}
_ = output
html := bluemonday.UGCPolicy().SanitizeBytes(output)
// println(string(html))
kek := template.HTML(html)
return kek
}
// func (ml MarkdownLib) MarkDowner(args ...interface{}) template.HTML {
// s := blackfriday.MarkdownCommon([]byte(fmt.Sprintf("%s", args...)))
// return template.HTML(s)
// }

195
main.go
View File

@ -1,139 +1,100 @@
package main package main
import ( import (
"context"
"errors"
"log" "log"
"net/http" "os"
"personalwebsite/routewde"
"personalwebsite/websiteapp"
"personalwebsite/websiteapp/finder"
imgviewer "personalwebsite/websiteapp/img-viewer"
"personalwebsite/websiteapp/personalprops"
"github.com/gin-gonic/gin" "personalwebsite/apps"
blogwriter "personalwebsite/apps/BlogWriter"
"personalwebsite/apps/aboutme"
"personalwebsite/apps/blogviewer"
"personalwebsite/apps/finder"
imgviewer "personalwebsite/apps/img-viewer"
"personalwebsite/apps/sunboard"
"personalwebsite/routes"
"personalwebsite/wde"
"personalwebsite/webfilesystem"
"github.com/joho/godotenv"
"go.mongodb.org/mongo-driver/mongo"
"go.mongodb.org/mongo-driver/mongo/options"
) )
// func main() {
// router := gin.Default()
// router.LoadHTMLGlob("templates/**/*")
// router.GET("/posts/index", func(c *gin.Context) {
// c.HTML(http.StatusOK, "posts/index.tmpl", gin.H{
// "title": "Posts",
// })
// })
// router.GET("/users/index", func(c *gin.Context) {
// c.HTML(http.StatusOK, "users/index.tmpl", gin.H{
// "title": "Users",
// })
// })
// router.Run(":8080")
// }
func main() { func main() {
router := gin.New() if err := godotenv.Load(); err != nil {
println("No .env file found")
router.LoadHTMLGlob("templates/**/*")
router.Static("/res", "resources")
router.GET("/", func(ctx *gin.Context) {
ctx.HTML(http.StatusOK, "index.tmpl", gin.H{})
})
persPropsApp := personalprops.NewPersPropsApp()
finderApp := finder.FinerApplication{}
imgViewerApp := imgviewer.NewImgViewerApp()
appsStorage := websiteapp.ApplicationsStorage{
Apps: map[string]websiteapp.WebDEApplication{},
}
appsStorage.Apps["personal-properties"] = &persPropsApp
appsStorage.Apps["finder"] = &finderApp
appsStorage.Apps["img-viewer"] = &imgViewerApp
system := router.Group("system")
{
wde := system.Group("wde")
{
routewde.Route(wde)
}
apps := system.Group("applications")
{
apps.GET("/:appid/:method", func(ctx *gin.Context) {
appId := ctx.Param("appid")
method := ctx.Param("method")
app, isExist := appsStorage.Apps[appId]
if !isExist {
ctx.Status(http.StatusNoContent)
return
}
switch method {
case "getmanifest":
ctx.JSON(http.StatusOK, app.GetManifest())
case "app.js":
ctx.File("resources/sys/" + appId + "/" + appId + ".js")
case "app.css":
ctx.File("resources/sys/" + appId + "/" + appId + ".css")
default:
ctx.Status(http.StatusBadRequest)
}
})
} }
websiteapp.Route(apps.Group("/storage"), &appsStorage) mongoConnect, err := FindEnv("MONGO_CONNECT")
if err != nil {
panic(err.Error())
} }
app := router.Group("application") dBName, err := FindEnv("DATABASE")
{ if err != nil {
persPropApp := app.Group("personal-properties") panic(err.Error())
{
persPropApp.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
if isMobile {
ctx.HTML(http.StatusOK, "personal-properties/mobile-app.tmpl", persPropsApp.Render())
} else {
ctx.HTML(http.StatusOK, "personal-properties/app.tmpl", persPropsApp.Render())
}
})
}
finderAppRoute := app.Group("finder")
{
finderAppRoute.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
if isMobile {
ctx.HTML(http.StatusOK, "finder/mobile-app.tmpl", finderApp.Render(isMobile))
} else {
ctx.HTML(http.StatusOK, "finder/app.tmpl", finderApp.Render(isMobile))
} }
}) webFsCollection, err := FindEnv("COLLECTION_WEBFS")
finderAppRoute.GET("renderMobileDesktop", func(ctx *gin.Context) { if err != nil {
ctx.HTML(http.StatusOK, "finder/mobile-desktop.tmpl", gin.H{}) panic(err.Error())
})
}
imgViewerRoute := app.Group("img-viewer")
{
imgViewerRoute.GET("render", func(ctx *gin.Context) {
isMobileParam := ctx.Query("isMobile")
isMobile := isMobileParam == "true"
if isMobile {
ctx.HTML(http.StatusOK, "img-viewer/mobile-app.tmpl", imgViewerApp.Render(isMobile))
} else {
ctx.HTML(http.StatusOK, "img-viewer/app.tmpl", imgViewerApp.Render(isMobile))
} }
}) publicPort, err := FindEnv("PUBLIC_PORT")
if err != nil {
panic(err.Error())
} }
}
router.GET("/test", func(ctx *gin.Context) {
ctx.HTML(200, "kek/kek.tmpl", gin.H{})
})
if err := router.Run(":8080"); err != nil { privatePort, err := FindEnv("PRIVATE_PORT")
log.Panicf("error: %s", err) if err != nil {
panic(err.Error())
} }
clientOptions := options.Client().ApplyURI(mongoConnect)
client, err := mongo.Connect(context.TODO(), clientOptions)
if err != nil {
log.Fatal(err)
}
err = client.Ping(context.TODO(), nil)
if err != nil {
log.Fatal(err)
}
webfs := webfilesystem.NewWebFileSystem(client, dBName, webFsCollection)
appsStorage := apps.NewApplicationsStorage(map[string]apps.WebDEApplication{}, webfs)
webde := wde.NewWDE(webfs)
//TODO Split to different apps init for private and public?
persPropsApp := aboutme.NewAboutMeApp(webfs)
finderApp := finder.NewFinderApplication(webfs)
imgViewerApp := imgviewer.NewImgViewerApp(webfs)
blogViewerApp := blogviewer.NewBlogViewerApp(webfs)
blogWriterApp := blogwriter.NewBlogWriterApp(webfs)
sunBoardApp := sunboard.NewSunboardApp(webfs, webde, appsStorage)
appsStorage.Apps["personal-properties"] = persPropsApp
appsStorage.Apps["finder"] = finderApp
appsStorage.Apps["img-viewer"] = imgViewerApp
appsStorage.Apps[blogViewerApp.GetAppID()] = blogViewerApp
appsStorage.Apps["BlogWriter"] = blogWriterApp
appsStorage.Apps["Sunboard"] = sunBoardApp
go routes.PublicRoutes(publicPort, webfs, webde, appsStorage)
routes.PrivateRoutes(privatePort, webfs, webde, appsStorage)
} }
func index(c *gin.Context) { // TODO to for loop with aal vars in slice
c.HTML(http.StatusOK, "base.html", nil) func FindEnv(parameter string) (string, error) {
path, exists := os.LookupEnv(parameter)
if exists {
println("[ENV] Requsted " + parameter + " = " + path) //FIXME Only in Debug log
return path, nil
} else {
panic("[ENV] Requsted " + parameter + " not found")
return "", errors.New("env parameter not found")
}
} }

View File

@ -13,7 +13,7 @@
<div id="WindowsLayer"></div> <div id="WindowsLayer"></div>
<div id="Applications"></div> <div id="Applications"></div>
<!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" > <!-- <div id="TestWindow" style="width: 100px; height: 100px; background-color: darkkhaki; position: absolute;" >
<div id="TestWindowHeader" class="WindowDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;"> <div id="TestWindowHeader" class="VisualDragArea" style="width: 100%;height: 15px; background-color: cornflowerblue;">
</div> --> </div> -->
</body> </body>
</html> </html>

View File

@ -3,11 +3,11 @@
<div id="WindowBorder" class="Frame"> <div id="WindowBorder" class="Frame">
<div id="TestWindowHeader" class="WindowFrameTopBar"> <div id="TestWindowHeader" class="WindowFrameTopBar">
<button class="WindowFrameTopBarButton"></button> <button class="WindowFrameTopBarButton"></button>
<div id="Drag" class="WindowDragArea"></div> <div id="Drag" class="VisualDragArea"></div>
<div class="WindowFrameTitle"> <div class="Lable">
Test Title Test Title
</div> </div>
<div id="Drag" class="WindowDragArea"></div> <div id="Drag" class="VisualDragArea"></div>
<button class="WindowFrameTopBarButton" ></button> <button class="WindowFrameTopBarButton" ></button>
</div> </div>
<div id="ContentFrame" class="ContentFrame"> <div id="ContentFrame" class="ContentFrame">

View File

@ -0,0 +1,37 @@
class AboutMe{
static appID = "AboutMe"
/**
* @param {HTMLElement} appElem
*/
constructor(appElem){
this.appElem = appElem
}
/**
* @param {[]string} args
* @param {Object} runContext
*/
async NewWindow(args, runContext){
const params = new URLSearchParams({
path: `:/aboutme.props`,
})
const response = await fetch(`/app/${AboutMe.appID}/render?`+ params,{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
WebDesktopEnvironment.Alert("Error TODO") //TODO
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 360, document.body.clientHeight*0.8 )
newWindow.innerHTML = html
newWindow.style.height = 'auto'
newWindow.querySelector("#closeWindowButton").addEventListener('click', () => {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}

View File

@ -1,10 +1,30 @@
.ScrollContent { /* TODO Move this to body? */
/*.ScrollContent {
width: 100%; width: 100%;
height: 100%; height: 100%;
overflow: scroll; overflow: scroll;
overflow-x: hidden; overflow-x: hidden;
scrollbar-width: none; /* Firefox */ /* Firefox */
-ms-overflow-style: none; /* Internet Explorer 10+ */ /* 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 */ /* Auto layout */
display: flex; display: flex;
@ -14,11 +34,11 @@
padding: 0px; padding: 0px;
} }
.ScrollContent::-webkit-scrollbar { /* WebKit */ .PersPropsContent .PropsView{
width: 0; /* background-color: rebeccapurple; */
height: 0; width: 100%;
height: auto;
} }
.PropertiesList{ .PropertiesList{
/* width: 100%; /* width: 100%;
height: auto; */ height: auto; */
@ -37,7 +57,7 @@
} }
.Personal-properties-bio{ .PropertiesList .ShortBio{
/* width: 100%; /* width: 100%;
height: auto; */ height: auto; */
/* margin-right: -20px; */ /* margin-right: -20px; */
@ -57,9 +77,13 @@
gap:15px; gap:15px;
} }
.ShortBio .Image{
width: 48px;
height: 48px;
padding-left: 10px;
}
.ShortBio .Text{
.Personal-properties-textbio{
/* width: 100%; /* width: 100%;
height: auto; */ height: auto; */
@ -77,8 +101,35 @@
gap:1px; gap:1px;
} }
.ShortBio .Name{
font-family: "Virtue";
/* FIXME */
letter-spacing: 0.35px;
}
.Personal-properties-prop{ .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%; width: 100%;
height: auto; height: auto;
border: 1px solid #888888; border: 1px solid #888888;
@ -93,11 +144,9 @@
gap:1px; */ gap:1px; */
} }
.Island .Title {
.Personal-properties-prop-title{
font-family: "Virtue"; font-family: "Virtue";
/* FIXME */
letter-spacing: 0.35px; letter-spacing: 0.35px;
position:relative; position:relative;
display: inline-block; display: inline-block;
@ -107,7 +156,11 @@
top: -9px; top: -9px;
} }
.Personal-properties-prop-content{ .Focused .Island .Title{
background-color: #CCCCCC;
}
.Island .Content{
width: 100%; width: 100%;
/* top: 0px; */ /* top: 0px; */
/* Auto layout */ /* Auto layout */
@ -118,7 +171,7 @@
gap: 12px; gap: 12px;
} }
.Personal-properties-prop-row{ .Island .Row{
margin-left: 12px; margin-left: 12px;
margin-right: 12px; margin-right: 12px;
/* Auto layout */ /* Auto layout */
@ -128,7 +181,7 @@
padding: 0px; padding: 0px;
gap: 5px; gap: 5px;
} }
.Personal-properties-prop-key{ .Island .Key{
position: relative; position: relative;
font-family: "Virtue"; font-family: "Virtue";
font-size: 11px; font-size: 11px;
@ -141,7 +194,7 @@
/* font-weight: bold; */ /* font-weight: bold; */
} }
.Personal-properties-prop-key-comments{ .Island .KeyComment{
/* color: rgb(129, 129, 129); TODO*/ /* color: rgb(129, 129, 129); TODO*/
color: #646464; color: #646464;
font-size: 9px; font-size: 9px;
@ -150,7 +203,8 @@
white-space:normal; white-space:normal;
/* filter: drop-shadow(-.5px -.5px 0px #616161); */ /* filter: drop-shadow(-.5px -.5px 0px #616161); */
} }
.Personal-properties-prop-values{
.Island .Values{
width: 55%; width: 55%;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
@ -160,7 +214,7 @@
} }
.Personal-properties-prop-value{ .Values .Value{
/* width: 55%; */ /* width: 55%; */
} }

View File

@ -0,0 +1,51 @@
class BlogViewer{
static appID = "BlogViewer"
/**
* @param {string[]} args
* @param {Object} runContext
*/
async NewWindow(args, runContext){
const params = new URLSearchParams({
path: args[0],
})
runContext.runPath = args[0]
const response = await fetch(`app/${BlogViewer.appID}/render?` + params, {
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
WebDesktopEnvironment.Alert("Error render TODO") //TODO
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 500, 350 )
newWindow.innerHTML = html
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".ScrollContent"))
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
/**
* @param {MouseEvent} event
* @param {string} path
*/
static Click(event, path){
let fileType = event.target.getAttribute("fileType")
switch (fileType) {
case "app":
//TODO get real id
WebDesktopEnvironment.Open("personal-properties", [])
break;
case "img":
WebDesktopEnvironment.Open("img-viewer", ["pizda"])
break;
default:
console.log("Unsupported file type")
break;
}
}
}

View File

@ -0,0 +1,85 @@
.BlogView{
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: row;
align-items: flex-start;
justify-content: flex-start;
/* gap: 50px; */
/* row-gap: 20px; */
/* padding: 0px 20px 0px 20px; */
background-color: #FFFFFF;
}
.BlogView .Content {
overflow: scroll;
width: 100%;
height: 100%;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
/* gap: 50px; */
/* row-gap: 20px; */
/* padding: 0px 20px 0px 20px; */
/* margin: 0px 20px 0px 20px; */
}
.BlogView .ScrollContent {
position: relative;
width: 92%;
left: 4%;
right: 4%;
height: auto;
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 10px;
/* row-gap: 20px; */
/* padding: 0px 20px 0px 20px; */
/* margin: 0px 20px 0px 20px; */
/* padding-left: 20px; */
}
.BlogView .header-h1{
font-size:x-large;
padding-bottom: 10px;
}
.BlogView .header-h2{
font-size:large;
padding-bottom: 6px;
}
.BlogView .header-h3{
font-size:larger;
padding-bottom: 2px;
}
.BlogView .image{
width: 100%;
}
.image .ImageProp{
position: relative;
width: 100%;
height: auto;
/* left: 50%;
margin-left: -50%; */
}
.BlogView .plain-text{
/* Auto layout */
display: flex;
flex-direction: column;
align-items: flex-start;
justify-content: flex-start;
gap: 5px;
/* row-gap: 20px; */
}

View File

@ -0,0 +1,10 @@
class BlogWriter{
static AppId = "BlogWriter"
/**
* @param {string[]} args
*/
async NewWindow(args){
console.log("kek")
}
}

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,317 @@
class Finder{
static AppId = "Finder"
/**
* @param {string[]} args
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
await newFinder.Init(args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
static async RenderProperites(path){
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 = WebDesktopEnvironment.CreateNewWindow(Finder.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}
class FinderWindow{
curPath = ""
fileView = undefined
windowElem = undefined
async Init(args, appContext){
if (args[1] == "--desktop"){
let desktopNode = document.body.querySelector(`#${args[2]}`)
if (desktopNode == null){
WebDesktopEnvironment.Alert("Desktop node not found")
return
}
const params = new URLSearchParams({
path: args[0]
})
const response = await fetch(`/app/${Finder.AppId}/renderDesktop?` + params,
{
method: "POST",
body: JSON.stringify(appContext)
})
if (response.status != 200){
console.log(response.status)
WebDesktopEnvironment.Alert("Error in render desktop") //TODO
return
}
const html = await response.text()
desktopNode.innerHTML = html
this.fileView = new 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: WebDesktopEnvironment.isMobile})
const response = await fetch(`/app/${Finder.AppId}/render?` + params,
{
method: "POST",
body: JSON.stringify(appContext)
})
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(Finder.AppId, 500, 350 )
newWindow.innerHTML = html
this.fileView = new 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', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.RenderDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.RenderDir('/home/user')
})
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.RenderDir(args[0])
}
/**
* @param {string} path
*/
RenderDir(path){
this.curPath = path
this.fileView.OpenFolder(path)
}
ReRenderDir(){
this.RenderDir(this.curPath)
}
/**
* @param {DragEvent} event
* @param {HTMLElement} draggedElem
*/
async DropEvent(event){
// console.log(event.dataTransfer.getData("dropType"))
if (event.dataTransfer.getData("dropType") == "move"){
const sourcePath= event.dataTransfer.getData("filePath")
const targetPath = this.curPath + "/" + event.dataTransfer.getData("fileName")
const res = await WebFS.MoveFile(sourcePath, targetPath)
if (res){
this.ReRenderDir()
} else {
WebDesktopEnvironment.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()
}
}
return
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){
WebDesktopEnvironment.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":
WebDesktopEnvironment.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":
WebDesktopEnvironment.Open(`${parentPath}/${fileName}`, [])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open(`/Applications/BlogViewer.app`, [`${parentPath}/${fileName}`])
break
case fileType == "directory":
WebDesktopEnvironment.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
WebDesktopEnvironment.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
WebDesktopEnvironment.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/${Finder.AppId}/contextMenu?` + params)
if (response.status != 200){
WebDesktopEnvironment.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":
WebDesktopEnvironment.Open(`/Applications/${Finder.AppId}.app`,[`${this.curPath}/${fileName}`])
break
default:
break;
}
}
overlay.remove()
})
overlay.addEventListener('contextmenu', (event) => {
event.preventDefault();
overlay.remove()
})
}
}

View File

@ -0,0 +1,305 @@
class FinderAdmin{
static AppId = "FinderAdmin"
/**
* @param {string[]} args
*/
async NewWindow(args, runContext){
let newFinder = new FinderWindow()
await newFinder.Init(args, runContext)
}
/**
* @param {string} path
* @returns {boolean}
*/
static async RenderProperites(path){
if (path == null || path ==""){
return
}
const params = new URLSearchParams({
path: path
})
const response = await fetch(`/app/Finder/renderProps?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in properties render") //TODO
return false
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(FinderAdmin.AppId, 350, 500 )
newWindow.innerHTML = html
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
}
}
class FinderWindow{
curPath = ""
fileView = undefined
windowElem = undefined
addressBar = undefined
async Init(args, runContext){
if (args[1] === "-desktop"){
//todo pass div id, not div in args[]
const params = new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile,
path: args[0]
})
const response = await fetch(`/app/Finder/renderDesktop?` + params)
if (response.status != 200){
WebDesktopEnvironment.Alert("Error in render desktop") //TODO
}
const html = await response.text()
args[2].innerHTML = html
this.fileView = new FileView(
args[2].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: WebDesktopEnvironment.isMobile})
const response = await fetch(`/app/Finder/render?` + params,{
method: "POST",
body: JSON.stringify(runContext)
})
if (response.status != 200){
const error = await response.json()
WebDesktopEnvironment.Alert(error.message)
return
}
const html = await response.text()
let newWindow = WebDesktopEnvironment.CreateNewWindow(FinderAdmin.AppId, 500, 350 )
newWindow.innerHTML = html
this.fileView = new 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', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow)
})
newWindow.querySelector("#RootButton").addEventListener('click', () =>{
this.RenderDir('/')
})
newWindow.querySelector("#HomeButton").addEventListener('click', () =>{
this.RenderDir('/home/user')
})
let scrollBar = new WdeScrollBar(newWindow.querySelector(".ScrollbarPlace"), newWindow.querySelector(".FileTileView"))
this.windowElem = newWindow
this.addressBar = newWindow.querySelector(".AddressBar")
this.RenderDir(args[0])
}
/**
* @param {string} path
*/
RenderDir(path){
console.log(path)
this.curPath = path
this.addressBar.innerHTML = 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 {
WebDesktopEnvironment.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()
}
}
return
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){
WebDesktopEnvironment.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":
WebDesktopEnvironment.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":
WebDesktopEnvironment.Open(`${parentPath}/${fileName}`, [])
break
case fileType == "directory":
WebDesktopEnvironment.Open(`/Applications/Finder.app`, [`${parentPath}/${fileName}`])
break
case fileExtension == "blog":
WebDesktopEnvironment.Open("/Applications/BlogViewer.app", [`${parentPath}/${fileName}`])
break
case fileExtension == "jpeg" | fileExtension == "png":
WebDesktopEnvironment.Open("img-viewer", [`${parentPath}/${fileName}`])
break;
default:
WebDesktopEnvironment.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/Finder/contextMenu?` + params)
if (response.status != 200){
WebDesktopEnvironment.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":
WebDesktopEnvironment.Open(`/Applications/Finder.app`,[`${this.curPath}/${fileName}`])
break
default:
break;
}
}
overlay.remove()
})
overlay.addEventListener('contextmenu', (event) => {
event.preventDefault();
overlay.remove()
})
}
}

View File

@ -0,0 +1,53 @@
.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;
/* Auto layout */
display: flex;
flex-direction: row;
justify-content:left;
align-items: flex-start;
padding: 0px;
gap: 5px;
}
.ToolBar .AddressBar{
width:100%;
height: 100%;
background-color: white;
}
.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

@ -5,12 +5,13 @@
.Img-Viewer-Picture{ .Img-Viewer-Picture{
width: 100%; width: 100%;
height: 100%; height: 100%;
background-image: url("./test-image.jpg"); /* background-image: url("./test-image.jpg");
background-size: contain; background-size: contain;
background-repeat: no-repeat; background-repeat: no-repeat;
background-position: center center; background-position: center center; */
} }
.Img-Viewer-Picture-Toolbar{ .Img-Viewer-Picture-Toolbar{
width: 100%; width: 100%;
height: 35px; height: 35px;

View File

@ -1,23 +1,23 @@
class ImgViewer{ class ImgViewer{
appId = "img-viewer" appId = "img-viewer"
/** /**
* @param {string} path * @param {string[]} args
*/ */
NewWindow(path){ NewWindow(args){
fetch(`${window.location.origin}/application/${this.appId}/render?`+ new URLSearchParams({ fetch(`${window.location.origin}/application/${this.appId}/render?`+ new URLSearchParams({
isMobile: WebDesktopEnvironment.isMobile, isMobile: WebDesktopEnvironment.isMobile,
path: args[0]
})) }))
.then((response) => response.text()) .then((response) => response.text())
.then((html) => { .then((html) => {
let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 450,400 ) let newWindow = WebDesktopEnvironment.CreateNewWindow(this.appId, 450,400 )
newWindow.innerHTML = html newWindow.innerHTML = html
let closeButton = newWindow.children[0].children[0] if (!WebDesktopEnvironment.isMobile){
newWindow.querySelector("#closeWindowButton").addEventListener('click', function (params) {
closeButton.addEventListener('click', function (params) {
WebDesktopEnvironment.CloseWindow(newWindow) WebDesktopEnvironment.CloseWindow(newWindow)
}) })
}
}) })
.catch((error) => { .catch((error) => {
WebDesktopEnvironment.Alert(error); WebDesktopEnvironment.Alert(error);
@ -25,7 +25,3 @@ class ImgViewer{
} }
} }
class test{
}

0
res/dev-fs/libs/fs.js Normal file
View File

73
res/dev-fs/wde/base.css Normal file
View File

@ -0,0 +1,73 @@
@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: #9999CC;
}

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;
}

54
res/dev-fs/wde/decorat.js Normal file
View File

@ -0,0 +1,54 @@
class WindowsCompositor{
static windowsLayer
constructor(){
this.windowLayer = document.body.querySelector('#windows-layer')
WindowsCompositor.windowsLayer = document.body.querySelector('#windows-layer')
if (!WebDesktopEnvironment.isMobile) {
let startDrag = function(event) {
let window = event.target.closest('.WindowFrame')
WindowsCompositor.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)
}
}
WindowsCompositor.windowsLayer.addEventListener('mousedown', startDrag)
}
}
/**
* @param {HTMLElement} window
*/
static bringWindowToFront(window){ //FIXME
let previousWindow = WindowsCompositor.windowsLayer.lastChild
if (window == null || window == undefined){
return
}
if (window != previousWindow){
WindowsCompositor.windowsLayer.insertBefore(window, previousWindow.nextSibling)
previousWindow.classList.remove("Focused")
window.classList.add("Focused")
} else {
window.classList.add("Focused")
}
return
}
static ChangeURL(appWindow){
let appId = appWindow.getAttribute('appid')
window.history.replaceState(null, "", `/${appId}/`);
}
}

View File

Some files were not shown because too many files have changed in this diff Show More