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