diff --git a/pixelapi/file.go b/pixelapi/file.go
index fe4cefb..21f0d4f 100644
--- a/pixelapi/file.go
+++ b/pixelapi/file.go
@@ -24,7 +24,12 @@ type FileInfo struct {
MimeType string `json:"mime_type"`
MimeImage string `json:"mime_image"`
ThumbnailHREF string `json:"thumbnail_href"`
- Availability string `json:"availability"`
+
+ Availability string `json:"availability"`
+ AvailabilityMessage string `json:"availability_message"`
+ AvailabilityName string `json:"availability_name"`
+
+ CanEdit bool `json:"can_edit"`
}
// GetFileInfo gets the FileInfo from the pixeldrain API
diff --git a/res/include/img/icons/edit.svg b/res/include/img/icons/edit.svg
new file mode 100644
index 0000000..4b8a056
--- /dev/null
+++ b/res/include/img/icons/edit.svg
@@ -0,0 +1,3 @@
+
+
+
diff --git a/res/include/script/dependencies/Modal.js b/res/include/script/dependencies/Modal.js
new file mode 100644
index 0000000..95f15fb
--- /dev/null
+++ b/res/include/script/dependencies/Modal.js
@@ -0,0 +1,95 @@
+
+let modal_global_index = 100
+
+// Modal creates a new modal window and shows it. The width and height are will
+// be adjusted to the screen size. Content should be added to the `body`
+// property
+function Modal(parent, closeCallback, title, width, height) {
+ this.parent = parent
+ this.closeCallback = closeCallback
+ this.title = title
+ this.width = width
+ this.height = height
+ this.visible = false
+
+ this.background = document.createElement("div")
+ this.background.classList = "modal_background"
+ this.background.addEventListener("click", e => { this.close() })
+
+ this.window = document.createElement("div")
+ this.window.classList = "modal_window"
+ this.window.style.width = this.width
+ this.window.style.height = this.height
+ this.window.addEventListener("click", e => { e.stopPropagation() })
+
+ this.header = document.createElement("div")
+ this.header.classList = "modal_header highlight_1"
+
+ this.titleDiv = document.createElement("div")
+ this.titleDiv.classList = "modal_title"
+ this.titleDiv.innerText = this.title
+
+ this.btnClose = document.createElement("button")
+ this.btnClose.classList = "modal_btn_close button_red"
+ this.btnClose.innerHTML = 'close '
+ this.btnClose.addEventListener("click", e => { this.close() })
+
+ this.body = document.createElement("div")
+ this.body.classList = "modal_body"
+
+ // And add all the elements to eachother.
+ this.header.append(this.titleDiv)
+ this.header.append(this.btnClose)
+ this.window.append(this.header)
+ this.window.append(this.body)
+ this.background.append(this.window)
+}
+
+Modal.prototype.setTitle = function(title) {
+ this.title = title
+ this.titleDiv.innerText = title
+}
+
+Modal.prototype.setBody = function(element) {
+ this.body.innerHTML = ""
+ this.body.append(element)
+}
+
+Modal.prototype.open = function() {
+ if (this.visible) { return }
+ this.visible = true
+
+ console.debug("Showing modal "+this.title)
+
+ // Each time a modal is shown it gets a z-index which is one higher of the
+ // previous one. This makes sure they are always shown and closed in order
+ this.background.style.zIndex = modal_global_index
+ modal_global_index++
+
+ this.parent.prepend(this.background)
+
+ // If an element is created and shown in the same frame it won't render the
+ // transition. So here we wait for a few frames to make it visible
+ this.background.style.display = ""
+ setTimeout(() => { this.background.style.opacity = 1 }, 40)
+
+ // This is a workaround for a chrome bug which makes it so hidden
+ // windows can't be scrolled after they are shown
+ this.body.focus()
+}
+
+Modal.prototype.close = function() {
+ if (!this.visible) { return }
+ this.visible = false
+
+ if (this.closeCallback) {
+ this.closeCallback()
+ }
+
+ // First we make it invisible with a transition. When we remove it so the
+ // user can click through it
+ this.background.style.opacity = 0
+
+ // Wait for the animation to finish and remove the window
+ setTimeout(() => {this.parent.removeChild(this.background)}, 400)
+}
diff --git a/res/include/script/file_manager/DirectoryElement.js b/res/include/script/file_manager/DirectoryElement.js
index 7c8c994..3b035cd 100644
--- a/res/include/script/file_manager/DirectoryElement.js
+++ b/res/include/script/file_manager/DirectoryElement.js
@@ -53,7 +53,7 @@ function DirectoryElement(directoryArea, footer) {
// files in the directory and the last scroll position. These are used for
// rendering the file list correctly
- // type: {icon, name, href, type, size, sizeLabel, dateCreated}
+ // type: {icon, name, href, type, size, sizeLabel, dateCreated, selected}
this.allFiles = []
// This array contains indexes referring to places in the allFiles array
@@ -77,6 +77,7 @@ DirectoryElement.prototype.addFile = function(icon, name, href, type, size, size
size: size,
sizeLabel: sizeLabel,
dateCreated: dateCreated,
+ selected: false,
})
}
diff --git a/res/include/script/file_manager/DirectoryNode.js b/res/include/script/file_manager/DirectoryNode.js
new file mode 100644
index 0000000..0933a91
--- /dev/null
+++ b/res/include/script/file_manager/DirectoryNode.js
@@ -0,0 +1,99 @@
+
+function DirectoryNode(file, index) {
+ this.el = document.createElement("div")
+ this.el.classList = "node"
+ if (file.selected) {
+ this.el.classList += " node_selected"
+ }
+ this.el.href = file.href
+ this.el.target = "_blank"
+ this.el.title = file.name
+ this.el.setAttribute("fileindex", index)
+
+ this.el.addEventListener("click", e => {
+ if (e.detail > 1) {
+ return // Prevent dblclick from triggering click
+ }
+ if (e.which == 2) {
+ // Middle mouse button opens the file in a new window
+ this.open(true)
+ return
+ }
+ this.select()
+ })
+ this.el.addEventListener("tap")
+ this.el.addEventListener("dblclick", e => {
+ this.open(false)
+ })
+
+ {
+ let cell = document.createElement("div")
+ let thumb = document.createElement("img")
+ thumb.src = file.icon
+ cell.appendChild(thumb)
+ let label = document.createElement("span")
+ label.innerText = file.name
+ cell.appendChild(label)
+ cell.appendChild(label)
+ this.el.appendChild(cell)
+ }
+ {
+ let cell = document.createElement("div")
+ cell.style.width = this.fieldDateWidth
+ let label = document.createElement("span")
+ label.innerText = printDate(new Date(file.dateCreated), true, true, false)
+ cell.appendChild(label)
+ this.el.appendChild(cell)
+ }
+ {
+ let cell = document.createElement("div")
+ cell.style.width = this.fieldSizeWidth
+ let label = document.createElement("span")
+ label.innerText = file.sizeLabel
+ cell.appendChild(label)
+ this.el.appendChild(cell)
+ }
+ {
+ let cell = document.createElement("div")
+ cell.style.width = this.fieldTypeWidth
+ let label = document.createElement("span")
+ label.innerText = file.type
+ cell.appendChild(label)
+ this.el.appendChild(cell)
+ }
+
+ return this.el
+}
+
+DirectoryNode.prototype.select = function() {
+ if (this.el.classList.contains("node_selected")) {
+ this.el.classList = "node"
+ file.selected = false
+ } else {
+ this.el.classList = "node node_selected"
+ file.selected = true
+ }
+}
+DirectoryNode.prototype.open = function(newTab) {
+ if (newTab) {
+ window.open(file.href, "_blank")
+ } else {
+ window.open(file.href)
+ }
+}
+DirectoryNode.prototype.click = function(e) {
+ if (e.detail > 1) {
+ return // Prevent dblclick from triggering click
+ }
+ if (e.which == 2) {
+ // Middle mouse button opens the file in a new window
+ e.preventDefault()
+ window.open(file.href, "_blank")
+ return
+ }
+
+
+}
+DirectoryNode.prototype.doubleClick = function() {
+ window.open(file.href)
+}
diff --git a/res/include/script/file_viewer/DetailsWindow.js b/res/include/script/file_viewer/DetailsWindow.js
index a7401fb..8afe5ca 100644
--- a/res/include/script/file_viewer/DetailsWindow.js
+++ b/res/include/script/file_viewer/DetailsWindow.js
@@ -3,32 +3,30 @@ function DetailsWindow(viewer) {
this.visible = false
this.file = null
this.graph = 0
+ this.modal = new Modal(
+ document.getElementById("file_viewer"),
+ () => { this.toggle() },
+ "File Details", "1200px", "1000px",
+ )
- this.divPopup = document.getElementById("details_popup")
- this.btnDetails = document.getElementById("btn_details")
- this.btnCloseDetails = document.getElementById("btn_close_details")
- this.divFileDetails = document.getElementById("info_file_details")
+ let clone = document.getElementById("tpl_details_popup").content.cloneNode(true)
+ this.divFileDetails = clone.querySelector(".info_file_details")
+ this.modal.setBody(clone)
- this.btnDetails.addEventListener("click", () => { this.toggle() })
- this.btnCloseDetails.addEventListener("click", () => { this.toggle() })
+ this.btnDetails = document.getElementById("btn_details")
+ this.btnDetails.addEventListener("click", () => { this.toggle() })
}
DetailsWindow.prototype.toggle = function() {
if (this.visible) {
- this.divPopup.style.opacity = "0"
- this.divPopup.style.visibility = "hidden"
+ this.modal.close()
this.btnDetails.classList.remove("button_highlight")
this.visible = false
} else {
- this.divPopup.style.opacity = "1"
- this.divPopup.style.visibility = "visible"
+ this.modal.open()
this.btnDetails.classList.add("button_highlight")
this.visible = true
- // This is a workaround for a chrome bug which makes it so hidden
- // windows can't be scrolled after they are shown
- this.divPopup.focus()
-
if (this.graph === 0) {
this.renderGraph()
}
@@ -42,8 +40,7 @@ DetailsWindow.prototype.setFile = function(file) {
if (this.viewer.isList) {
desc = file.description
}
- this.divFileDetails.innerHTML = "
"
- + "Name " + escapeHTML(file.name) + " "
+ this.divFileDetails.innerHTML = "Name " + escapeHTML(file.name) + " "
+ "URL "+file.link+" "
+ "Mime Type " + escapeHTML(file.mime_type) + " "
+ "ID " + file.id + " "
@@ -51,7 +48,6 @@ DetailsWindow.prototype.setFile = function(file) {
+ "Bandwidth " + formatDataVolume(file.bandwidth_used, 4) + " "
+ "Upload Date " + printDate(file.date_created, true, true, true) + " "
+ "Description " + escapeHTML(desc) + " "
- + "
"
if(this.visible && file.timeseries_href !== "") {
this.updateGraph(file)
diff --git a/res/include/script/file_viewer/EditWindow.js b/res/include/script/file_viewer/EditWindow.js
new file mode 100644
index 0000000..26c84a9
--- /dev/null
+++ b/res/include/script/file_viewer/EditWindow.js
@@ -0,0 +1,52 @@
+function EditWindow() {
+ this.visible = false
+ this.modal = new Modal(
+ document.getElementById("file_viewer"),
+ () => { this.toggle() },
+ "Edit File", "1000px", "auto",
+ )
+
+ let clone = document.getElementById("tpl_edit_file").content.cloneNode(true)
+ clone.querySelector(".btn_delete_file").addEventListener("click", () => { this.deleteFile() })
+ this.modal.setBody(clone)
+
+ this.btnEdit = document.getElementById("btn_edit")
+ this.btnEdit.addEventListener("click", () => { this.toggle() })
+}
+
+EditWindow.prototype.toggle = function() {
+ if (this.visible) {
+ this.modal.close()
+ this.btnEdit.classList.remove("button_highlight")
+ this.visible = false
+ } else if (!this.visible && this.file.can_edit) {
+ this.modal.open()
+ this.btnEdit.classList.add("button_highlight")
+ this.visible = true
+ }
+}
+
+EditWindow.prototype.setFile = function(file) {
+ this.file = file
+ this.modal.setTitle("Editing "+file.name)
+
+ if (this.file.can_edit) {
+ this.btnEdit.style.display = ""
+ } else {
+ this.btnEdit.style.display = "none"
+ }
+}
+
+EditWindow.prototype.deleteFile = function() {
+ if (!confirm("Are you sure you want to delete '"+this.file.name+"'?")) {
+ return
+ }
+
+ fetch(
+ this.file.get_href, {method: "DELETE"}
+ ).then(resp => {
+ this.modal.setBody(document.createTextNode("This file has been deleted"))
+ }).catch(err => {
+ alert("Error! Could not delete file")
+ })
+}
diff --git a/res/include/script/file_viewer/Toolbar.js b/res/include/script/file_viewer/Toolbar.js
index c9d00a1..d7be9b4 100644
--- a/res/include/script/file_viewer/Toolbar.js
+++ b/res/include/script/file_viewer/Toolbar.js
@@ -1,8 +1,9 @@
function Toolbar(viewer) {
- this.viewer = viewer
- this.visible = false
- this.sharebarVisible = false
- this.currentFile = null
+ this.viewer = viewer
+ this.visible = false
+ this.sharebarVisible = false
+ this.currentFile = null
+ this.editWindow = null
this.divToolbar = document.getElementById("toolbar")
this.divFilePreview = document.getElementById("filepreview")
@@ -69,71 +70,67 @@ Toolbar.prototype.toggleSharebar = function() {
}
Toolbar.prototype.download = function() {
- let triggerDL = (captchaResp = "") => {
- if (captchaResp === "") {
- this.downloadFrame.src = this.currentFile.download_href
- } else {
- this.downloadFrame.src = this.currentFile.download_href+"&recaptcha_response="+captchaResp
- }
- }
-
if (captchaKey === "none" || captchaKey === ""){
- // If the server doesn't support captcha there's no use in checking
- // availability
- triggerDL()
- return
- }
- if (recaptchaResponse !== "") {
- // Captcha already filled in. Use the saved captcha responsse to
- // download the file
- triggerDL(recaptchaResponse)
-
- // Reset the key
- recaptchaResponse = ""
+ console.debug("Server doesn't support captcha, starting download")
+ this.downloadFrame.src = this.currentFile.download_href
return
}
- fetch(this.currentFile.availability_href).then(resp => {
- return resp.json()
- }).then(resp => {
- let popupDiv = document.getElementById("captcha_popup")
- let popupTitle = document.getElementById("captcha_popup_title")
- let popupContent = document.getElementById("captcha_popup_content")
+ if (this.currentFile.availability === "") {
+ console.debug("File is available, starting download")
+ this.downloadFrame.src = this.currentFile.download_href
+ } else {
+ console.debug("File is not readily available, showing captcha dialog")
+
+ let showCaptcha = (title, text) => {
+ // Create the modal
+ this.captchaModal = new Modal(
+ document.getElementById("file_viewer"),
+ null, title, "500px", "auto",
+ )
+
+ // Clone the popup contents and insert them into the popup
+ let clone = document.getElementById("tpl_captcha_popup").content.cloneNode(true)
+ clone.querySelector(".captcha_text").innerText = text
+ recaptchaElement = clone.querySelector(".captcha_popup_captcha")
+ this.captchaModal.setBody(clone)
+
+ // Set the callback function
+ recaptchaCallback = token => {
+ // Download the file using the recaptcha token
+ this.downloadFrame.src = this.currentFile.download_href+"&recaptcha_response="+token
+ this.captchaModal.close()
+ }
- let showCaptcha = () => {
// Load the recaptcha script with a load function
let script = document.createElement("script")
script.src = "https://www.google.com/recaptcha/api.js?onload=loadCaptcha&render=explicit"
document.body.appendChild(script)
// Show the popup
- popupDiv.style.opacity = "1"
- popupDiv.style.visibility = "visible"
+ this.captchaModal.open()
}
- if (resp.value === "file_rate_limited_captcha_required") {
- popupTitle.innerText = "Rate limiting enabled!"
- popupContent.innerText = "This file is using a suspicious "+
- "amount of bandwidth relative to its popularity. To "+
- "continue downloading this file you will have to "+
- "prove that you're a human first."
- showCaptcha()
- } else if (resp.value === "virus_detected_captcha_required") {
- popupTitle.innerText = "Malware warning!"
- popupContent.innerText = "According to our scanning "+
- "systems this file may contain a virus of type '"+
- resp.extra+"'. You can continue downloading this file at "+
- "your own risk, but you will have to prove that you're a "+
- "human first."
- showCaptcha()
- } else {
- console.warn("resp.value not valid: "+resp.value)
- triggerDL()
+ console.log(this.currentFile.availability)
+ if (this.currentFile.availability === "file_rate_limited_captcha_required") {
+ console.debug("Showing rate limiting captcha")
+ showCaptcha(
+ "Rate limiting enabled!",
+ "This file is using a suspicious amount of bandwidth relative "+
+ "to its popularity. To continue downloading this file you "+
+ "will have to prove that you're a human first.",
+ )
+ } else if (this.currentFile.availability === "virus_detected_captcha_required") {
+ console.debug("Showing virus captcha")
+ showCaptcha(
+ "Malware warning!",
+ "According to our scanning systems this file may contain a "+
+ "virus of type '"+this.currentFile.availability_name+"'. You "+
+ "can continue downloading this file at your own risk, but you "+
+ "will have to prove that you're a human first.",
+ )
}
- }).catch(e => {
- console.warn("fetch availability failed: "+e)
- triggerDL()
- })
+ }
}
Toolbar.prototype.copyUrl = function() {
@@ -154,23 +151,13 @@ Toolbar.prototype.copyUrl = function() {
}, 60000)
}
-
// Called by the google recaptcha script
-let recaptchaResponse = ""
+let recaptchaElement = null
+let recaptchaCallback = null
function loadCaptcha(){
- grecaptcha.render("captcha_popup_captcha", {
+ grecaptcha.render(recaptchaElement, {
sitekey: captchaKey,
theme: "dark",
- callback: token => {
- recaptchaResponse = token
- document.getElementById("btn_download").click()
-
- // Hide the popup
- setTimeout(() => {
- let popupDiv = document.getElementById("captcha_popup")
- popupDiv.style.opacity = "0"
- popupDiv.style.visibility = "hidden"
- }, 1000)
- }
+ callback: recaptchaCallback,
})
}
diff --git a/res/include/script/file_viewer/Viewer.js b/res/include/script/file_viewer/Viewer.js
index e208e65..89bb2e4 100644
--- a/res/include/script/file_viewer/Viewer.js
+++ b/res/include/script/file_viewer/Viewer.js
@@ -4,6 +4,7 @@ function Viewer(type, viewToken, data) {
this.listNavigator = null
this.detailsWindow = null
this.divFilepreview = null
+ this.file = null
this.title = "" // Contains either the file name or list title
this.listId = ""
this.viewToken = ""
@@ -14,6 +15,7 @@ function Viewer(type, viewToken, data) {
this.viewToken = viewToken
this.toolbar = new Toolbar(this)
this.detailsWindow = new DetailsWindow(this)
+ this.editWindow = new EditWindow()
this.divFilepreview = document.getElementById("filepreview")
@@ -63,7 +65,13 @@ function Viewer(type, viewToken, data) {
this.initialized = true
}
+Viewer.prototype.getFile = function() {
+ return this.file
+}
+
Viewer.prototype.setFile = function(file) {
+ this.file = file
+
if (this.isList) {
document.getElementById("file_viewer_headerbar_title").style.lineHeight = "1em"
document.getElementById("file_viewer_list_title").innerText = this.title
@@ -76,6 +84,7 @@ Viewer.prototype.setFile = function(file) {
// Relay the file change event to all components
this.detailsWindow.setFile(file)
+ this.editWindow.setFile(file)
this.toolbar.setFile(file)
// Register a new view. We don't care what this returns becasue we can't
@@ -169,6 +178,7 @@ Viewer.prototype.keyboardEvent = function(evt) {
return // prevent custom shortcuts from interfering with system shortcuts
}
+ console.debug("Key pressed: "+evt.keyCode)
switch (evt.keyCode) {
case 65: // A or left arrow key go to previous file
case 37:
@@ -200,6 +210,9 @@ Viewer.prototype.keyboardEvent = function(evt) {
case 73: // I to open the details window
this.detailsWindow.toggle()
break
+ case 69: // E to open the edit window
+ this.editWindow.toggle()
+ break
case 81: // Q to close the window
window.close()
break
@@ -217,35 +230,28 @@ function escapeHTML(str) {
}
function fileFromAPIResp(resp) {
- let file = {
- id: resp.id,
- name: resp.name,
- mime_type: resp.mime_type,
- size: resp.size,
- date_created: new Date(resp.date_upload),
- date_last_view: new Date(resp.date_last_view),
- views: resp.views,
- bandwidth_used: resp.bandwidth_used,
- description: "",
- icon_href: apiEndpoint+"/file/"+resp.id+"/thumbnail",
- get_href: apiEndpoint+"/file/"+resp.id,
- download_href: apiEndpoint+"/file/"+resp.id+"?download",
- availability_href: apiEndpoint+"/file/"+resp.id+"/availability",
- view_href: apiEndpoint+"/file/"+resp.id+"/view",
- timeseries_href: apiEndpoint+"/file/"+resp.id+"/timeseries",
- link: domainURL()+"/u/"+resp.id,
+ resp.date_created = new Date(resp.date_upload)
+ resp.date_last_view = new Date(resp.date_last_view)
+ resp.icon_href = apiEndpoint+"/file/"+resp.id+"/thumbnail"
+ resp.get_href = apiEndpoint+"/file/"+resp.id
+ resp.download_href = apiEndpoint+"/file/"+resp.id+"?download"
+ resp.view_href = apiEndpoint+"/file/"+resp.id+"/view"
+ resp.timeseries_href = apiEndpoint+"/file/"+resp.id+"/timeseries"
+ resp.link = domainURL()+"/u/"+resp.id
+ if (resp.description === undefined) {
+ resp.description = ""
}
- if (resp.description !== undefined) {
- file.description = resp.description
- }
- return file
+
+ console.debug("New file:")
+ console.debug(resp)
+
+ return resp
}
function fileFromSkyNet(resp) {
let file = fileFromAPIResp(resp)
file.icon_href = "/res/img/mime/empty.png"
- file.get_href = "https://sky.pixeldrain.com/file/"+resp.id
- file.download_href = "https://sky.pixeldrain.com/file/"+resp.id+"?attachment=1"
- file.availability_href = ""
+ file.get_href = "https://skydrain.net/file/"+resp.id
+ file.download_href = "https://skydrain.net/file/"+resp.id+"?attachment=1"
file.view_href = ""
file.timeseries_href = ""
file.link = domainURL()+"/s/"+resp.id
diff --git a/res/include/style/file_manager.css b/res/include/style/file_manager.css
index fea4098..6386613 100644
--- a/res/include/style/file_manager.css
+++ b/res/include/style/file_manager.css
@@ -123,11 +123,15 @@
/* padding-top: 6px; */
}
-.node:hover, .node_selected {
+.node:hover:not(.node_selected) {
background-color: var(--input_color_dark);
color: var(--input_text_color);
text-decoration: none;
}
+.node_selected {
+ background-color: var(--highlight_color);
+ color: var(--highlight_text_color);
+}
.node > div {
height: 100%;
overflow: hidden;
diff --git a/res/include/style/layout.css b/res/include/style/layout.css
index 1388005..ee054c6 100644
--- a/res/include/style/layout.css
+++ b/res/include/style/layout.css
@@ -17,7 +17,35 @@
local('Cantarell Light'),
local('Cantarell, Light'),
local('Cantarell-Light'),
- url("/res/misc/Cantarell-Light.otf") format("opentype");
+ url(/res/misc/Cantarell-Light.otf) format("opentype");
+}
+
+@font-face {
+ font-family: 'Material Icons';
+ font-style: normal;
+ font-weight: 400;
+ src: local('Material Icons'),
+ local('MaterialIcons-Regular'),
+ url(/res/misc/MaterialIcons-Regular.woff2) format('woff2'),
+ url(/res/misc/MaterialIcons-Regular.woff) format('woff'),
+ url(/res/misc/MaterialIcons-Regular.ttf) format('truetype');
+}
+.icon {
+ font-family: 'Material Icons';
+ font-weight: normal;
+ font-style: normal;
+ font-size: 24px; /* Preferred icon size */
+ display: inline-block;
+ line-height: 1;
+ text-transform: none;
+ letter-spacing: normal;
+ word-wrap: normal;
+ white-space: nowrap;
+ direction: ltr;
+ text-rendering: optimizeLegibility;
+}
+.icon.small {
+ font-size: 16px;
}
/* Page rendering configuration */
diff --git a/res/include/style/modal.css b/res/include/style/modal.css
new file mode 100644
index 0000000..4873931
--- /dev/null
+++ b/res/include/style/modal.css
@@ -0,0 +1,58 @@
+.modal_background {
+ position: absolute;
+ top: 0;
+ right: 0;
+ bottom: 0;
+ left: 0;
+ background-color: rgba(0, 0, 0, 0.6);
+ opacity: 0;
+ transition: opacity .4s;
+}
+
+.modal_window {
+ position: absolute;
+ z-index: inherit;
+ display: flex;
+ flex-direction: column;
+ background-color: var(--layer_2_color);
+ max-height: 100%;
+ max-width: 100%;
+ top: 20%;
+ left: 50%;
+ transform: translate(-50%, -20%);
+ padding: 0;
+ box-sizing: border-box;
+ text-align: left;
+ box-shadow: var(--shadow_color) 0px 0px 50px;
+}
+
+.modal_header {
+ flex-grow: 0;
+ flex-shrink: 0;
+ display: flex;
+ flex-direction: row;
+ padding: 4px;
+}
+
+.modal_title {
+ flex-grow: 1;
+ flex-shrink: 0;
+
+ display: flex;
+ flex-direction: row;
+ align-items: center;
+ justify-content: center;
+ font-size: 1.2em;
+}
+
+.modal_btn_close {
+ flex-grow: 0;
+ flex-shrink: 0;
+}
+
+.modal_body {
+ flex-grow: 1;
+ flex-shrink: 1;
+ overflow: auto;
+ padding: 10px;
+}
diff --git a/res/include/style/viewer.css b/res/include/style/viewer.css
index 3d6816d..2aa3959 100644
--- a/res/include/style/viewer.css
+++ b/res/include/style/viewer.css
@@ -253,45 +253,7 @@
|| MISC COMPONENTS ||
===================== */
-.popup {
- position: absolute;
- visibility: hidden;
- display: flex;
- flex-direction: column;
- opacity: 0;
- transition: visibility .5s, opacity .5s;
- background-color: var(--layer_2_color);
- border-color: var(--layer_2_color_border);
- max-height: 100%;
- max-width: 100%;
- top: 20%;
- left: 50%;
- transform: translate(-50%, -20%);
- padding: 0;
- box-sizing: border-box;
- text-align: left;
- box-shadow: var(--shadow_color) 0px 0px 50px;
-}
-.popup > .highlight_1 {
- font-size: 1.2em;
-}
-.popup > .content_area {
- flex: 1;
- overflow: auto;
- padding: 10px;
-}
-
-.details_popup{
- width: 1500px;
- height: 800px;
- z-index: 200;
-}
-.captcha_popup{
- height: auto;
- width: 450px;
- z-index: 201;
-}
-#captcha_popup_captcha > div {
+.captcha_popup_captcha > div {
display: inline-block;
}
diff --git a/res/static/misc/MaterialIcons-Regular.ttf b/res/static/misc/MaterialIcons-Regular.ttf
new file mode 100644
index 0000000..7015564
Binary files /dev/null and b/res/static/misc/MaterialIcons-Regular.ttf differ
diff --git a/res/static/misc/MaterialIcons-Regular.woff b/res/static/misc/MaterialIcons-Regular.woff
new file mode 100644
index 0000000..b648a3e
Binary files /dev/null and b/res/static/misc/MaterialIcons-Regular.woff differ
diff --git a/res/static/misc/MaterialIcons-Regular.woff2 b/res/static/misc/MaterialIcons-Regular.woff2
new file mode 100644
index 0000000..9fa2112
Binary files /dev/null and b/res/static/misc/MaterialIcons-Regular.woff2 differ
diff --git a/res/template/account/file_manager.html b/res/template/account/file_manager.html
index 09b865b..1cdfa38 100644
--- a/res/template/account/file_manager.html
+++ b/res/template/account/file_manager.html
@@ -50,10 +50,10 @@
let breadcrumbs = document.querySelector("#nav_bar > .breadcrumbs")
if (window.location.href.endsWith("?files")) {
- breadcrumbs.value += "/Files"
+ breadcrumbs.value = "/{{.Username}}/Files"
fm.getUserFiles()
} else if (window.location.href.endsWith("?lists")) {
- breadcrumbs.value += "/Lists"
+ breadcrumbs.value = "/{{.Username}}/Lists"
fm.getUserLists()
} else {
alert("invalid file manager type")
diff --git a/res/template/file_viewer.html b/res/template/file_viewer.html
index 57c0fb5..bcec57b 100644
--- a/res/template/file_viewer.html
+++ b/res/template/file_viewer.html
@@ -13,7 +13,7 @@
{{.OGData}}
@@ -22,7 +22,7 @@
- {{template `close.svg` .}}
+
+ close
+
@@ -43,29 +45,33 @@
N/A
- {{template `save.svg` .}}
+ save
Download
-
- {{template `save.svg` .}}
+
+ save
DL all files
- {{template `copy.svg` .}}
+ content_copy
C opy Link
- {{template `share.svg` .}}
+ share
Share
-
- {{template `shuffle.svg` .}}
+
+ shuffle
Shuffle ☐
- {{template `help.svg` .}}
+ help
Detai ls
+
+ edit
+ E dit
+
{{template "advertisement" .}}
@@ -99,52 +105,61 @@
{{template "spinner.svg" .}}
-
-
-
-
+
+
+
+ Delete file
+
+ When you delete a file it cannot be recovered.
+ Nobody will be able to download it and the link will
+ stop working. The file will also disappear from any
+ lists it's contained in.
+
+
+
+ delete Delete this file
+
+
+
+
+
+