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"
|
2024-10-30 18:27:42 +00:00
|
|
|
"io"
|
|
|
|
|
"net/http"
|
2024-10-13 11:35:27 +00:00
|
|
|
"strings"
|
|
|
|
|
)
|
|
|
|
|
|
2024-10-30 18:27:42 +00:00
|
|
|
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
|
2024-10-30 18:27:42 +00:00
|
|
|
lexer := lexers.Get(props.Lang)
|
2024-10-13 11:35:27 +00:00
|
|
|
style := styles.Get("github")
|
|
|
|
|
formatter := html.New(
|
2024-10-30 18:27:42 +00:00
|
|
|
html.WithLineNumbers(!props.SingleLine && !props.HideLineNumbers),
|
2024-10-13 11:35:27 +00:00
|
|
|
html.WithCustomCSS(map[chroma.TokenType]string{
|
2024-10-30 18:27:42 +00:00
|
|
|
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
|
|
|
}))
|
2024-10-30 18:27:42 +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()
|
|
|
|
|
}
|
|
|
|
|
|
2024-10-30 18:27:42 +00:00
|
|
|
type CodeSnippetProps struct {
|
|
|
|
|
Code string
|
|
|
|
|
Lang string
|
|
|
|
|
CustomStyles []string
|
|
|
|
|
HideLineNumbers bool
|
|
|
|
|
SingleLine bool
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
func CodeSnippet(props CodeSnippetProps) *h.Element {
|
2024-10-28 23:47:00 +00:00
|
|
|
id := fmt.Sprintf("code-snippet-%s", uuid.NewString())
|
2024-10-30 18:27:42 +00:00
|
|
|
|
|
|
|
|
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-10-28 23:47:00 +00:00
|
|
|
h.Class("relative"),
|
|
|
|
|
h.Div(
|
2024-10-30 18:27:42 +00:00
|
|
|
h.UnsafeRaw(props.Code),
|
2024-10-28 23:47:00 +00:00
|
|
|
h.Class("hidden"),
|
|
|
|
|
h.Id(id),
|
|
|
|
|
),
|
2024-10-30 18:27:42 +00:00
|
|
|
AbsoluteCopyButton("#"+id),
|
2024-10-28 23:47:00 +00:00
|
|
|
h.UnsafeRaw(
|
2024-10-30 18:27:42 +00:00
|
|
|
FormatCode(props),
|
2024-10-28 23:47:00 +00:00
|
|
|
),
|
2024-10-13 11:35:27 +00:00
|
|
|
)
|
|
|
|
|
}
|
2024-10-30 18:27:42 +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)
|
|
|
|
|
}
|