169 lines
4.9 KiB
Go
169 lines
4.9 KiB
Go
package service
|
|
|
|
import (
|
|
"fmt"
|
|
"github.com/cespare/xxhash/v2"
|
|
"strings"
|
|
|
|
"github.com/cortezaproject/corteza/server/pkg/sass"
|
|
"github.com/cortezaproject/corteza/server/system/types"
|
|
"go.uber.org/zap"
|
|
)
|
|
|
|
// GenerateCSS takes care of creating CSS for webapps by reading SASS content from embedded assets,
|
|
// combining it with different themeSASS and customCSS themes, and then transpiling it using the dart-sass compiler.
|
|
//
|
|
// If dart sass isn't installed on the host machine, it will default to css content from the minified-custom.css which is
|
|
// generated from [Boostrap, bootstrap-vue and custom variables sass content].
|
|
// If dart isn't installed on the host machine, customCustom css will continue to function, but without sass support.
|
|
//
|
|
// In case of an error, it will return default css and log out the error
|
|
func GenerateCSS(settings *types.AppSettings, sassDirPath string, log *zap.Logger) (err error) {
|
|
var (
|
|
studio = settings.UI.Studio
|
|
customCSSMap = make(map[string]string)
|
|
)
|
|
|
|
for _, customCSS := range studio.CustomCSS {
|
|
customCSSMap[customCSS.ID] = customCSS.Values
|
|
}
|
|
|
|
sass.DefaultCSS(log, customCSSMap[sass.GeneralTheme])
|
|
|
|
if studio.Themes == nil && studio.CustomCSS == nil {
|
|
return
|
|
}
|
|
|
|
// if dart sass is not installed, or when the sass transpiler creation and startup process fails.
|
|
if !studio.SassInstalled {
|
|
return
|
|
}
|
|
|
|
transpiler := sass.DartSassTranspiler(log)
|
|
|
|
// transpile sass to css for each theme
|
|
for _, theme := range studio.Themes {
|
|
if studio.CustomCSS == nil {
|
|
err := sass.Transpile(transpiler, log, theme.ID, theme.Values, "", sassDirPath)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
}
|
|
|
|
customCSS := processCustomCSS(theme.ID, customCSSMap)
|
|
// transpile sass to css
|
|
err := sass.Transpile(transpiler, log, theme.ID, theme.Values, customCSS, sassDirPath)
|
|
if err != nil {
|
|
continue
|
|
}
|
|
}
|
|
|
|
return
|
|
}
|
|
|
|
// processCustomCSS, processes CustomCSS input and gives priority to theme specific customCSS
|
|
func processCustomCSS(themeID string, customCSSMap map[string]string) (customCSS string) {
|
|
var stringsBuilder strings.Builder
|
|
|
|
// add theme mode on customCSS
|
|
if themeID == sass.DarkTheme {
|
|
stringsBuilder.WriteString(fmt.Sprintf("\n[data-color-mode=\"%s\"] {\n", themeID))
|
|
}
|
|
|
|
stringsBuilder.WriteString(customCSSMap[sass.GeneralTheme])
|
|
stringsBuilder.WriteString("\n")
|
|
stringsBuilder.WriteString(customCSSMap[themeID])
|
|
|
|
if themeID == sass.DarkTheme {
|
|
stringsBuilder.WriteString("}\n")
|
|
}
|
|
|
|
return stringsBuilder.String()
|
|
}
|
|
|
|
// updateCSS, updates theme css when ui.studio.themes or ui.studio.custom-css settings are updated
|
|
func updateCSS(current, old, compStyles *types.SettingValue, name, sassDirPath string, log *zap.Logger) {
|
|
transpiler := sass.DartSassTranspiler(log)
|
|
|
|
complimentaryStylesMap := themeMap(compStyles)
|
|
oldThemesMap := themeMap(old)
|
|
currentThemesMap := themeMap(current)
|
|
|
|
transpileSASS := func(themeID, themeSASS string, themeCustomCSS map[string]string) {
|
|
customCSS := processCustomCSS(themeID, themeCustomCSS)
|
|
err := sass.Transpile(transpiler, log, themeID, themeSASS, customCSS, sassDirPath)
|
|
if err != nil {
|
|
log.Error("failed to transpile sass to css", zap.Error(err))
|
|
}
|
|
}
|
|
|
|
for key := range currentThemesMap {
|
|
if xxhash.Sum64String(oldThemesMap[key]) == xxhash.Sum64String(currentThemesMap[key]) {
|
|
continue
|
|
}
|
|
|
|
if name == "ui.studio.themes" {
|
|
transpileSASS(key, currentThemesMap[key], complimentaryStylesMap)
|
|
continue
|
|
}
|
|
|
|
if key == sass.GeneralTheme {
|
|
if complimentaryStylesMap == nil {
|
|
transpileSASS(sass.LightTheme, complimentaryStylesMap[sass.LightTheme], currentThemesMap)
|
|
continue
|
|
}
|
|
|
|
for themeID := range complimentaryStylesMap {
|
|
transpileSASS(themeID, complimentaryStylesMap[themeID], currentThemesMap)
|
|
}
|
|
continue
|
|
}
|
|
|
|
transpileSASS(key, complimentaryStylesMap[key], currentThemesMap)
|
|
}
|
|
}
|
|
|
|
func themeMap(settingsValue *types.SettingValue) (themeMap map[string]string) {
|
|
var themes []types.Theme
|
|
|
|
if settingsValue == nil {
|
|
return themeMap
|
|
}
|
|
|
|
_ = settingsValue.Value.Unmarshal(&themes)
|
|
|
|
themeMap = make(map[string]string)
|
|
for _, theme := range themes {
|
|
themeMap[theme.ID] = theme.Values
|
|
}
|
|
|
|
return themeMap
|
|
}
|
|
|
|
func FetchCSS() string {
|
|
var (
|
|
stringsBuilder strings.Builder
|
|
rootLight = sass.StylesheetCache.Get(fmt.Sprintf("%s-%s", sass.SectionRoot, sass.LightTheme))
|
|
)
|
|
|
|
if rootLight == "" {
|
|
return sass.StylesheetCache.Get("default-theme")
|
|
}
|
|
|
|
// root css section
|
|
stringsBuilder.WriteString(rootLight)
|
|
stringsBuilder.WriteString("\n")
|
|
stringsBuilder.WriteString(sass.StylesheetCache.Get(fmt.Sprintf("%s-%s", sass.SectionRoot, sass.DarkTheme)))
|
|
stringsBuilder.WriteString("\n")
|
|
|
|
//theme css section
|
|
stringsBuilder.WriteString(sass.StylesheetCache.Get(fmt.Sprintf("%s-%s", sass.SectionTheme, sass.DarkTheme)))
|
|
stringsBuilder.WriteString("\n")
|
|
|
|
// body css section
|
|
stringsBuilder.WriteString(sass.StylesheetCache.Get(fmt.Sprintf("%s-%s", sass.SectionMain, sass.LightTheme)))
|
|
stringsBuilder.WriteString("\n")
|
|
|
|
return stringsBuilder.String()
|
|
}
|