diff --git a/README.md b/README.md index 28559fd..5a1c43d 100644 --- a/README.md +++ b/README.md @@ -4,16 +4,16 @@ The ssg currently requires the following directory structure ```text ssg/ -|--content/ -| |--index.md (This file is necessary and cannot be omitted) -| |--about.md +|--content/ +| |--index.md (This file is necessary and cannot be omitted) +| |--about.md | |--posts/ | |--post1.md -| .... +| .... | -|--layout/ +|--layout/ | |--page.html (This file is necessary and cannot be omitted) -| |--posts.html (This file is necessary to create a 'Posts' section) +| |--posts.html (This file is necessary to create a 'Posts' section) | |--partials/ | |--header.html | .... @@ -45,20 +45,22 @@ ssg/ - Static assets such as images and fonts are stored in static/ - The layout of the site is configured using html files in layout/ - - The 'config.yml' file stores the configuration of the site and includes details such as the baseURL - - The 'page.html' file defines the layout of a basic page of the site - - The 'posts.html' file defines the layout of a page displaying all the posts of the site - - The layout files can be composed of smaller html files which are stored in the partials/ folder + - The 'config.yml' file stores the configuration of the site and includes details such as the baseURL + - The 'page.html' file defines the layout of a basic page of the site + - The 'posts.html' file defines the layout of a page displaying all the posts of the site + - The layout files can be composed of smaller html files which are stored in the partials/ folder #### Layout The layout files can access the following rendered data from the markdown files: - {{.Body}} : Returns the markdown body rendered to HTML +- {{.Filename}} : Returns the name of the current file +- {{.Date}} : Returns the last modified date of the current file - {{.Frontmatter.[Tagname]}} : Returns the value of the frontmatter tag - - Example: {{.Frontmatter.Title}} : Returns the value of the title tag + - Example: {{.Frontmatter.Title}} : Returns the value of the title tag - {{.Layout.[Tagname]}}: Returns the particular configuration detail of the page - - Example: {{.Layout.Navbar}} : Returns a string slice with the names of all the navbar elements + - Example: {{.Layout.Navbar}} : Returns a string slice with the names of all the navbar elements ## Notes @@ -67,9 +69,11 @@ The layout files can access the following rendered data from the markdown files: 2. CSS: CSS can be added in the following ways: - In an external file in the 'static/' directory and linked to the layout files - - To link the stylesheet, use the baseURL along with the relative path - Example: `` + - To link the stylesheet, use the baseURL along with the relative path + + Example: `` + - Placed inside `` tags in the `
` of the layout files - Inline with the html elements @@ -77,11 +81,23 @@ The layout files can access the following rendered data from the markdown files: - title : The title of the current page - date: The date of the current page +- draft: When set to 'true', the current page is not rendered unless the '-d' flag is used +- type: Sets the type of the page. Use type 'post' for posts +- previewimage: Stores the preview image of the current page +- description: Stores the description of the current post previewed in posts.html +- scripts: Stores a slice of javascript files to be included with the current page only + +(**The above tags are Frontmatter tags**) -4. config.yml: This file stores additional information regarding the layout +4. config.yml: This file stores additional information regarding the layout of the site - navbar: Stores the links to be added to the navbar (same name as the markdown files) - baseURL: Stores the base URL of the site +- siteTitle: Stores the name of the site +- siteScripts: Stores the javascript files to be included with every page. The following scripts are currently available: + - prism.js : Provides syntax highlighting for code blocks + +(**The above tags are Layout tags**) Sample config.yml: @@ -93,13 +109,17 @@ navbar: baseURL: http://localhost:8000/ # Replace this with the actual canonical-url of your site. -# baseURL tells search-engines (SEO), web-crawlers (robots.txt) so people can discover your site on the internet. -# It's also embeded in your sitemap / atom feed and can be used to change metadata about your site. +# baseURL tells search-engines (SEO), web-crawlers (robots.txt) so people can discover your site on the internet. +# It's also embeded in your sitemap / atom feed and can be used to change metadata about your site. + +siteTitle: ssg +siteScripts: + - prism.js ``` ## Flags -``` +```text Usage: ssg [flags] diff --git a/cmd/ssg/main.go b/cmd/ssg/main.go index 205f0e2..24edc7e 100644 --- a/cmd/ssg/main.go +++ b/cmd/ssg/main.go @@ -2,23 +2,20 @@ package ssg import ( "bytes" - "fmt" "html/template" "log" "os" "sort" "strings" - "time" - "github.com/yuin/goldmark" - "gopkg.in/yaml.v3" + "github.com/acmpesuecc/ssg/pkg/helpers" ) type LayoutConfig struct { - Navbar []string `yaml:"navbar"` - BaseURL string `yaml:"baseURL"` - SiteTitle string `yaml:"siteTitle"` - SitePlugs []string `yaml:"plugins"` // example : "light.js" + Navbar []string `yaml:"navbar"` + BaseURL string `yaml:"baseURL"` + SiteTitle string `yaml:"siteTitle"` + SiteScripts []string `yaml:"siteScripts"` } type Frontmatter struct { @@ -31,127 +28,85 @@ type Frontmatter struct { PreviewImage string `yaml:"previewimage"` } -type Page struct { - Filename string - Date int64 - Frontmatter Frontmatter - Body template.HTML - Layout LayoutConfig - Posts []string -} +type Date int64 type Generator struct { + // Templates stores the template data of all the pages of the site + // Access the data for a particular page by using the relative path to the file as the key + Templates map[template.URL]TemplateData + Posts []TemplateData + LayoutConfig LayoutConfig + ErrorLogger *log.Logger mdFilesName []string mdFilesPath []string - mdParsed []Page - LayoutConfig LayoutConfig - MdPosts []Page - Draft bool + RenderDrafts bool } -func getFileNames(page []Page) []string { - var filenames []string - for _, p := range page { - filenames = append(filenames, p.Filename) - } - return filenames +// This struct holds all of the data required to render any page of the site +// Pass this struct without modification to ExecuteTemplate() +type TemplateData struct { + Filename string + Date int64 + Frontmatter Frontmatter + Body template.HTML + Layout LayoutConfig } -func (g *Generator) dateParse(date string) time.Time { - parsedTime, err := time.Parse("2006-01-02", date) - if err != nil { - g.ErrorLogger.Fatal(err) - } - return parsedTime +// This struct holds the data required to render posts.html +type postsTemplateData struct { + Posts []TemplateData + TemplateData } -// Write rendered HTML to disk func (g *Generator) RenderSite(addr string) { // Creating the "rendered" directory if not present err := os.RemoveAll("rendered/") if err != nil { g.ErrorLogger.Fatal(err) } - err = os.RemoveAll("rendered/") - if err != nil { - g.ErrorLogger.Fatal(err) - } + err = os.MkdirAll("rendered/", 0750) if err != nil { g.ErrorLogger.Fatal(err) } + g.Posts = []TemplateData{} g.parseConfig() - g.MdPosts = []Page{} g.readMdDir("content/") g.parseRobots() g.generateSitemap() g.generateFeed() - g.copyStaticContent() - g.copyScriptContent() - templ := g.parseLayoutFiles() - - // Writing each parsed markdown file as a separate HTML file - for i, page := range g.mdParsed { - - // Adding the names of all the files in posts/ dir to the page data - g.mdParsed[i].Posts = getFileNames(g.MdPosts) - page.Posts = getFileNames(g.MdPosts) - - filename, _ := strings.CutPrefix(g.mdFilesPath[i], "content/") - // Creating subdirectories if the filepath contains '/' - if strings.Contains(filename, "/") { - // Extracting the directory path from the filepath - dirPath, _ := strings.CutSuffix(filename, g.mdFilesName[i]) - dirPath = "rendered/" + dirPath + sort.Slice(g.Posts, func(i, j int) bool { + return g.Posts[i].Frontmatter.Date > g.Posts[j].Frontmatter.Date + }) - err := os.MkdirAll(dirPath, 0750) - if err != nil { - g.ErrorLogger.Fatal(err) - } - } + helper := helpers.Helper{ + ErrorLogger: g.ErrorLogger, + } - filename, _ = strings.CutSuffix(filename, ".md") - filepath := "rendered/" + filename + ".html" - var buffer bytes.Buffer + // Copies the contents of the 'static/' directory to 'rendered/' + helper.CopyDirectoryContents("static/", "rendered/static/") + helper.CopyDirectoryContents("script/", "rendered/script/") - // Storing the rendered HTML file to a buffer - err = templ.ExecuteTemplate(&buffer, "page", page) - if err != nil { - g.ErrorLogger.Fatal(err) - } + template := helper.ParseLayoutFiles() - // Flushing data from the buffer to the disk - err := os.WriteFile(filepath, buffer.Bytes(), 0666) - if err != nil { - g.ErrorLogger.Fatal(err) - } + for pagePath, templateData := range g.Templates { + g.RenderPage(pagePath, templateData, template) } var buffer bytes.Buffer - // Rendering the 'posts.html' separately - out := g.MdPosts - - sort.Slice(out, func(i, j int) bool { - return out[i].Date > out[j].Date - }) - - fmt.Printf("%v\n", getFileNames(out)) - type TemplateData struct { - Generator *Generator - Frontmatter Frontmatter - Layout LayoutConfig - } - data := TemplateData{ - Generator: g, - Frontmatter: Frontmatter{Title: "Posts"}, - Layout: g.LayoutConfig, + postsData := postsTemplateData{ + Posts: g.Posts, + TemplateData: TemplateData{ + Frontmatter: Frontmatter{Title: "Posts"}, + Layout: g.LayoutConfig, + }, } - err = templ.ExecuteTemplate(&buffer, "posts", data) + err = template.ExecuteTemplate(&buffer, "posts", postsData) if err != nil { g.ErrorLogger.Fatal(err) } @@ -163,161 +118,33 @@ func (g *Generator) RenderSite(addr string) { } } -func (g *Generator) parseRobots() { - tmpl, err := template.ParseFiles("layout/robots.txt") - if err != nil { - g.ErrorLogger.Fatal(err) - } - var buffer bytes.Buffer - err = tmpl.Execute(&buffer, g.LayoutConfig) - if err != nil { - g.ErrorLogger.Fatal(err) - } - outputFile, err := os.Create("rendered/robots.txt") - if err != nil { - g.ErrorLogger.Fatal(err) - } - defer outputFile.Close() - _, err = outputFile.Write(buffer.Bytes()) - if err != nil { - g.ErrorLogger.Fatal(err) - } -} - -func (g *Generator) generateSitemap() { - var buffer bytes.Buffer - buffer.WriteString("\n") - buffer.WriteString("