summaryrefslogtreecommitdiff
diff refs
from: back
to: back
| flip
diff options
context:
space:
mode:
-rw-r--r--config/config.go6
-rw-r--r--config/config.local.yaml10
-rw-r--r--config/config.prod.yaml10
-rw-r--r--config/config.stage.yaml10
-rw-r--r--internal/factgiver/factgiver.go67
-rw-r--r--internal/frontmatter/parser.go2
-rw-r--r--internal/router/api-v1-blog-search.go6
-rw-r--r--internal/router/api-v1-general-page-body.go15
-rw-r--r--internal/router/api-v1-general-page-bottom-embeds.go4
-rw-r--r--internal/router/api-v1-general-page-footer.go4
-rw-r--r--internal/router/api-v1-general-page-header.go5
-rw-r--r--internal/router/api-v1-general-page-top-embeds.go4
-rw-r--r--internal/router/api-v1-general-page.go2
-rw-r--r--internal/router/client-cache.go164
-rw-r--r--internal/templatemanager/templatemanager.go19
-rw-r--r--locale/localization.en.yaml13
-rw-r--r--locale/localization.go16
-rw-r--r--locale/localization.ru.yaml13
-rw-r--r--main.go20
-rw-r--r--static/input.css28
-rw-r--r--views/index.html2
-rw-r--r--views/layouts/general-page.html8
-rw-r--r--views/pages/blog-page.html9
-rw-r--r--views/pages/global-map.html2
-rw-r--r--views/pages/home-page.html121
-rw-r--r--views/partials/catalogue-blog-cards.html11
-rw-r--r--views/partials/general-page-header.html6
27 files changed, 79 insertions, 498 deletions
diff --git a/config/config.go b/config/config.go
index f57b5cd..7438fe1 100644
--- a/config/config.go
+++ b/config/config.go
@@ -11,7 +11,6 @@ import (
type Config struct {
LogLevel slog.Level `json:"LogLevel" yaml:"logLevel" validate:"required"`
BlogPages BlogPagesConfig `json:"BlogPages" yaml:"blogPages" validate:"required"`
- FactGiver FactGiverConfig `json:"FactGiver" yaml:"factGiver" validate:"required"`
LocalePath string `json:"LocalePath" yaml:"localePath" validate:"required,filepath"`
AvailableLanguages []AvailableLanguageConfig `json:"AvailableLanguages" yaml:"availableLanguages" validate:"required"`
Auth AuthConfig `json:"Auth" yaml:"auth" validate:"required"`
@@ -34,11 +33,6 @@ type B2Config struct {
ApplicationKey string `json:"ApplicationKey" yaml:"applicationKey"`
}
-type FactGiverConfig struct {
- Storage StorageConfig `json:"Storage" yaml:"storage" validate:"required"`
- FactsFileName string `json:"FactsFileName" yaml:"factsFileName" validate:"required"`
-}
-
type AvailableLanguageConfig struct {
Name string `json:"Name" yaml:"name" validate:"required"`
Alt string `json:"Alt" yaml:"alt"`
diff --git a/config/config.local.yaml b/config/config.local.yaml
index 6d0abf3..0b48e47 100644
--- a/config/config.local.yaml
+++ b/config/config.local.yaml
@@ -8,16 +8,6 @@ blogPages:
prefix: 'stage-'
keyID: '${B2_KEY_ID}'
applicationKey: '${B2_APPLICATION_KEY}'
-factGiver:
- storage:
- type: b2
- config:
- bucketName: sayana-pages
- region: eu-central-003
- prefix: ''
- keyID: '${B2_KEY_ID}'
- applicationKey: '${B2_APPLICATION_KEY}'
- factsFileName: 'facts-*.txt'
localePath: ./locale/
availableLanguages:
- name: ru
diff --git a/config/config.prod.yaml b/config/config.prod.yaml
index 38981a8..e1294c0 100644
--- a/config/config.prod.yaml
+++ b/config/config.prod.yaml
@@ -8,16 +8,6 @@ blogPages:
prefix: 'prod-'
keyID: '${B2_KEY_ID}'
applicationKey: '${B2_APPLICATION_KEY}'
-factGiver:
- storage:
- type: b2
- config:
- bucketName: sayana-pages
- region: eu-central-003
- prefix: ''
- keyID: '${B2_KEY_ID}'
- applicationKey: '${B2_APPLICATION_KEY}'
- factsFileName: 'facts-*.txt'
localePath: ./locale/
availableLanguages:
- name: ru
diff --git a/config/config.stage.yaml b/config/config.stage.yaml
index b05edaf..30233c1 100644
--- a/config/config.stage.yaml
+++ b/config/config.stage.yaml
@@ -8,16 +8,6 @@ blogPages:
prefix: 'stage-'
keyID: '${B2_KEY_ID}'
applicationKey: '${B2_APPLICATION_KEY}'
-factGiver:
- storage:
- type: b2
- config:
- bucketName: sayana-pages
- region: eu-central-003
- prefix: ''
- keyID: '${B2_KEY_ID}'
- applicationKey: '${B2_APPLICATION_KEY}'
- factsFileName: 'facts-*.txt'
localePath: ./locale/
availableLanguages:
- name: ru
diff --git a/internal/factgiver/factgiver.go b/internal/factgiver/factgiver.go
deleted file mode 100644
index 6f77403..0000000
--- a/internal/factgiver/factgiver.go
+++ /dev/null
@@ -1,67 +0,0 @@
-package factgiver
-
-import (
- "fmt"
- "math/rand"
- "regexp"
- "strings"
- "time"
-
- "github.com/SayaAndy/saya-today-web/config"
- "github.com/SayaAndy/saya-today-web/internal/b2"
-)
-
-type FactGiver struct {
- b2Client *b2.B2Client
- cache map[string][]string
- langs []string
- factsFileName string
- nlRe *regexp.Regexp
- randGen *rand.Rand
-}
-
-func NewFactGiver(cfg *config.FactGiverConfig, langs []string) (*FactGiver, error) {
- b2Client, err := b2.NewB2Client(&cfg.Storage.Config)
- if err != nil {
- return nil, fmt.Errorf("fail to init b2 client for a new fact giver: %s", err.Error())
- }
-
- factGiver := &FactGiver{
- b2Client: b2Client,
- cache: make(map[string][]string, len(langs)),
- langs: langs,
- factsFileName: cfg.FactsFileName,
- nlRe: regexp.MustCompile(`\r?\n`),
- randGen: rand.New(rand.NewSource(time.Now().UnixNano())),
- }
- if err = factGiver.initCache(); err != nil {
- return nil, fmt.Errorf("fail to init cache for a new fact giver: %s", err.Error())
- }
-
- return factGiver, nil
-}
-
-func (g *FactGiver) Give(lang string) [3]string {
- factSlice := make([]string, len(g.cache[lang]))
- copy(factSlice, g.cache[lang])
- g.randGen.Shuffle(len(factSlice), func(i, j int) {
- factSlice[i], factSlice[j] = factSlice[j], factSlice[i]
- })
- return [3]string{factSlice[0], factSlice[1], factSlice[2]}
-}
-
-func (g *FactGiver) initCache() error {
- for _, lang := range g.langs {
- localFacts := strings.Replace(g.factsFileName, "*", lang, 1)
- factsContentBytes, err := g.b2Client.ReadAll(localFacts)
- if err != nil {
- return fmt.Errorf("fail to read '%s' facts file: %s", lang, err.Error())
- }
- factsContent := string(factsContentBytes)
- g.cache[lang] = g.nlRe.Split(factsContent, -1)
- if g.cache[lang][len(g.cache[lang])-1] == "" {
- g.cache[lang] = g.cache[lang][:len(g.cache[lang])-1]
- }
- }
- return nil
-}
diff --git a/internal/frontmatter/parser.go b/internal/frontmatter/parser.go
index 83312dc..1a521c0 100644
--- a/internal/frontmatter/parser.go
+++ b/internal/frontmatter/parser.go
@@ -16,8 +16,6 @@ type Metadata struct {
Thumbnail string `yaml:"thumbnail"`
Tags []string `yaml:"tags"`
Geolocation string `yaml:"geolocation"`
- Medley string `yaml:"medley"`
- MedleyPart int `yaml:"medleyPart"`
}
func ParseFrontmatter(content []byte) (metadata *Metadata, markdown []byte, err error) {
diff --git a/internal/router/api-v1-blog-search.go b/internal/router/api-v1-blog-search.go
index 69be651..41f2dec 100644
--- a/internal/router/api-v1-blog-search.go
+++ b/internal/router/api-v1-blog-search.go
@@ -36,9 +36,8 @@ func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []string, b2Clie
slog.Warn("unable to parse a client timezone, defaulting to UTC", slog.String("error", err.Error()), slog.String("tz", tz))
}
- cacheKey := "blog-search." + lang + ".pages-list"
var pages []*b2.BlogPage
- if pagesBytes, ok := PCache.Get(cacheKey); pagesBytes != nil || ok {
+ if pagesBytes, ok := PCache.Get("blog-search.pages-list"); pagesBytes != nil || ok {
json.Unmarshal(pagesBytes, &pages)
} else {
pages, err = b2Client.Scan(lang + "/")
@@ -47,7 +46,7 @@ func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []string, b2Clie
return c.Status(fiber.ErrInternalServerError.Code).SendString(fmt.Sprintf("failed to scan pages for '%s' lang: %v", lang, err))
}
pagesBytes, _ := json.Marshal(pages)
- PCache.SetWithTTL(cacheKey, pagesBytes, int64(len(pagesBytes)), 5*time.Minute)
+ PCache.SetWithTTL("blog-search.pages-list", pagesBytes, int64(len(pagesBytes)), 5*time.Minute)
}
encodedQuery := c.Request().URI().QueryString()
@@ -79,7 +78,6 @@ func Api_V1_BlogSearch(l map[string]*locale.LocaleConfig, langs []string, b2Clie
"Thumbnail": page.Metadata.Thumbnail,
"Tags": page.Metadata.Tags,
"LikeCount": CCache.GetLikeCount(page.FileName),
- "ViewCount": CCache.GetViewCount(page.FileName),
})
break
}
diff --git a/internal/router/api-v1-general-page-body.go b/internal/router/api-v1-general-page-body.go
index b2fa268..cdb558a 100644
--- a/internal/router/api-v1-general-page-body.go
+++ b/internal/router/api-v1-general-page-body.go
@@ -4,7 +4,6 @@ import (
"fmt"
"html/template"
"log/slog"
- "math/rand"
"net/url"
"regexp"
"slices"
@@ -12,14 +11,11 @@ import (
"time"
"github.com/SayaAndy/saya-today-web/internal/b2"
- "github.com/SayaAndy/saya-today-web/internal/factgiver"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/gofiber/fiber/v2"
"github.com/yuin/goldmark"
)
-var FactGiver *factgiver.FactGiver
-
func init() {
tm.Add("general-page-body", "views/partials/general-page-body.html")
}
@@ -46,7 +42,7 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []string,
}
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
@@ -138,15 +134,6 @@ func Api_V1_GeneralPage_Body(l map[string]*locale.LocaleConfig, langs []string,
values["ParsedMarkdown"] = template.HTML(parsedMarkdown)
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
-
- go CCache.View(c.IP(), pathParts[2])
- } else if len(pathParts) == 1 {
- values["Title"] = l[lang].HomePage.Header
- values["FilledHeartCount"] = uint(40)
- values["OutlineHeartCount"] = uint(40)
- values["GifName"] = fmt.Sprintf("otter-%d.gif", rand.Int()%3+1)
- values["FunFacts"] = FactGiver.Give(lang)
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
}
content, err := tm.Render("general-page-body", values, additionalTemplates...)
diff --git a/internal/router/api-v1-general-page-bottom-embeds.go b/internal/router/api-v1-general-page-bottom-embeds.go
index c4d9543..df766a7 100644
--- a/internal/router/api-v1-general-page-bottom-embeds.go
+++ b/internal/router/api-v1-general-page-bottom-embeds.go
@@ -38,7 +38,7 @@ func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []
}
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
@@ -58,8 +58,6 @@ func Api_V1_GeneralPage_BottomEmbeds(l map[string]*locale.LocaleConfig, langs []
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
}
content, err := tm.Render("general-page-bottom-embeds", values, additionalTemplates...)
diff --git a/internal/router/api-v1-general-page-footer.go b/internal/router/api-v1-general-page-footer.go
index 003f54c..98da6bb 100644
--- a/internal/router/api-v1-general-page-footer.go
+++ b/internal/router/api-v1-general-page-footer.go
@@ -38,7 +38,7 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []string
}
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
@@ -58,8 +58,6 @@ func Api_V1_GeneralPage_Footer(l map[string]*locale.LocaleConfig, langs []string
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
}
content, err := tm.Render("general-page-footer", values, additionalTemplates...)
diff --git a/internal/router/api-v1-general-page-header.go b/internal/router/api-v1-general-page-header.go
index 80228f7..1d65966 100644
--- a/internal/router/api-v1-general-page-header.go
+++ b/internal/router/api-v1-general-page-header.go
@@ -39,7 +39,7 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []string
}
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
@@ -67,9 +67,6 @@ func Api_V1_GeneralPage_Header(l map[string]*locale.LocaleConfig, langs []string
values["PublishedDate"] = metadata.PublishedTime.Format("2006-01-02 15:04:05 -07:00")
values["ActionDate"] = metadata.ActionDate
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- values["Title"] = l[lang].HomePage.Header
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
}
content, err := tm.Render("general-page-header", values, additionalTemplates...)
diff --git a/internal/router/api-v1-general-page-top-embeds.go b/internal/router/api-v1-general-page-top-embeds.go
index 78021b2..b26675f 100644
--- a/internal/router/api-v1-general-page-top-embeds.go
+++ b/internal/router/api-v1-general-page-top-embeds.go
@@ -38,7 +38,7 @@ func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []str
}
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("'Referer' header is invalid: expect format '/{lang}/...'")
}
@@ -58,8 +58,6 @@ func Api_V1_GeneralPage_TopEmbeds(l map[string]*locale.LocaleConfig, langs []str
additionalTemplates = append(additionalTemplates, "views/pages/blog-catalogue.html")
} else if len(pathParts) == 3 && pathParts[1] == "blog" {
additionalTemplates = append(additionalTemplates, "views/pages/blog-page.html")
- } else if len(pathParts) == 1 {
- additionalTemplates = append(additionalTemplates, "views/pages/home-page.html")
}
content, err := tm.Render("general-page-top-embeds", values, additionalTemplates...)
diff --git a/internal/router/api-v1-general-page.go b/internal/router/api-v1-general-page.go
index d0ea559..8e1387b 100644
--- a/internal/router/api-v1-general-page.go
+++ b/internal/router/api-v1-general-page.go
@@ -20,7 +20,7 @@ func Api_V1_GeneralPage(l map[string]*locale.LocaleConfig, langs []string) func(
path := c.Path()
pathParts := strings.Split(strings.Trim(path, "/"), "/")
- if len(pathParts) == 0 {
+ if len(pathParts) < 2 {
return c.Status(fiber.ErrBadRequest.Code).SendString("url path is invalid: expect format '/{lang}/...'")
}
diff --git a/internal/router/client-cache.go b/internal/router/client-cache.go
index d607cdd..e448fb3 100644
--- a/internal/router/client-cache.go
+++ b/internal/router/client-cache.go
@@ -16,7 +16,6 @@ type ClientCache struct {
hashMapMutex sync.RWMutex
likePageMap map[string]map[string]struct{}
- viewPageMap map[string]map[string]struct{}
pageMutexMap map[string]*sync.RWMutex
pageMutexMapMutex sync.Mutex
@@ -39,7 +38,6 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
}
likePageMap := make(map[string]map[string]struct{})
- viewPageMap := make(map[string]map[string]struct{})
pageMutexMap := make(map[string]*sync.RWMutex)
for rows.Next() {
@@ -52,32 +50,9 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
userIdString := base64.RawStdEncoding.EncodeToString(userId)
if _, ok := likePageMap[pageRef]; !ok {
likePageMap[pageRef] = make(map[string]struct{})
- viewPageMap[pageRef] = make(map[string]struct{})
pageMutexMap[pageRef] = &sync.RWMutex{}
}
likePageMap[pageRef][userIdString] = struct{}{}
- viewPageMap[pageRef][userIdString] = struct{}{}
- }
-
- rows, err = tx.Query("select * from blog_views;")
- if err != nil {
- tx.Rollback()
- return nil, fmt.Errorf("fail to query db for blog_views to fill cache: %w", err)
- }
-
- for rows.Next() {
- var pageRef string
- var userId []byte
- if err = rows.Scan(&pageRef, &userId); err != nil {
- tx.Rollback()
- return nil, fmt.Errorf("fail scanning blog_views to fill cache: %w", err)
- }
- userIdString := base64.RawStdEncoding.EncodeToString(userId)
- if _, ok := viewPageMap[pageRef]; !ok {
- viewPageMap[pageRef] = make(map[string]struct{})
- pageMutexMap[pageRef] = &sync.RWMutex{}
- }
- viewPageMap[pageRef][userIdString] = struct{}{}
}
if err = tx.Commit(); err != nil {
@@ -87,7 +62,6 @@ func NewClientCache(db *sql.DB, salt []byte) (*ClientCache, error) {
return &ClientCache{
hashMap: make(map[string]string),
likePageMap: likePageMap,
- viewPageMap: viewPageMap,
pageMutexMap: pageMutexMap,
salt: salt,
db: db,
@@ -100,14 +74,51 @@ func (c *ClientCache) Close() error {
return fmt.Errorf("fail to init transaction with db to dump cache: %w", err)
}
- if err = batchSave(tx, "blog_likes", c.likePageMap); err != nil {
+ if _, err = tx.Exec("delete from blog_likes;"); err != nil {
tx.Rollback()
- return fmt.Errorf("fail to save blog_likes: %s", err)
+ return fmt.Errorf("fail to truncate table blog_likes: %w", err)
}
- if err = batchSave(tx, "blog_views", c.viewPageMap); err != nil {
- tx.Rollback()
- return fmt.Errorf("fail to save blog_views: %s", err)
+ userIdBytes := make(map[string][]byte)
+
+ sqlStatement := fmt.Sprintf(`
+ INSERT OR IGNORE INTO blog_likes (page_ref, user_id)
+ VALUES %s(?, ?);
+ `, strings.Repeat("(?, ?), ", 99))
+ sqlStatementVars := make([]any, 0, 200)
+
+ for pageRef, userSet := range c.likePageMap {
+ for userId := range userSet {
+ if _, ok := userIdBytes[userId]; !ok {
+ userIdBytes[userId], err = base64.RawStdEncoding.DecodeString(userId)
+ if err != nil {
+ slog.Warn("couldn't parse one of user hashes into bytes back", slog.String("hash", userId), slog.String("error", err.Error()))
+ continue
+ }
+ }
+
+ sqlStatementVars = append(sqlStatementVars, any(pageRef), any(userIdBytes[userId]))
+ if len(sqlStatementVars) < 200 {
+ continue
+ }
+
+ if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
+ slog.Warn("couldn't insert blog like pairs into db", slog.String("error", err.Error()))
+ }
+
+ sqlStatementVars = make([]any, 0, 200)
+ }
+ }
+
+ if len(sqlStatementVars) > 0 {
+ sqlStatement = fmt.Sprintf(`
+ INSERT OR IGNORE INTO blog_likes (page_ref, user_id)
+ VALUES %s(?, ?);
+ `, strings.Repeat("(?, ?), ", len(sqlStatementVars)/2-1))
+
+ if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
+ slog.Warn("couldn't insert blog like pairs into db", slog.String("error", err.Error()))
+ }
}
return tx.Commit()
@@ -211,94 +222,3 @@ func (c *ClientCache) LikeOff(id string, page string) (alreadyUnliked bool) {
delete(c.likePageMap[page], hash)
return false
}
-
-func (c *ClientCache) GetViewStatus(id string, page string) bool {
- page = strings.Clone(page)
-
- mutex := c.getPageMutex(page)
- mutex.RLock()
- defer mutex.RUnlock()
-
- if _, ok := c.viewPageMap[page]; !ok {
- return false
- }
- _, ok := c.viewPageMap[page][c.GetHash(id)]
- return ok
-}
-
-func (c *ClientCache) GetViewCount(page string) int {
- page = strings.Clone(page)
-
- mutex := c.getPageMutex(page)
- mutex.RLock()
- defer mutex.RUnlock()
-
- if userSet, ok := c.viewPageMap[page]; ok {
- return len(userSet)
- }
- return 0
-}
-
-func (c *ClientCache) View(id string, page string) {
- page = strings.Clone(page)
- hash := c.GetHash(id)
-
- mutex := c.getPageMutex(page)
- mutex.Lock()
- defer mutex.Unlock()
-
- if _, ok := c.viewPageMap[page]; !ok {
- c.viewPageMap[page] = make(map[string]struct{})
- }
- c.viewPageMap[page][hash] = struct{}{}
-}
-
-func batchSave(tx *sql.Tx, table string, pageMap map[string]map[string]struct{}) (err error) {
- if _, err = tx.Exec(fmt.Sprintf("delete from %s;", table)); err != nil {
- return fmt.Errorf("fail to truncate table %s: %w", table, err)
- }
-
- userIdBytes := make(map[string][]byte)
-
- sqlStatement := fmt.Sprintf(`
- INSERT OR IGNORE INTO %s (page_ref, user_id)
- VALUES %s(?, ?);
- `, table, strings.Repeat("(?, ?), ", 99))
- sqlStatementVars := make([]any, 0, 200)
-
- for pageRef, userSet := range pageMap {
- for userId := range userSet {
- if _, ok := userIdBytes[userId]; !ok {
- userIdBytes[userId], err = base64.RawStdEncoding.DecodeString(userId)
- if err != nil {
- slog.Warn("couldn't parse one of user hashes into bytes back", slog.String("hash", userId), slog.String("error", err.Error()))
- continue
- }
- }
-
- sqlStatementVars = append(sqlStatementVars, any(pageRef), any(userIdBytes[userId]))
- if len(sqlStatementVars) < 200 {
- continue
- }
-
- if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
- slog.Warn("couldn't insert blog stat pairs into db", slog.String("table", table), slog.String("error", err.Error()))
- }
-
- sqlStatementVars = make([]any, 0, 200)
- }
- }
-
- if len(sqlStatementVars) > 0 {
- sqlStatement = fmt.Sprintf(`
- INSERT OR IGNORE INTO %s (page_ref, user_id)
- VALUES %s(?, ?);
- `, table, strings.Repeat("(?, ?), ", len(sqlStatementVars)/2-1))
-
- if _, err := tx.Exec(sqlStatement, sqlStatementVars...); err != nil {
- slog.Warn("couldn't insert blog stat pairs into db", slog.String("table", table), slog.String("error", err.Error()))
- }
- }
-
- return nil
-}
diff --git a/internal/templatemanager/templatemanager.go b/internal/templatemanager/templatemanager.go
index 4bf9a49..d8adab6 100644
--- a/internal/templatemanager/templatemanager.go
+++ b/internal/templatemanager/templatemanager.go
@@ -22,22 +22,13 @@ type TemplateManagerTemplates struct {
Files []string
}
-var templateFuncMap = template.FuncMap{
- "contains": strings.Contains,
- "iterate": func(count uint) []uint {
- items := make([]uint, count)
- for i := range count {
- items[i] = i
- }
- return items
- },
-}
-
func NewTemplateManager(templates ...TemplateManagerTemplates) (*TemplateManager, error) {
templateMap := make(map[string]templateManagerRender)
for _, tmplStruct := range templates {
- tmpl := template.New("").Funcs(templateFuncMap)
+ tmpl := template.New("").Funcs(template.FuncMap{
+ "contains": strings.Contains,
+ })
tmpl, err := tmpl.ParseFiles(tmplStruct.Files...)
if err != nil {
return nil, err
@@ -84,7 +75,9 @@ func (tm *TemplateManager) Add(name string, files ...string) error {
return fmt.Errorf("you can't add template without any files")
}
- tmpl := template.New("").Funcs(templateFuncMap)
+ tmpl := template.New("").Funcs(template.FuncMap{
+ "contains": strings.Contains,
+ })
tmpl, err := tmpl.ParseFiles(files...)
if err != nil {
diff --git a/locale/localization.en.yaml b/locale/localization.en.yaml
index 1b3654b..f5ee6c9 100644
--- a/locale/localization.en.yaml
+++ b/locale/localization.en.yaml
@@ -9,16 +9,3 @@ BlogSearch:
ChooseAllTags: 'Choose All'
GlobalMap:
Header: 'Global Map'
-HomePage:
- Header: 'Home Page'
- Contacts: 'Contacts'
- DidYouKnowThat: 'Did you know, that...'
- SidebarDescription: 'Describing the Sidebar'
- HomePageDescription: 'Home Page -- where we are right now!'
- BlogSearchDescription: 'Blog Search. You can find my travel notes there and, maybe, something else!'
- MarkerMapDescription: 'Map with markers of my travel notes -- a convinient way to find an interesting region and find related posts!'
- ThemeSwitchDescription: 'Theme Palette lets you change the theme of the site -- there are 2 dark and 2 bright themes currently!'
- Hymn1: 'We welcome you to Sayasite!'
- Hymn2: "We've been expecting you!"
- Hymn3: 'You bring such joy in Sayasite!'
- Hymn4: 'No matter where you roam, know our love is true!~'
diff --git a/locale/localization.go b/locale/localization.go
index 088783f..56b6462 100644
--- a/locale/localization.go
+++ b/locale/localization.go
@@ -11,7 +11,6 @@ type LocaleConfig struct {
TagsLabel string `yaml:"TagsLabel" json:"TagsLabel"`
BlogSearch BlogSearchConfig `yaml:"BlogSearch" json:"BlogSearch"`
GlobalMap GlobalMapConfig `yaml:"GlobalMap" json:"GlobalMap"`
- HomePage HomePageConfig `yaml:"HomePage" json:"HomePage"`
}
type BlogSearchConfig struct {
@@ -28,21 +27,6 @@ type GlobalMapConfig struct {
Header string `yaml:"Header" json:"Header"`
}
-type HomePageConfig struct {
- Header string `yaml:"Header" json:"Header"`
- Contacts string `yaml:"Contacts" json:"Contacts"`
- DidYouKnowThat string `yaml:"DidYouKnowThat" json:"DidYouKnowThat"`
- SidebarDescription string `yaml:"SidebarDescription" json:"SidebarDescription"`
- HomePageDescription string `yaml:"HomePageDescription" json:"HomePageDescription"`
- BlogSearchDescription string `yaml:"BlogSearchDescription" json:"BlogSearchDescription"`
- MarkerMapDescription string `yaml:"MarkerMapDescription" json:"MarkerMapDescription"`
- ThemeSwitchDescription string `yaml:"ThemeSwitchDescription" json:"ThemeSwitchDescription"`
- Hymn1 string `yaml:"Hymn1" json:"Hymn1"`
- Hymn2 string `yaml:"Hymn2" json:"Hymn2"`
- Hymn3 string `yaml:"Hymn3" json:"Hymn3"`
- Hymn4 string `yaml:"Hymn4" json:"Hymn4"`
-}
-
func LoadConfig(path string, config *LocaleConfig) error {
fileBytes, err := os.ReadFile(path)
if err != nil {
diff --git a/locale/localization.ru.yaml b/locale/localization.ru.yaml
index 9d7084f..c236d1e 100644
--- a/locale/localization.ru.yaml
+++ b/locale/localization.ru.yaml
@@ -9,16 +9,3 @@ BlogSearch:
ChooseAllTags: 'Выбрать все'
GlobalMap:
Header: 'Глобальная карта'
-HomePage:
- Header: 'Домашняя страница'
- Contacts: 'Контакты'
- DidYouKnowThat: 'А вы знали, что...'
- SidebarDescription: 'Поясняем за сайдбар'
- HomePageDescription: 'Домашняя страница -- где мы сейчас и находимся!'
- BlogSearchDescription: 'Поиск по блогу. Там размещены мои путевые заметки и, может, что-то ещё!'
- MarkerMapDescription: 'Карта с маркерами моих путевых заметок, -- удобный способ найти интересный регион и перейти на заинтересовавшие посты!'
- ThemeSwitchDescription: 'Позволяет поменять тему сайта -- есть 2 светлые и 2 тёмные темы!'
- Hymn1: 'Приветствуем Вас на Саясайте!'
- Hymn2: 'Мы Вас столько ждали!'
- Hymn3: 'Столько радости от Вас на Саясайте!'
- Hymn4: 'Где бы Вы не были, знайте, -- наша любовь крепка!'
diff --git a/main.go b/main.go
index 20e90f4..2f8ef4b 100644
--- a/main.go
+++ b/main.go
@@ -11,14 +11,13 @@ import (
"github.com/SayaAndy/saya-today-web/config"
"github.com/SayaAndy/saya-today-web/internal/b2"
- "github.com/SayaAndy/saya-today-web/internal/factgiver"
"github.com/SayaAndy/saya-today-web/internal/lightgallery"
"github.com/SayaAndy/saya-today-web/internal/router"
"github.com/SayaAndy/saya-today-web/internal/tailwind"
"github.com/SayaAndy/saya-today-web/locale"
"github.com/dgraph-io/ristretto/v2"
"github.com/gofiber/fiber/v2"
- "github.com/gofiber/fiber/v2/middleware/cors"
+ "github.com/gofiber/fiber/v2/middleware/redirect"
"github.com/golang-migrate/migrate/v4"
"github.com/golang-migrate/migrate/v4/database/sqlite3"
"github.com/yuin/goldmark"
@@ -108,10 +107,12 @@ func main() {
ProxyHeader: "X-Forwarded-For",
})
- app.Use(cors.New(cors.Config{
- AllowOrigins: "https://f003.backblazeb2.com",
- AllowMethods: "GET,POST,OPTIONS",
- AllowHeaders: "Origin, Content-Type, Accept",
+ app.Use(redirect.New(redirect.Config{
+ Rules: map[string]string{
+ "/ru": "/",
+ "/en": "/",
+ },
+ StatusCode: 301,
}))
router.CCache, err = router.NewClientCache(db, []byte(cfg.Auth.Salt))
@@ -130,14 +131,7 @@ func main() {
os.Exit(1)
}
- router.FactGiver, err = factgiver.NewFactGiver(&cfg.FactGiver, availableLanguages)
- if err != nil {
- slog.Error("fail to initialize fact giver", slog.String("error", err.Error()))
- os.Exit(1)
- }
-
app.Get("/", router.Root(cfg.AvailableLanguages))
- app.Get("/:lang<len(2)>", router.Api_V1_GeneralPage(localization, availableLanguages))
app.Get("/:lang/map", router.Lang_Map(localization, availableLanguages, b2Client))
app.Get("/:lang/blog", router.Api_V1_GeneralPage(localization, availableLanguages))
app.Get("/:lang/blog/:title", router.Api_V1_GeneralPage(localization, availableLanguages))
diff --git a/static/input.css b/static/input.css
index 739bea7..261aeb3 100644
--- a/static/input.css
+++ b/static/input.css
@@ -10,7 +10,6 @@
--main-medium-color: #8a9d8a;
--main-light-color: #a5b8a5;
--background-dark-color: #ffffdd;
- --background-medium-color: var(--background-dark-color);
--background-light-color: #fffff0;
--sidebar-text-color: var(--background-dark-color);
--sidebar-stroke-color: var(--main-dark-color);
@@ -32,7 +31,6 @@
--main-medium-color: #9bb665;
--main-light-color: #bbd095;
--background-dark-color: #f5eee2;
- --background-medium-color: var(--background-dark-color);
--background-light-color: #fff9ef;
--sidebar-text-color: var(--main-dark-color);
--sidebar-stroke-color: var(--background-dark-color);
@@ -54,7 +52,6 @@
--main-medium-color: var(--color-sky-200);
--main-light-color: var(--color-sky-300);
--background-dark-color: #13131b;
- --background-medium-color: var(--background-dark-color);
--background-light-color: #222230;
--sidebar-text-color: var(--main-dark-color);
--sidebar-stroke-color: var(--background-light-color);
@@ -76,7 +73,6 @@
--main-medium-color: #f6e4c5;
--main-light-color: #e8d4b8;
--background-dark-color: #413b34;
- --background-medium-color: #62584f;
--background-light-color: #6d6258;
--sidebar-text-color: var(--main-dark-color);
--sidebar-stroke-color: var(--background-light-color);
@@ -619,22 +615,6 @@ body[data-theme~="ram"] .leaflet-tile {
}
}
-@media (min-aspect-ratio: 0.6/1) {
- .ar-gt-0\.6\:flex-3\/5 {
- flex: 60%;
- }
-
- .ar-gt-0\.6\:flex-2\/5 {
- flex: 40%;
- }
-}
-
-@media (max-aspect-ratio: 0.6/1) {
- .ar-lt-0\.6\:flex-col {
- flex-direction: column;
- }
-}
-
@media (max-aspect-ratio: 0.4/1) {
.ar-lt-0\.4\:w-\[100vw\] {
width: 100vw;
@@ -645,14 +625,6 @@ body[data-theme~="ram"] .leaflet-tile {
}
}
-.home-page-heart {
- position: absolute;
- color: var(--color-pink-700);
- user-select: none;
- pointer-events: none;
- font-family: serif;
-}
-
.night-star {
color: var(--color-yellow-100);
animation-name: blink;
diff --git a/views/index.html b/views/index.html
index b52df94..2b8c937 100644
--- a/views/index.html
+++ b/views/index.html
@@ -106,7 +106,7 @@
<p class="font-patua mx-auto text-[2.5vmax] mt-[0.8vmin] mb-[0.8vmin]">saya.today</p>
<div class="menu-inner-body grow bg-background-light flex flex-adaptive mx-auto opacity-100">
{{- range .AvailableLanguages }}
- <img onclick="location.href='/{{ .Name }}';" class="object-scale-down cursor-pointer flex-1 rounded-[20%] language-icon mx-auto my-auto relative" src="{{ .Flag }}" alt="{{ .Alt }}">
+ <img onclick="location.href='/{{ .Name }}/blog';" class="object-scale-down cursor-pointer flex-1 rounded-[20%] language-icon mx-auto my-auto relative" src="{{ .Flag }}" alt="{{ .Alt }}">
{{- end }}
</div>
<p class="font-spectral mx-auto text-[1.5vmax] text-secondary mt-[0.8vmin] mb-[0.8vmin]">Choose your language</p>
diff --git a/views/layouts/general-page.html b/views/layouts/general-page.html
index 60608f4..cb85a09 100644
--- a/views/layouts/general-page.html
+++ b/views/layouts/general-page.html
@@ -7,9 +7,9 @@
<link rel="preconnect" href="https://fonts.googleapis.com">
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin>
<link href="https://fonts.googleapis.com/css2?family=Spectral:ital,wght@0,200;0,300;0,400;0,500;0,600;0,700;0,800;1,200;1,300;1,400;1,500;1,600;1,700;1,800&family=Patua+One&display=swap" rel="stylesheet">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lightgallery.min.css">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lg-zoom.min.css">
- <link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/lightgallery/2.8.3/css/lg-thumbnail.min.css">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lightgallery.min.css">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-zoom.min.css">
+ <link rel="stylesheet" href="https://cdnjs.cloudflare.com/ajax/libs/lightgallery/2.8.3/css/lg-thumbnail.min.css">
<link rel="stylesheet" href="https://f003.backblazeb2.com/file/sayana-static/libs/leaflet/1.9.4/leaflet.css">
<link href="/output.css" rel="stylesheet">
</head>
@@ -166,7 +166,7 @@
saya.today
</div>
<div class="text-[3vw] ar-lt-1.1:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-1.1:flex-row gap-0 relative z-20">
- <i onclick="changeUrl('/{{ .Lang }}');" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="location.href='/{{ .Lang }}';" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="changeUrl('/{{ .Lang }}/blog');" class="fas fa-search w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
diff --git a/views/pages/blog-page.html b/views/pages/blog-page.html
index 863b417..b121cc6 100644
--- a/views/pages/blog-page.html
+++ b/views/pages/blog-page.html
@@ -1,7 +1,7 @@
{{ define "top-embeds" }}
<script>
- let galleryMap = new Map();
- let map;
+ var galleryMap = new Map();
+ var map;
window.addEventListener('popout', (e) => {
map.remove();
@@ -9,8 +9,6 @@
g.destroy();
});
galleryMap.clear();
- map = null;
- galleryMap = null;
}, {once: true});
</script>
{{ end }}
@@ -89,8 +87,7 @@
window.addEventListener('resize', resizeCb);
document.addEventListener('popout', (e) => {
- window.removeEventListener('resize', resizeCb);
- galleryResizeTimeout = null;
+ window.removeEventListener('resize', resizeCb, {once: true});
});
</script>
{{ end }} \ No newline at end of file
diff --git a/views/pages/global-map.html b/views/pages/global-map.html
index a844e06..d6e7281 100644
--- a/views/pages/global-map.html
+++ b/views/pages/global-map.html
@@ -45,7 +45,7 @@
saya.today
</div>
<div class="text-[3vw] ar-lt-1.1:text-[5vh] text-stroke-(--sidebar-stroke-color) text-stroke-[0.1vw] flex flex-col ar-lt-1.1:flex-row gap-0 relative z-20">
- <i onclick="location.href='/{{ .Lang }}';" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
+ <i onclick="location.href='/';" class="fas fa-home w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="location.href='/{{ .Lang }}/blog';" class="fas fa-search w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="location.href='/{{ .Lang }}/map';" class="fas fa-map w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
<i onclick="toggleThemeWheel();" id="theme-button" class="fas fa-swatchbook w-[5vw] ar-lt-1.1:w-[8vh] h-[5vw] ar-lt-1.1:h-[8vh] content-center text-center text-sidebar hover:bg-background-dark cursor-pointer transition-colors duration-300 flex rounded-lg"></i>
diff --git a/views/pages/home-page.html b/views/pages/home-page.html
deleted file mode 100644
index 6fd716b..0000000
--- a/views/pages/home-page.html
+++ /dev/null
@@ -1,121 +0,0 @@
-{{ define "body" }}
-<div class="bg-background-light flex flex-row ar-lt-0.6:flex-col w-full h-full inset-shadow overflow-y-auto text-[1vmax]/[2] tracking-[0.04vmin]">
- <div class="ar-gt-0.6:flex-3/5 justify-center content-start p-[5%]">
- <div class="flex flex-col justify-start items-start bg-background-dark mb-[2vmax]">
- <p class="text-[3vmax]/[2] tracking-[0.2vmin] uppercase w-full font-spectral italic text-left
- border-l-[0.4vmax] border-solid border-(--background-dark-color)
- bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.Hymn1 }}</p>
- <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
- <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn2 }}</p>
- <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn3 }}</p>
- <p class="text-[2vmax]/[2] -indent-[2vmax] ml-[2vmax] p-[0.4vmax]">{{ .L.HomePage.Hymn4 }}</p>
- </div>
-
- <div class="flex flex-col justify-center items-center">
- <p class="text-[2vmax] w-full font-spectral italic text-left
- border-l-[0.4vmax] border-solid border-(--background-dark-color)
- bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.DidYouKnowThat }}</p>
- <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
- <ul class="w-full text-left list-[circle]">
- <li class="ml-[2vmax] mb-[0.8vmin]">{{ index .FunFacts 0 }}</li>
- <li class="ml-[2vmax] mb-[0.8vmin]">{{ index .FunFacts 1 }}</li>
- <li class="ml-[2vmax]">{{ index .FunFacts 2 }}</li>
- </ul>
- </div>
- </div>
-
- <div class="ar-gt-0.6:flex-2/5 justify-center content-start p-[5%]">
- <div class="flex flex-col justify-center items-start mb-[2vmax]">
- <p class="text-[2vmax] w-full font-spectral italic text-left
- border-l-[0.4vmax] border-solid border-(--background-dark-color)
- bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.Contacts }}</p>
- <a href="https://t.me/EarlInisMona">
- <i class="fa-brands fa-telegram w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
- <span class="font-bold">Telegram:</span>
- <span>@EarlInisMona</span>
- </a>
- <a href="https://discord.com/users/356057270951346176">
- <i class="fa-brands fa-discord w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
- <span class="font-bold">Discord:</span>
- <span>montferrat</span>
- </a>
- <a href="mailto:saya.andy@posteo.com">
- <i class="fas fa-envelope w-[1vmax] h-[1vmax] mr-[0.4vmax]"></i>
- <span class="font-bold">E-mail:</span>
- <span>saya.andy@posteo.com</span>
- </a>
- </div>
-
- <div class="flex relative aspect-square justify-center content-center mb-[2vmax]">
- {{- range $_ := iterate .FilledHeartCount }}
- <div class="home-page-heart z-50">♥</div>
- {{- end }}
- {{- range $_ := iterate .OutlineHeartCount }}
- <div class="home-page-heart z-50">♡</div>
- {{- end }}
- <img src="https://f003.backblazeb2.com/file/sayana-static/home-page-gifs/{{ .GifName }}"
- class="home-page-gif z-49 -rotate-12 max-w-[70%] max-h-[70%] border-[1vmin] border-(--background-dark-color) border-inset">
- </div>
-
- <script>
- function shuffleHearts() {
- vmin = calculateVmin(1);
- document.querySelectorAll('.home-page-heart').forEach((e) => {
- let top, left;
- do {
- top = Math.floor(rand() * 90) + 5;
- left = Math.floor(rand() * 90) + 5;
- } while (top > 30 && top < 70 && left > 30 && left < 70);
- const opacity = rand() * 0.7 + 0.2;
- const size = rand() * 3.2 + 0.8;
- e.style["top"] = `calc(${top}% - ${size}vmin / 2)`;
- e.style["left"] = `calc(${left}% - ${size}vmin / 2)`;
- e.style["opacity"] = `${opacity}`;
- e.style["font-size"] = `${size}vmin`;
- });
- }
-
- let shuffleHeartsResizeTimeout;
- function shuffleHeartsResizeCb() {
- clearTimeout(shuffleHeartsResizeTimeout);
- shuffleHeartsResizeTimeout = setTimeout(shuffleHearts, 300);
- }
- window.addEventListener('resize', shuffleHeartsResizeCb);
-
- document.addEventListener('popout', (e) => {
- window.removeEventListener('resize', shuffleHeartsResizeCb);
- shuffleHeartsResizeCb = null;
- });
- </script>
-
- <script>
- document.addEventListener('htmx:afterRequest', (e) => {
- if (e.detail.xhr.status == 404 || e.detail.successful != true) {
- return console.error(e);
- }
- if (e.detail.target.id == 'general-page-body') {
- shuffleHearts();
- }
- }, {once: true});
- </script>
-
- <div class="flex flex-col justify-center items-center">
- <p class="text-[2vmax] w-full font-spectral italic text-left
- border-l-[0.4vmax] border-solid border-(--background-dark-color)
- bg-gradient-to-r from-(--background-dark-color) to-(--background-light-color)">{{ .L.HomePage.SidebarDescription }}</p>
- <hr class="w-full border-t-[0.2vmax] border-dotted border-main-dark mb-[0.8vmin]">
- <div class="w-full grid grid-cols-[1fr_4fr] content-center items-center
- [&>*:nth-child(4n+2)]:bg-(--background-medium-color) [&>*:nth-child(4n+3)]:bg-(--background-medium-color)" style="container-type: inline-size;">
- <i class="fas fa-home w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
- <p class="p-[0.4vmax]">{{ .L.HomePage.HomePageDescription }}</p>
- <i class="fas fa-search w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
- <p class="p-[0.4vmax]">{{ .L.HomePage.BlogSearchDescription }}</p>
- <i class="fas fa-map w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
- <p class="p-[0.4vmax]">{{ .L.HomePage.MarkerMapDescription }}</p>
- <i class="fas fa-swatchbook w-full h-full text-[10cqi] content-center text-center text-main-dark"></i>
- <p class="p-[0.4vmax]">{{ .L.HomePage.ThemeSwitchDescription }}</p>
- </div>
- </div>
- </div>
-</div>
-{{ end }}
diff --git a/views/partials/catalogue-blog-cards.html b/views/partials/catalogue-blog-cards.html
index 37b3f57..06d99d5 100644
--- a/views/partials/catalogue-blog-cards.html
+++ b/views/partials/catalogue-blog-cards.html
@@ -8,17 +8,14 @@
<span class="font-extrabold">{{ .Title }}</span>
<span class="font-extrabold select-none text-secondary">//</span>
<span class="italic text-secondary">{{ .ActionDate }}</span>
+ <span class="font-extrabold select-none text-secondary">//</span>
+ <i class="fas fa-thumbs-up w-[1vmax] h-[1vmax]"></i>
+ <span class="italic text-secondary">{{ .LikeCount }}</span>
</a>
+ <div hx-trigger="click from:#user_search_bar" hx-get="/endpoint1" hx-target="#users-list"></div>
<p class="flex-3/12 grow-0 text-[1vmax] italic text-secondary text-right">{{ .PublishedTime }}</p>
</div>
<p class="text-[1vmax] text-main-dark">{{ .ShortDescription }}</p>
- <p class="text-[1vmax] text-secondary italic">
- <i class="fas fa-thumbs-up w-[1vmax] h-[1vmax]"></i>
- <span>{{ .LikeCount }}</span>
- <span class="font-extrabold select-none">//</span>
- <i class="fas fa-eye w-[1vmax] h-[1vmax]"></i>
- <span>{{ .ViewCount }}</span>
- </p>
<p class="text-[1vmax] text-secondary">{{ $.L.TagsLabel }} {{ template "catalogue-blog-card-tags.html" . }}</p>
</div>
</div>
diff --git a/views/partials/general-page-header.html b/views/partials/general-page-header.html
index 6cb87b7..63803bd 100644
--- a/views/partials/general-page-header.html
+++ b/views/partials/general-page-header.html
@@ -1,8 +1,8 @@
<div {{ if .PublishedDate }} hx-get="/api/v1/tz" hx-vals='js:{timestamp: "{{ .PublishedDate }}", tz: clientTimeZone}' hx-target="#published-date" hx-swap="innerHTML" hx-trigger="load" {{ end }}
class="flex flex-row mb-[0.4vmin]">
<i onclick="changeUrl('/../', true);" class="fas fa-circle-left hover:bg-main-dark hover:bg-opacity-10 cursor-pointer transition-colors duration-300 rounded-md text-[2vmax] mt-auto mb-auto px-[0.8vmin]"></i>
- <p class="text-[2.5vmin] font-spectral italic font-extrabold select-none mt-auto pl-[0.8vmin] pr-[1.2vmin]">//</p>
- <p class="text-[2.5vmin] font-spectral italic text-left mt-auto">{{ .Title }}</p>
- <p id="published-date" class="grow text-[1.75vmin] font-spectral text-secondary text-right mt-auto">{{ .PublishedDate }}</p>
+ <p class="text-[2vmax] font-spectral italic font-extrabold select-none mt-auto pl-[0.8vmin] pr-[1.2vmin]">//</p>
+ <p class="text-[2vmax] font-spectral italic text-left mt-auto">{{ .Title }}</p>
+ <p id="published-date" class="grow text-[1.5vmax] font-spectral text-secondary text-right mt-auto">{{ .PublishedDate }}</p>
</div>
{{ block "header" . }}{{ end }}