lang
This commit is contained in:
+14
-13
@@ -14,19 +14,19 @@ import (
|
|||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
"prestaproxy/internal/assets"
|
"git.ma-al.com/goc_marek/ps_shop/internal/assets"
|
||||||
"prestaproxy/internal/http/handlers"
|
"git.ma-al.com/goc_marek/ps_shop/internal/http/handlers"
|
||||||
appmiddleware "prestaproxy/internal/http/middleware"
|
appmiddleware "git.ma-al.com/goc_marek/ps_shop/internal/http/middleware"
|
||||||
httpproxy "prestaproxy/internal/http/proxy"
|
httpproxy "git.ma-al.com/goc_marek/ps_shop/internal/http/proxy"
|
||||||
pscart "prestaproxy/internal/prestashop/cart"
|
pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
|
||||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
psconfig "prestaproxy/internal/prestashop/config"
|
psconfig "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/config"
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
|
||||||
psroutes "prestaproxy/internal/prestashop/routes"
|
psroutes "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/routes"
|
||||||
pssession "prestaproxy/internal/prestashop/session"
|
pssession "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/session"
|
||||||
"prestaproxy/internal/render"
|
"git.ma-al.com/goc_marek/ps_shop/internal/render"
|
||||||
"prestaproxy/internal/store"
|
"git.ma-al.com/goc_marek/ps_shop/internal/store"
|
||||||
)
|
)
|
||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
@@ -95,6 +95,7 @@ func run() error {
|
|||||||
render.New(assetManifest),
|
render.New(assetManifest),
|
||||||
cfg,
|
cfg,
|
||||||
productRoute,
|
productRoute,
|
||||||
|
categoryRoute,
|
||||||
)
|
)
|
||||||
|
|
||||||
proxyHandler, err := httpproxy.New(cfg.PrestaShopProxyTarget)
|
proxyHandler, err := httpproxy.New(cfg.PrestaShopProxyTarget)
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
module prestaproxy
|
module git.ma-al.com/goc_marek/ps_shop
|
||||||
|
|
||||||
go 1.25.0
|
go 1.25.0
|
||||||
|
|
||||||
|
|||||||
@@ -8,14 +8,14 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
appmiddleware "prestaproxy/internal/http/middleware"
|
appmiddleware "git.ma-al.com/goc_marek/ps_shop/internal/http/middleware"
|
||||||
pscart "prestaproxy/internal/prestashop/cart"
|
pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
|
||||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
psconfig "prestaproxy/internal/prestashop/config"
|
psconfig "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/config"
|
||||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
|
||||||
psroutes "prestaproxy/internal/prestashop/routes"
|
psroutes "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/routes"
|
||||||
"prestaproxy/internal/render"
|
"git.ma-al.com/goc_marek/ps_shop/internal/render"
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
const categorySlugContextKey = "category_slug"
|
const categorySlugContextKey = "category_slug"
|
||||||
@@ -28,9 +28,10 @@ type CategoryHandler struct {
|
|||||||
renderer *render.Engine
|
renderer *render.Engine
|
||||||
config psconfig.Config
|
config psconfig.Config
|
||||||
products *psroutes.ProductRoute
|
products *psroutes.ProductRoute
|
||||||
|
categories *psroutes.CategoryRoute
|
||||||
}
|
}
|
||||||
|
|
||||||
func NewCategoryHandler(catalog *pscatalog.Service, customers *pscustomer.Service, carts *pscart.Service, renderer *render.Engine, cfg psconfig.Config, products *psroutes.ProductRoute) *CategoryHandler {
|
func NewCategoryHandler(catalog *pscatalog.Service, customers *pscustomer.Service, carts *pscart.Service, renderer *render.Engine, cfg psconfig.Config, products *psroutes.ProductRoute, categories *psroutes.CategoryRoute) *CategoryHandler {
|
||||||
return &CategoryHandler{
|
return &CategoryHandler{
|
||||||
catalog: catalog,
|
catalog: catalog,
|
||||||
customers: customers,
|
customers: customers,
|
||||||
@@ -38,14 +39,12 @@ func NewCategoryHandler(catalog *pscatalog.Service, customers *pscustomer.Servic
|
|||||||
renderer: renderer,
|
renderer: renderer,
|
||||||
config: cfg,
|
config: cfg,
|
||||||
products: products,
|
products: products,
|
||||||
|
categories: categories,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func (h *CategoryHandler) Show(c echo.Context) error {
|
func (h *CategoryHandler) Show(c echo.Context) error {
|
||||||
session := appmiddleware.GetSession(c)
|
session := appmiddleware.GetSession(c)
|
||||||
if session == nil {
|
|
||||||
session = appmiddleware.GetSession(c)
|
|
||||||
}
|
|
||||||
if h == nil || h.catalog == nil || h.renderer == nil {
|
if h == nil || h.catalog == nil || h.renderer == nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "category handler is not initialized")
|
return echo.NewHTTPError(http.StatusInternalServerError, "category handler is not initialized")
|
||||||
}
|
}
|
||||||
@@ -91,6 +90,16 @@ func (h *CategoryHandler) Show(c echo.Context) error {
|
|||||||
ShopBaseURL: h.config.PrestaShopBaseURL,
|
ShopBaseURL: h.config.PrestaShopBaseURL,
|
||||||
}
|
}
|
||||||
assignCategoryProductLinks(c.Request(), h.products, &page)
|
assignCategoryProductLinks(c.Request(), h.products, &page)
|
||||||
|
menu, err := loadMenu(c.Request(), h.catalog, h.categories, languageID, shopID)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "menu query failed: "+err.Error())
|
||||||
|
}
|
||||||
|
page.Menu = menu
|
||||||
|
locale, err := loadHeaderLocale(c.Request(), h.catalog, session, languageID)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "locale query failed: "+err.Error())
|
||||||
|
}
|
||||||
|
page.Locale = locale
|
||||||
|
|
||||||
if err := h.renderer.Category(c.Response(), c.Request(), page); err != nil {
|
if err := h.renderer.Category(c.Response(), c.Request(), page); err != nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "category render failed: "+err.Error())
|
return echo.NewHTTPError(http.StatusInternalServerError, "category render failed: "+err.Error())
|
||||||
@@ -141,22 +150,3 @@ func assignCategoryProductLinks(req *http.Request, route *psroutes.ProductRoute,
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
func requestLanguagePrefix(req *http.Request) string {
|
|
||||||
if req == nil || req.URL == nil {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
path := strings.Trim(req.URL.Path, "/")
|
|
||||||
if path == "" {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
first := path
|
|
||||||
if idx := strings.IndexByte(path, '/'); idx >= 0 {
|
|
||||||
first = path[:idx]
|
|
||||||
}
|
|
||||||
first = strings.TrimSpace(first)
|
|
||||||
if len(first) < 2 || len(first) > 5 {
|
|
||||||
return ""
|
|
||||||
}
|
|
||||||
return "/" + first
|
|
||||||
}
|
|
||||||
|
|||||||
@@ -0,0 +1,151 @@
|
|||||||
|
package handlers
|
||||||
|
|
||||||
|
import (
|
||||||
|
"net/http"
|
||||||
|
"net/url"
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
|
psroutes "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/routes"
|
||||||
|
)
|
||||||
|
|
||||||
|
func loadMenu(req *http.Request, catalog *pscatalog.Service, route *psroutes.CategoryRoute, languageID int64, shopID int64) ([]pscatalog.MenuItem, error) {
|
||||||
|
if catalog == nil || route == nil {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
menu, err := catalog.GetCategoryMenu(req.Context(), languageID, shopID)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
assignMenuLinks(req, route, menu)
|
||||||
|
return menu, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func assignMenuLinks(req *http.Request, route *psroutes.CategoryRoute, items []pscatalog.MenuItem) {
|
||||||
|
langPrefix := requestLanguagePrefix(req)
|
||||||
|
for i := range items {
|
||||||
|
items[i].URL = route.BuildPath(psroutes.CategoryURLData{
|
||||||
|
ID: items[i].ID,
|
||||||
|
Slug: items[i].Slug,
|
||||||
|
LanguagePrefix: langPrefix,
|
||||||
|
})
|
||||||
|
if len(items[i].Children) > 0 {
|
||||||
|
assignMenuLinks(req, route, items[i].Children)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func loadHeaderLocale(req *http.Request, catalog *pscatalog.Service, session *pscookie.SessionContext, languageID int64) (pscatalog.HeaderLocaleData, error) {
|
||||||
|
if catalog == nil || req == nil {
|
||||||
|
return pscatalog.HeaderLocaleData{}, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
var currencyID int64
|
||||||
|
countryISO := ""
|
||||||
|
if session != nil {
|
||||||
|
currencyID = int64Default(session.CurrencyID, 0)
|
||||||
|
countryISO = strings.TrimSpace(session.Values["iso_code_country"])
|
||||||
|
}
|
||||||
|
|
||||||
|
locale, err := catalog.GetHeaderLocale(req.Context(), languageID, currencyID, countryISO)
|
||||||
|
if err != nil {
|
||||||
|
return pscatalog.HeaderLocaleData{}, err
|
||||||
|
}
|
||||||
|
assignLanguageSwitchLinks(req, &locale)
|
||||||
|
assignMarketSwitchLinks(req, &locale)
|
||||||
|
return locale, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func assignLanguageSwitchLinks(req *http.Request, locale *pscatalog.HeaderLocaleData) {
|
||||||
|
if req == nil || req.URL == nil || locale == nil || len(locale.Languages) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
basePath := stripLanguagePrefix(req.URL.Path, locale.Languages)
|
||||||
|
rawQuery := req.URL.RawQuery
|
||||||
|
for i := range locale.Languages {
|
||||||
|
code := strings.ToLower(strings.TrimSpace(locale.Languages[i].Code))
|
||||||
|
path := "/" + code
|
||||||
|
if basePath != "/" {
|
||||||
|
path += basePath
|
||||||
|
}
|
||||||
|
if rawQuery != "" {
|
||||||
|
path += "?" + rawQuery
|
||||||
|
}
|
||||||
|
locale.Languages[i].URL = path
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func assignMarketSwitchLinks(req *http.Request, locale *pscatalog.HeaderLocaleData) {
|
||||||
|
if req == nil || req.URL == nil || locale == nil || len(locale.Countries) == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
for i := range locale.Countries {
|
||||||
|
marketCode := strings.ToUpper(strings.TrimSpace(locale.Countries[i].Code))
|
||||||
|
if marketCode == "" || locale.Countries[i].CurrencyID == 0 {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
query := req.URL.Query()
|
||||||
|
query.Set("market", strconv.FormatInt(locale.Countries[i].ID, 10)+":"+marketCode+":"+strconv.FormatInt(locale.Countries[i].CurrencyID, 10))
|
||||||
|
locale.Countries[i].URL = rebuildURL(req.URL.Path, query)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func requestLanguagePrefix(req *http.Request) string {
|
||||||
|
if req == nil || req.URL == nil {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
path := strings.Trim(req.URL.Path, "/")
|
||||||
|
if path == "" {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
first := path
|
||||||
|
if idx := strings.IndexByte(path, '/'); idx >= 0 {
|
||||||
|
first = path[:idx]
|
||||||
|
}
|
||||||
|
first = strings.TrimSpace(first)
|
||||||
|
if len(first) < 2 || len(first) > 5 {
|
||||||
|
return ""
|
||||||
|
}
|
||||||
|
return "/" + first
|
||||||
|
}
|
||||||
|
|
||||||
|
func stripLanguagePrefix(path string, languages []pscatalog.LocaleOption) string {
|
||||||
|
if path == "" {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
codes := make(map[string]struct{}, len(languages))
|
||||||
|
for _, language := range languages {
|
||||||
|
code := strings.ToLower(strings.TrimSpace(language.Code))
|
||||||
|
if code != "" {
|
||||||
|
codes[code] = struct{}{}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
trimmed := strings.Trim(path, "/")
|
||||||
|
if trimmed == "" {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
parts := strings.Split(trimmed, "/")
|
||||||
|
if _, ok := codes[strings.ToLower(parts[0])]; ok {
|
||||||
|
parts = parts[1:]
|
||||||
|
}
|
||||||
|
if len(parts) == 0 {
|
||||||
|
return "/"
|
||||||
|
}
|
||||||
|
return "/" + strings.Join(parts, "/")
|
||||||
|
}
|
||||||
|
|
||||||
|
func rebuildURL(path string, query url.Values) string {
|
||||||
|
if path == "" {
|
||||||
|
path = "/"
|
||||||
|
}
|
||||||
|
encoded := query.Encode()
|
||||||
|
if encoded == "" {
|
||||||
|
return path
|
||||||
|
}
|
||||||
|
return path + "?" + encoded
|
||||||
|
}
|
||||||
@@ -8,14 +8,14 @@ import (
|
|||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
|
|
||||||
appmiddleware "prestaproxy/internal/http/middleware"
|
appmiddleware "git.ma-al.com/goc_marek/ps_shop/internal/http/middleware"
|
||||||
pscart "prestaproxy/internal/prestashop/cart"
|
pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
|
||||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
psconfig "prestaproxy/internal/prestashop/config"
|
psconfig "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/config"
|
||||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
|
||||||
psroutes "prestaproxy/internal/prestashop/routes"
|
psroutes "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/routes"
|
||||||
"prestaproxy/internal/render"
|
"git.ma-al.com/goc_marek/ps_shop/internal/render"
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
const productSlugContextKey = "product_slug"
|
const productSlugContextKey = "product_slug"
|
||||||
@@ -43,9 +43,6 @@ func NewProductHandler(products *pscatalog.Service, customers *pscustomer.Servic
|
|||||||
|
|
||||||
func (h *ProductHandler) Show(c echo.Context) error {
|
func (h *ProductHandler) Show(c echo.Context) error {
|
||||||
session := appmiddleware.GetSession(c)
|
session := appmiddleware.GetSession(c)
|
||||||
if session == nil {
|
|
||||||
session = appmiddleware.GetSession(c)
|
|
||||||
}
|
|
||||||
if h == nil || h.products == nil || h.renderer == nil {
|
if h == nil || h.products == nil || h.renderer == nil {
|
||||||
return echo.NewHTTPError(http.StatusInternalServerError, "product handler is not initialized")
|
return echo.NewHTTPError(http.StatusInternalServerError, "product handler is not initialized")
|
||||||
}
|
}
|
||||||
@@ -91,6 +88,16 @@ func (h *ProductHandler) Show(c echo.Context) error {
|
|||||||
CartSummary: cartSummary,
|
CartSummary: cartSummary,
|
||||||
ShopBaseURL: h.config.PrestaShopBaseURL,
|
ShopBaseURL: h.config.PrestaShopBaseURL,
|
||||||
}
|
}
|
||||||
|
menu, err := loadMenu(c.Request(), h.products, h.categories, languageID, shopID)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "menu query failed: "+err.Error())
|
||||||
|
}
|
||||||
|
page.Menu = menu
|
||||||
|
locale, err := loadHeaderLocale(c.Request(), h.products, session, languageID)
|
||||||
|
if err != nil {
|
||||||
|
return echo.NewHTTPError(http.StatusInternalServerError, "locale query failed: "+err.Error())
|
||||||
|
}
|
||||||
|
page.Locale = locale
|
||||||
|
|
||||||
return h.renderer.Product(c.Response(), c.Request(), page)
|
return h.renderer.Product(c.Response(), c.Request(), page)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
package middleware
|
package middleware
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"prestaproxy/internal/prestashop/cookie"
|
"git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ import (
|
|||||||
"context"
|
"context"
|
||||||
"fmt"
|
"fmt"
|
||||||
"hash/crc32"
|
"hash/crc32"
|
||||||
|
"net"
|
||||||
"net/http"
|
"net/http"
|
||||||
"net/url"
|
"net/url"
|
||||||
"path"
|
"path"
|
||||||
@@ -12,8 +13,8 @@ import (
|
|||||||
|
|
||||||
"github.com/labstack/echo/v4"
|
"github.com/labstack/echo/v4"
|
||||||
|
|
||||||
psconfig "prestaproxy/internal/prestashop/config"
|
psconfig "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/config"
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
)
|
)
|
||||||
|
|
||||||
type AnonymousSessionInitializer interface {
|
type AnonymousSessionInitializer interface {
|
||||||
@@ -62,6 +63,7 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
|
|||||||
}
|
}
|
||||||
if ownedRoute {
|
if ownedRoute {
|
||||||
applyRequestLanguage(session, resolveRequestLanguageID(c.Request().Context(), c.Request(), session, languageResolver))
|
applyRequestLanguage(session, resolveRequestLanguageID(c.Request().Context(), c.Request(), session, languageResolver))
|
||||||
|
applyRequestMarket(session, requestMarketSelection(c.Request()))
|
||||||
}
|
}
|
||||||
if ownedRoute && shouldSetSessionCookie(rawCookie, session) {
|
if ownedRoute && shouldSetSessionCookie(rawCookie, session) {
|
||||||
encoded, err := codec.Encode(session)
|
encoded, err := codec.Encode(session)
|
||||||
@@ -70,6 +72,9 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
|
|||||||
}
|
}
|
||||||
session.RawCookie = encoded
|
session.RawCookie = encoded
|
||||||
setPrestaShopCookie(c.Request(), c.Response(), ownership.ProductPrefixes, cookieName, encoded)
|
setPrestaShopCookie(c.Request(), c.Response(), ownership.ProductPrefixes, cookieName, encoded)
|
||||||
|
if redirectURL, ok := clearMarketSelectionURL(c.Request()); ok {
|
||||||
|
return c.Redirect(http.StatusSeeOther, redirectURL)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
SetSession(c, session)
|
SetSession(c, session)
|
||||||
@@ -78,6 +83,12 @@ func Session(cfg psconfig.Config, codec pscookie.Codec, initializer AnonymousSes
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type marketSelection struct {
|
||||||
|
CountryID int64
|
||||||
|
CountryISO string
|
||||||
|
CurrencyID int64
|
||||||
|
}
|
||||||
|
|
||||||
func resolveRequestLanguageID(ctx context.Context, req *http.Request, session *pscookie.SessionContext, resolver LanguageResolver) int64 {
|
func resolveRequestLanguageID(ctx context.Context, req *http.Request, session *pscookie.SessionContext, resolver LanguageResolver) int64 {
|
||||||
if resolver == nil {
|
if resolver == nil {
|
||||||
return 0
|
return 0
|
||||||
@@ -177,6 +188,50 @@ func applyRequestLanguage(session *pscookie.SessionContext, languageID int64) {
|
|||||||
session.RawCookie = ""
|
session.RawCookie = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func applyRequestMarket(session *pscookie.SessionContext, selection marketSelection) {
|
||||||
|
if session == nil || selection.CountryISO == "" || selection.CurrencyID == 0 {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
currentCountry := ""
|
||||||
|
currentCurrency := int64(0)
|
||||||
|
currentCountryID := int64(0)
|
||||||
|
if session.Values != nil {
|
||||||
|
currentCountry = strings.ToUpper(strings.TrimSpace(session.Values["iso_code_country"]))
|
||||||
|
if session.CurrencyID != nil {
|
||||||
|
currentCurrency = *session.CurrencyID
|
||||||
|
}
|
||||||
|
currentCountryID, _ = strconv.ParseInt(session.Values["id_country"], 10, 64)
|
||||||
|
}
|
||||||
|
if currentCountry == selection.CountryISO && currentCurrency == selection.CurrencyID && currentCountryID == selection.CountryID {
|
||||||
|
return
|
||||||
|
}
|
||||||
|
|
||||||
|
if session.Values == nil {
|
||||||
|
session.Values = map[string]string{}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.CurrencyID = int64Ptr(selection.CurrencyID)
|
||||||
|
session.Values["iso_code_country"] = selection.CountryISO
|
||||||
|
if selection.CountryID > 0 {
|
||||||
|
session.Values["id_country"] = strconv.FormatInt(selection.CountryID, 10)
|
||||||
|
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_country", 5)
|
||||||
|
}
|
||||||
|
session.Values["id_currency"] = strconv.FormatInt(selection.CurrencyID, 10)
|
||||||
|
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "iso_code_country", 4)
|
||||||
|
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "id_currency", 6)
|
||||||
|
|
||||||
|
if !session.IsLoggedIn {
|
||||||
|
if checksum := anonymousSessionChecksum(session, sessionLanguageID(session)); checksum != "" {
|
||||||
|
session.Values["checksum"] = checksum
|
||||||
|
session.OrderedKeys = ensureOrderedKey(session.OrderedKeys, "checksum", len(session.OrderedKeys))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
session.Plaintext = ""
|
||||||
|
session.RawCookie = ""
|
||||||
|
}
|
||||||
|
|
||||||
func sessionLanguageID(session *pscookie.SessionContext) int64 {
|
func sessionLanguageID(session *pscookie.SessionContext) int64 {
|
||||||
if session == nil || session.LanguageID == nil {
|
if session == nil || session.LanguageID == nil {
|
||||||
return 0
|
return 0
|
||||||
@@ -237,6 +292,67 @@ func int64Ptr(value int64) *int64 {
|
|||||||
return &v
|
return &v
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func requestMarketSelection(req *http.Request) marketSelection {
|
||||||
|
if req == nil || req.URL == nil {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
raw := strings.TrimSpace(req.URL.Query().Get("market"))
|
||||||
|
if raw == "" {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
parts := strings.Split(raw, ":")
|
||||||
|
if len(parts) != 2 && len(parts) != 3 {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
|
||||||
|
selection := marketSelection{}
|
||||||
|
var countryISO string
|
||||||
|
var currencyValue string
|
||||||
|
if len(parts) == 3 {
|
||||||
|
countryID, err := strconv.ParseInt(strings.TrimSpace(parts[0]), 10, 64)
|
||||||
|
if err != nil || countryID == 0 {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
selection.CountryID = countryID
|
||||||
|
countryISO = strings.ToUpper(strings.TrimSpace(parts[1]))
|
||||||
|
currencyValue = parts[2]
|
||||||
|
} else {
|
||||||
|
countryISO = strings.ToUpper(strings.TrimSpace(parts[0]))
|
||||||
|
currencyValue = parts[1]
|
||||||
|
}
|
||||||
|
|
||||||
|
currencyID, err := strconv.ParseInt(strings.TrimSpace(currencyValue), 10, 64)
|
||||||
|
if err != nil || currencyID == 0 {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
if len(countryISO) < 2 || len(countryISO) > 5 {
|
||||||
|
return marketSelection{}
|
||||||
|
}
|
||||||
|
|
||||||
|
selection.CountryISO = countryISO
|
||||||
|
selection.CurrencyID = currencyID
|
||||||
|
return selection
|
||||||
|
}
|
||||||
|
|
||||||
|
func clearMarketSelectionURL(req *http.Request) (string, bool) {
|
||||||
|
if req == nil || req.URL == nil {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
query := req.URL.Query()
|
||||||
|
if query.Get("market") == "" {
|
||||||
|
return "", false
|
||||||
|
}
|
||||||
|
query.Del("market")
|
||||||
|
cleanPath := req.URL.Path
|
||||||
|
if cleanPath == "" {
|
||||||
|
cleanPath = "/"
|
||||||
|
}
|
||||||
|
if encoded := query.Encode(); encoded != "" {
|
||||||
|
return cleanPath + "?" + encoded, true
|
||||||
|
}
|
||||||
|
return cleanPath, true
|
||||||
|
}
|
||||||
|
|
||||||
func setPrestaShopCookie(req *http.Request, res *echo.Response, ownedPrefixes []string, name, value string) {
|
func setPrestaShopCookie(req *http.Request, res *echo.Response, ownedPrefixes []string, name, value string) {
|
||||||
http.SetCookie(res.Writer, &http.Cookie{
|
http.SetCookie(res.Writer, &http.Cookie{
|
||||||
Name: name,
|
Name: name,
|
||||||
@@ -277,7 +393,11 @@ func requestCookieDomain(req *http.Request) string {
|
|||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
if parsed, err := url.Parse("http://" + host); err == nil {
|
if parsed, err := url.Parse("http://" + host); err == nil {
|
||||||
return parsed.Hostname()
|
host = parsed.Hostname()
|
||||||
|
}
|
||||||
|
host = strings.TrimSpace(strings.TrimPrefix(host, "."))
|
||||||
|
if host == "" || strings.EqualFold(host, "localhost") || net.ParseIP(host) != nil {
|
||||||
|
return ""
|
||||||
}
|
}
|
||||||
return host
|
return host
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -55,6 +55,32 @@ type CategoryProductCard struct {
|
|||||||
EAN13 string
|
EAN13 string
|
||||||
}
|
}
|
||||||
|
|
||||||
|
type MenuItem struct {
|
||||||
|
ID int64
|
||||||
|
ParentID int64
|
||||||
|
Name string
|
||||||
|
Slug string
|
||||||
|
Depth int
|
||||||
|
URL string `gorm:"-"`
|
||||||
|
Children []MenuItem `gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type LocaleOption struct {
|
||||||
|
ID int64
|
||||||
|
CurrencyID int64 `gorm:"column:currency_id"`
|
||||||
|
Label string
|
||||||
|
Code string
|
||||||
|
Meta string
|
||||||
|
URL string `gorm:"-"`
|
||||||
|
}
|
||||||
|
|
||||||
|
type HeaderLocaleData struct {
|
||||||
|
CurrentLanguage LocaleOption
|
||||||
|
CurrentCountry LocaleOption
|
||||||
|
Languages []LocaleOption
|
||||||
|
Countries []LocaleOption
|
||||||
|
}
|
||||||
|
|
||||||
type Service struct {
|
type Service struct {
|
||||||
db *gorm.DB
|
db *gorm.DB
|
||||||
prefix string
|
prefix string
|
||||||
@@ -239,3 +265,237 @@ func (s *Service) ResolveLanguageID(ctx context.Context, req *http.Request, fall
|
|||||||
}
|
}
|
||||||
return row.ID
|
return row.ID
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetCategoryMenu(ctx context.Context, languageID int64, shopID int64) ([]MenuItem, error) {
|
||||||
|
rootCategoryID, err := s.rootCategoryID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
|
||||||
|
query := fmt.Sprintf(`
|
||||||
|
WITH RECURSIVE category_tree AS (
|
||||||
|
SELECT c.id_category AS id,
|
||||||
|
c.id_parent AS parent_id,
|
||||||
|
cl.name AS name,
|
||||||
|
cl.link_rewrite AS slug,
|
||||||
|
0 AS depth
|
||||||
|
FROM %scategory c
|
||||||
|
JOIN %scategory_shop cs ON cs.id_category = c.id_category
|
||||||
|
JOIN %scategory_lang cl ON cl.id_category = c.id_category
|
||||||
|
WHERE c.id_parent = ?
|
||||||
|
AND c.active = 1
|
||||||
|
AND cs.id_shop = ?
|
||||||
|
AND cl.id_lang = ?
|
||||||
|
UNION ALL
|
||||||
|
SELECT c.id_category AS id,
|
||||||
|
c.id_parent AS parent_id,
|
||||||
|
cl.name AS name,
|
||||||
|
cl.link_rewrite AS slug,
|
||||||
|
tree.depth + 1 AS depth
|
||||||
|
FROM %scategory c
|
||||||
|
JOIN %scategory_shop cs ON cs.id_category = c.id_category
|
||||||
|
JOIN %scategory_lang cl ON cl.id_category = c.id_category
|
||||||
|
JOIN category_tree tree ON tree.id = c.id_parent
|
||||||
|
WHERE c.active = 1
|
||||||
|
AND cs.id_shop = ?
|
||||||
|
AND cl.id_lang = ?
|
||||||
|
)
|
||||||
|
SELECT id, parent_id, name, slug, depth
|
||||||
|
FROM category_tree
|
||||||
|
ORDER BY depth ASC, parent_id ASC, name ASC
|
||||||
|
`, s.prefix, s.prefix, s.prefix, s.prefix, s.prefix, s.prefix)
|
||||||
|
|
||||||
|
var flat []MenuItem
|
||||||
|
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(query), rootCategoryID, shopID, languageID, shopID, languageID).Scan(&flat).Error; err != nil {
|
||||||
|
return nil, err
|
||||||
|
}
|
||||||
|
if len(flat) == 0 {
|
||||||
|
return nil, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
nodes := make(map[int64]MenuItem, len(flat))
|
||||||
|
childrenByParent := make(map[int64][]int64, len(flat))
|
||||||
|
for i := range flat {
|
||||||
|
item := flat[i]
|
||||||
|
nodes[item.ID] = item
|
||||||
|
childrenByParent[item.ParentID] = append(childrenByParent[item.ParentID], item.ID)
|
||||||
|
}
|
||||||
|
|
||||||
|
rootIDs := childrenByParent[rootCategoryID]
|
||||||
|
roots := make([]MenuItem, 0, len(rootIDs))
|
||||||
|
for _, id := range rootIDs {
|
||||||
|
if item, ok := buildMenuTree(id, nodes, childrenByParent); ok {
|
||||||
|
roots = append(roots, item)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return roots, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) GetHeaderLocale(ctx context.Context, languageID int64, currencyID int64, countryISO string) (HeaderLocaleData, error) {
|
||||||
|
var locale HeaderLocaleData
|
||||||
|
defaultCurrencyID, err := s.defaultCurrencyID(ctx)
|
||||||
|
if err != nil {
|
||||||
|
return HeaderLocaleData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
languageQuery := fmt.Sprintf(`
|
||||||
|
SELECT id_lang AS id,
|
||||||
|
name AS label,
|
||||||
|
UPPER(iso_code) AS code,
|
||||||
|
COALESCE(NULLIF(language_code, ''), UPPER(iso_code)) AS meta
|
||||||
|
FROM %slang
|
||||||
|
WHERE active = 1
|
||||||
|
ORDER BY id_lang ASC
|
||||||
|
`, s.prefix)
|
||||||
|
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(languageQuery)).Scan(&locale.Languages).Error; err != nil {
|
||||||
|
return HeaderLocaleData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
hasCountryCurrency, err := s.columnExists(ctx, s.prefix+"country", "id_currency")
|
||||||
|
if err != nil {
|
||||||
|
return HeaderLocaleData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
var countryQuery string
|
||||||
|
var countryArgs []any
|
||||||
|
if hasCountryCurrency {
|
||||||
|
countryQuery = fmt.Sprintf(`
|
||||||
|
SELECT c.id_country AS id,
|
||||||
|
COALESCE(c.id_currency, ?) AS currency_id,
|
||||||
|
cl.name AS label,
|
||||||
|
UPPER(c.iso_code) AS code,
|
||||||
|
TRIM(CONCAT(COALESCE(UPPER(cur.iso_code), ''), ' ', COALESCE(cur.sign, ''))) AS meta
|
||||||
|
FROM %scountry c
|
||||||
|
JOIN %scountry_lang cl ON cl.id_country = c.id_country
|
||||||
|
LEFT JOIN %scurrency cur ON cur.id_currency = c.id_currency
|
||||||
|
WHERE c.active = 1
|
||||||
|
AND cl.id_lang = ?
|
||||||
|
ORDER BY cl.name ASC
|
||||||
|
`, s.prefix, s.prefix, s.prefix)
|
||||||
|
countryArgs = []any{defaultCurrencyID, languageID}
|
||||||
|
} else {
|
||||||
|
countryQuery = fmt.Sprintf(`
|
||||||
|
SELECT c.id_country AS id,
|
||||||
|
? AS currency_id,
|
||||||
|
cl.name AS label,
|
||||||
|
UPPER(c.iso_code) AS code,
|
||||||
|
UPPER(c.iso_code) AS meta
|
||||||
|
FROM %scountry c
|
||||||
|
JOIN %scountry_lang cl ON cl.id_country = c.id_country
|
||||||
|
WHERE c.active = 1
|
||||||
|
AND cl.id_lang = ?
|
||||||
|
ORDER BY cl.name ASC
|
||||||
|
`, s.prefix, s.prefix)
|
||||||
|
countryArgs = []any{defaultCurrencyID, languageID}
|
||||||
|
}
|
||||||
|
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(countryQuery), countryArgs...).Scan(&locale.Countries).Error; err != nil {
|
||||||
|
return HeaderLocaleData{}, err
|
||||||
|
}
|
||||||
|
|
||||||
|
locale.CurrentLanguage = pickLocaleOptionByID(locale.Languages, languageID)
|
||||||
|
locale.CurrentCountry = pickLocaleOptionByCode(locale.Countries, countryISO)
|
||||||
|
return locale, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) rootCategoryID(ctx context.Context) (int64, error) {
|
||||||
|
var row struct {
|
||||||
|
Value string `gorm:"column:value"`
|
||||||
|
}
|
||||||
|
query := fmt.Sprintf("SELECT value FROM %sconfiguration WHERE name = 'PS_ROOT_CATEGORY' LIMIT 1", s.prefix)
|
||||||
|
if err := s.db.WithContext(ctx).Raw(query).Scan(&row).Error; err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
id := parseInt64(row.Value)
|
||||||
|
if id == 0 {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) defaultCurrencyID(ctx context.Context) (int64, error) {
|
||||||
|
var row struct {
|
||||||
|
Value string `gorm:"column:value"`
|
||||||
|
}
|
||||||
|
query := fmt.Sprintf("SELECT value FROM %sconfiguration WHERE name = 'PS_CURRENCY_DEFAULT' LIMIT 1", s.prefix)
|
||||||
|
if err := s.db.WithContext(ctx).Raw(query).Scan(&row).Error; err != nil {
|
||||||
|
return 0, err
|
||||||
|
}
|
||||||
|
id := parseInt64(row.Value)
|
||||||
|
if id == 0 {
|
||||||
|
return 1, nil
|
||||||
|
}
|
||||||
|
return id, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func (s *Service) columnExists(ctx context.Context, tableName string, columnName string) (bool, error) {
|
||||||
|
var count int64
|
||||||
|
query := `
|
||||||
|
SELECT COUNT(*)
|
||||||
|
FROM information_schema.columns
|
||||||
|
WHERE table_schema = DATABASE()
|
||||||
|
AND table_name = ?
|
||||||
|
AND column_name = ?
|
||||||
|
`
|
||||||
|
if err := s.db.WithContext(ctx).Raw(strings.TrimSpace(query), tableName, columnName).Scan(&count).Error; err != nil {
|
||||||
|
return false, err
|
||||||
|
}
|
||||||
|
return count > 0, nil
|
||||||
|
}
|
||||||
|
|
||||||
|
func parseInt64(value string) int64 {
|
||||||
|
var n int64
|
||||||
|
for _, r := range value {
|
||||||
|
if r < '0' || r > '9' {
|
||||||
|
return 0
|
||||||
|
}
|
||||||
|
n = n*10 + int64(r-'0')
|
||||||
|
}
|
||||||
|
return n
|
||||||
|
}
|
||||||
|
|
||||||
|
func buildMenuTree(id int64, nodes map[int64]MenuItem, childrenByParent map[int64][]int64) (MenuItem, bool) {
|
||||||
|
item, ok := nodes[id]
|
||||||
|
if !ok {
|
||||||
|
return MenuItem{}, false
|
||||||
|
}
|
||||||
|
childIDs := childrenByParent[id]
|
||||||
|
if len(childIDs) == 0 {
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
item.Children = make([]MenuItem, 0, len(childIDs))
|
||||||
|
for _, childID := range childIDs {
|
||||||
|
child, ok := buildMenuTree(childID, nodes, childrenByParent)
|
||||||
|
if ok {
|
||||||
|
item.Children = append(item.Children, child)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return item, true
|
||||||
|
}
|
||||||
|
|
||||||
|
func pickLocaleOptionByID(options []LocaleOption, id int64) LocaleOption {
|
||||||
|
for _, option := range options {
|
||||||
|
if option.ID == id && id != 0 {
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(options) > 0 {
|
||||||
|
return options[0]
|
||||||
|
}
|
||||||
|
return LocaleOption{}
|
||||||
|
}
|
||||||
|
|
||||||
|
func pickLocaleOptionByCode(options []LocaleOption, code string) LocaleOption {
|
||||||
|
code = strings.ToUpper(strings.TrimSpace(code))
|
||||||
|
for _, option := range options {
|
||||||
|
if option.Code == code && code != "" {
|
||||||
|
return option
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(options) > 0 {
|
||||||
|
return options[0]
|
||||||
|
}
|
||||||
|
if code == "" {
|
||||||
|
return LocaleOption{}
|
||||||
|
}
|
||||||
|
return LocaleOption{Code: code, Label: code, Meta: code}
|
||||||
|
}
|
||||||
|
|||||||
@@ -13,7 +13,7 @@ import (
|
|||||||
"regexp"
|
"regexp"
|
||||||
"strings"
|
"strings"
|
||||||
|
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Config struct {
|
type Config struct {
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ import (
|
|||||||
"strings"
|
"strings"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
|
|
||||||
"gorm.io/gorm"
|
"gorm.io/gorm"
|
||||||
)
|
)
|
||||||
|
|||||||
@@ -3,9 +3,9 @@ package render
|
|||||||
import (
|
import (
|
||||||
"net/http"
|
"net/http"
|
||||||
|
|
||||||
"prestaproxy/internal/assets"
|
"git.ma-al.com/goc_marek/ps_shop/internal/assets"
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
"prestaproxy/templates"
|
"git.ma-al.com/goc_marek/ps_shop/templates"
|
||||||
)
|
)
|
||||||
|
|
||||||
type Engine struct {
|
type Engine struct {
|
||||||
|
|||||||
@@ -1,14 +1,16 @@
|
|||||||
package viewmodel
|
package viewmodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
pscart "prestaproxy/internal/prestashop/cart"
|
pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
|
||||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type CategoryPageData struct {
|
type CategoryPageData struct {
|
||||||
Category pscatalog.CategoryPageData
|
Category pscatalog.CategoryPageData
|
||||||
|
Menu []pscatalog.MenuItem
|
||||||
|
Locale pscatalog.HeaderLocaleData
|
||||||
Session *pscookie.SessionContext
|
Session *pscookie.SessionContext
|
||||||
Customer *pscustomer.Profile
|
Customer *pscustomer.Profile
|
||||||
CartSummary *pscart.Summary
|
CartSummary *pscart.Summary
|
||||||
|
|||||||
@@ -1,15 +1,17 @@
|
|||||||
package viewmodel
|
package viewmodel
|
||||||
|
|
||||||
import (
|
import (
|
||||||
pscart "prestaproxy/internal/prestashop/cart"
|
pscart "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cart"
|
||||||
pscatalog "prestaproxy/internal/prestashop/catalog"
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
pscookie "prestaproxy/internal/prestashop/cookie"
|
pscookie "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/cookie"
|
||||||
pscustomer "prestaproxy/internal/prestashop/customer"
|
pscustomer "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/customer"
|
||||||
)
|
)
|
||||||
|
|
||||||
type ProductPageData struct {
|
type ProductPageData struct {
|
||||||
Product pscatalog.ProductPageData
|
Product pscatalog.ProductPageData
|
||||||
CategoryURL string
|
CategoryURL string
|
||||||
|
Menu []pscatalog.MenuItem
|
||||||
|
Locale pscatalog.HeaderLocaleData
|
||||||
Session *pscookie.SessionContext
|
Session *pscookie.SessionContext
|
||||||
Customer *pscustomer.Profile
|
Customer *pscustomer.Profile
|
||||||
CartSummary *pscart.Summary
|
CartSummary *pscart.Summary
|
||||||
|
|||||||
+3
-3
@@ -1,9 +1,9 @@
|
|||||||
{
|
{
|
||||||
"name": "prestaproxy",
|
"name": "ps_shop",
|
||||||
"private": true,
|
"private": true,
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"build:js": "bun build ./web/src/app.js --outdir ./web/dist --naming app.js",
|
"build:js": "bun build ./web/src/app.js --outfile ./web/dist/app.js --target browser --minify",
|
||||||
"build:css": "bunx tailwindcss -i ./web/src/app.css -o ./web/dist/app.css --minify",
|
"build:css": "env BUN_TMPDIR=/tmp bunx tailwindcss -i ./web/src/app.css -o ./web/dist/app.css --minify",
|
||||||
"build:manifest": "bun ./web/write-manifest.mjs",
|
"build:manifest": "bun ./web/write-manifest.mjs",
|
||||||
"build": "bun run build:js && bun run build:css && bun run build:manifest",
|
"build": "bun run build:js && bun run build:css && bun run build:manifest",
|
||||||
"dev": "bun run build"
|
"dev": "bun run build"
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package templates
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
templ CategoryPage(data viewmodel.CategoryPageData, cssPath string, jsPath string) {
|
templ CategoryPage(data viewmodel.CategoryPageData, cssPath string, jsPath string) {
|
||||||
@Layout(data.Category.Name, cssPath, jsPath) {
|
@Layout(data.Category.Name, cssPath, jsPath, data.Menu, data.Locale) {
|
||||||
<main class="min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(34,197,94,0.18),_transparent_35%),linear-gradient(180deg,#0b1020,#111827)]">
|
<main class="min-h-screen bg-[radial-gradient(circle_at_top_left,_rgba(34,197,94,0.18),_transparent_35%),linear-gradient(180deg,#0b1020,#111827)]">
|
||||||
<div class="mx-auto flex max-w-7xl flex-col gap-10 px-6 py-10 lg:px-8">
|
<div class="mx-auto flex max-w-7xl flex-col gap-10 px-6 py-10 lg:px-8">
|
||||||
<header class="rounded-[2rem] border border-emerald-500/20 bg-white/5 p-8 backdrop-blur">
|
<header class="rounded-[2rem] border border-emerald-500/20 bg-white/5 p-8 backdrop-blur">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import templruntime "github.com/a-h/templ/runtime"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func CategoryPage(data viewmodel.CategoryPageData, cssPath string, jsPath string) templ.Component {
|
func CategoryPage(data viewmodel.CategoryPageData, cssPath string, jsPath string) templ.Component {
|
||||||
@@ -187,7 +187,7 @@ func CategoryPage(data viewmodel.CategoryPageData, cssPath string, jsPath string
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
templ_7745c5c3_Err = Layout(data.Category.Name, cssPath, jsPath).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
templ_7745c5c3_Err = Layout(data.Category.Name, cssPath, jsPath, data.Menu, data.Locale).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
|||||||
+180
-3
@@ -1,8 +1,10 @@
|
|||||||
package templates
|
package templates
|
||||||
|
|
||||||
templ Layout(title string, cssPath string, jsPath string) {
|
import pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
|
|
||||||
|
templ Layout(title string, cssPath string, jsPath string, menu []pscatalog.MenuItem, locale pscatalog.HeaderLocaleData) {
|
||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang={ pageLanguage(locale) }>
|
||||||
<head>
|
<head>
|
||||||
<meta charset="utf-8"/>
|
<meta charset="utf-8"/>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
@@ -10,8 +12,183 @@ templ Layout(title string, cssPath string, jsPath string) {
|
|||||||
<link rel="stylesheet" href={ cssPath }/>
|
<link rel="stylesheet" href={ cssPath }/>
|
||||||
<script type="module" src={ jsPath } defer></script>
|
<script type="module" src={ jsPath } defer></script>
|
||||||
</head>
|
</head>
|
||||||
<body class="bg-stone-950 text-stone-100 antialiased">
|
<body class="min-h-screen text-stone-900 antialiased">
|
||||||
|
<header class="site-header">
|
||||||
|
<div class="utility-bar">
|
||||||
|
<div class="site-container flex flex-wrap items-center justify-between gap-3 py-3 text-[0.92rem] text-stone-700">
|
||||||
|
<div class="flex flex-wrap items-center gap-x-6 gap-y-2">
|
||||||
|
<a class="inline-flex items-center gap-2 transition hover:text-amber-600" href="mailto:info@9b-plus.com">
|
||||||
|
<span class="text-base">✉</span>
|
||||||
|
<span>info@9b-plus.com</span>
|
||||||
|
</a>
|
||||||
|
<a class="inline-flex items-center gap-2 transition hover:text-amber-600" href="tel:+420533312341">
|
||||||
|
<span class="text-base">☎</span>
|
||||||
|
<span>+420 533 312 341</span>
|
||||||
|
</a>
|
||||||
|
</div>
|
||||||
|
if hasHeaderLocale(locale) {
|
||||||
|
<div class="header-locale">
|
||||||
|
@LocalePicker("Market", locale.CurrentCountry, locale.Countries, true)
|
||||||
|
@LocalePicker("Language", locale.CurrentLanguage, locale.Languages, true)
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
<div class="main-nav">
|
||||||
|
<div class="site-container header-bar">
|
||||||
|
<a class="brand-mark shrink-0" href="/">
|
||||||
|
<span class="brand-mark__strong">9b</span>
|
||||||
|
<span class="brand-mark__accent">plus</span>
|
||||||
|
</a>
|
||||||
|
<div class="ml-auto flex items-center gap-3 lg:hidden">
|
||||||
|
<button class="menu-toggle" type="button" aria-expanded="false" aria-controls="site-menu" data-menu-toggle>
|
||||||
|
Menu
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
if len(menu) > 0 {
|
||||||
|
<nav class="menu-panel hidden basis-full lg:ml-10 lg:flex lg:min-w-0 lg:flex-1 lg:basis-auto lg:items-center lg:justify-center" id="site-menu" data-menu-panel>
|
||||||
|
<div class="w-full lg:hidden">
|
||||||
|
@MenuTree(menu, 0)
|
||||||
|
</div>
|
||||||
|
<div class="hidden w-full lg:block">
|
||||||
|
@MegaMenuBar(menu)
|
||||||
|
</div>
|
||||||
|
</nav>
|
||||||
|
}
|
||||||
|
<div class="header-actions">
|
||||||
|
<a class="nav-icon" href="#" aria-label="Search">⌕</a>
|
||||||
|
<a class="nav-icon" href="#" aria-label="Cart">🛒</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</header>
|
||||||
{ children... }
|
{ children... }
|
||||||
</body>
|
</body>
|
||||||
</html>
|
</html>
|
||||||
}
|
}
|
||||||
|
|
||||||
|
templ LocalePicker(title string, current pscatalog.LocaleOption, options []pscatalog.LocaleOption, navigable bool) {
|
||||||
|
<details class="locale-picker">
|
||||||
|
<summary class="locale-picker__summary">
|
||||||
|
<span class="locale-picker__value">
|
||||||
|
if current.Label != "" {
|
||||||
|
{ current.Label }
|
||||||
|
} else {
|
||||||
|
{ title }
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
if current.Code != "" {
|
||||||
|
<span class="locale-picker__code">{ current.Code }</span>
|
||||||
|
}
|
||||||
|
<span class="locale-picker__chevron">⌄</span>
|
||||||
|
</summary>
|
||||||
|
if len(options) > 0 {
|
||||||
|
<div class="locale-picker__panel">
|
||||||
|
<p class="locale-picker__title">{ title }</p>
|
||||||
|
<ul class="space-y-1">
|
||||||
|
for _, option := range options {
|
||||||
|
<li>
|
||||||
|
if navigable && option.URL != "" {
|
||||||
|
<a class={ localeOptionClass(option, current) } href={ option.URL }>
|
||||||
|
<span>{ option.Label }</span>
|
||||||
|
if option.Meta != "" {
|
||||||
|
<span class="locale-picker__item-meta">{ option.Meta }</span>
|
||||||
|
} else if option.Code != "" {
|
||||||
|
<span class="locale-picker__item-meta">{ option.Code }</span>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
} else {
|
||||||
|
<span class={ localeOptionClass(option, current) }>
|
||||||
|
<span>{ option.Label }</span>
|
||||||
|
if option.Meta != "" {
|
||||||
|
<span class="locale-picker__item-meta">{ option.Meta }</span>
|
||||||
|
}
|
||||||
|
</span>
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
</details>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ MenuTree(items []pscatalog.MenuItem, depth int) {
|
||||||
|
<ul class={ menuListClass(depth) }>
|
||||||
|
for _, item := range items {
|
||||||
|
<li class={ menuItemClass(depth, len(item.Children) > 0) }>
|
||||||
|
<a class={ menuLinkClass(depth) } href={ item.URL }>
|
||||||
|
{ item.Name }
|
||||||
|
if depth == 0 && len(item.Children) > 0 {
|
||||||
|
<span class="text-[0.65rem] text-amber-300/80">+</span>
|
||||||
|
}
|
||||||
|
</a>
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
@MenuTree(item.Children, depth + 1)
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ MegaMenuBar(items []pscatalog.MenuItem) {
|
||||||
|
<ul class="desktop-nav">
|
||||||
|
for _, item := range items {
|
||||||
|
<li class={ desktopNavItemClass(len(item.Children) > 0) }>
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
<div class="desktop-nav__item">
|
||||||
|
<a
|
||||||
|
class={ desktopNavLinkClass() }
|
||||||
|
href={ item.URL }
|
||||||
|
aria-label={ "Open " + item.Name + " submenu" }
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls={ menuPanelID(item.ID) }
|
||||||
|
data-mega-trigger
|
||||||
|
data-mega-target={ menuPanelID(item.ID) }>{ item.Name }</a>
|
||||||
|
<button
|
||||||
|
class="desktop-nav__toggle"
|
||||||
|
type="button"
|
||||||
|
aria-label={ "Open " + item.Name + " submenu" }
|
||||||
|
aria-expanded="false"
|
||||||
|
aria-controls={ menuPanelID(item.ID) }
|
||||||
|
data-mega-trigger
|
||||||
|
data-mega-target={ menuPanelID(item.ID) }>
|
||||||
|
⌄
|
||||||
|
</button>
|
||||||
|
</div>
|
||||||
|
} else {
|
||||||
|
<a class={ desktopNavLinkClass() } href={ item.URL }>{ item.Name }</a>
|
||||||
|
}
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
@MegaMenu(item.ID, item.URL, item.Name, item.Children)
|
||||||
|
}
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
}
|
||||||
|
|
||||||
|
templ MegaMenu(id int64, href string, label string, columns []pscatalog.MenuItem) {
|
||||||
|
<div class="mega-menu hidden" id={ menuPanelID(id) } data-mega-menu>
|
||||||
|
<div class="mega-menu__grid">
|
||||||
|
for _, column := range columns {
|
||||||
|
<div class="mega-menu__column">
|
||||||
|
<a class="mega-menu__heading" href={ column.URL }>{ column.Name }</a>
|
||||||
|
if len(column.Children) > 0 {
|
||||||
|
<ul class="space-y-3">
|
||||||
|
for _, child := range column.Children {
|
||||||
|
<li>
|
||||||
|
<a class="mega-menu__link" href={ child.URL }>{ child.Name }</a>
|
||||||
|
</li>
|
||||||
|
}
|
||||||
|
</ul>
|
||||||
|
} else {
|
||||||
|
<a class="mega-menu__link" href={ column.URL }>View all</a>
|
||||||
|
}
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
<div class="mega-menu__all">
|
||||||
|
<a class="mega-menu__all-link" href={ href }>{ label }</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
}
|
||||||
|
|||||||
@@ -0,0 +1,78 @@
|
|||||||
|
package templates
|
||||||
|
|
||||||
|
import (
|
||||||
|
"strconv"
|
||||||
|
"strings"
|
||||||
|
|
||||||
|
pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
|
)
|
||||||
|
|
||||||
|
func menuListClass(depth int) string {
|
||||||
|
if depth == 0 {
|
||||||
|
return "flex min-w-0 flex-col gap-2 text-sm"
|
||||||
|
}
|
||||||
|
return "mt-2 space-y-2 border-l border-stone-200 pl-4 text-sm"
|
||||||
|
}
|
||||||
|
|
||||||
|
func menuLinkClass(depth int) string {
|
||||||
|
if depth == 0 {
|
||||||
|
return "inline-flex items-center gap-2 px-2 py-2 text-[1.02rem] font-medium text-stone-900 transition hover:text-amber-600"
|
||||||
|
}
|
||||||
|
return "inline-flex items-center gap-2 text-stone-700 transition hover:text-amber-600"
|
||||||
|
}
|
||||||
|
|
||||||
|
func menuItemClass(depth int, hasChildren bool) string {
|
||||||
|
if depth == 0 && hasChildren {
|
||||||
|
return "min-w-0"
|
||||||
|
}
|
||||||
|
return "min-w-0"
|
||||||
|
}
|
||||||
|
|
||||||
|
func desktopNavItemClass(hasChildren bool) string {
|
||||||
|
if hasChildren {
|
||||||
|
return "desktop-nav__entry desktop-nav__entry--has-children"
|
||||||
|
}
|
||||||
|
return "desktop-nav__entry"
|
||||||
|
}
|
||||||
|
|
||||||
|
func desktopNavLinkClass() string {
|
||||||
|
return "desktop-nav__link"
|
||||||
|
}
|
||||||
|
|
||||||
|
func hasHeaderLocale(locale pscatalog.HeaderLocaleData) bool {
|
||||||
|
return len(locale.Languages) > 0 || len(locale.Countries) > 0
|
||||||
|
}
|
||||||
|
|
||||||
|
func pageLanguage(locale pscatalog.HeaderLocaleData) string {
|
||||||
|
code := strings.TrimSpace(locale.CurrentLanguage.Code)
|
||||||
|
if code == "" {
|
||||||
|
return "en"
|
||||||
|
}
|
||||||
|
return strings.ToLower(code)
|
||||||
|
}
|
||||||
|
|
||||||
|
func localeOptionClass(option pscatalog.LocaleOption, current pscatalog.LocaleOption) string {
|
||||||
|
base := "locale-picker__item"
|
||||||
|
if option.ID != 0 && option.ID == current.ID {
|
||||||
|
return base + " locale-picker__item--active"
|
||||||
|
}
|
||||||
|
if option.Code != "" && option.Code == current.Code {
|
||||||
|
return base + " locale-picker__item--active"
|
||||||
|
}
|
||||||
|
return base
|
||||||
|
}
|
||||||
|
|
||||||
|
func productInitial(name string) string {
|
||||||
|
name = strings.TrimSpace(name)
|
||||||
|
if name == "" {
|
||||||
|
return "P"
|
||||||
|
}
|
||||||
|
return strings.ToUpper(name[:1])
|
||||||
|
}
|
||||||
|
|
||||||
|
func menuPanelID(id int64) string {
|
||||||
|
if id <= 0 {
|
||||||
|
return "mega-menu-panel"
|
||||||
|
}
|
||||||
|
return "mega-menu-panel-" + strconv.FormatInt(id, 10)
|
||||||
|
}
|
||||||
+900
-14
@@ -8,7 +8,9 @@ package templates
|
|||||||
import "github.com/a-h/templ"
|
import "github.com/a-h/templ"
|
||||||
import templruntime "github.com/a-h/templ/runtime"
|
import templruntime "github.com/a-h/templ/runtime"
|
||||||
|
|
||||||
func Layout(title string, cssPath string, jsPath string) templ.Component {
|
import pscatalog "git.ma-al.com/goc_marek/ps_shop/internal/prestashop/catalog"
|
||||||
|
|
||||||
|
func Layout(title string, cssPath string, jsPath string, menu []pscatalog.MenuItem, locale pscatalog.HeaderLocaleData) templ.Component {
|
||||||
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
@@ -29,46 +31,107 @@ func Layout(title string, cssPath string, jsPath string) templ.Component {
|
|||||||
templ_7745c5c3_Var1 = templ.NopComponent
|
templ_7745c5c3_Var1 = templ.NopComponent
|
||||||
}
|
}
|
||||||
ctx = templ.ClearChildren(ctx)
|
ctx = templ.ClearChildren(ctx)
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"en\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 1, "<!doctype html><html lang=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var2 string
|
var templ_7745c5c3_Var2 string
|
||||||
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
templ_7745c5c3_Var2, templ_7745c5c3_Err = templ.JoinStringErrs(pageLanguage(locale))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 9, Col: 17}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 7, Col: 34}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var2))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "</title><link rel=\"stylesheet\" href=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 2, "\"><head><meta charset=\"utf-8\"><meta name=\"viewport\" content=\"width=device-width, initial-scale=1\"><title>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var3 templ.SafeURL
|
var templ_7745c5c3_Var3 string
|
||||||
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinURLErrs(cssPath)
|
templ_7745c5c3_Var3, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 10, Col: 40}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 11, Col: 17}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var3))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "\"><script type=\"module\" src=\"")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 3, "</title><link rel=\"stylesheet\" href=\"")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
var templ_7745c5c3_Var4 string
|
var templ_7745c5c3_Var4 templ.SafeURL
|
||||||
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinStringErrs(jsPath)
|
templ_7745c5c3_Var4, templ_7745c5c3_Err = templ.JoinURLErrs(cssPath)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 11, Col: 37}
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 12, Col: 40}
|
||||||
}
|
}
|
||||||
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var4))
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\" defer></script></head><body class=\"bg-stone-950 text-stone-100 antialiased\">")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 4, "\"><script type=\"module\" src=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var5 string
|
||||||
|
templ_7745c5c3_Var5, templ_7745c5c3_Err = templ.JoinStringErrs(jsPath)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 13, Col: 37}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var5))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "\" defer></script></head><body class=\"min-h-screen text-stone-900 antialiased\"><header class=\"site-header\"><div class=\"utility-bar\"><div class=\"site-container flex flex-wrap items-center justify-between gap-3 py-3 text-[0.92rem] text-stone-700\"><div class=\"flex flex-wrap items-center gap-x-6 gap-y-2\"><a class=\"inline-flex items-center gap-2 transition hover:text-amber-600\" href=\"mailto:info@9b-plus.com\"><span class=\"text-base\">✉</span> <span>info@9b-plus.com</span></a> <a class=\"inline-flex items-center gap-2 transition hover:text-amber-600\" href=\"tel:+420533312341\"><span class=\"text-base\">☎</span> <span>+420 533 312 341</span></a></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if hasHeaderLocale(locale) {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 6, "<div class=\"header-locale\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = LocalePicker("Market", locale.CurrentCountry, locale.Countries, true).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = LocalePicker("Language", locale.CurrentLanguage, locale.Languages, true).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 7, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 8, "</div></div><div class=\"main-nav\"><div class=\"site-container header-bar\"><a class=\"brand-mark shrink-0\" href=\"/\"><span class=\"brand-mark__strong\">9b</span> <span class=\"brand-mark__accent\">plus</span></a><div class=\"ml-auto flex items-center gap-3 lg:hidden\"><button class=\"menu-toggle\" type=\"button\" aria-expanded=\"false\" aria-controls=\"site-menu\" data-menu-toggle>Menu</button></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(menu) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 9, "<nav class=\"menu-panel hidden basis-full lg:ml-10 lg:flex lg:min-w-0 lg:flex-1 lg:basis-auto lg:items-center lg:justify-center\" id=\"site-menu\" data-menu-panel><div class=\"w-full lg:hidden\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = MenuTree(menu, 0).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 10, "</div><div class=\"hidden w-full lg:block\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = MegaMenuBar(menu).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 11, "</div></nav>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 12, "<div class=\"header-actions\"><a class=\"nav-icon\" href=\"#\" aria-label=\"Search\">⌕</a> <a class=\"nav-icon\" href=\"#\" aria-label=\"Cart\">🛒</a></div></div></div></header>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
@@ -76,7 +139,830 @@ func Layout(title string, cssPath string, jsPath string) templ.Component {
|
|||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 5, "</body></html>")
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 13, "</body></html>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func LocalePicker(title string, current pscatalog.LocaleOption, options []pscatalog.LocaleOption, navigable bool) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var6 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var6 == nil {
|
||||||
|
templ_7745c5c3_Var6 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 14, "<details class=\"locale-picker\"><summary class=\"locale-picker__summary\"><span class=\"locale-picker__value\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if current.Label != "" {
|
||||||
|
var templ_7745c5c3_Var7 string
|
||||||
|
templ_7745c5c3_Var7, templ_7745c5c3_Err = templ.JoinStringErrs(current.Label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 75, Col: 20}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var7))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var templ_7745c5c3_Var8 string
|
||||||
|
templ_7745c5c3_Var8, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 77, Col: 12}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var8))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 15, "</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if current.Code != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 16, "<span class=\"locale-picker__code\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var9 string
|
||||||
|
templ_7745c5c3_Var9, templ_7745c5c3_Err = templ.JoinStringErrs(current.Code)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 81, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var9))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 17, "</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 18, "<span class=\"locale-picker__chevron\">⌄</span></summary> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(options) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 19, "<div class=\"locale-picker__panel\"><p class=\"locale-picker__title\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var10 string
|
||||||
|
templ_7745c5c3_Var10, templ_7745c5c3_Err = templ.JoinStringErrs(title)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 87, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var10))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 20, "</p><ul class=\"space-y-1\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, option := range options {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 21, "<li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if navigable && option.URL != "" {
|
||||||
|
var templ_7745c5c3_Var11 = []any{localeOptionClass(option, current)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var11...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 22, "<a class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var12 string
|
||||||
|
templ_7745c5c3_Var12, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var11).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var12))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 23, "\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var13 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var13, templ_7745c5c3_Err = templ.JoinURLErrs(option.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 92, Col: 73}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var13))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 24, "\"><span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var14 string
|
||||||
|
templ_7745c5c3_Var14, templ_7745c5c3_Err = templ.JoinStringErrs(option.Label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 93, Col: 29}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var14))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 25, "</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if option.Meta != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 26, "<span class=\"locale-picker__item-meta\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var15 string
|
||||||
|
templ_7745c5c3_Var15, templ_7745c5c3_Err = templ.JoinStringErrs(option.Meta)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 95, Col: 62}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var15))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 27, "</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else if option.Code != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 28, "<span class=\"locale-picker__item-meta\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var16 string
|
||||||
|
templ_7745c5c3_Var16, templ_7745c5c3_Err = templ.JoinStringErrs(option.Code)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 97, Col: 62}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var16))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 29, "</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 30, "</a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var templ_7745c5c3_Var17 = []any{localeOptionClass(option, current)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var17...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 31, "<span class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var18 string
|
||||||
|
templ_7745c5c3_Var18, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var17).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var18))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 32, "\"><span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var19 string
|
||||||
|
templ_7745c5c3_Var19, templ_7745c5c3_Err = templ.JoinStringErrs(option.Label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 102, Col: 29}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var19))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 33, "</span> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if option.Meta != "" {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 34, "<span class=\"locale-picker__item-meta\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var20 string
|
||||||
|
templ_7745c5c3_Var20, templ_7745c5c3_Err = templ.JoinStringErrs(option.Meta)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 104, Col: 62}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var20))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 35, "</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 36, "</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 37, "</li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 38, "</ul></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 39, "</details>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func MenuTree(items []pscatalog.MenuItem, depth int) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var21 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var21 == nil {
|
||||||
|
templ_7745c5c3_Var21 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
var templ_7745c5c3_Var22 = []any{menuListClass(depth)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var22...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 40, "<ul class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var23 string
|
||||||
|
templ_7745c5c3_Var23, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var22).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var23))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 41, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, item := range items {
|
||||||
|
var templ_7745c5c3_Var24 = []any{menuItemClass(depth, len(item.Children) > 0)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var24...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 42, "<li class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var25 string
|
||||||
|
templ_7745c5c3_Var25, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var24).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var25))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 43, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var26 = []any{menuLinkClass(depth)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var26...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 44, "<a class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var27 string
|
||||||
|
templ_7745c5c3_Var27, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var26).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var27))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 45, "\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var28 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var28, templ_7745c5c3_Err = templ.JoinURLErrs(item.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 120, Col: 53}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var28))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 46, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var29 string
|
||||||
|
templ_7745c5c3_Var29, templ_7745c5c3_Err = templ.JoinStringErrs(item.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 121, Col: 16}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var29))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 47, " ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if depth == 0 && len(item.Children) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 48, "<span class=\"text-[0.65rem] text-amber-300/80\">+</span>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 49, "</a> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
templ_7745c5c3_Err = MenuTree(item.Children, depth+1).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 50, "</li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 51, "</ul>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func MegaMenuBar(items []pscatalog.MenuItem) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var30 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var30 == nil {
|
||||||
|
templ_7745c5c3_Var30 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 52, "<ul class=\"desktop-nav\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, item := range items {
|
||||||
|
var templ_7745c5c3_Var31 = []any{desktopNavItemClass(len(item.Children) > 0)}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var31...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 53, "<li class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var32 string
|
||||||
|
templ_7745c5c3_Var32, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var31).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var32))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 54, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 55, "<div class=\"desktop-nav__item\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var33 = []any{desktopNavLinkClass()}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var33...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 56, "<a class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var34 string
|
||||||
|
templ_7745c5c3_Var34, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var33).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var34))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 57, "\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var35 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var35, templ_7745c5c3_Err = templ.JoinURLErrs(item.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 142, Col: 22}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var35))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 58, "\" aria-label=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var36 string
|
||||||
|
templ_7745c5c3_Var36, templ_7745c5c3_Err = templ.JoinStringErrs("Open " + item.Name + " submenu")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 143, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var36))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 59, "\" aria-expanded=\"false\" aria-controls=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var37 string
|
||||||
|
templ_7745c5c3_Var37, templ_7745c5c3_Err = templ.JoinStringErrs(menuPanelID(item.ID))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 145, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var37))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 60, "\" data-mega-trigger data-mega-target=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var38 string
|
||||||
|
templ_7745c5c3_Var38, templ_7745c5c3_Err = templ.JoinStringErrs(menuPanelID(item.ID))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 147, Col: 46}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var38))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 61, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var39 string
|
||||||
|
templ_7745c5c3_Var39, templ_7745c5c3_Err = templ.JoinStringErrs(item.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 147, Col: 60}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var39))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 62, "</a> <button class=\"desktop-nav__toggle\" type=\"button\" aria-label=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var40 string
|
||||||
|
templ_7745c5c3_Var40, templ_7745c5c3_Err = templ.JoinStringErrs("Open " + item.Name + " submenu")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 151, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var40))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 63, "\" aria-expanded=\"false\" aria-controls=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var41 string
|
||||||
|
templ_7745c5c3_Var41, templ_7745c5c3_Err = templ.JoinStringErrs(menuPanelID(item.ID))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 153, Col: 43}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var41))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 64, "\" data-mega-trigger data-mega-target=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var42 string
|
||||||
|
templ_7745c5c3_Var42, templ_7745c5c3_Err = templ.JoinStringErrs(menuPanelID(item.ID))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 155, Col: 46}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var42))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 65, "\">⌄</button></div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
var templ_7745c5c3_Var43 = []any{desktopNavLinkClass()}
|
||||||
|
templ_7745c5c3_Err = templ.RenderCSSItems(ctx, templ_7745c5c3_Buffer, templ_7745c5c3_Var43...)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 66, "<a class=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var44 string
|
||||||
|
templ_7745c5c3_Var44, templ_7745c5c3_Err = templ.JoinStringErrs(templ.CSSClasses(templ_7745c5c3_Var43).String())
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 1, Col: 0}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var44))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 67, "\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var45 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var45, templ_7745c5c3_Err = templ.JoinURLErrs(item.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 160, Col: 55}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var45))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 68, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var46 string
|
||||||
|
templ_7745c5c3_Var46, templ_7745c5c3_Err = templ.JoinStringErrs(item.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 160, Col: 69}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var46))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 69, "</a> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if len(item.Children) > 0 {
|
||||||
|
templ_7745c5c3_Err = MegaMenu(item.ID, item.URL, item.Name, item.Children).Render(ctx, templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 70, "</li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 71, "</ul>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
return nil
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func MegaMenu(id int64, href string, label string, columns []pscatalog.MenuItem) templ.Component {
|
||||||
|
return templruntime.GeneratedTemplate(func(templ_7745c5c3_Input templruntime.GeneratedComponentInput) (templ_7745c5c3_Err error) {
|
||||||
|
templ_7745c5c3_W, ctx := templ_7745c5c3_Input.Writer, templ_7745c5c3_Input.Context
|
||||||
|
if templ_7745c5c3_CtxErr := ctx.Err(); templ_7745c5c3_CtxErr != nil {
|
||||||
|
return templ_7745c5c3_CtxErr
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Buffer, templ_7745c5c3_IsBuffer := templruntime.GetBuffer(templ_7745c5c3_W)
|
||||||
|
if !templ_7745c5c3_IsBuffer {
|
||||||
|
defer func() {
|
||||||
|
templ_7745c5c3_BufErr := templruntime.ReleaseBuffer(templ_7745c5c3_Buffer)
|
||||||
|
if templ_7745c5c3_Err == nil {
|
||||||
|
templ_7745c5c3_Err = templ_7745c5c3_BufErr
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
ctx = templ.InitializeContext(ctx)
|
||||||
|
templ_7745c5c3_Var47 := templ.GetChildren(ctx)
|
||||||
|
if templ_7745c5c3_Var47 == nil {
|
||||||
|
templ_7745c5c3_Var47 = templ.NopComponent
|
||||||
|
}
|
||||||
|
ctx = templ.ClearChildren(ctx)
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 72, "<div class=\"mega-menu hidden\" id=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var48 string
|
||||||
|
templ_7745c5c3_Var48, templ_7745c5c3_Err = templ.JoinStringErrs(menuPanelID(id))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 171, Col: 51}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var48))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 73, "\" data-mega-menu><div class=\"mega-menu__grid\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, column := range columns {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 74, "<div class=\"mega-menu__column\"><a class=\"mega-menu__heading\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var49 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var49, templ_7745c5c3_Err = templ.JoinURLErrs(column.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 175, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var49))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 75, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var50 string
|
||||||
|
templ_7745c5c3_Var50, templ_7745c5c3_Err = templ.JoinStringErrs(column.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 175, Col: 68}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var50))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 76, "</a> ")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
if len(column.Children) > 0 {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 77, "<ul class=\"space-y-3\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
for _, child := range column.Children {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 78, "<li><a class=\"mega-menu__link\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var51 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var51, templ_7745c5c3_Err = templ.JoinURLErrs(child.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 180, Col: 52}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var51))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 79, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var52 string
|
||||||
|
templ_7745c5c3_Var52, templ_7745c5c3_Err = templ.JoinStringErrs(child.Name)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 180, Col: 67}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var52))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 80, "</a></li>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 81, "</ul>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 82, "<a class=\"mega-menu__link\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var53 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var53, templ_7745c5c3_Err = templ.JoinURLErrs(column.URL)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 185, Col: 50}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var53))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 83, "\">View all</a>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 84, "</div>")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 85, "<div class=\"mega-menu__all\"><a class=\"mega-menu__all-link\" href=\"")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var54 templ.SafeURL
|
||||||
|
templ_7745c5c3_Var54, templ_7745c5c3_Err = templ.JoinURLErrs(href)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 190, Col: 46}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var54))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 86, "\">")
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
var templ_7745c5c3_Var55 string
|
||||||
|
templ_7745c5c3_Var55, templ_7745c5c3_Err = templ.JoinStringErrs(label)
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ.Error{Err: templ_7745c5c3_Err, FileName: `templates/layout.templ`, Line: 190, Col: 56}
|
||||||
|
}
|
||||||
|
_, templ_7745c5c3_Err = templ_7745c5c3_Buffer.WriteString(templ.EscapeString(templ_7745c5c3_Var55))
|
||||||
|
if templ_7745c5c3_Err != nil {
|
||||||
|
return templ_7745c5c3_Err
|
||||||
|
}
|
||||||
|
templ_7745c5c3_Err = templruntime.WriteString(templ_7745c5c3_Buffer, 87, "</a></div></div></div>")
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,11 +3,11 @@ package templates
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
templ ProductPage(data viewmodel.ProductPageData, cssPath string, jsPath string) {
|
templ ProductPage(data viewmodel.ProductPageData, cssPath string, jsPath string) {
|
||||||
@Layout(data.Product.Name, cssPath, jsPath) {
|
@Layout(data.Product.Name, cssPath, jsPath, data.Menu, data.Locale) {
|
||||||
<main class="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(245,158,11,0.28),_transparent_40%),linear-gradient(180deg,#0c0a09,#1c1917)]">
|
<main class="min-h-screen bg-[radial-gradient(circle_at_top,_rgba(245,158,11,0.28),_transparent_40%),linear-gradient(180deg,#0c0a09,#1c1917)]">
|
||||||
<div class="mx-auto flex max-w-6xl flex-col gap-12 px-6 py-10 lg:px-8">
|
<div class="mx-auto flex max-w-6xl flex-col gap-12 px-6 py-10 lg:px-8">
|
||||||
<header class="flex items-center justify-between border-b border-stone-800 pb-6">
|
<header class="flex items-center justify-between border-b border-stone-800 pb-6">
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ import templruntime "github.com/a-h/templ/runtime"
|
|||||||
import (
|
import (
|
||||||
"fmt"
|
"fmt"
|
||||||
|
|
||||||
"prestaproxy/internal/viewmodel"
|
"git.ma-al.com/goc_marek/ps_shop/internal/viewmodel"
|
||||||
)
|
)
|
||||||
|
|
||||||
func ProductPage(data viewmodel.ProductPageData, cssPath string, jsPath string) templ.Component {
|
func ProductPage(data viewmodel.ProductPageData, cssPath string, jsPath string) templ.Component {
|
||||||
@@ -235,7 +235,7 @@ func ProductPage(data viewmodel.ProductPageData, cssPath string, jsPath string)
|
|||||||
}
|
}
|
||||||
return nil
|
return nil
|
||||||
})
|
})
|
||||||
templ_7745c5c3_Err = Layout(data.Product.Name, cssPath, jsPath).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
templ_7745c5c3_Err = Layout(data.Product.Name, cssPath, jsPath, data.Menu, data.Locale).Render(templ.WithChildren(ctx, templ_7745c5c3_Var2), templ_7745c5c3_Buffer)
|
||||||
if templ_7745c5c3_Err != nil {
|
if templ_7745c5c3_Err != nil {
|
||||||
return templ_7745c5c3_Err
|
return templ_7745c5c3_Err
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1exit status 1
|
||||||
Vendored
+1
-1
File diff suppressed because one or more lines are too long
Vendored
+1
-1
@@ -1 +1 @@
|
|||||||
document.documentElement.dataset.js="ready";
|
var l=document.documentElement;l.dataset.js="ready";var a=document.querySelector("[data-menu-toggle]"),d=document.querySelector("[data-menu-panel]"),r=[...document.querySelectorAll("[data-mega-trigger]")],c=[...document.querySelectorAll("[data-mega-menu]")];if(a&&d){let t=()=>{d.classList.add("hidden"),a.setAttribute("aria-expanded","false")},i=()=>{d.classList.remove("hidden"),a.setAttribute("aria-expanded","true")};a.addEventListener("click",()=>{if(a.getAttribute("aria-expanded")==="true"){t();return}i()}),window.addEventListener("resize",()=>{if(window.innerWidth>=1024){d.classList.remove("hidden"),a.setAttribute("aria-expanded","true");return}t()})}if(r.length>0&&c.length>0){let t=()=>{r.forEach((e)=>{e.setAttribute("aria-expanded","false"),e.closest(".desktop-nav__entry")?.classList.remove("desktop-nav__entry--open")}),c.forEach((e)=>{e.classList.add("hidden")})},i=(e)=>{let n=e.dataset.megaTarget;if(!n)return;t(),e.setAttribute("aria-expanded","true"),e.closest(".desktop-nav__entry")?.classList.add("desktop-nav__entry--open"),document.getElementById(n)?.classList.remove("hidden")};r.forEach((e)=>{e.addEventListener("click",(n)=>{if(window.innerWidth<1024)return;let s=e.getAttribute("aria-expanded")==="true";if(e instanceof HTMLAnchorElement&&s)return;if(n.preventDefault(),s){t();return}i(e)})}),document.addEventListener("click",(e)=>{if(window.innerWidth<1024)return;let n=e.target;if(!(n instanceof Node))return;let s=r.some((o)=>o.contains(n)),m=c.some((o)=>o.contains(n));if(!s&&!m)t()}),document.addEventListener("keydown",(e)=>{if(e.key==="Escape")t()}),window.addEventListener("resize",()=>{if(window.innerWidth<1024)t()})}var u=document.querySelector("button[type='submit']");if(u)u.addEventListener("mouseenter",()=>{l.style.setProperty("--cta-glow","0 0 0 4px rgba(252, 211, 77, 0.12)")}),u.addEventListener("mouseleave",()=>{l.style.setProperty("--cta-glow","0 0 0 0 rgba(0,0,0,0)")});
|
||||||
|
|||||||
+158
-3
@@ -8,15 +8,170 @@
|
|||||||
}
|
}
|
||||||
|
|
||||||
body {
|
body {
|
||||||
font-family: "IBM Plex Sans", sans-serif;
|
font-family:
|
||||||
|
"IBM Plex Sans",
|
||||||
|
"Avenir Next",
|
||||||
|
"Segoe UI",
|
||||||
|
sans-serif;
|
||||||
|
background:
|
||||||
|
radial-gradient(circle at top left, rgba(241, 196, 110, 0.24), transparent 28%),
|
||||||
|
radial-gradient(circle at top right, rgba(157, 217, 210, 0.16), transparent 34%),
|
||||||
|
linear-gradient(180deg, #fbfaf6 0%, #f5efe3 55%, #f7f3ea 100%);
|
||||||
|
@apply text-stone-900;
|
||||||
}
|
}
|
||||||
|
|
||||||
h1, h2, h3 {
|
h1,
|
||||||
font-family: "Cormorant Garamond", serif;
|
h2,
|
||||||
|
h3 {
|
||||||
|
font-family:
|
||||||
|
"Cormorant Garamond",
|
||||||
|
"IBM Plex Sans",
|
||||||
|
serif;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@layer components {
|
@layer components {
|
||||||
|
.site-container {
|
||||||
|
@apply mx-auto w-full max-w-7xl px-4 sm:px-5 lg:px-8;
|
||||||
|
}
|
||||||
|
|
||||||
|
.site-header {
|
||||||
|
@apply sticky top-0 z-40 backdrop-blur;
|
||||||
|
}
|
||||||
|
|
||||||
|
.utility-bar {
|
||||||
|
background: linear-gradient(90deg, rgba(20, 33, 61, 0.98), rgba(37, 58, 89, 0.94));
|
||||||
|
@apply border-b border-white/10 text-stone-100;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-locale {
|
||||||
|
@apply flex w-full flex-wrap items-center justify-start gap-2 text-sm text-stone-100 sm:w-auto sm:justify-end;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker {
|
||||||
|
@apply relative w-full sm:w-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__summary {
|
||||||
|
@apply flex w-full cursor-pointer list-none items-center justify-between gap-2 rounded-full border border-white/0 px-3 py-1.5 text-stone-100 transition hover:border-white/20 hover:bg-white/10 hover:text-white sm:w-auto sm:justify-start;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker[open] .locale-picker__summary {
|
||||||
|
@apply border-white/20 bg-white/10 text-white;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__summary::-webkit-details-marker {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__value {
|
||||||
|
@apply font-medium;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__code,
|
||||||
|
.locale-picker__item-meta,
|
||||||
|
.locale-picker__chevron {
|
||||||
|
@apply text-[0.74rem] uppercase tracking-[0.16em] text-stone-300/80;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__panel {
|
||||||
|
@apply left-0 right-0 z-50 mt-3 min-w-[13rem] rounded-3xl border border-white/70 bg-white/95 p-3 text-stone-900 shadow-[0_22px_48px_rgba(20,33,61,0.18)] backdrop-blur sm:absolute sm:left-auto sm:right-0;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__title {
|
||||||
|
@apply mb-2 px-2 text-[0.68rem] font-semibold uppercase tracking-[0.2em] text-stone-400;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__item {
|
||||||
|
@apply flex w-full items-center justify-between rounded-2xl px-3 py-2 text-sm text-stone-700 transition hover:bg-stone-100 hover:text-stone-900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.locale-picker__item--active {
|
||||||
|
@apply bg-stone-100 font-medium text-stone-900;
|
||||||
|
}
|
||||||
|
|
||||||
|
.main-nav {
|
||||||
|
background: rgba(255, 251, 245, 0.82);
|
||||||
|
@apply border-b border-white/60 shadow-[0_10px_30px_rgba(20,33,61,0.08)];
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-bar {
|
||||||
|
@apply flex flex-wrap items-center gap-4 py-4 sm:gap-5 sm:py-5 lg:flex-nowrap;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-mark {
|
||||||
|
@apply inline-flex items-end gap-0.5 text-4xl font-black leading-none tracking-tight text-black transition-transform duration-300 hover:-translate-y-0.5 sm:text-5xl;
|
||||||
|
}
|
||||||
|
|
||||||
|
.brand-mark__accent {
|
||||||
|
@apply text-amber-500;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-toggle {
|
||||||
|
@apply inline-flex h-11 items-center justify-center rounded-full border border-stone-300/70 bg-white/80 px-5 text-xs font-semibold uppercase tracking-[0.28em] text-stone-900 transition hover:border-amber-500 hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.menu-panel {
|
||||||
|
@apply order-last w-full rounded-3xl border border-white/70 bg-white/95 p-4 shadow-[0_16px_34px_rgba(20,33,61,0.12)] backdrop-blur lg:order-none lg:rounded-none lg:border-0 lg:bg-transparent lg:p-0 lg:shadow-none;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-nav {
|
||||||
|
@apply flex items-center justify-center gap-8 xl:gap-12;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-nav__link {
|
||||||
|
@apply inline-flex items-center py-4 text-[1.04rem] font-medium text-stone-800 transition hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-nav__toggle {
|
||||||
|
@apply inline-flex h-8 w-5 items-center justify-center text-sm text-stone-400 transition hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.desktop-nav__entry--open .desktop-nav__link,
|
||||||
|
.desktop-nav__entry--open .desktop-nav__toggle {
|
||||||
|
@apply text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu {
|
||||||
|
background: linear-gradient(180deg, rgba(255, 252, 247, 0.98), rgba(252, 248, 240, 0.98));
|
||||||
|
@apply absolute inset-x-0 top-full z-50 border-t border-white/70 shadow-[0_28px_60px_rgba(20,33,61,0.16)] backdrop-blur;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu__grid {
|
||||||
|
@apply site-container grid grid-cols-2 gap-x-12 gap-y-10 py-10 lg:grid-cols-4 xl:grid-cols-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu__heading {
|
||||||
|
@apply mb-4 inline-flex text-sm font-semibold uppercase tracking-[0.12em] text-stone-900 transition hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu__link {
|
||||||
|
@apply inline-flex text-[1.02rem] leading-7 text-stone-700 transition hover:translate-x-1 hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu__all {
|
||||||
|
@apply col-span-full flex items-start justify-end border-t border-stone-200 pt-5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.mega-menu__all-link {
|
||||||
|
@apply inline-flex text-sm font-semibold uppercase tracking-[0.18em] text-amber-600 transition hover:text-amber-700;
|
||||||
|
}
|
||||||
|
|
||||||
|
.header-actions {
|
||||||
|
@apply ml-0 flex items-center gap-4 text-2xl text-stone-900 lg:ml-auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.nav-icon {
|
||||||
|
@apply flex h-11 w-11 items-center justify-center rounded-full bg-white/70 text-[1.35rem] shadow-[0_10px_24px_rgba(20,33,61,0.08)] transition hover:-translate-y-0.5 hover:text-amber-600;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1023px) {
|
||||||
|
.desktop-nav,
|
||||||
|
.mega-menu {
|
||||||
|
display: none;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
button[type='submit'] {
|
button[type='submit'] {
|
||||||
box-shadow: var(--cta-glow);
|
box-shadow: var(--cta-glow);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,102 @@
|
|||||||
const root = document.documentElement;
|
const root = document.documentElement;
|
||||||
root.dataset.js = "ready";
|
root.dataset.js = "ready";
|
||||||
|
|
||||||
|
const menuToggle = document.querySelector("[data-menu-toggle]");
|
||||||
|
const menuPanel = document.querySelector("[data-menu-panel]");
|
||||||
|
const megaTriggers = [...document.querySelectorAll("[data-mega-trigger]")];
|
||||||
|
const megaMenus = [...document.querySelectorAll("[data-mega-menu]")];
|
||||||
|
|
||||||
|
if (menuToggle && menuPanel) {
|
||||||
|
const closeMenu = () => {
|
||||||
|
menuPanel.classList.add("hidden");
|
||||||
|
menuToggle.setAttribute("aria-expanded", "false");
|
||||||
|
};
|
||||||
|
|
||||||
|
const openMenu = () => {
|
||||||
|
menuPanel.classList.remove("hidden");
|
||||||
|
menuToggle.setAttribute("aria-expanded", "true");
|
||||||
|
};
|
||||||
|
|
||||||
|
menuToggle.addEventListener("click", () => {
|
||||||
|
const expanded = menuToggle.getAttribute("aria-expanded") === "true";
|
||||||
|
if (expanded) {
|
||||||
|
closeMenu();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openMenu();
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
if (window.innerWidth >= 1024) {
|
||||||
|
menuPanel.classList.remove("hidden");
|
||||||
|
menuToggle.setAttribute("aria-expanded", "true");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
closeMenu();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (megaTriggers.length > 0 && megaMenus.length > 0) {
|
||||||
|
const closeMegaMenus = () => {
|
||||||
|
megaTriggers.forEach((trigger) => {
|
||||||
|
trigger.setAttribute("aria-expanded", "false");
|
||||||
|
trigger.closest(".desktop-nav__entry")?.classList.remove("desktop-nav__entry--open");
|
||||||
|
});
|
||||||
|
megaMenus.forEach((menu) => {
|
||||||
|
menu.classList.add("hidden");
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const openMegaMenu = (trigger) => {
|
||||||
|
const target = trigger.dataset.megaTarget;
|
||||||
|
if (!target) return;
|
||||||
|
closeMegaMenus();
|
||||||
|
trigger.setAttribute("aria-expanded", "true");
|
||||||
|
trigger.closest(".desktop-nav__entry")?.classList.add("desktop-nav__entry--open");
|
||||||
|
document.getElementById(target)?.classList.remove("hidden");
|
||||||
|
};
|
||||||
|
|
||||||
|
megaTriggers.forEach((trigger) => {
|
||||||
|
trigger.addEventListener("click", (event) => {
|
||||||
|
if (window.innerWidth < 1024) return;
|
||||||
|
const expanded = trigger.getAttribute("aria-expanded") === "true";
|
||||||
|
const isLinkTrigger = trigger instanceof HTMLAnchorElement;
|
||||||
|
if (isLinkTrigger && expanded) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
event.preventDefault();
|
||||||
|
if (expanded) {
|
||||||
|
closeMegaMenus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
openMegaMenu(trigger);
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("click", (event) => {
|
||||||
|
if (window.innerWidth < 1024) return;
|
||||||
|
const target = event.target;
|
||||||
|
if (!(target instanceof Node)) return;
|
||||||
|
const insideTrigger = megaTriggers.some((trigger) => trigger.contains(target));
|
||||||
|
const insideMenu = megaMenus.some((menu) => menu.contains(target));
|
||||||
|
if (!insideTrigger && !insideMenu) {
|
||||||
|
closeMegaMenus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
document.addEventListener("keydown", (event) => {
|
||||||
|
if (event.key === "Escape") {
|
||||||
|
closeMegaMenus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
window.addEventListener("resize", () => {
|
||||||
|
if (window.innerWidth < 1024) {
|
||||||
|
closeMegaMenus();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
const cartButton = document.querySelector("button[type='submit']");
|
const cartButton = document.querySelector("button[type='submit']");
|
||||||
if (cartButton) {
|
if (cartButton) {
|
||||||
cartButton.addEventListener("mouseenter", () => {
|
cartButton.addEventListener("mouseenter", () => {
|
||||||
|
|||||||
Reference in New Issue
Block a user