996 lines
27 KiB
Go
996 lines
27 KiB
Go
package indexgen
|
|
|
|
import (
|
|
"fmt"
|
|
"html/template"
|
|
"net/url"
|
|
"os"
|
|
"path/filepath"
|
|
"regexp"
|
|
"sort"
|
|
"strconv"
|
|
"strings"
|
|
"time"
|
|
)
|
|
|
|
const (
|
|
DefaultOutputFile = "index.html"
|
|
)
|
|
|
|
var ExtensionTypes = map[string]string{
|
|
"id_rsa": "cert",
|
|
"LICENSE": "license",
|
|
"README": "license",
|
|
".jpg": "image",
|
|
".jpeg": "image",
|
|
".png": "image",
|
|
".gif": "image",
|
|
".webp": "image",
|
|
".tiff": "image",
|
|
".bmp": "image",
|
|
".heif": "image",
|
|
".heic": "image",
|
|
".svg": "image",
|
|
".mp4": "video",
|
|
".mov": "video",
|
|
".mpeg": "video",
|
|
".avi": "video",
|
|
".ogv": "video",
|
|
".webm": "video",
|
|
".mkv": "video",
|
|
".vob": "video",
|
|
".gifv": "video",
|
|
".3gp": "video",
|
|
".mp3": "audio",
|
|
".m4a": "audio",
|
|
".aac": "audio",
|
|
".ogg": "audio",
|
|
".flac": "audio",
|
|
".wav": "audio",
|
|
".wma": "audio",
|
|
".midi": "audio",
|
|
".cda": "audio",
|
|
".aiff": "audio",
|
|
".aif": "audio",
|
|
".caf": "audio",
|
|
".pdf": "pdf",
|
|
".csv": "csv",
|
|
".txt": "doc",
|
|
".doc": "doc",
|
|
".docx": "doc",
|
|
".odt": "doc",
|
|
".fodt": "doc",
|
|
".rtf": "doc",
|
|
".abw": "doc",
|
|
".pages": "doc",
|
|
".xls": "sheet",
|
|
".xlsx": "sheet",
|
|
".ods": "sheet",
|
|
".fods": "sheet",
|
|
".numbers": "sheet",
|
|
".ppt": "ppt",
|
|
".pptx": "ppt",
|
|
".odp": "ppt",
|
|
".fodp": "ppt",
|
|
".zip": "archive",
|
|
".gz": "archive",
|
|
".xz": "archive",
|
|
".tar": "archive",
|
|
".7z": "archive",
|
|
".rar": "archive",
|
|
".zst": "archive",
|
|
".bz2": "archive",
|
|
".bzip": "archive",
|
|
".arj": "archive",
|
|
".z": "archive",
|
|
".deb": "deb",
|
|
".dpkg": "deb",
|
|
".rpm": "dist",
|
|
".exe": "dist",
|
|
".flatpak": "dist",
|
|
".appimage": "dist",
|
|
".jar": "dist",
|
|
".msi": "dist",
|
|
".apk": "dist",
|
|
".ps1": "ps1",
|
|
".py": "py",
|
|
".pyc": "py",
|
|
".pyo": "py",
|
|
".egg": "py",
|
|
".sh": "sh",
|
|
".bash": "sh",
|
|
".com": "sh",
|
|
".bat": "sh",
|
|
".dll": "sh",
|
|
".so": "sh",
|
|
".dmg": "dmg",
|
|
".iso": "iso",
|
|
".img": "iso",
|
|
".md": "md",
|
|
".mdown": "md",
|
|
".markdown": "md",
|
|
".ttf": "font",
|
|
".ttc": "font",
|
|
".otf": "font",
|
|
".woff": "font",
|
|
".woff2": "font",
|
|
".eof": "font",
|
|
".apf": "font",
|
|
".go": "go",
|
|
".html": "html",
|
|
".htm": "html",
|
|
".php": "html",
|
|
".php3": "html",
|
|
".asp": "html",
|
|
".aspx": "html",
|
|
".css": "css",
|
|
".scss": "css",
|
|
".less": "css",
|
|
".json": "json",
|
|
".json5": "json",
|
|
".jsonc": "json",
|
|
".ts": "ts",
|
|
".js": "js",
|
|
".sql": "sql",
|
|
".db": "db",
|
|
".sqlite": "db",
|
|
".mdb": "db",
|
|
".odb": "db",
|
|
".eml": "email",
|
|
".email": "email",
|
|
".mailbox": "email",
|
|
".mbox": "email",
|
|
".msg": "email",
|
|
".crt": "cert",
|
|
".pem": "cert",
|
|
".x509": "cert",
|
|
".cer": "cert",
|
|
".der": "cert",
|
|
".ca-bundle": "cert",
|
|
".key": "keystore",
|
|
".keystore": "keystore",
|
|
".jks": "keystore",
|
|
".p12": "keystore",
|
|
".pfx": "keystore",
|
|
".pub": "keystore",
|
|
"symlink": "symlink",
|
|
"generic": "generic",
|
|
}
|
|
|
|
type Options struct {
|
|
TopDir string
|
|
Filter string
|
|
OutputFile string
|
|
DirAppend bool
|
|
Recursive bool
|
|
IncludeHidden bool
|
|
ExcludeRegex *regexp.Regexp
|
|
Verbose bool
|
|
DryRun bool
|
|
}
|
|
|
|
type FileEntry struct {
|
|
Name string
|
|
Path string
|
|
IsDir bool
|
|
IsSymlink bool
|
|
Size int64
|
|
ModTime time.Time
|
|
IconType string
|
|
CSSClass string
|
|
SizePretty string
|
|
ModTimeISO string
|
|
ModTimeHuman string
|
|
}
|
|
|
|
func ProcessDir(topDir string, opts *Options) error {
|
|
absPath, err := filepath.Abs(topDir)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to get absolute path: %w", err)
|
|
}
|
|
|
|
if opts.Verbose {
|
|
fmt.Printf("Traversing dir %s\n", absPath)
|
|
}
|
|
|
|
indexPath := filepath.Join(absPath, opts.OutputFile)
|
|
|
|
dirName := filepath.Base(absPath)
|
|
|
|
entries, err := ReadDirEntries(absPath, opts)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to read directory: %w", err)
|
|
}
|
|
|
|
sort.Slice(entries, func(i, j int) bool {
|
|
if entries[i].IsDir != entries[j].IsDir {
|
|
return entries[i].IsDir
|
|
}
|
|
return entries[i].Name < entries[j].Name
|
|
})
|
|
|
|
templateData := struct {
|
|
DirName string
|
|
Entries []FileEntry
|
|
DirAppend bool
|
|
OutputFile string
|
|
IsRoot bool
|
|
}{
|
|
DirName: dirName,
|
|
Entries: entries,
|
|
DirAppend: opts.DirAppend,
|
|
OutputFile: opts.OutputFile,
|
|
IsRoot: false, // Local filesystem always shows parent directory
|
|
}
|
|
|
|
if opts.DryRun {
|
|
// Dry run mode: show what would be written
|
|
fmt.Printf("Would write index file: %s\n", indexPath)
|
|
fmt.Printf("Directory: %s\n", dirName)
|
|
fmt.Printf("Entries found: %d\n", len(entries))
|
|
for _, entry := range entries {
|
|
entryType := "file"
|
|
if entry.IsDir {
|
|
entryType = "directory"
|
|
}
|
|
fmt.Printf(" %s: %s\n", entryType, entry.Name)
|
|
}
|
|
} else {
|
|
// Normal mode: actually write the file
|
|
file, err := os.Create(indexPath)
|
|
if err != nil {
|
|
return fmt.Errorf("cannot create file %s: %w", indexPath, err)
|
|
}
|
|
defer file.Close()
|
|
|
|
err = GetHTMLTemplate().Execute(file, templateData)
|
|
if err != nil {
|
|
return fmt.Errorf("failed to execute template: %w", err)
|
|
}
|
|
}
|
|
|
|
if opts.Recursive {
|
|
for _, entry := range entries {
|
|
if entry.IsDir && !entry.IsSymlink {
|
|
fullPath := filepath.Join(absPath, entry.Name)
|
|
err := ProcessDir(fullPath, opts)
|
|
if err != nil {
|
|
fmt.Printf("Error processing directory %s: %v\n", fullPath, err)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func ReadDirEntries(dirPath string, opts *Options) ([]FileEntry, error) {
|
|
files, err := os.ReadDir(dirPath)
|
|
if err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
var entries []FileEntry
|
|
|
|
for _, file := range files {
|
|
fileName := file.Name()
|
|
|
|
if strings.EqualFold(fileName, opts.OutputFile) {
|
|
continue
|
|
}
|
|
|
|
if !opts.IncludeHidden && strings.HasPrefix(fileName, ".") {
|
|
continue
|
|
}
|
|
|
|
if opts.ExcludeRegex != nil && opts.ExcludeRegex.MatchString(fileName) {
|
|
continue
|
|
}
|
|
|
|
fullPath := filepath.Join(dirPath, fileName)
|
|
|
|
info, err := file.Info()
|
|
if err != nil {
|
|
fmt.Printf("*** WARNING *** entry %s is not accessible! SKIPPING! Error: %v\n", fullPath, err)
|
|
continue
|
|
}
|
|
|
|
if opts.Verbose {
|
|
fmt.Println(fullPath)
|
|
}
|
|
|
|
entry := FileEntry{
|
|
Name: fileName,
|
|
Path: fileName,
|
|
IsDir: file.IsDir(),
|
|
ModTime: info.ModTime(),
|
|
}
|
|
|
|
entry.IsSymlink = info.Mode()&os.ModeSymlink != 0
|
|
|
|
if file.IsDir() && !entry.IsSymlink {
|
|
entry.Size = -1
|
|
entry.SizePretty = "—"
|
|
entry.IconType = "folder"
|
|
entry.CSSClass = "folder_filled"
|
|
entry.Path = fileName + "/"
|
|
} else if file.IsDir() && entry.IsSymlink {
|
|
entry.Size = -1
|
|
entry.SizePretty = "—"
|
|
entry.IconType = "folder-symlink"
|
|
fmt.Printf("dir-symlink %s\n", fullPath)
|
|
} else if !file.IsDir() && entry.IsSymlink {
|
|
entry.Size = info.Size()
|
|
entry.SizePretty = PrettySize(entry.Size)
|
|
entry.IconType = "symlink"
|
|
fmt.Printf("file-symlink %s\n", fullPath)
|
|
} else {
|
|
entry.Size = info.Size()
|
|
entry.SizePretty = PrettySize(entry.Size)
|
|
entry.IconType = GetIconType(fileName)
|
|
}
|
|
|
|
if file.IsDir() && opts.DirAppend {
|
|
entry.Path += opts.OutputFile
|
|
}
|
|
|
|
entry.ModTimeISO = entry.ModTime.Format(time.RFC3339)
|
|
entry.ModTimeHuman = entry.ModTime.Format(time.RFC822)
|
|
|
|
entries = append(entries, entry)
|
|
}
|
|
|
|
return entries, nil
|
|
}
|
|
|
|
func GetIconType(fileName string) string {
|
|
ext := strings.ToLower(filepath.Ext(fileName))
|
|
if iconType, exists := ExtensionTypes[ext]; exists {
|
|
return iconType
|
|
}
|
|
|
|
if iconType, exists := ExtensionTypes[fileName]; exists {
|
|
return iconType
|
|
}
|
|
|
|
return "generic"
|
|
}
|
|
|
|
func PrettySize(bytes int64) string {
|
|
units := []struct {
|
|
factor int64
|
|
suffix string
|
|
}{
|
|
{1024 * 1024 * 1024 * 1024 * 1024, " PB"},
|
|
{1024 * 1024 * 1024 * 1024, " TB"},
|
|
{1024 * 1024 * 1024, " GB"},
|
|
{1024 * 1024, " MB"},
|
|
{1024, " KB"},
|
|
{1, " byte"},
|
|
}
|
|
|
|
for _, unit := range units {
|
|
if bytes >= unit.factor {
|
|
amount := bytes / unit.factor
|
|
if unit.suffix == " byte" {
|
|
if amount == 1 {
|
|
return strconv.FormatInt(amount, 10) + " byte"
|
|
}
|
|
return strconv.FormatInt(amount, 10) + " bytes"
|
|
}
|
|
return strconv.FormatInt(amount, 10) + unit.suffix
|
|
}
|
|
}
|
|
return "0 bytes"
|
|
}
|
|
|
|
func GetHTMLTemplate() *template.Template {
|
|
return template.Must(template.New("index").Funcs(template.FuncMap{
|
|
"urlEscape": func(s string) string {
|
|
return url.QueryEscape(s)
|
|
},
|
|
"safeHTML": func(s string) template.HTML {
|
|
return template.HTML(s)
|
|
},
|
|
}).Parse(htmlTemplateString))
|
|
}
|
|
|
|
const htmlTemplateString = `<!DOCTYPE html>
|
|
<html>
|
|
<head>
|
|
<meta charset="utf-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<style>
|
|
* { padding: 0; margin: 0; }
|
|
|
|
path_FIXME {
|
|
color: #ffb900 !important;
|
|
}
|
|
path {
|
|
color: #8a8a8a;
|
|
}
|
|
|
|
body {
|
|
font-family: sans-serif;
|
|
text-rendering: optimizespeed;
|
|
background-color: #ffffff;
|
|
min-height: 100vh;
|
|
}
|
|
|
|
body,
|
|
a,
|
|
svg,
|
|
.layout.current,
|
|
.layout.current svg,
|
|
.go-up {
|
|
color: #333;
|
|
text-decoration: none;
|
|
}
|
|
|
|
a {
|
|
color: #006ed3;
|
|
text-decoration: none;
|
|
}
|
|
|
|
a:hover,
|
|
h1 a:hover {
|
|
color: #319cff;
|
|
}
|
|
|
|
header,
|
|
#summary {
|
|
padding-left: 5%;
|
|
padding-right: 5%;
|
|
}
|
|
|
|
th:first-child,
|
|
td:first-child {
|
|
width: 5%;
|
|
}
|
|
|
|
th:last-child,
|
|
td:last-child {
|
|
width: 5%;
|
|
}
|
|
|
|
header {
|
|
padding-top: 25px;
|
|
padding-bottom: 15px;
|
|
background-color: #f2f2f2;
|
|
}
|
|
|
|
h1 {
|
|
font-size: 20px;
|
|
font-weight: normal;
|
|
white-space: nowrap;
|
|
overflow-x: hidden;
|
|
text-overflow: ellipsis;
|
|
color: #999;
|
|
}
|
|
|
|
h1 a {
|
|
color: #000;
|
|
margin: 0 4px;
|
|
}
|
|
|
|
h1 a:hover {
|
|
text-decoration: underline;
|
|
}
|
|
|
|
h1 a:first-child {
|
|
margin: 0;
|
|
}
|
|
|
|
main {
|
|
display: block;
|
|
margin: 3em auto 0;
|
|
border-radius: 5px;
|
|
box-shadow: 0 2px 5px 1px rgb(0 0 0 / 5%);
|
|
}
|
|
|
|
.meta {
|
|
font-size: 12px;
|
|
font-family: Verdana, sans-serif;
|
|
border-bottom: 1px solid #9C9C9C;
|
|
padding-top: 10px;
|
|
padding-bottom: 10px;
|
|
}
|
|
|
|
.meta-item {
|
|
margin-right: 1em;
|
|
}
|
|
|
|
#filter {
|
|
padding: 4px;
|
|
border: 1px solid #CCC;
|
|
}
|
|
|
|
table {
|
|
width: 100%;
|
|
border-collapse: collapse;
|
|
}
|
|
|
|
tr {
|
|
border-bottom: 1px dashed #dadada;
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background-color: #ffffec;
|
|
}
|
|
|
|
th,
|
|
td {
|
|
text-align: left;
|
|
padding: 10px 0;
|
|
}
|
|
|
|
th {
|
|
padding-top: 15px;
|
|
padding-bottom: 15px;
|
|
font-size: 16px;
|
|
white-space: nowrap;
|
|
}
|
|
|
|
th a {
|
|
color: black;
|
|
}
|
|
|
|
th svg {
|
|
vertical-align: middle;
|
|
z-index: 1;
|
|
}
|
|
|
|
|
|
td {
|
|
white-space: nowrap;
|
|
font-size: 14px;
|
|
}
|
|
|
|
td:nth-child(2) {
|
|
width: 80%;
|
|
}
|
|
|
|
td:nth-child(3) {
|
|
padding: 0 20px 0 20px;
|
|
}
|
|
|
|
th:nth-child(4),
|
|
td:nth-child(4) {
|
|
text-align: right;
|
|
}
|
|
|
|
td:nth-child(2) svg {
|
|
position: absolute;
|
|
}
|
|
|
|
td .name {
|
|
margin-left: 2.34em;
|
|
word-break: break-all;
|
|
overflow-wrap: break-word;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
td .goup {
|
|
margin-left: 1.75em;
|
|
padding: 0;
|
|
word-break: break-all;
|
|
overflow-wrap: break-word;
|
|
white-space: pre-wrap;
|
|
}
|
|
|
|
.icon {
|
|
margin-right: 5px;
|
|
}
|
|
|
|
tr.clickable {
|
|
cursor: pointer;
|
|
}
|
|
tr.clickable a {
|
|
display: block;
|
|
}
|
|
|
|
.folder-filled {
|
|
color: #ffb900 !important;
|
|
}
|
|
|
|
@media (max-width: 600px) {
|
|
|
|
* {
|
|
font-size: 1.06rem;
|
|
}
|
|
.hideable {
|
|
display: none;
|
|
}
|
|
|
|
td:nth-child(2) {
|
|
width: auto;
|
|
}
|
|
|
|
th:nth-child(3),
|
|
td:nth-child(3) {
|
|
padding-right: 5%;
|
|
text-align: right;
|
|
}
|
|
|
|
h1 {
|
|
color: #000;
|
|
}
|
|
|
|
h1 a {
|
|
margin: 0;
|
|
}
|
|
|
|
#filter {
|
|
max-width: 100px;
|
|
}
|
|
}
|
|
|
|
@media (prefers-color-scheme: dark) {
|
|
body {
|
|
color: #eee;
|
|
background: #121212;
|
|
}
|
|
|
|
header {
|
|
color: #eee;
|
|
background: #151515;
|
|
}
|
|
|
|
tbody tr:hover {
|
|
background-color: #000020;
|
|
}
|
|
}
|
|
</style>
|
|
</head>
|
|
<body>
|
|
<svg version="1.1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round" style="color: red;">
|
|
<defs>
|
|
<g id="go-up">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M18 18h-6a3 3 0 0 1 -3 -3v-10l-4 4m8 0l-4 -4"></path>
|
|
</g>
|
|
|
|
<g id="folder">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M9 3a1 1 0 0 1 .608 .206l.1 .087l2.706 2.707h6.586a3 3 0 0 1 2.995 2.824l.005 .176v8a3 3 0 0 1 -2.824 2.995l-.176 .005h-14a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-11a3 3 0 0 1 2.824 -2.995l.176 -.005h4z" stroke-width="0" fill="#ffb900"></path>
|
|
</g>
|
|
|
|
<g id="folder-symlink">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M9 3a1 1 0 0 1 .608 .206l.1 .087l2.706 2.707h6.586a3 3 0 0 1 2.995 2.824l.005 .176v8a3 3 0 0 1 -2.824 2.995l-.176 .005h-14a3 3 0 0 1 -2.995 -2.824l-.005 -.176v-11a3 3 0 0 1 2.824 -2.995l.176 -.005h4z" stroke-width="0" fill="#ffb900"></path>
|
|
<path
|
|
fill="#000000"
|
|
d="M 2.4,49.68 C 2.4,31.056 16.464,15.84 34.392,14.088 V 5.424 c 0,-2.688 3.216,-4.056 5.112,-2.136 l 19.224,19.552 c 0.408,0.416 0.408,1.056 0,1.472 l -19.224,19.552 c -1.896,1.92 -5.112,0.544 -5.112,-2.136 V 33.464 C 19.576,35.8 7.44,44.376 4.448,59.04 3.072,56.064 2.4,52.944 2.4,49.68 Z"
|
|
id="path1"
|
|
transform="scale(0.16) translate(20,50)"/>
|
|
</g>
|
|
|
|
<g id="symlink">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M4 21v-4a3 3 0 0 1 3 -3h5"></path>
|
|
<path d="M9 17l3 -3l-3 -3"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 11v-6a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2h-9.5"></path>
|
|
</g>
|
|
|
|
<g id="generic">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
|
|
</g>
|
|
|
|
<g id="license">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M15 21h-9a3 3 0 0 1 -3 -3v-1h10v2a2 2 0 0 0 4 0v-14a2 2 0 1 1 2 2h-2m2 -4h-11a3 3 0 0 0 -3 3v11"></path>
|
|
<path d="M9 7l4 0"></path>
|
|
<path d="M9 11l4 0"></path>
|
|
</g>
|
|
|
|
<g id="image">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M15 8h.01"></path>
|
|
<path d="M3 6a3 3 0 0 1 3 -3h12a3 3 0 0 1 3 3v12a3 3 0 0 1 -3 3h-12a3 3 0 0 1 -3 -3v-12z"></path>
|
|
<path d="M3 16l5 -5c.928 -.893 2.072 -.893 3 0l5 5"></path>
|
|
<path d="M14 14l1 -1c.928 -.893 2.072 -.893 3 0l3 3"></path>
|
|
</g>
|
|
|
|
<g id="video">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M4 4m0 2a2 2 0 0 1 2 -2h12a2 2 0 0 1 2 2v12a2 2 0 0 1 -2 2h-12a2 2 0 0 1 -2 -2z"></path>
|
|
<path d="M8 4l0 16"></path>
|
|
<path d="M16 4l0 16"></path>
|
|
<path d="M4 8l4 0"></path>
|
|
<path d="M4 16l4 0"></path>
|
|
<path d="M4 12l16 0"></path>
|
|
<path d="M16 8l4 0"></path>
|
|
<path d="M16 16l4 0"></path>
|
|
</g>
|
|
|
|
<g id="audio">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M6 17m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0"></path>
|
|
<path d="M16 17m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0"></path>
|
|
<path d="M9 17l0 -13l10 0l0 13"></path>
|
|
<path d="M9 8l10 0"></path>
|
|
</g>
|
|
|
|
<g id="pdf">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v4"></path>
|
|
<path d="M5 18h1.5a1.5 1.5 0 0 0 0 -3h-1.5v6"></path>
|
|
<path d="M17 18h2"></path>
|
|
<path d="M20 15h-3v6"></path>
|
|
<path d="M11 15v6h1a2 2 0 0 0 2 -2v-2a2 2 0 0 0 -2 -2h-1z"></path>
|
|
</g>
|
|
|
|
<g id="csv">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v4"></path>
|
|
<path d="M7 16.5a1.5 1.5 0 0 0 -3 0v3a1.5 1.5 0 0 0 3 0"></path>
|
|
<path d="M10 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
<path d="M16 15l2 6l2 -6"></path>
|
|
</g>
|
|
|
|
<g id="doc">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
|
|
<path d="M9 9l1 0"></path>
|
|
<path d="M9 13l6 0"></path>
|
|
<path d="M9 17l6 0"></path>
|
|
</g>
|
|
|
|
<g id="sheet">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
|
|
<path d="M8 11h8v7h-8z"></path>
|
|
<path d="M8 15h8"></path>
|
|
<path d="M11 11v7"></path>
|
|
</g>
|
|
|
|
<g id="ppt">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M9 12v-4"></path>
|
|
<path d="M15 12v-2"></path>
|
|
<path d="M12 12v-1"></path>
|
|
<path d="M3 4h18"></path>
|
|
<path d="M4 4v10a2 2 0 0 0 2 2h12a2 2 0 0 0 2 -2v-10"></path>
|
|
<path d="M12 16v4"></path>
|
|
<path d="M9 20h6"></path>
|
|
</g>
|
|
|
|
<g id="archive">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M6 20.735a2 2 0 0 1 -1 -1.735v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2h-1"></path>
|
|
<path d="M11 17a2 2 0 0 1 2 2v2a1 1 0 0 1 -1 1h-2a1 1 0 0 1 -1 -1v-2a2 2 0 0 1 2 -2z"></path>
|
|
<path d="M11 5l-1 0"></path>
|
|
<path d="M13 7l-1 0"></path>
|
|
<path d="M11 9l-1 0"></path>
|
|
<path d="M13 11l-1 0"></path>
|
|
<path d="M11 13l-1 0"></path>
|
|
<path d="M13 15l-1 0"></path>
|
|
</g>
|
|
|
|
<g id="deb">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M12 17c-2.397 -.943 -4 -3.153 -4 -5.635c0 -2.19 1.039 -3.14 1.604 -3.595c2.646 -2.133 6.396 -.27 6.396 3.23c0 2.5 -2.905 2.121 -3.5 1.5c-.595 -.621 -1 -1.5 -.5 -2.5"></path>
|
|
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
|
</g>
|
|
|
|
<g id="dist">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M12 3l8 4.5l0 9l-8 4.5l-8 -4.5l0 -9l8 -4.5"></path>
|
|
<path d="M12 12l8 -4.5"></path>
|
|
<path d="M12 12l0 9"></path>
|
|
<path d="M12 12l-8 -4.5"></path>
|
|
<path d="M16 5.25l-8 4.5"></path>
|
|
</g>
|
|
|
|
<g id="ps1">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M4.887 20h11.868c.893 0 1.664 -.665 1.847 -1.592l2.358 -12c.212 -1.081 -.442 -2.14 -1.462 -2.366a1.784 1.784 0 0 0 -.385 -.042h-11.868c-.893 0 -1.664 .665 -1.847 1.592l-2.358 12c-.212 1.081 .442 2.14 1.462 2.366c.127 .028 .256 .042 .385 .042z"></path>
|
|
<path d="M9 8l4 4l-6 4"></path>
|
|
<path d="M12 16h3"></path>
|
|
</g>
|
|
|
|
<g id="py">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M12 9h-7a2 2 0 0 0 -2 2v4a2 2 0 0 0 2 2h3"></path>
|
|
<path d="M12 15h7a2 2 0 0 0 2 -2v-4a2 2 0 0 0 -2 -2h-3"></path>
|
|
<path d="M8 9v-4a2 2 0 0 1 2 -2h4a2 2 0 0 1 2 2v5a2 2 0 0 1 -2 2h-4a2 2 0 0 0 -2 2v5a2 2 0 0 0 2 2h4a2 2 0 0 0 2 -2v-4"></path>
|
|
<path d="M11 6l0 .01"></path>
|
|
<path d="M13 18l0 .01"></path>
|
|
</g>
|
|
|
|
<g id="sh">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M17 20h-11a3 3 0 0 1 0 -6h11a3 3 0 0 0 0 6h1a3 3 0 0 0 3 -3v-11a2 2 0 0 0 -2 -2h-10a2 2 0 0 0 -2 2v8"></path>
|
|
</g>
|
|
|
|
<g id="dmg">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M3 4m0 1a1 1 0 0 1 1 -1h16a1 1 0 0 1 1 1v14a1 1 0 0 1 -1 1h-16a1 1 0 0 1 -1 -1z"></path>
|
|
<path d="M7 8v1"></path>
|
|
<path d="M17 8v1"></path>
|
|
<path d="M12.5 4c-.654 1.486 -1.26 3.443 -1.5 9h2.5c-.19 2.867 .094 5.024 .5 7"></path>
|
|
<path d="M7 15.5c3.667 2 6.333 2 10 0"></path>
|
|
</g>
|
|
|
|
<g id="iso">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M12 12m-9 0a9 9 0 1 0 18 0a9 9 0 1 0 -18 0"></path>
|
|
<path d="M12 12m-1 0a1 1 0 1 0 2 0a1 1 0 1 0 -2 0"></path>
|
|
<path d="M7 12a5 5 0 0 1 5 -5"></path>
|
|
<path d="M12 17a5 5 0 0 0 5 -5"></path>
|
|
</g>
|
|
|
|
<g id="md">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M3 5m0 2a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2z"></path>
|
|
<path d="M7 15v-6l2 2l2 -2v6"></path>
|
|
<path d="M14 13l2 2l2 -2m-2 2v-6"></path>
|
|
</g>
|
|
|
|
<g id="font">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M17 21h-10a2 2 0 0 1 -2 -2v-14a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2z"></path>
|
|
<path d="M11 18h2"></path>
|
|
<path d="M12 18v-7"></path>
|
|
<path d="M9 12v-1h6v1"></path>
|
|
</g>
|
|
|
|
<g id="go">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M15.695 14.305c1.061 1.06 2.953 .888 4.226 -.384c1.272 -1.273 1.444 -3.165 .384 -4.226c-1.061 -1.06 -2.953 -.888 -4.226 .384c-1.272 1.273 -1.444 3.165 -.384 4.226z"></path>
|
|
<path d="M12.68 9.233c-1.084 -.497 -2.545 -.191 -3.591 .846c-1.284 1.273 -1.457 3.165 -.388 4.226c1.07 1.06 2.978 .888 4.261 -.384a3.669 3.669 0 0 0 1.038 -1.921h-2.427"></path>
|
|
<path d="M5.5 15h-1.5"></path>
|
|
<path d="M6 9h-2"></path>
|
|
<path d="M5 12h-3"></path>
|
|
</g>
|
|
|
|
<g id="html">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v4"></path>
|
|
<path d="M2 21v-6"></path>
|
|
<path d="M5 15v6"></path>
|
|
<path d="M2 18h3"></path>
|
|
<path d="M20 15v6h2"></path>
|
|
<path d="M13 21v-6l2 3l2 -3v6"></path>
|
|
<path d="M7.5 15h3"></path>
|
|
<path d="M9 15v6"></path>
|
|
</g>
|
|
|
|
<g id="js">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M3 15h3v4.5a1.5 1.5 0 0 1 -3 0"></path>
|
|
<path d="M9 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2h-1"></path>
|
|
</g>
|
|
|
|
<g id="css">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v4"></path>
|
|
<path d="M8 16.5a1.5 1.5 0 0 0 -3 0v3a1.5 1.5 0 0 0 3 0"></path>
|
|
<path d="M11 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
<path d="M17 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
</g>
|
|
|
|
<g id="json">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M20 16v-8l3 8v-8"></path>
|
|
<path d="M15 8a2 2 0 0 1 2 2v4a2 2 0 1 1 -4 0v-4a2 2 0 0 1 2 -2z"></path>
|
|
<path d="M1 8h3v6.5a1.5 1.5 0 0 1 -3 0v-.5"></path>
|
|
<path d="M7 15a1 1 0 0 0 1 1h1a1 1 0 0 0 1 -1v-2a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-2a1 1 0 0 1 1 -1h1a1 1 0 0 1 1 1"></path>
|
|
</g>
|
|
|
|
<g id="ts">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v11a2 2 0 0 1 -2 2h-1"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M9 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
<path d="M3.5 15h3"></path>
|
|
<path d="M5 15v6"></path>
|
|
</g>
|
|
|
|
<g id="sql">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M14 3v4a1 1 0 0 0 1 1h4"></path>
|
|
<path d="M5 20.25c0 .414 .336 .75 .75 .75h1.25a1 1 0 0 0 1 -1v-1a1 1 0 0 0 -1 -1h-1a1 1 0 0 1 -1 -1v-1a1 1 0 0 1 1 -1h1.25a.75 .75 0 0 1 .75 .75"></path>
|
|
<path d="M5 12v-7a2 2 0 0 1 2 -2h7l5 5v4"></path>
|
|
<path d="M18 15v6h2"></path>
|
|
<path d="M13 15a2 2 0 0 1 2 2v2a2 2 0 1 1 -4 0v-2a2 2 0 0 1 2 -2z"></path>
|
|
<path d="M14 20l1.5 1.5"></path>
|
|
</g>
|
|
|
|
<g id="db">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M12 6m-8 0a8 3 0 1 0 16 0a8 3 0 1 0 -16 0"></path>
|
|
<path d="M4 6v6a8 3 0 0 0 16 0v-6"></path>
|
|
<path d="M4 12v6a8 3 0 0 0 16 0v-6"></path>
|
|
</g>
|
|
|
|
<g id="email">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M3 7a2 2 0 0 1 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -2 2h-14a2 2 0 0 1 -2 -2v-10z"></path>
|
|
<path d="M3 7l9 6l9 -6"></path>
|
|
</g>
|
|
|
|
<g id="cert">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M15 15m-3 0a3 3 0 1 0 6 0a3 3 0 1 0 -6 0"></path>
|
|
<path d="M13 17.5v4.5l2 -1.5l2 1.5v-4.5"></path>
|
|
<path d="M10 19h-5a2 2 0 0 1 -2 -2v-10c0 -1.1 .9 -2 2 -2h14a2 2 0 0 1 2 2v10a2 2 0 0 1 -1 1.73"></path>
|
|
<path d="M6 9l12 0"></path>
|
|
<path d="M6 12l3 0"></path>
|
|
<path d="M6 15l2 0"></path>
|
|
</g>
|
|
|
|
<g id="keystore">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M16.555 3.843l3.602 3.602a2.877 2.877 0 0 1 0 4.069l-2.643 2.643a2.877 2.877 0 0 1 -4.069 0l-.301 -.301l-6.558 6.558a2 2 0 0 1 -1.239 .578l-.175 .008h-1.172a1 1 0 0 1 -.993 -.883l-.007 -.117v-1.172a2 2 0 0 1 .467 -1.284l.119 -.13l.414 -.414h2v-2h2v-2l2.144 -2.144l-.301 -.301a2.877 2.877 0 0 1 0 -4.069l2.643 -2.643a2.877 2.877 0 0 1 4.069 0z"></path>
|
|
<path d="M15 9h.01"></path>
|
|
</g>
|
|
</defs>
|
|
</svg>
|
|
<header>
|
|
<h1>{{.DirName}}</h1>
|
|
</header>
|
|
<main>
|
|
<div class="listing">
|
|
<table aria-describedby="summary">
|
|
<thead>
|
|
<tr>
|
|
<th></th>
|
|
<th>Name</th>
|
|
<th>Size</th>
|
|
<th class="hideable">
|
|
Modified
|
|
</th>
|
|
<th class="hideable"></th>
|
|
</tr>
|
|
</thead>
|
|
<tbody>
|
|
{{if not .IsRoot}}
|
|
<tr class="clickable">
|
|
<td></td>
|
|
<td><a href="../{{if .DirAppend}}{{.OutputFile}}{{end}}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" class="icon icon-tabler icon-tabler-corner-left-up" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round">
|
|
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
|
|
<path d="M18 18h-6a3 3 0 0 1 -3 -3v-10l-4 4m8 0l-4 -4"></path>
|
|
</svg>
|
|
<span class="goup">..</span></a></td>
|
|
<td>—</td>
|
|
<td class="hideable">—</td>
|
|
<td class="hideable"></td>
|
|
</tr>
|
|
{{end}}
|
|
{{range .Entries}}
|
|
<tr class="file">
|
|
<td></td>
|
|
<td>
|
|
<a href="{{.Path}}">
|
|
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24" viewBox="0 0 24 24" stroke-width="2" stroke="currentColor" fill="none" stroke-linecap="round" stroke-linejoin="round"><use xlink:href="#{{.IconType}}" class="{{.CSSClass}}"></use></svg>
|
|
<span class="name">{{.Name}}</span>
|
|
</a>
|
|
</td>
|
|
<td data-order="{{.Size}}">{{safeHTML .SizePretty}}</td>
|
|
<td class="hideable"><time datetime="{{.ModTimeISO}}">{{.ModTimeHuman}}</time></td>
|
|
<td class="hideable"></td>
|
|
</tr>
|
|
{{end}}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</main>
|
|
</body>
|
|
</html>`
|