Created
August 27, 2025 07:48
-
-
Save Kjaer/34501e1a72c1aee2512bbe69fa7359db to your computer and use it in GitHub Desktop.
PROJE
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| <!DOCTYPE html> | |
| <html lang="en"> | |
| <head> | |
| <meta charset="UTF-8" /> | |
| <link rel="icon" type="image/png" href="favicon_octopus.png" /> | |
| <meta name="viewport" content="width=device-width, initial-scale=1.0" /> | |
| <link | |
| rel="stylesheet" | |
| href="https://cdnjs.cloudflare.com/ajax/libs/font-awesome/7.0.0/css/all.min.css" | |
| integrity="sha512-DxV+EoADOkOygM4IR9yXP8Sb2qwgidEmeqAEmDKIOfPRQZOWbXCzLC6vjbZyy0vPisbH2SyW27+ddLVCN+OMzQ==" | |
| crossorigin="anonymous" | |
| referrerpolicy="no-referrer" | |
| /> | |
| <link rel="stylesheet" href="/src/style.css" /> | |
| <title>CSV to JSON APP</title> | |
| </head> | |
| <body> | |
| <div class="container"> | |
| <h1>CSV to JSON Converter</h1> | |
| <div class="content"> | |
| <div class="form-section"> | |
| <h2>Datei-Section:</h2> | |
| <form name="csv-converter-form" id="csv-form" class="csv-form"> | |
| <h3>CSV-Datei hochladen:</h3> | |
| <label | |
| for="csv-file-input" | |
| class="csv-form-block tooltip-element" | |
| id="file-upload-label" | |
| title="File upload" | |
| > | |
| <span class="tooltip-text">Wählen Sie ein CSV-Datei ein</span> | |
| Datei auswählen | |
| <i class="fa-solid fa-plus"></i> | |
| <input | |
| type="file" | |
| name="csv-file" | |
| id="csv-file-input" | |
| accept=".csv" | |
| /> | |
| </label> | |
| <span id="selected-file-name"></span> | |
| <label for="delimiter-select" class="csv-form-block"> | |
| <h3>Trennzeichen:</h3> | |
| <select name="csv-delimiter" id="delimiter-select"> | |
| <option value="" disabled selected> | |
| Wählen Sie ein Trennzeichen | |
| </option> | |
| <option value=",">Komma (CSV)</option> | |
| <option value=";">Semikolon</option> | |
| <option value="\t">Tabulator</option> | |
| <option value='"'>Gänsefüßchen</option> | |
| </select> | |
| </label> | |
| <div id="upload-convert-button-container"> | |
| <button | |
| id="upload-button" | |
| type="button" | |
| class="octopus-button" | |
| disabled | |
| > | |
| Upload | |
| </button> | |
| <button | |
| id="convert-button" | |
| type="submit" | |
| class="octopus-button" | |
| disabled | |
| > | |
| Convert | |
| </button> | |
| </div> | |
| </form> | |
| </div> | |
| <div class="csv-section"> | |
| <h2>CSV-Datei in Tabellenformat</h2> | |
| <div id="csv-output"> | |
| <table> | |
| <thead> | |
| <tr> | |
| <th>Prop-1</th> | |
| <th>Prop-2</th> | |
| <th>Prop-3</th> | |
| <th>Prop-4</th> | |
| </tr> | |
| </thead> | |
| <tbody> | |
| <tr> | |
| <td>Value 1</td> | |
| <td>Value 2</td> | |
| <td>Value 3</td> | |
| <td>Value 4</td> | |
| </tr> | |
| </tbody> | |
| </table> | |
| </div> | |
| </div> | |
| <div class="splitter-bar" id="splitter-bar"> | |
| <button id="arrow-btn-left"> | |
| <i class="fa-solid fa-chevron-left"></i> | |
| </button> | |
| <button id="arrow-btn-right"> | |
| <i class="fa-solid fa-chevron-right"></i> | |
| </button> | |
| </div> | |
| <!-- 🢒 alternative arrow--> | |
| <div class="json-section" id="json-section"> | |
| <h2>JSON-Datei</h2> | |
| <pre id="json-output"> | |
| [ | |
| { | |
| "data": { | |
| "company": { | |
| "name": "Lazz", | |
| "contactperson": { | |
| "name": "DioneTweedlie", | |
| "phone": "374-(954)488-9771" | |
| } | |
| }, | |
| "price": "€35260,85", | |
| "dateoforder": "02/29/2016", | |
| "dateoffinish": "05/18/2017" | |
| } | |
| } | |
| ] | |
| </pre | |
| > | |
| <button | |
| id="download-button" | |
| type="button" | |
| class="octopus-button" | |
| disabled | |
| > | |
| Download JSON-Datei | |
| <i class="fa-solid fa-download"></i> | |
| </button> | |
| </div> | |
| </div> | |
| </div> | |
| <script type="module" src="/src/main.js"></script> | |
| </body> | |
| </html> |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| import { normalisePropertyNames } from "./normalise-property-names.js"; | |
| const form = document.getElementById("csv-form"); | |
| const csvFileInput = document.getElementById("csv-file-input"); | |
| const convertBtn = document.getElementById("convert-button"); | |
| const uploadBtn = document.getElementById("upload-button"); | |
| const jsonOutput = document.getElementById("json-output"); | |
| const delimiterSelect = document.getElementById("delimiter-select"); | |
| const downloadButton = document.getElementById("download-button"); | |
| const csvOutput = document.getElementById("csv-output"); | |
| const arrowBtnLeft = document.getElementById("arrow-btn-left"); | |
| const arrowBtnRight = document.getElementById("arrow-btn-right"); | |
| const jsonSection = document.getElementById("json-section"); | |
| const fileUploadLabel = document.getElementById("file-upload-label"); | |
| const selectedFileName = document.getElementById("selected-file-name"); | |
| arrowBtnLeft.style.display = "none"; | |
| arrowBtnRight.style.display === "block"; | |
| arrowBtnRight.addEventListener("click", function () { | |
| arrowBtnLeft.style.display === "block"; | |
| jsonSection.style.display = "none"; | |
| }); | |
| arrowBtnLeft.addEventListener("click", function () { | |
| if (arrowBtnRight.style.display === "block") { | |
| arrowBtnLeft.style.display = "block"; | |
| arrowBtnRight.style.display = "none"; | |
| jsonSection.style.display = "none"; | |
| } | |
| }); | |
| let lines = []; | |
| let propertyNames = []; | |
| uploadBtn.disabled = true; | |
| convertBtn.disabled = true; | |
| downloadButton.disabled = true; | |
| fileUploadLabel.disabled = true; | |
| //fileUploadLabel with select file | |
| csvFileInput.addEventListener("change", csvFileInputLabelState); | |
| function csvFileInputLabelState(){ | |
| if(csvFileInput.files.length === 0){ | |
| fileUploadLabel.disabled = true; | |
| fileUploadLabel.innerText = "Bitte wählen Sie ein CSV-File ein!"; | |
| fileUploadLabel.classList.add("disabled-label"); | |
| }else{ | |
| fileUploadLabel.disabled = false; | |
| selectedFileName.innerText = csvFileInput.files[0].name; | |
| fileUploadLabel.classList.remove("disabled-label"); | |
| } | |
| } | |
| // activateUploadButton with select file and delimiter | |
| csvFileInput.addEventListener("change", updateUploadButtonState); | |
| delimiterSelect.addEventListener("change", updateUploadButtonState); | |
| function updateUploadButtonState() { | |
| if (csvFileInput.files.length === 0 || delimiterSelect.value === "") { | |
| uploadBtn.disabled = true; | |
| } else { | |
| uploadBtn.disabled = false; | |
| } | |
| } | |
| //function updateUploadButtonState() { | |
| //uploadBtn.disabled = csvfileInput.files.length === 0 || delimiterSelect.value === ""; | |
| //} | |
| // Upload process | |
| uploadBtn.addEventListener("click", async (e) => { | |
| const file = csvFileInput.files[0]; | |
| if (!file) { | |
| //alert('ungültiges File! Versuchen Sie wieder'); If t is not a .csv.LATER!! | |
| return; | |
| } | |
| const text = await file.text(); | |
| lines = text.trim().split("\n"); | |
| propertyNames = normalisePropertyNames(lines, delimiterSelect.value); | |
| const csvDelimiter = delimiterSelect.value; | |
| // CSV Table | |
| const tableHeading = document.querySelector("#csv-output table thead"); | |
| const tableBody = document.querySelector("#csv-output table tbody"); | |
| let tableHeader = ""; | |
| for (let pn = 0; pn < propertyNames.length; pn++) { | |
| tableHeader += `<th>${propertyNames[pn]}</th>`; | |
| } | |
| tableHeading.querySelector("tr").innerHTML = tableHeader; | |
| let tableRow = ""; | |
| let tableRows = ""; | |
| for (let l = 1; l < lines.length; l++) { | |
| tableRow = "<tr>"; | |
| const values = lines[l] | |
| .split(csvDelimiter) | |
| .map((item) => item.replace(/^"|"$/g, "")); | |
| for (let v = 0; v < values.length; v++) { | |
| tableRow += `<td>${values[v]}</td>`; | |
| } | |
| tableRow += "</tr>"; | |
| tableRows += tableRow; | |
| } | |
| tableBody.innerHTML = tableRows; | |
| // Convert button activation | |
| convertBtn.disabled = false; | |
| }); | |
| // Download Button Activation | |
| form.addEventListener("submit", async function (event) { | |
| event.preventDefault(); | |
| //downloadButton.disabled = true; | |
| const csvData = new FormData(form); | |
| const csvDelimiter = csvData.get("csv-delimiter"); | |
| const csvFileContent = await csvData.get("csv-file").text(); | |
| const lines = csvFileContent.trim().split("\n"); | |
| const propertyNames = normalisePropertyNames(lines, csvDelimiter); | |
| const result = []; | |
| for (let i = 1; i < lines.length; i++) { | |
| const values = lines[i] | |
| .split(csvDelimiter) | |
| .map((item) => item.replace(/^"|"$/g, "")); | |
| const jsonData = {}; | |
| for (let j = 0; j < propertyNames.length; j++) { | |
| const propertyName = propertyNames[j].trim(); | |
| const propertyValue = values[j] ? values[j].trim() : ""; | |
| jsonData[propertyName] = propertyValue; | |
| } | |
| result.push(jsonData); | |
| } | |
| jsonOutput.innerHTML = JSON.stringify(result, null, 2); | |
| downloadButton.disabled = false; | |
| }); |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| html { | |
| font-size: 16px; | |
| } | |
| body { | |
| font-family: Sans-serif, Arial, Helvetica; | |
| margin: 0; | |
| padding: 0; | |
| } | |
| h1 { | |
| background-color: #ce0058; | |
| color: #fff; | |
| padding: 1rem; | |
| margin: 0; | |
| padding-left: 2.5rem; | |
| border: 2px solid #c94396; | |
| border-image: linear-gradient(to left, #af798e 40%, transparent 90%) 1; | |
| } | |
| h2 { | |
| max-height: 50px; | |
| margin: 1rem; | |
| padding: 1.5rem; | |
| } | |
| .container { | |
| display: flex; | |
| flex-basis: 90%; | |
| flex-direction: column; | |
| overflow-x: hidden; | |
| gap: 20px; | |
| } | |
| .content { | |
| display: flex; | |
| flex-direction: row; | |
| background-color: #fffefd; | |
| width: 100%; /*content scrollbar hidden*/ | |
| overflow: auto; | |
| position: absolute; | |
| top: 4.5rem; | |
| bottom: 0; | |
| height: auto; | |
| } | |
| .form-section { | |
| flex-basis: 10%; | |
| background-color: #d1d1d1; | |
| background: linear-gradient(90deg, #d1d1d1, #f5f4f54a); | |
| } | |
| .csv-section { | |
| flex-basis: 50%; | |
| max-width: 50%; | |
| background: linear-gradient(0deg, #eae6e6, #f9f9f94a); | |
| } | |
| .json-section { | |
| flex-basis: 35%; | |
| background: linear-gradient(-90deg, #d1d1d1, #f5f4f54a); | |
| display: flex; | |
| flex-direction: column; | |
| padding: 0 16px; | |
| } | |
| .json-section:second-child { | |
| align-self: flex-end; | |
| } | |
| #selected-file-name{ | |
| margin-top: -16px; | |
| } | |
| #csv-file-input{ | |
| display: none; | |
| } | |
| #file-upload-label { | |
| display: flex; | |
| flex-direction: row; | |
| justify-content: space-evenly; | |
| align-items:flex-end; | |
| background-color: #ce0058; | |
| color: #fff; | |
| border: 2px ridge #b9b0b9; | |
| padding: 8px 30px; | |
| border-radius: 18px; | |
| font-size: 18px; | |
| margin-top: 10px; | |
| margin-bottom: 30px; | |
| font-size: 20px; | |
| } | |
| #file-upload-label:hover { | |
| cursor: pointer; | |
| background-color: #df0563; | |
| color: #fff; | |
| } | |
| #file-upload-label.disabled-label { | |
| opacity: 0.8 !important; | |
| background-color: #b4aeae !important; | |
| color: #fff !important; | |
| pointer-events: none; | |
| } | |
| #delimiter-select { | |
| font-size: 16px; | |
| cursor: pointer; | |
| margin-top: 2px; | |
| margin-bottom: 50px; | |
| padding: 8px; | |
| font-family: sans-serif; | |
| border: 1px solid #b4aeae ; | |
| border-radius: 3px; | |
| } | |
| #csv-form { | |
| display: flex; | |
| flex-direction: column; | |
| justify-content: space-between; | |
| padding: 1.5rem; | |
| margin: 1rem; | |
| /*border: 2px solid #838080; | |
| border-radius: 3px;*/ | |
| } | |
| #upload-convert-button-container { | |
| display: flex; | |
| flex-direction: column; | |
| align-items: center; | |
| } | |
| .octopus-button { | |
| width: fit-content; | |
| background-color: #ce0058; | |
| color: #fff; | |
| border: 2px ridge #b9b0b9; | |
| padding: 8px 30px; | |
| border-radius: 18px; | |
| font-size: 18px; | |
| margin-top: 10px; | |
| margin-bottom: 30px; | |
| } | |
| .octopus-button:hover { | |
| cursor: pointer; | |
| background-color: #df0563; | |
| color: #fff; | |
| } | |
| .octopus-button:disabled { | |
| opacity: 0.8 !important; | |
| background-color: #b4aeae !important; | |
| color: #fff !important; | |
| pointer-events: none; | |
| } | |
| pre#json-output { | |
| background-color: #fff; | |
| color: black; | |
| text-align: left; | |
| padding: 1rem; | |
| overflow-x: auto; | |
| overflow-y: auto; | |
| white-space: break-spaces; | |
| height: 80%; | |
| overscroll-behavior-y: contain; | |
| background: linear-gradient(-90deg, #d1d1d1, #efedef4a, transparent 90%); | |
| } | |
| /*#convert-button:disabled { | |
| background-color: #e9dddd; | |
| color: #6d6c6c; | |
| pointer-events: none; | |
| } | |
| #upload-button:disabled { | |
| background-color: #786767; | |
| color: #fff; | |
| pointer-events: none; | |
| }*/ | |
| #download-button { | |
| align-self: flex-end; | |
| } | |
| /*#download-button:disabled { | |
| background-color: #897878; | |
| color: #fff; | |
| pointer-events: none; | |
| }*/ | |
| .splitter-bar { | |
| display: flex; | |
| width: fit-content; | |
| height: 100%; | |
| justify-items: center; | |
| align-items: center; | |
| background: linear-gradient(20deg, #e5e0e4, transparent); | |
| } | |
| #arrow-btn-right { | |
| transform: rotate(-180deg); | |
| -webkit-transform: rotate(-180deg); | |
| border: none; | |
| cursor: pointer; | |
| } | |
| #arrow-btn-left { | |
| transform: rotate(0deg); | |
| -webkit-transform: rotate(0deg); | |
| border: none; | |
| cursor: pointer; | |
| } | |
| #csv-output { | |
| padding: 1rem; | |
| height: 80%; | |
| overflow-x: auto; | |
| overflow-y: auto; | |
| overscroll-behavior-y: contain; | |
| } | |
| #csv-output table { | |
| width: 100%; | |
| border-collapse: collapse; | |
| overflow-wrap: break-word; | |
| overflow-x: auto; | |
| overflow-y: auto; | |
| } | |
| #csv-output table th, | |
| #csv-output table td { | |
| border: 1px solid black; | |
| padding: 10px 1rem; | |
| min-width: 60px; | |
| } | |
| /* TOOLTIP STYLES */ | |
| .tooltip-text { | |
| visibility: hidden; | |
| font-size: 13px; | |
| width: 160px; | |
| background-color: black; | |
| opacity: 0.8; | |
| color: #fff; | |
| text-align: center; | |
| padding: 5px 0; | |
| border-radius: 6px; | |
| /* Position the tooltip text! */ | |
| position: absolute; | |
| z-index: 1; | |
| bottom: 100%; | |
| left: 50%; | |
| margin-left: -80px; /* Use half of the width (160/2 = 80), to center the tooltip */ | |
| } | |
| .tooltip-text::after { | |
| content: " "; | |
| position: absolute; | |
| top: 100%; /* At the bottom of the tooltip */ | |
| left: 50%; | |
| margin-left: -5px; | |
| border-width: 5px; | |
| border-style: solid; | |
| border-color: black transparent transparent transparent; | |
| } | |
| .tooltip-element { | |
| position: relative; | |
| } | |
| .tooltip-element:hover .tooltip-text { | |
| visibility: visible; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment