Skip to content

Instantly share code, notes, and snippets.

@Kjaer
Created August 27, 2025 07:48
Show Gist options
  • Select an option

  • Save Kjaer/34501e1a72c1aee2512bbe69fa7359db to your computer and use it in GitHub Desktop.

Select an option

Save Kjaer/34501e1a72c1aee2512bbe69fa7359db to your computer and use it in GitHub Desktop.
PROJE
<!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>
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;
});
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