diff --git a/sui/core/block.go b/sui/core/block.go new file mode 100644 index 00000000..58d1d039 --- /dev/null +++ b/sui/core/block.go @@ -0,0 +1,23 @@ +package core + +import ( + "fmt" + "strings" +) + +// Compile compile the block +func (block *Block) Compile() (string, error) { + + if block.Codes.JS.Code == "" { + return "", fmt.Errorf("Block %s has no JS code", block.ID) + } + + js := strings.Replace(block.Codes.JS.Code, "export default", fmt.Sprintf("window.block__%s =", block.ID), 1) + if block.Codes.HTML.Code != "" && !strings.Contains(block.Codes.JS.Code, "content:") { + html := strings.ReplaceAll(block.Codes.HTML.Code, "`", "\\`") + js = strings.Replace(js, "{", fmt.Sprintf("{\n content: `%s`,", html), 1) + } + + block.Compiled = js + return js, nil +} diff --git a/sui/core/interfaces.go b/sui/core/interfaces.go index c6325890..81c2c188 100644 --- a/sui/core/interfaces.go +++ b/sui/core/interfaces.go @@ -36,12 +36,12 @@ type IPage interface { // IBlock is the interface for the block type IBlock interface { - Get() error - Save() error + Compile() (string, error) + Load() error } // IComponent is the interface for the component type IComponent interface { - Get() error - Save() error + Compile() (string, error) + Load() error } diff --git a/sui/core/types.go b/sui/core/types.go index ca22b1a3..b5993cc6 100644 --- a/sui/core/types.go +++ b/sui/core/types.go @@ -7,21 +7,20 @@ type SUI interface { UploadTemplate(src string, dst string) (ITemplate, error) } -// Page is the struct for the page -type Page struct { - Route string `json:"route"` - Root string `json:"root"` - Files PageFiles `json:"files"` +// DSL the struct for the DSL +type DSL struct { + ID string `json:"-"` + Name string `json:"name,omitempty"` + Storage *Storage `json:"storage,omitempty"` + Public *Public `json:"public,omitempty"` } -// PageFiles is the struct for the page files -type PageFiles struct { - HTML string `json:"html"` - CSS string `json:"css"` - JS string `json:"js"` - TS string `json:"ts"` - LESS string `json:"less"` - DATA string `json:"data"` +// Page is the struct for the page +type Page struct { + Route string `json:"route"` + Name string `json:"name,omitempty"` + Root string `json:"-"` + Codes SourceCodes `json:"-"` } // Component is the struct for the component @@ -32,8 +31,10 @@ type Component struct { // Block is the struct for the block type Block struct { - template *Template - name string + ID string `json:"id"` + Name string `json:"name,omitempty"` + Compiled string `json:"-"` + Codes SourceCodes `json:"-"` } // Template is the struct for the template @@ -45,12 +46,20 @@ type Template struct { Screenshots []string `json:"screenshots"` } -// DSL the struct for the DSL -type DSL struct { - ID string `json:"-"` - Name string `json:"name,omitempty"` - Storage *Storage `json:"storage,omitempty"` - Public *Public `json:"public,omitempty"` +// SourceCodes is the struct for the page codes +type SourceCodes struct { + HTML Source `json:"-"` + CSS Source `json:"-"` + JS Source `json:"-"` + TS Source `json:"-"` + LESS Source `json:"-"` + DATA Source `json:"-"` +} + +// Source is the struct for the source +type Source struct { + File string `json:"-"` + Code string `json:"-"` } // Public is the struct for the static diff --git a/sui/storages/local/block.go b/sui/storages/local/block.go index 83c89d57..5e287041 100644 --- a/sui/storages/local/block.go +++ b/sui/storages/local/block.go @@ -1,16 +1,28 @@ package local -// NewBlock create a new local block -func NewBlock(file string) (*Block, error) { - return nil, nil -} +import ( + "path/filepath" +) + +// Load get the block from the storage +func (block *Block) Load() error { + + root := filepath.Join(block.tmpl.Root, "__blocks") + jsFile := filepath.Join(root, block.Codes.JS.File) + jsCode, err := block.tmpl.local.fs.ReadFile(jsFile) + if err != nil { + return err + } + block.Codes.JS.Code = string(jsCode) + + htmlFile := filepath.Join(root, block.Codes.HTML.File) + if exist, _ := block.tmpl.local.fs.Exists(htmlFile); exist { + htmlCode, err := block.tmpl.local.fs.ReadFile(htmlFile) + if err != nil { + return err + } + block.Codes.HTML.Code = string(htmlCode) + } -// Get get the block -func (block *Block) Get() error { - return nil -} - -// Save save the block -func (block *Block) Save() error { return nil } diff --git a/sui/storages/local/local.go b/sui/storages/local/local.go index 30083e49..591de96d 100644 --- a/sui/storages/local/local.go +++ b/sui/storages/local/local.go @@ -101,6 +101,10 @@ func (local *Local) getTemplateFrom(path string) (*Template, error) { // getTemplate get the template func (local *Local) getTemplate(id string, path string) (*Template, error) { + if !local.fs.IsDir(path) { + return nil, fmt.Errorf("Template %s not found", id) + } + tmpl := Template{ local: local, Root: path, diff --git a/sui/storages/local/page.go b/sui/storages/local/page.go index deea95c7..0c5772a6 100644 --- a/sui/storages/local/page.go +++ b/sui/storages/local/page.go @@ -1,10 +1,5 @@ package local -// NewPage create a new local page -func NewPage(file string) (*Page, error) { - return nil, nil -} - // Get get the page func (page *Page) Get() error { return nil diff --git a/sui/storages/local/template.go b/sui/storages/local/template.go index 25d52643..e8f56b4b 100644 --- a/sui/storages/local/template.go +++ b/sui/storages/local/template.go @@ -75,13 +75,13 @@ func (tmpl *Template) getPage(route, file string) (core.IPage, error) { Page: &core.Page{ Route: route, Root: root, - Files: core.PageFiles{ - HTML: fmt.Sprintf("%s%s", route, filepath.Ext(file)), - CSS: fmt.Sprintf("%s.css", route), - JS: fmt.Sprintf("%s.js", route), - DATA: fmt.Sprintf("%s.json", route), - TS: fmt.Sprintf("%s.ts", route), - LESS: fmt.Sprintf("%s.less", route), + Codes: core.SourceCodes{ + HTML: core.Source{File: fmt.Sprintf("%s%s", route, filepath.Ext(file))}, + CSS: core.Source{File: fmt.Sprintf("%s.css", route)}, + JS: core.Source{File: fmt.Sprintf("%s.js", route)}, + DATA: core.Source{File: fmt.Sprintf("%s.json", route)}, + TS: core.Source{File: fmt.Sprintf("%s.ts", route)}, + LESS: core.Source{File: fmt.Sprintf("%s.less", route)}, }, }, }, nil @@ -93,7 +93,90 @@ func (tmpl *Template) getPageRoute(path string) string { // Blocks get the blocks func (tmpl *Template) Blocks() ([]core.IBlock, error) { - return nil, nil + path := filepath.Join(tmpl.Root, "__blocks") + + blocks := []core.IBlock{} + if exist, _ := tmpl.local.fs.Exists(path); !exist { + return blocks, nil + } + + dirs, err := tmpl.local.fs.ReadDir(path, false) + if err != nil { + return nil, err + } + + for _, dir := range dirs { + if !tmpl.local.fs.IsDir(dir) { + continue + } + + block, err := tmpl.getBlockFrom(dir) + if err != nil { + log.Error("Get block error: %v", err) + continue + } + + blocks = append(blocks, block) + } + + return blocks, nil +} + +// Block get the block +func (tmpl *Template) Block(id string) (core.IBlock, error) { + path := filepath.Join(tmpl.Root, "__blocks", id) + if exist, _ := tmpl.local.fs.Exists(path); !exist { + return nil, fmt.Errorf("Block %s not found", id) + } + + block, err := tmpl.getBlockFrom(path) + if err != nil { + return nil, err + } + + err = block.Load() + if err != nil { + return nil, err + } + + _, err = block.Compile() + if err != nil { + return nil, err + } + + return block, nil +} + +func (tmpl *Template) getBlockFrom(path string) (core.IBlock, error) { + id := tmpl.getBlockID(path) + return tmpl.getBlock(id) +} + +func (tmpl *Template) getBlock(id string) (core.IBlock, error) { + + path := filepath.Join(tmpl.Root, "__blocks", id) + if !tmpl.local.fs.IsDir(path) { + return nil, fmt.Errorf("Block %s not found", id) + } + + jsFile := filepath.Join("/", id, "main.js") + htmlFile := filepath.Join("/", id, "main.html") + block := &Block{ + tmpl: tmpl, + Block: &core.Block{ + ID: id, + Codes: core.SourceCodes{ + HTML: core.Source{File: htmlFile}, + JS: core.Source{File: jsFile}, + }, + }, + } + + return block, nil +} + +func (tmpl *Template) getBlockID(path string) string { + return filepath.Base(path) } // Components get the components @@ -101,11 +184,6 @@ func (tmpl *Template) Components() ([]core.IComponent, error) { return nil, nil } -// Block get the block -func (tmpl *Template) Block(name string) (core.IBlock, error) { - return nil, nil -} - // Component get the component func (tmpl *Template) Component(name string) (core.IComponent, error) { return nil, nil diff --git a/sui/storages/local/template_test.go b/sui/storages/local/template_test.go index 4db652d2..39fb0429 100644 --- a/sui/storages/local/template_test.go +++ b/sui/storages/local/template_test.go @@ -26,15 +26,16 @@ func TestTemplatePages(t *testing.T) { assert.Equal(t, "/index", pages[0].(*Page).Route) assert.Equal(t, "/templates/website-ai", pages[0].(*Page).Root) - assert.Equal(t, "/index.css", pages[0].(*Page).Files.CSS) - assert.Equal(t, "/index.html", pages[0].(*Page).Files.HTML) - assert.Equal(t, "/index.js", pages[0].(*Page).Files.JS) - assert.Equal(t, "/index.less", pages[0].(*Page).Files.LESS) - assert.Equal(t, "/index.ts", pages[0].(*Page).Files.TS) - assert.Equal(t, "/index.json", pages[0].(*Page).Files.DATA) + assert.Equal(t, "/index.css", pages[0].(*Page).Codes.CSS.File) + assert.Equal(t, "/index.html", pages[0].(*Page).Codes.HTML.File) + assert.Equal(t, "/index.js", pages[0].(*Page).Codes.JS.File) + assert.Equal(t, "/index.less", pages[0].(*Page).Codes.LESS.File) + assert.Equal(t, "/index.ts", pages[0].(*Page).Codes.TS.File) + assert.Equal(t, "/index.json", pages[0].(*Page).Codes.DATA.File) } func TestTemplatePage(t *testing.T) { + tests := prepare(t) defer clean() @@ -49,13 +50,65 @@ func TestTemplatePage(t *testing.T) { } assert.Equal(t, "/index", page.(*Page).Route) assert.Equal(t, "/templates/website-ai", page.(*Page).Root) - assert.Equal(t, "/index.css", page.(*Page).Files.CSS) - assert.Equal(t, "/index.html", page.(*Page).Files.HTML) - assert.Equal(t, "/index.js", page.(*Page).Files.JS) - assert.Equal(t, "/index.less", page.(*Page).Files.LESS) - assert.Equal(t, "/index.ts", page.(*Page).Files.TS) - assert.Equal(t, "/index.json", page.(*Page).Files.DATA) + assert.Equal(t, "/index.css", page.(*Page).Codes.CSS.File) + assert.Equal(t, "/index.html", page.(*Page).Codes.HTML.File) + assert.Equal(t, "/index.js", page.(*Page).Codes.JS.File) + assert.Equal(t, "/index.less", page.(*Page).Codes.LESS.File) + assert.Equal(t, "/index.ts", page.(*Page).Codes.TS.File) + assert.Equal(t, "/index.json", page.(*Page).Codes.DATA.File) _, err = tmpl.Page("/the/page/could/not/be/found") assert.Contains(t, err.Error(), "Page /the/page/could/not/be/found not found") } + +func TestTemplateBlocks(t *testing.T) { + tests := prepare(t) + defer clean() + + tmpl, err := tests.Demo.GetTemplate("tech-blue") + if err != nil { + t.Fatalf("GetTemplate error: %v", err) + } + + blocks, err := tmpl.Blocks() + if err != nil { + t.Fatalf("Blocks error: %v", err) + } + + if len(blocks) < 3 { + t.Fatalf("Blocks error: %v", len(blocks)) + } + + assert.Equal(t, "columns-two", blocks[0].(*Block).ID) + assert.Equal(t, "/columns-two/main.html", blocks[0].(*Block).Codes.HTML.File) + assert.Equal(t, "/columns-two/main.js", blocks[0].(*Block).Codes.JS.File) + + assert.Equal(t, "hero", blocks[1].(*Block).ID) + assert.Equal(t, "/hero/main.html", blocks[1].(*Block).Codes.HTML.File) + assert.Equal(t, "/hero/main.js", blocks[1].(*Block).Codes.JS.File) + + assert.Equal(t, "section", blocks[2].(*Block).ID) + assert.Equal(t, "/section/main.html", blocks[2].(*Block).Codes.HTML.File) + assert.Equal(t, "/section/main.js", blocks[2].(*Block).Codes.JS.File) +} + +func TestTemplateBlock(t *testing.T) { + tests := prepare(t) + defer clean() + + tmpl, err := tests.Demo.GetTemplate("tech-blue") + if err != nil { + t.Fatalf("GetTemplate error: %v", err) + } + + block, err := tmpl.Block("columns-two") + if err != nil { + t.Fatalf("Blocks error: %v", err) + } + + assert.Equal(t, "columns-two", block.(*Block).ID) + assert.NotEmpty(t, block.(*Block).Codes.HTML.Code) + assert.NotEmpty(t, block.(*Block).Codes.JS.Code) + assert.Contains(t, block.(*Block).Compiled, "window.block__columns-two") + assert.Contains(t, block.(*Block).Compiled, `