updates
parent
8393244e9d
commit
e137f46169
|
@ -417,7 +417,8 @@ td, th {
|
|||
body {
|
||||
font-family: 'Roboto', sans-serif;
|
||||
text-rendering: optimizespeed;
|
||||
padding-top: 4em;
|
||||
padding-top: 5em;
|
||||
background-color: #f5f5f5;
|
||||
}
|
||||
a {
|
||||
color: #006ed3;
|
||||
|
@ -462,6 +463,7 @@ table {
|
|||
tr {
|
||||
border-bottom: 1px dashed #dadada;
|
||||
transition: .1s ease all;
|
||||
cursor: pointer;
|
||||
}
|
||||
tr.selected {
|
||||
background-color: #ccc;
|
||||
|
@ -503,18 +505,19 @@ td .name, td .goup {
|
|||
vertical-align: middle;
|
||||
}
|
||||
footer {
|
||||
padding: 40px 20px;
|
||||
font-size: 12px;
|
||||
font-size: .6em;
|
||||
text-align: center;
|
||||
color: grey;
|
||||
}
|
||||
footer a,
|
||||
footer a:hover {
|
||||
color: inherit;
|
||||
}
|
||||
.container {
|
||||
margin: 0 auto;
|
||||
width: 95%;
|
||||
max-width: 960px;
|
||||
}
|
||||
.listing i {
|
||||
vertical-align: middle;
|
||||
}
|
||||
pre {
|
||||
border: 1px solid #e6e6e6;
|
||||
background-color: #f5f5f5;
|
||||
|
@ -577,47 +580,53 @@ header h1 {
|
|||
}
|
||||
header p {
|
||||
font-size: 1.5em;
|
||||
padding: 0.25em 0;
|
||||
}
|
||||
header p i {
|
||||
vertical-align: middle;
|
||||
font-size: 1em !important;
|
||||
color: rgba(0, 0, 0, 0.21);
|
||||
}
|
||||
header p i {
|
||||
vertical-align: middle;
|
||||
}
|
||||
header form {
|
||||
display: inline-block;
|
||||
background-color: #1E88E5;
|
||||
padding: .75em;
|
||||
color: #212121;
|
||||
border-radius: .3em;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
display: inline-block;
|
||||
background-color: #1E88E5;
|
||||
padding: .75em;
|
||||
color: #212121;
|
||||
border-radius: .3em;
|
||||
height: 100%;
|
||||
vertical-align: middle;
|
||||
}
|
||||
header form input,
|
||||
header form i {
|
||||
header form input, header form i {
|
||||
vertical-align: middle;
|
||||
}
|
||||
header form i {
|
||||
margin-right: .3em;
|
||||
color: rgba(0,0,0,0.5)
|
||||
color: rgba(0, 0, 0, 0.5)
|
||||
}
|
||||
header form input {
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background-color: transparent;
|
||||
min-width: 20em;
|
||||
border: 0;
|
||||
outline: 0;
|
||||
background-color: transparent;
|
||||
min-width: 20em;
|
||||
}
|
||||
::-webkit-input-placeholder { /* WebKit, Blink, Edge */
|
||||
color: rgba(0,0,0,0.5);
|
||||
::-webkit-input-placeholder {
|
||||
/* WebKit, Blink, Edge */
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
:-moz-placeholder { /* Mozilla Firefox 4 to 18 */
|
||||
color: rgba(0,0,0,0.5);
|
||||
opacity: 1;
|
||||
:-moz-placeholder {
|
||||
/* Mozilla Firefox 4 to 18 */
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
::-moz-placeholder { /* Mozilla Firefox 19+ */
|
||||
color: rgba(0,0,0,0.5);
|
||||
opacity: 1;
|
||||
::-moz-placeholder {
|
||||
/* Mozilla Firefox 19+ */
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
opacity: 1;
|
||||
}
|
||||
:-ms-input-placeholder { /* Internet Explorer 10-11 */
|
||||
color: rgba(0,0,0,0.5);
|
||||
:-ms-input-placeholder {
|
||||
/* Internet Explorer 10-11 */
|
||||
color: rgba(0, 0, 0, 0.5);
|
||||
}
|
||||
header, #toolbar {
|
||||
position: fixed;
|
||||
|
@ -627,17 +636,19 @@ header, #toolbar {
|
|||
padding: .5em;
|
||||
display: flex;
|
||||
}
|
||||
#toolbar div,
|
||||
header div {
|
||||
#toolbar div, header div {
|
||||
flex-grow: 1;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#toolbar p,
|
||||
header p {
|
||||
#toolbar p, header p {
|
||||
display: inline-block;
|
||||
margin: 0;
|
||||
vertical-align: middle;
|
||||
}
|
||||
#toolbar p a, header p a,
|
||||
#toolbar p a:hover, header p a:hover {
|
||||
color: inherit;
|
||||
}
|
||||
#toolbar {
|
||||
background-color: #6f6f6f;
|
||||
color: #fff;
|
||||
|
@ -646,11 +657,10 @@ header p {
|
|||
transition: .2s ease-in-out all;
|
||||
}
|
||||
#toolbar.enabled {
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
top: 0;
|
||||
opacity: 1;
|
||||
}
|
||||
#toolbar div:nth-child(2),
|
||||
header div:nth-child(2) {
|
||||
#toolbar div:nth-child(2), header div:nth-child(2) {
|
||||
text-align: right;
|
||||
}
|
||||
.action {
|
||||
|
@ -662,7 +672,7 @@ header div:nth-child(2) {
|
|||
transition: .2s ease all;
|
||||
}
|
||||
.action.disabled {
|
||||
opacity: 0;
|
||||
opacity: .2;
|
||||
}
|
||||
.action i {
|
||||
padding: .5em;
|
||||
|
@ -672,3 +682,45 @@ header div:nth-child(2) {
|
|||
.action:hover i {
|
||||
background-color: rgba(0, 0, 0, 0.1);
|
||||
}
|
||||
|
||||
/* LISTING */
|
||||
|
||||
#listing {
|
||||
display: flex;
|
||||
flex-wrap: wrap;
|
||||
justify-content: space-between;
|
||||
padding: 0 .5em;
|
||||
}
|
||||
#listing .item {
|
||||
background-color: #fff;
|
||||
border-radius: .2em;
|
||||
padding: .5em;
|
||||
margin: 0 .5em 1em;
|
||||
border: .2em solid #fff;
|
||||
cursor: pointer;
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.06), 0 1px 2px rgba(0, 0, 0, 0.12);
|
||||
transition: .2s ease all;
|
||||
flex-grow: 1;
|
||||
}
|
||||
.item:hover {
|
||||
box-shadow: 0 1px 3px rgba(0, 0, 0, 0.12), 0 1px 2px rgba(0, 0, 0, 0.24) !important;
|
||||
}
|
||||
.item.selected {
|
||||
border-color: #6f6f6f !important;
|
||||
}
|
||||
.item div {
|
||||
display: inline-block;
|
||||
vertical-align: middle;
|
||||
}
|
||||
.item p {
|
||||
margin: 0;
|
||||
font-size: .9em;
|
||||
color: #4e4e4e;
|
||||
}
|
||||
.item span {
|
||||
font-weight: bold;
|
||||
}
|
||||
.item i {
|
||||
font-size: 4em;
|
||||
margin-right: .1em;
|
||||
}
|
||||
|
|
|
@ -3,7 +3,7 @@
|
|||
var selectedItems = [];
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function(event) {
|
||||
var items = document.getElementsByTagName('tr');
|
||||
var items = document.getElementsByClassName('item');
|
||||
Array.from(items).forEach(link => {
|
||||
link.addEventListener('click', function(event) {
|
||||
var url = link.getElementsByTagName('a')[0].getAttribute('href');
|
||||
|
@ -31,7 +31,7 @@ document.addEventListener("DOMContentLoaded", function(event) {
|
|||
});
|
||||
|
||||
var backEvent = function(event) {
|
||||
var items = document.getElementsByTagName('tr');
|
||||
var items = document.getElementsByClassName('item');
|
||||
Array.from(items).forEach(link => {
|
||||
link.classList.remove('selected');
|
||||
});
|
||||
|
|
|
@ -5,17 +5,17 @@
|
|||
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
||||
<link href="https://fonts.googleapis.com/icon?family=Material+Icons" rel="stylesheet">
|
||||
<link href='https://fonts.googleapis.com/css?family=Roboto:400,500' rel='stylesheet' type='text/css'>
|
||||
<link rel="stylesheet" href="/_filemanagerinternal/css/styles.css">
|
||||
|
||||
<script src="/_filemanagerinternal/js/application.js"></script>
|
||||
<style>
|
||||
|
||||
</style>
|
||||
<link rel="stylesheet" href="{{ .Config.BaseURL }}/_filemanagerinternal/css/styles.css">
|
||||
<script src="{{ .Config.BaseURL }}/_filemanagerinternal/js/application.js"></script>
|
||||
{{ if ne .Config.StyleSheet "" }}<style>{{ .Config.StyleSheet}}</style>{{ end }}
|
||||
</head>
|
||||
<body>
|
||||
<header>
|
||||
<div>
|
||||
<p>File Manager <i class="material-icons">chevron_right</i> {{ .Name }}</p>
|
||||
{{ $lnk := .PreviousLink }}
|
||||
{{ if ne $lnk ""}}<a href="../../{{.PreviousLink}}"><div class="action" id="prev"><i class="material-icons">subdirectory_arrow_left</i></div></a>{{ else }}
|
||||
<div class="action disabled" id="prev"><i class="material-icons">subdirectory_arrow_left</i></div>{{ end }}
|
||||
<p><a href="{{ if eq .Config.BaseURL "" }}/{{ else }}{{ .Config.BaseURL }}{{ end }}">File Manager</a> {{ if ne .Name "."}}<i class="material-icons">chevron_right</i> {{ .Name }}</p>{{ end }}
|
||||
</div>
|
||||
<div>
|
||||
<form>
|
||||
|
@ -39,12 +39,11 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
File Manager {{range $url, $name := .BreadcrumbMap}}<i>></i><a href="/{{$url}}">{{$name}}</a>{{end}}
|
||||
<main>
|
||||
{{ template "content" .Data }}
|
||||
</main>
|
||||
<footer>
|
||||
Served with <a rel="noopener noreferrer" href="https://caddyserver.com">Caddy</a>.
|
||||
Served with <a rel="noopener noreferrer" href="https://caddyserver.com">Caddy</a> and <a rel="noopener noreferrer" href="https://github.com/hacdias/caddy-filemanager">File Manager</a>.
|
||||
</footer>
|
||||
<script type="text/javascript">
|
||||
function localizeDatetime(e, index, ar) {
|
||||
|
|
|
@ -1,7 +1,32 @@
|
|||
{{ define "content" }}
|
||||
<div class="listing">
|
||||
<div>There are {{.NumDirs}}</b> director{{if eq 1 .NumDirs}}y{{else}}ies{{end}} and {{.NumFiles}}</b> file{{if ne 1 .NumFiles}}s{{end}} in here.</div>
|
||||
<div class="container" id="listing">
|
||||
{{- range .Items}}
|
||||
<div class="item">
|
||||
<div>
|
||||
<a href="{{.URL}}">
|
||||
{{- if .IsDir}}
|
||||
<i class="material-icons">folder</i>
|
||||
{{- else}}
|
||||
<i class="material-icons">insert_drive_file</i>
|
||||
{{- end}}
|
||||
</a>
|
||||
</div>
|
||||
<div>
|
||||
<span class="name">{{.Name}}</span>
|
||||
{{- if .IsDir}}
|
||||
<p data-order="-1">—</p>
|
||||
{{- else}}
|
||||
<p data-order="{{.Size}}">{{.HumanSize}}</p>
|
||||
{{- end}}
|
||||
<p class="hideable"><time datetime="{{.HumanModTime "2006-01-02T15:04:05Z"}}">{{.HumanModTime "01/02/2006 03:04:05 PM -07:00"}}</time></p>
|
||||
</div>
|
||||
</div>
|
||||
{{- end}}
|
||||
</div>
|
||||
|
||||
|
||||
<!--
|
||||
<table class="container" aria-describedby="summary">
|
||||
<thead>
|
||||
<tr>
|
||||
|
@ -57,6 +82,6 @@
|
|||
</tr>
|
||||
{{- end}}
|
||||
</tbody>
|
||||
</table>
|
||||
</table> -->
|
||||
</div>
|
||||
{{ end }}
|
||||
|
|
20
fileinfo.go
20
fileinfo.go
|
@ -35,7 +35,7 @@ type FileInfo struct {
|
|||
func GetFileInfo(url *url.URL, c *Config) (*FileInfo, int, error) {
|
||||
var err error
|
||||
|
||||
path := strings.Replace(url.Path, c.BaseURL, c.PathScope, 1)
|
||||
path := strings.Replace(url.Path, c.BaseURL, "", 1)
|
||||
path = filepath.Clean(path)
|
||||
path = strings.Replace(path, "\\", "/", -1)
|
||||
|
||||
|
@ -138,10 +138,10 @@ func (fi FileInfo) ServeAsHTML(w http.ResponseWriter, r *http.Request, c *Config
|
|||
return fi.serveListing(w, r, c)
|
||||
}
|
||||
|
||||
return fi.serveSingleFile(w, r)
|
||||
return fi.serveSingleFile(w, r, c)
|
||||
}
|
||||
|
||||
func (fi FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request) (int, error) {
|
||||
func (fi FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request, c *Config) (int, error) {
|
||||
err := fi.GetExtendedFileInfo()
|
||||
if err != nil {
|
||||
return ErrorToHTTPCode(err), err
|
||||
|
@ -149,9 +149,10 @@ func (fi FileInfo) serveSingleFile(w http.ResponseWriter, r *http.Request) (int,
|
|||
|
||||
page := &Page{
|
||||
Info: &PageInfo{
|
||||
Name: fi.Path,
|
||||
Path: fi.Path,
|
||||
Data: fi,
|
||||
Name: fi.Path,
|
||||
Path: fi.Path,
|
||||
Data: fi,
|
||||
Config: c,
|
||||
},
|
||||
}
|
||||
|
||||
|
@ -202,9 +203,10 @@ func (fi FileInfo) serveListing(w http.ResponseWriter, r *http.Request, c *Confi
|
|||
|
||||
page := &Page{
|
||||
Info: &PageInfo{
|
||||
Name: listing.Name,
|
||||
Path: listing.Path,
|
||||
Data: listing,
|
||||
Name: listing.Name,
|
||||
Path: listing.Path,
|
||||
Config: c,
|
||||
Data: listing,
|
||||
},
|
||||
}
|
||||
|
||||
|
|
11
page.go
11
page.go
|
@ -49,6 +49,17 @@ func (p PageInfo) BreadcrumbMap() map[string]string {
|
|||
return result
|
||||
}
|
||||
|
||||
// PreviousLink returns the path of the previous folder
|
||||
func (p PageInfo) PreviousLink() string {
|
||||
parts := strings.Split(p.Path, "/")
|
||||
|
||||
if len(parts) <= 1 {
|
||||
return ""
|
||||
}
|
||||
|
||||
return parts[len(parts)-2]
|
||||
}
|
||||
|
||||
// PrintAsHTML formats the page in HTML and executes the template
|
||||
func (p Page) PrintAsHTML(w http.ResponseWriter, templates ...string) (int, error) {
|
||||
templates = append(templates, "base")
|
||||
|
|
6
setup.go
6
setup.go
|
@ -4,6 +4,7 @@ import (
|
|||
"fmt"
|
||||
"io/ioutil"
|
||||
"net/http"
|
||||
"strings"
|
||||
|
||||
"github.com/mholt/caddy"
|
||||
"github.com/mholt/caddy/caddyhttp/httpserver"
|
||||
|
@ -54,7 +55,7 @@ func parseConfiguration(c *caddy.Controller) ([]Config, error) {
|
|||
}
|
||||
|
||||
for c.Next() {
|
||||
var cfg = Config{PathScope: "."}
|
||||
var cfg = Config{PathScope: ".", BaseURL: ""}
|
||||
for c.NextBlock() {
|
||||
switch c.Val() {
|
||||
case "show":
|
||||
|
@ -67,6 +68,9 @@ func parseConfiguration(c *caddy.Controller) ([]Config, error) {
|
|||
return configs, c.ArgErr()
|
||||
}
|
||||
cfg.BaseURL = c.Val()
|
||||
cfg.BaseURL = strings.TrimPrefix(cfg.BaseURL, "/")
|
||||
cfg.BaseURL = strings.TrimSuffix(cfg.BaseURL, "/")
|
||||
cfg.BaseURL = "/" + cfg.BaseURL
|
||||
case "styles":
|
||||
if !c.NextArg() {
|
||||
return configs, c.ArgErr()
|
||||
|
|
Loading…
Reference in New Issue