Skip to content

Commit

Permalink
Implement tag index (aka tag cloud) page generation
Browse files Browse the repository at this point in the history
  • Loading branch information
kion committed Nov 13, 2024
1 parent 4daeef6 commit 743dd89
Show file tree
Hide file tree
Showing 12 changed files with 190 additions and 55 deletions.
12 changes: 11 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -245,10 +245,20 @@ or can even be completely omitted from the config):
- `generate` command generates an archive index page,
as well as pages with posts for all the relevant year/month combinations
(retrieved from the `date` property of each corresponding post content `.md` file) -
the generated index page lists all the year/month combinations with links to the corresponding content pages
the generated index page lists all the year/month combinations (along with the corresponding post counts)
with links to the corresponding content pages
- the generated archive index page is available under `/archive/` URI, e.g.:
- `<a href="/archive/">Archive</a>`
- set this setting to `no` to disable archive generation
* [optional] `generateTagIndex` - the tag index generation is enabled by default,
unless this setting is set to `no`
- `generate` command generates a tag index page
(note, that the pages with posts for each tag are generated always, even if tag index is not) -
the generated tag index page lists all the tags (along with the corresponding post counts)
with links to the corresponding content pages
- the generated archive index page is available under `/tags/` URI, e.g.:
- `<a href="/tags/">Tags</a>`
- set this setting to `no` to disable archive generation
* [optional] `enableSearch` - the built-in search functionality is enabled by default,
unless this setting is set to `no`
* `generate` command generates:
Expand Down
10 changes: 10 additions & 0 deletions commands.go
Original file line number Diff line number Diff line change
Expand Up @@ -181,11 +181,13 @@ func _cleanup(config appConfig, commandArgs ...string) {
cleanupContent := false
cleanupThumbs := false
cleanupArchive := false
cleanupTagIndex := false
cleanupSearch := false
if commandArgs == nil || len(commandArgs) == 0 {
cleanupContent = true
cleanupThumbs = !config.useThumbs
cleanupArchive = !config.generateArchive
cleanupTagIndex = !config.generateTagIndex
cleanupSearch = !config.enableSearch
} else {
target := commandArgs[0]
Expand All @@ -196,6 +198,8 @@ func _cleanup(config appConfig, commandArgs ...string) {
cleanupThumbs = true
case commandCleanupTargetArchive:
cleanupArchive = true
case commandCleanupTargetTagIndex:
cleanupTagIndex = true
case commandCleanupTargetSearch:
cleanupSearch = true
default:
Expand Down Expand Up @@ -257,6 +261,12 @@ func _cleanup(config appConfig, commandArgs ...string) {
sprintln(" - deleted archive dir: " + deployArchivePath)
}
}
if cleanupTagIndex {
deployTagIndexPath := fmt.Sprintf("%s%c%s%c%s", deployDirName, os.PathSeparator, deployTagsDirName, os.PathSeparator, indexPageFileName)
if deleteIfExists(deployTagIndexPath) {
sprintln(" - deleted tag index file: " + deployTagIndexPath)
}
}
if cleanupSearch {
deploySearchIndexPath := fmt.Sprintf("%s%c%s", deployDirName, os.PathSeparator, searchIndexFileName)
if deleteIfExists(deploySearchIndexPath) {
Expand Down
44 changes: 33 additions & 11 deletions config.go
Original file line number Diff line number Diff line change
Expand Up @@ -12,17 +12,18 @@ import (

func defaultConfig() appConfig {
return appConfig{
siteName: "",
theme: "",
homePage: "",
generateArchive: defaultGenerateArchive,
enableSearch: defaultEnableSearch,
pageSize: defaultPageSize,
useThumbs: defaultUseThumbs,
thumbSizes: defaultThumbSizes,
thumbThreshold: defaultThumbThreshold,
serveHost: defaultServeHost,
servePort: defaultServePort,
siteName: "",
theme: "",
homePage: "",
generateArchive: defaultGenerateArchive,
generateTagIndex: defaultGenerateTagIndex,
enableSearch: defaultEnableSearch,
pageSize: defaultPageSize,
useThumbs: defaultUseThumbs,
thumbSizes: defaultThumbSizes,
thumbThreshold: defaultThumbThreshold,
serveHost: defaultServeHost,
servePort: defaultServePort,
}
}

Expand Down Expand Up @@ -54,6 +55,12 @@ func readConfig() appConfig {
config.generateArchive = v != "no" && v != "false"
}

generateTagIndex := cm["generateTagIndex"]
if generateTagIndex != "" {
v := strings.ToLower(generateTagIndex)
config.generateTagIndex = v != "no" && v != "false"
}

enableSearch := cm["enableSearch"]
if enableSearch != "" {
v := strings.ToLower(enableSearch)
Expand Down Expand Up @@ -178,6 +185,21 @@ func writeConfig(config appConfig) {
yml += "no"
}

yml += "\n"
var generateTagIndex bool
if defaultGenerateTagIndex == config.generateTagIndex {
generateTagIndex = defaultGenerateTagIndex
yml += "#generateTagIndex: "
} else {
generateTagIndex = config.generateTagIndex
yml += "generateTagIndex: "
}
if generateTagIndex {
yml += "yes"
} else {
yml += "no"
}

yml += "\n"
var enableSearch bool
if defaultEnableSearch == config.enableSearch {
Expand Down
9 changes: 6 additions & 3 deletions const.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@ import (
)

const (
appVersion = "1.2.4"
appVersion = "1.2.5"
defaultGitHubRepoUrl = "github.com/kion/mbgen"
defaultGitHubRepoThemesUrl = defaultGitHubRepoUrl + "/themes"
defaultGitHubRepoPageContentSamplesUrl = defaultGitHubRepoUrl + "/content-samples/pages"
Expand All @@ -22,6 +22,7 @@ const (
postTemplateFileName = "post" + templateFileExtension
mediaTemplateFileName = "media" + templateFileExtension
archiveTemplateFileName = "archive" + templateFileExtension
tagIndexTemplateFileName = "tag-index" + templateFileExtension
searchTemplateFileName = "search" + templateFileExtension
pagerTemplateFileName = "pager" + templateFileExtension
contentDirectiveTemplateFileNameFormat = "content-%s" + templateFileExtension
Expand All @@ -30,7 +31,7 @@ const (
searchPageFileName = "search" + contentFileExtension
searchIndexFileName = "search.json"
directivePlaceholderReplacementFormat = ":@@@:%s:@@@:"
hashTagMarkdownReplacementFormat = "[#%s](/" + deployTagDirName + "/%s/)"
hashTagMarkdownReplacementFormat = "[#%s](/" + deployTagsDirName + "/%s/)"
stylesFileName = "styles.css"
stylesIncludeFileNameFormat = "styles-include-%s.css"
markdownPagesDirName = "pages"
Expand All @@ -42,13 +43,14 @@ const (
deployPostsDirName = "posts"
deployPageDirName = "page"
deployArchiveDirName = "archive"
deployTagDirName = "tag"
deployTagsDirName = "tags"
metaDataKeyDate = "date"
metaDataKeyTime = "time"
metaDataKeyTitle = "title"
metaDataKeyTags = "tags"
configFileName = "config.yml"
defaultGenerateArchive = true
defaultGenerateTagIndex = true
defaultEnableSearch = true
defaultPageSize = 10
minAllowedThumbWidth = 320
Expand All @@ -68,6 +70,7 @@ const (
commandCleanupTargetContent = "content"
commandCleanupTargetThumbs = "thumbs"
commandCleanupTargetArchive = "archive"
commandCleanupTargetTagIndex = "tag-index"
commandCleanupTargetSearch = "search"
commandServeOptionWatchReload = "--watch-reload"
commandThemeActionActivate = "activate"
Expand Down
40 changes: 39 additions & 1 deletion processor.go
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import (
"fmt"
"os"
"slices"
"sort"
"strconv"
"strings"
"text/template"
Expand Down Expand Up @@ -131,6 +132,7 @@ func processPosts(posts []post, searchIndex *mapSlice,
archiveContent := make(map[string][]string)

tagPostCnt := make(map[string]int)
tagTitleCnt := make(map[string]int)
tagContent := make(map[string][]string)

for _, post := range posts {
Expand Down Expand Up @@ -226,6 +228,7 @@ func processPosts(posts []post, searchIndex *mapSlice,

if len(post.Tags) > 0 {
for _, tag := range post.Tags {
tagTitleCnt[tag]++
t := strings.ToLower(tag)
tagPostCnt[t]++
tagContent[t] = append(tagContent[t], postContent)
Expand Down Expand Up @@ -269,8 +272,43 @@ func processPosts(posts []post, searchIndex *mapSlice,

tagPostCntLen := len(tagPostCnt)
if tagPostCntLen > 0 {
if config.generateTagIndex {
minTagPostCnt := -1
maxTagPostCnt := 0
for _, v := range tagPostCnt {
if minTagPostCnt == -1 || v < minTagPostCnt {
minTagPostCnt = v
}
if v > maxTagPostCnt {
maxTagPostCnt = v
}
}
// ======================================================================
// sort the tags by post count
// ======================================================================
var sortedTags []tagData
for tt, tc := range tagTitleCnt {
tr := float64(tc-minTagPostCnt) / float64(maxTagPostCnt-minTagPostCnt)
tr = float64(int(tr*100))/100 + 1
sortedTags = append(sortedTags, tagData{Title: tt, Count: tc, Ratio: tr})
}
sort.Slice(sortedTags, func(i, j int) bool {
return sortedTags[i].Count > sortedTags[j].Count
})
// ======================================================================
sprintln(" - generating tag index ...")
tagIndexTemplate := compileTagIndexTemplate(resLoader)
outputFilePath := fmt.Sprintf("%s%c%s%c%s", deployDirName, os.PathSeparator, deployTagsDirName, os.PathSeparator, indexPageFileName)
var tagIndexContentBuffer bytes.Buffer
err := tagIndexTemplate.Execute(&tagIndexContentBuffer, templateContent{EntityType: Page, Title: config.siteName + " - Tag Index", Content: sortedTags})
check(err)
if handleOutput != nil {
handleOutput(outputFilePath, tagIndexContentBuffer.Bytes())
}
}
sprintln(" - generating tag pages ...")
tagCnt = tagPostCntLen
processPaginatedPostContent(tagPostCnt, tagContent, pageSize, deployTagDirName, pagerTemplate, resLoader, handleOutput)
processPaginatedPostContent(tagPostCnt, tagContent, pageSize, deployTagsDirName, pagerTemplate, resLoader, handleOutput)
}
}
return len(posts), tagCnt
Expand Down
14 changes: 7 additions & 7 deletions processor_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -106,7 +106,7 @@ func basicTest(t *testing.T, customHomePage bool) {
}

for _, tag := range tags {
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagDirName+"/"+strings.ToLower(tag)+"/"+indexPageFileName)
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagsDirName+"/"+strings.ToLower(tag)+"/"+indexPageFileName)
}

if !customHomePage {
Expand Down Expand Up @@ -233,7 +233,7 @@ func testPagination(t *testing.T, postCnt int) {
}

unexpectedFiles := []string{
deployDirName + "/" + deployTagDirName + "/" + strings.ToLower(tag2) + "/2" + contentFileExtension,
deployDirName + "/" + deployTagsDirName + "/" + strings.ToLower(tag2) + "/2" + contentFileExtension,
}

totalPageCnt := postCnt / defaultPageSize
Expand All @@ -246,14 +246,14 @@ func testPagination(t *testing.T, postCnt int) {
}

for tag, cnt := range tagCnt {
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagDirName+"/"+strings.ToLower(tag)+"/"+indexPageFileName)
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagsDirName+"/"+strings.ToLower(tag)+"/"+indexPageFileName)
if cnt > defaultPageSize {
tagPageCnt := cnt / defaultPageSize
if cnt%defaultPageSize > 0 {
tagPageCnt++
}
for i := 2; i <= tagPageCnt; i++ {
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagDirName+"/"+strings.ToLower(tag)+"/"+strconv.Itoa(i)+contentFileExtension)
expectedFiles = append(expectedFiles, deployDirName+"/"+deployTagsDirName+"/"+strings.ToLower(tag)+"/"+strconv.Itoa(i)+contentFileExtension)
}
}
}
Expand Down Expand Up @@ -289,9 +289,9 @@ func testPagination(t *testing.T, postCnt int) {
for i := 1; i <= cnt; i++ {
var outputFile string
if i == 1 {
outputFile = deployDirName + "/" + deployTagDirName + "/" + strings.ToLower(tag) + "/" + indexPageFileName
outputFile = deployDirName + "/" + deployTagsDirName + "/" + strings.ToLower(tag) + "/" + indexPageFileName
} else {
outputFile = deployDirName + "/" + deployTagDirName + "/" + strings.ToLower(tag) + "/" + strconv.Itoa(i) + contentFileExtension
outputFile = deployDirName + "/" + deployTagsDirName + "/" + strings.ToLower(tag) + "/" + strconv.Itoa(i) + contentFileExtension
}
outputFileContent := output[outputFile]
for j := (i - 1) * defaultPageSize; j < i*defaultPageSize && j < cnt; j++ {
Expand Down Expand Up @@ -396,7 +396,7 @@ func getExpectedPostFileContent(p post) []string {
if len(p.Tags) > 0 {
expectedTagsContent := "<span class=\"tags\">"
for _, tag := range p.Tags {
expectedTagsContent += fmt.Sprintf("<a class=\"tag\" href=\"/tag/%s/\">%s</a>", strings.ToLower(tag), tag)
expectedTagsContent += fmt.Sprintf("<a class=\"tag\" href=\"/tags/%s/\">%s</a>", strings.ToLower(tag), tag)
}
expectedTagsContent += "</span>"
expectedContent = append(expectedContent, expectedTagsContent)
Expand Down
22 changes: 13 additions & 9 deletions tcutil.go
Original file line number Diff line number Diff line change
Expand Up @@ -56,19 +56,23 @@ func compilePageTemplate(p page, resLoader resourceLoader) *template.Template {
}

func compileArchiveTemplate(resLoader resourceLoader) *template.Template {
archiveTemplateMarkup, err := readTemplateFile(archiveTemplateFileName, resLoader)
check(err)
archiveTemplateMarkup = strings.Replace(archiveTemplateMarkup, pageHeadTemplatePlaceholder, "", 1)
archiveTemplate := compileFullTemplate(archiveTemplateFileName, archiveTemplateMarkup, nil, resLoader)
return archiveTemplate
return compileStandalonePageTemplate(archiveTemplateFileName, resLoader)
}

func compileTagIndexTemplate(resLoader resourceLoader) *template.Template {
return compileStandalonePageTemplate(tagIndexTemplateFileName, resLoader)
}

func compileSearchTemplate(resLoader resourceLoader) *template.Template {
searchTemplateMarkup, err := readTemplateFile(searchTemplateFileName, resLoader)
return compileStandalonePageTemplate(searchTemplateFileName, resLoader)
}

func compileStandalonePageTemplate(singlePageTemplateFileName string, resLoader resourceLoader) *template.Template {
singlePageTemplateMarkup, err := readTemplateFile(singlePageTemplateFileName, resLoader)
check(err)
searchTemplateMarkup = strings.Replace(searchTemplateMarkup, pageHeadTemplatePlaceholder, "", 1)
searchTemplate := compileFullTemplate(searchTemplateFileName, searchTemplateMarkup, nil, resLoader)
return searchTemplate
singlePageTemplateMarkup = strings.Replace(singlePageTemplateMarkup, pageHeadTemplatePlaceholder, "", 1)
singlePageTemplate := compileFullTemplate(singlePageTemplateFileName, singlePageTemplateMarkup, nil, resLoader)
return singlePageTemplate
}

func compilePagerTemplate(resLoader resourceLoader) *template.Template {
Expand Down
2 changes: 2 additions & 0 deletions themes/pretty-dark/include/header.html
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
<i class="fa-solid fa-square-check"></i> Sample Page</a></span>
<span class="link"><a href="/archive/">
<i class="fa-solid fa-calendar-days"></i> Archive</a></span>
<span class="link"><a href="/tags/">
<i class="fa-solid fa-tags"></i> Tags</a></span>
<span class="link search"><a href="/search.html">
<i class="fa-solid fa-search"></i> Search</a></span>
</div>
Expand Down
Loading

0 comments on commit 743dd89

Please sign in to comment.