code.gitea.io/gitea@v1.22.3/modules/svg/svg.go (about)

     1  // Copyright 2020 The Gitea Authors. All rights reserved.
     2  // SPDX-License-Identifier: MIT
     3  
     4  package svg
     5  
     6  import (
     7  	"fmt"
     8  	"html/template"
     9  	"path"
    10  	"strings"
    11  
    12  	gitea_html "code.gitea.io/gitea/modules/html"
    13  	"code.gitea.io/gitea/modules/log"
    14  	"code.gitea.io/gitea/modules/public"
    15  )
    16  
    17  var svgIcons map[string]string
    18  
    19  const defaultSize = 16
    20  
    21  // Init discovers SVG icons and populates the `svgIcons` variable
    22  func Init() error {
    23  	const svgAssetsPath = "assets/img/svg"
    24  	files, err := public.AssetFS().ListFiles(svgAssetsPath)
    25  	if err != nil {
    26  		return err
    27  	}
    28  
    29  	svgIcons = make(map[string]string, len(files))
    30  	for _, file := range files {
    31  		if path.Ext(file) != ".svg" {
    32  			continue
    33  		}
    34  		bs, err := public.AssetFS().ReadFile(svgAssetsPath, file)
    35  		if err != nil {
    36  			log.Error("Failed to read SVG file %s: %v", file, err)
    37  		} else {
    38  			svgIcons[file[:len(file)-4]] = string(Normalize(bs, defaultSize))
    39  		}
    40  	}
    41  	return nil
    42  }
    43  
    44  func MockIcon(icon string) func() {
    45  	if svgIcons == nil {
    46  		svgIcons = make(map[string]string)
    47  	}
    48  	orig, exist := svgIcons[icon]
    49  	svgIcons[icon] = fmt.Sprintf(`<svg class="svg %s" width="%d" height="%d"></svg>`, icon, defaultSize, defaultSize)
    50  	return func() {
    51  		if exist {
    52  			svgIcons[icon] = orig
    53  		} else {
    54  			delete(svgIcons, icon)
    55  		}
    56  	}
    57  }
    58  
    59  // RenderHTML renders icons - arguments icon name (string), size (int), class (string)
    60  func RenderHTML(icon string, others ...any) template.HTML {
    61  	size, class := gitea_html.ParseSizeAndClass(defaultSize, "", others...)
    62  	if svgStr, ok := svgIcons[icon]; ok {
    63  		// the code is somewhat hacky, but it just works, because the SVG contents are all normalized
    64  		if size != defaultSize {
    65  			svgStr = strings.Replace(svgStr, fmt.Sprintf(`width="%d"`, defaultSize), fmt.Sprintf(`width="%d"`, size), 1)
    66  			svgStr = strings.Replace(svgStr, fmt.Sprintf(`height="%d"`, defaultSize), fmt.Sprintf(`height="%d"`, size), 1)
    67  		}
    68  		if class != "" {
    69  			svgStr = strings.Replace(svgStr, `class="`, fmt.Sprintf(`class="%s `, class), 1)
    70  		}
    71  		return template.HTML(svgStr)
    72  	}
    73  	// during test (or something wrong happens), there is no SVG loaded, so use a dummy span to tell that the icon is missing
    74  	return template.HTML(fmt.Sprintf("<span>%s(%d/%s)</span>", template.HTMLEscapeString(icon), size, template.HTMLEscapeString(class)))
    75  }