-
-
-
+
+ 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;
+ }
+}