Files
MujicaUI/file_icon.go
T

126 lines
4.2 KiB
Go

package mujica
import (
"path"
"strings"
"github.com/egoist/mygo/ui"
"mujicaui/icons"
"mujicaui/theme"
)
// FileKind is the family a file belongs to.
type FileKind int
const (
FileOther FileKind = iota
FileFolder
FileImage
FileText
FileCode
FileDocument
FileArchive
FileAudio
FileVideo
)
var fileKinds = map[string]FileKind{
"png": FileImage, "jpg": FileImage, "jpeg": FileImage, "gif": FileImage, "svg": FileImage, "webp": FileImage, "bmp": FileImage, "heic": FileImage,
"txt": FileText, "md": FileText, "log": FileText, "csv": FileText, "rtf": FileText,
"go": FileCode, "js": FileCode, "ts": FileCode, "py": FileCode, "json": FileCode, "sh": FileCode, "sql": FileCode, "html": FileCode, "css": FileCode, "rs": FileCode, "c": FileCode, "h": FileCode, "java": FileCode, "yaml": FileCode, "yml": FileCode, "toml": FileCode,
"pdf": FileDocument, "doc": FileDocument, "docx": FileDocument, "xls": FileDocument, "xlsx": FileDocument, "ppt": FileDocument, "pptx": FileDocument, "pages": FileDocument, "key": FileDocument,
"zip": FileArchive, "tar": FileArchive, "gz": FileArchive, "tgz": FileArchive, "7z": FileArchive, "rar": FileArchive, "xz": FileArchive,
"mp3": FileAudio, "wav": FileAudio, "flac": FileAudio, "aac": FileAudio, "ogg": FileAudio, "m4a": FileAudio,
"mp4": FileVideo, "mov": FileVideo, "mkv": FileVideo, "avi": FileVideo, "webm": FileVideo,
}
// FileKindOf classifies a filename by its extension.
func FileKindOf(name string) FileKind {
return fileKinds[fileExt(name)]
}
// fileExt is the lower-case extension without the dot.
func fileExt(name string) string {
return strings.ToLower(strings.TrimPrefix(path.Ext(name), "."))
}
// FileIconOptions configure a FileIcon.
type FileIconOptions struct {
// Folder draws a folder; Open draws it opened.
Folder, Open bool
// Size is the icon's edge in DIPs; zero is 20.
Size float32
}
// fileFolderOpen is an opened folder glyph in Lucide's style.
var fileFolderOpen = ui.MustParseSVG([]byte(`<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="m6 14 1.5-2.9A2 2 0 0 1 9.24 10H20a2 2 0 0 1 1.94 2.5l-1.54 6a2 2 0 0 1-1.95 1.5H4a2 2 0 0 1-2-2V5a2 2 0 0 1 2-2h3.9a2 2 0 0 1 1.69.9l.81 1.2a2 2 0 0 0 1.67.9H18a2 2 0 0 1 2 2v2"/></svg>`))
// fileKindColor is a kind's tint, readable on Surface.
func fileKindColor(k theme.Tokens, kind FileKind) ui.Color {
switch kind {
case FileFolder:
return k.Warning
case FileImage, FileVideo:
return k.Info
case FileCode:
return k.AccentText
case FileArchive, FileAudio:
return k.Warning
case FileDocument:
return k.Success
}
return k.TextMuted
}
// FileIcon shows file type or folder opening state.
func FileIcon(c *ui.Context, name string, opts FileIconOptions) *ui.Element {
if opts.Size < 0 {
panic("mujica: FileIcon Size is negative")
}
if opts.Open && !opts.Folder {
panic("mujica: FileIcon Open needs Folder")
}
k := Tokens(c)
size := opts.Size
if size == 0 {
size = 20
}
kind := FileKindOf(name)
label := msg(c, "file_icon.file")
if ext := fileExt(name); ext != "" {
label = strings.ToUpper(ext) + " " + label
}
if opts.Folder {
kind, label = FileFolder, msg(c, "file_icon.folder")
if opts.Open {
label = msg(c, "file_icon.open")
}
}
col := fileKindColor(k, kind)
box := ui.Box(c).Size(size, size).Shrink(0).Role(ui.RoleImage).Label(label).TextColor(col)
return box.Children(func() {
switch {
case opts.Open:
ui.Icon(c, fileFolderOpen).Size(size, size)
case opts.Folder:
ui.Icon(c, icons.Must("folder")).Size(size, size)
case kind == FileImage:
ui.Icon(c, icons.Must("image")).Size(size, size)
case kind == FileText:
ui.Icon(c, icons.Must("file-text")).Size(size, size)
default:
ui.Icon(c, icons.Must("file")).Size(size, size)
ext := strings.ToUpper(fileExt(name))
if ext != "" && size >= 20 {
// The extension tag sits across the page's lower half.
if len(ext) > 3 {
ext = ext[:3]
}
ui.Text(c, ext).Font(theme.MonoFont).FontSize(FontSize(c, size*0.3)).FontWeight(700).TextColor(k.Surface).
Background(col).Radius(1).Padding(0, 1).Absolute().Bottom(size * 0.12).Left(0).Role(ui.RoleNone)
}
}
})
}