htmgo/htmgo-site/ui/snippet.go

132 lines
3 KiB
Go
Raw Normal View History

2024-10-13 11:35:27 +00:00
package ui
import (
"bytes"
"fmt"
"github.com/alecthomas/chroma/v2"
"github.com/alecthomas/chroma/v2/formatters/html"
"github.com/alecthomas/chroma/v2/lexers"
"github.com/alecthomas/chroma/v2/styles"
2024-10-28 23:47:00 +00:00
"github.com/google/uuid"
2024-10-13 11:35:27 +00:00
"github.com/maddalax/htmgo/framework/h"
"io"
"net/http"
2024-10-13 11:35:27 +00:00
"strings"
)
func FormatCode(props CodeSnippetProps) string {
if props.SingleLine {
props.CustomStyles = append(props.CustomStyles, "height: 50px; width: 100%;")
}
2024-10-13 11:35:27 +00:00
var buf bytes.Buffer
lexer := lexers.Get(props.Lang)
2024-10-13 11:35:27 +00:00
style := styles.Get("github")
formatter := html.New(
2024-10-31 14:56:37 +00:00
html.WrapLongLines(props.WrapLines),
html.WithLineNumbers(!props.SingleLine && !props.HideLineNumbers),
2024-10-13 11:35:27 +00:00
html.WithCustomCSS(map[chroma.TokenType]string{
chroma.PreWrapper: fmt.Sprintf("border-radius: 0.2rem; line-height: 24px; font-size: 14px; padding: 12px; overflow: auto; background-color: rgb(245, 245, 245) !important; %s", strings.Join(props.CustomStyles, ";")),
2024-10-13 11:35:27 +00:00
}))
iterator, err := lexer.Tokenise(nil, props.Code)
2024-10-13 11:35:27 +00:00
if err != nil {
return ""
}
err = formatter.Format(&buf, style, iterator)
return buf.String()
}
type CodeSnippetProps struct {
Code string
Lang string
CustomStyles []string
HideLineNumbers bool
SingleLine bool
2024-10-31 14:56:37 +00:00
WrapLines bool
}
func CodeSnippet(props CodeSnippetProps) *h.Element {
2024-10-28 23:47:00 +00:00
id := fmt.Sprintf("code-snippet-%s", uuid.NewString())
props.Code = strings.TrimPrefix(props.Code, "\n")
props.Code = strings.TrimSuffix(props.Code, "\n")
if props.SingleLine {
return h.Div(
h.Class("flex items-center w-full"),
h.Div(
h.UnsafeRaw(props.Code),
h.Class("hidden"),
h.Id(id),
),
h.UnsafeRaw(
FormatCode(props),
),
CopyButton("#"+id, "h-[50px] rounded-sm"),
)
}
2024-10-13 11:35:27 +00:00
return h.Div(
2024-11-25 16:34:22 +00:00
h.Class("relative max-w-[90vw]"),
2024-10-28 23:47:00 +00:00
h.Div(
h.UnsafeRaw(props.Code),
2024-10-28 23:47:00 +00:00
h.Class("hidden"),
h.Id(id),
),
AbsoluteCopyButton("#"+id),
2024-10-28 23:47:00 +00:00
h.UnsafeRaw(
FormatCode(props),
2024-10-28 23:47:00 +00:00
),
2024-10-13 11:35:27 +00:00
)
}
func BashCodeSnippet(code string, customStyles ...string) *h.Element {
return CodeSnippet(CodeSnippetProps{
Code: code,
Lang: "bash",
CustomStyles: customStyles,
})
}
func SingleLineBashCodeSnippet(code string, customStyles ...string) *h.Element {
return CodeSnippet(CodeSnippetProps{
Code: code,
Lang: "bash",
CustomStyles: customStyles,
SingleLine: true,
})
}
func GoCodeSnippet(code string, customStyles ...string) *h.Element {
return CodeSnippet(CodeSnippetProps{
Code: code,
Lang: "go",
CustomStyles: customStyles,
})
}
func GoCodeSnippetSingleLine(code string, customStyles ...string) *h.Element {
return CodeSnippet(CodeSnippetProps{
Code: code,
Lang: "go",
CustomStyles: customStyles,
SingleLine: true,
})
}
func CodeSnippetFromUrl(url string, props CodeSnippetProps) *h.Element {
data, err := http.Get(url)
if err != nil {
fmt.Printf("error: %s\n", err.Error())
return h.Empty()
}
defer data.Body.Close()
b, err := io.ReadAll(data.Body)
if err != nil {
return h.Empty()
}
props.Code = string(b)
return CodeSnippet(props)
}