diff --git a/src/GitHubCostVisualizer.Web/Views/Home/Index.cshtml b/src/GitHubCostVisualizer.Web/Views/Home/Index.cshtml index 8c56019..48af636 100644 --- a/src/GitHubCostVisualizer.Web/Views/Home/Index.cshtml +++ b/src/GitHubCostVisualizer.Web/Views/Home/Index.cshtml @@ -8,13 +8,11 @@

Unsure of where your money is going with your Github account? Upload your recent Usage report from Github to get a visual on where your money is going

- - -
- - - +
+ Drop a Github usage file here or click to upload +
+
Your uploaded file is never stored and processed in real-time only. @@ -28,7 +26,8 @@ @section scripts{ - + } diff --git a/src/GitHubCostVisualizer.Web/Views/Shared/_Start.cshtml b/src/GitHubCostVisualizer.Web/Views/Shared/_Start.cshtml index 7bbe003..4fbda92 100644 --- a/src/GitHubCostVisualizer.Web/Views/Shared/_Start.cshtml +++ b/src/GitHubCostVisualizer.Web/Views/Shared/_Start.cshtml @@ -11,6 +11,7 @@ + diff --git a/src/GitHubCostVisualizer.Web/wwwroot/css/dragdrop.css b/src/GitHubCostVisualizer.Web/wwwroot/css/dragdrop.css new file mode 100644 index 0000000..76d6437 --- /dev/null +++ b/src/GitHubCostVisualizer.Web/wwwroot/css/dragdrop.css @@ -0,0 +1,48 @@ + +.drop-zone { + max-width: 100%; + height: 200px; + padding: 25px; + display: flex; + align-items: center; + justify-content: center; + text-align: center; + font-family: "Quicksand", sans-serif; + font-weight: 500; + font-size: 20px; + cursor: pointer; + color: #cccccc; + border: 4px dashed #2286c9; + border-radius: 10px; +} + +.drop-zone--over { + border-style: solid; +} + +.drop-zone__input { + display: none; +} + +.drop-zone__thumb { + width: 100%; + height: 100%; + border-radius: 10px; + overflow: hidden; + background-color: #4a8fbd; + background-size: cover; + position: relative; +} + +.drop-zone__thumb::after { + content: attr(data-label); + position: absolute; + bottom: 0; + left: 0; + width: 100%; + padding: 5px 0; + color: #ffffff; + background: rgba(0, 0, 0, 0.75); + font-size: 14px; + text-align: center; +} diff --git a/src/GitHubCostVisualizer.Web/wwwroot/js/dragdrop.js b/src/GitHubCostVisualizer.Web/wwwroot/js/dragdrop.js new file mode 100644 index 0000000..519eaa3 --- /dev/null +++ b/src/GitHubCostVisualizer.Web/wwwroot/js/dragdrop.js @@ -0,0 +1,71 @@ +document.querySelectorAll(".drop-zone__input").forEach((inputElement) => { + const dropZoneElement = inputElement.closest(".drop-zone"); + + dropZoneElement.addEventListener("click", (e) => { + inputElement.click(); + }); + + inputElement.addEventListener("change", (e) => { + if (inputElement.files.length) { + updateThumbnail(dropZoneElement, inputElement.files[0]); + } + }); + + dropZoneElement.addEventListener("dragover", (e) => { + e.preventDefault(); + dropZoneElement.classList.add("drop-zone--over"); + }); + + ["dragleave", "dragend"].forEach((type) => { + dropZoneElement.addEventListener(type, (e) => { + dropZoneElement.classList.remove("drop-zone--over"); + }); + }); + + dropZoneElement.addEventListener("drop", (e) => { + e.preventDefault(); + + if (e.dataTransfer.files.length) { + inputElement.files = e.dataTransfer.files; + updateThumbnail(dropZoneElement, e.dataTransfer.files[0]); + } + + dropZoneElement.classList.remove("drop-zone--over"); + }); +}); + +/** + * Updates the thumbnail on a drop zone element. + * + * @param {HTMLElement} dropZoneElement + * @param {File} file + */ +function updateThumbnail(dropZoneElement, file) { + let thumbnailElement = dropZoneElement.querySelector(".drop-zone__thumb"); + + // First time - remove the prompt + if (dropZoneElement.querySelector(".drop-zone__prompt")) { + dropZoneElement.querySelector(".drop-zone__prompt").remove(); + } + + // First time - there is no thumbnail element, so lets create it + if (!thumbnailElement) { + thumbnailElement = document.createElement("div"); + thumbnailElement.classList.add("drop-zone__thumb"); + dropZoneElement.appendChild(thumbnailElement); + } + + thumbnailElement.dataset.label = file.name; + + // Show thumbnail for image files + if (file.type.startsWith("image/")) { + const reader = new FileReader(); + + reader.readAsDataURL(file); + reader.onload = () => { + thumbnailElement.style.backgroundImage = `url('${reader.result}')`; + }; + } else { + thumbnailElement.style.backgroundImage = null; + } +}