From ad90a4ed58608e00bd0ae8781c3a292cff1cd62d Mon Sep 17 00:00:00 2001 From: Janis Hutz Date: Wed, 8 Oct 2025 11:54:45 +0200 Subject: [PATCH] Add new task skeleton --- task_2_ts/.prettierrc.json | 1 + task_2_ts/Dockerfile | 8 +++ task_2_ts/css/layout.css | 115 +++++++++++++++++++++++++++++++++++++ task_2_ts/index.html | 68 ++++++++++++++++++++++ task_2_ts/package.json | 21 +++++++ task_2_ts/ts/csv.ts | 30 ++++++++++ task_2_ts/ts/main.ts | 5 ++ task_2_ts/tsconfig.json | 33 +++++++++++ task_2_ts/vite-env.d.ts | 1 + task_2_ts/vite.config.js | 7 +++ 10 files changed, 289 insertions(+) create mode 100644 task_2_ts/.prettierrc.json create mode 100644 task_2_ts/Dockerfile create mode 100644 task_2_ts/css/layout.css create mode 100644 task_2_ts/index.html create mode 100644 task_2_ts/package.json create mode 100644 task_2_ts/ts/csv.ts create mode 100644 task_2_ts/ts/main.ts create mode 100644 task_2_ts/tsconfig.json create mode 100644 task_2_ts/vite-env.d.ts create mode 100644 task_2_ts/vite.config.js diff --git a/task_2_ts/.prettierrc.json b/task_2_ts/.prettierrc.json new file mode 100644 index 0000000..0967ef4 --- /dev/null +++ b/task_2_ts/.prettierrc.json @@ -0,0 +1 @@ +{} diff --git a/task_2_ts/Dockerfile b/task_2_ts/Dockerfile new file mode 100644 index 0000000..b60efdc --- /dev/null +++ b/task_2_ts/Dockerfile @@ -0,0 +1,8 @@ +FROM node +WORKDIR /app +COPY package.json . +RUN npm i +COPY . . +## EXPOSE [Port you mentioned in the vite.config file] +EXPOSE 5173 +CMD ["npm", "run", "dev"] \ No newline at end of file diff --git a/task_2_ts/css/layout.css b/task_2_ts/css/layout.css new file mode 100644 index 0000000..480745a --- /dev/null +++ b/task_2_ts/css/layout.css @@ -0,0 +1,115 @@ +:root { + --spacing: 0.25rem; + --border-color: #a0a0a0; +} + +/* Style for definition list */ +dl { + margin-top: 0; + margin-bottom: 20px; +} + +dt, +dd { + line-height: 1.42857143; +} + +dt { + font-weight: 700; +} + +dd { + margin-left: 0; +} + +body h1, +body h2 { + margin-bottom: 0; +} + +nav { + border-bottom: 1px solid var(--border-color); +} + +article { + width: 400px; +} + +body>main { + max-height: calc(100vh - 100px); + overflow-y: auto; + + padding: var(--spacing) !important; + display: flex; + flex-direction: row; + flex-wrap: wrap; + justify-content: space-between; + align-items: start; + gap: var(--spacing); + + & article { + margin: 0; + padding: var(--spacing); + + &>header { + margin: calc(var(--spacing) * -1) calc(var(--spacing) * -1) var(--spacing); + padding: var(--spacing); + } + } +} + +/* Set a fixed scrollable wrapper */ +#table-content { + max-height: 400px; + overflow: auto; + + /* Set header to stick to the top of the container. */ + & thead tr th { + position: sticky; + top: 0; + } + + /* If we use border, we must use table-collapse to avoid a slight movement of the header row */ + & table { + border-collapse: collapse; + border-top: 0; + } + + /* Because we must set sticky on th, we have to apply background styles here rather than on thead */ + & th { + border-left: 1px dotted rgba(200, 209, 224, 0.6); + border-bottom: 1px solid #ddd; + + background: #eee; + text-align: left; + box-shadow: 0px 0px 0 2px #e8e8e8; + + &.active { + background: #ddd; + } + + &.sortable::after { + font-family: FontAwesome; + content: "\f0dc"; + position: absolute; + right: 8px; + color: #999; + } + + &.active::after { + position: absolute; + right: 8px; + color: #999; + } + + &.active.asc::after { + font-family: FontAwesome; + content: "\f0d8"; + } + + &.active.desc::after { + font-family: FontAwesome; + content: "\f0d7"; + } + } +} diff --git a/task_2_ts/index.html b/task_2_ts/index.html new file mode 100644 index 0000000..e0aaf4f --- /dev/null +++ b/task_2_ts/index.html @@ -0,0 +1,68 @@ + + + + + + + + Open data explorer + + + + + + + +
+
+
+

Select csv data

+
+
+ + + Please upload a csv file, where the first row is the header. And the values are + comma(,) seperated. +
+
+ +
+
+

Data infos

+
+
+
+ +
+
+

Selected column infos

+
+
+
+ +
+
+

Filter active column

+
+ +
+ +
+
+

Data table

+
+
+
+
+ + + diff --git a/task_2_ts/package.json b/task_2_ts/package.json new file mode 100644 index 0000000..e67d2e7 --- /dev/null +++ b/task_2_ts/package.json @@ -0,0 +1,21 @@ +{ + "name": "vite-typescript-starter", + "private": true, + "version": "0.0.0", + "type": "module", + "scripts": { + "dev": "vite", + "format": "prettier . --write", + "tsc": "tsc" + }, + "devDependencies": { + "prettier": "^3.0.1", + "typescript": "^5.1.6", + "vite": "^4.4.9" + }, + "dependencies": { + "@fortawesome/fontawesome-free": "^6.4.2", + "@picocss/pico": "^1.5.10", + "json-2-csv": "^4.1.0" + } +} diff --git a/task_2_ts/ts/csv.ts b/task_2_ts/ts/csv.ts new file mode 100644 index 0000000..d45100e --- /dev/null +++ b/task_2_ts/ts/csv.ts @@ -0,0 +1,30 @@ +import { + csv2json +} from 'json-2-csv'; + +export type CSV_Data = Array>; + +const convertCSVtoJSON = async ( csvText: string ) => { + // Type cast OK, as the typing of the external library is not perfect. + return ( await csv2json( csvText ) ) as CSV_Data; +}; + +/** + * Reads a CSV file and returns the data as JSON. + * @param event The change event of the file input. + */ +export const readCSV = async ( event: Event ): Promise => { + if ( !( event.target instanceof HTMLInputElement ) ) { + throw new Error( 'Not an HTMLInputElement' ); + } + + const file = event.target.files?.[0]; + + if ( file == null ) { + throw new Error( 'No file selected' ); + } + + const result = await file.text(); + + return await convertCSVtoJSON( result ); +}; diff --git a/task_2_ts/ts/main.ts b/task_2_ts/ts/main.ts new file mode 100644 index 0000000..1bb0220 --- /dev/null +++ b/task_2_ts/ts/main.ts @@ -0,0 +1,5 @@ +import "@fortawesome/fontawesome-free/css/all.css"; +import "../css/layout.css"; +import "@picocss/pico/css/pico.min.css"; + +// TODO start here with the first entry point diff --git a/task_2_ts/tsconfig.json b/task_2_ts/tsconfig.json new file mode 100644 index 0000000..b7fbeec --- /dev/null +++ b/task_2_ts/tsconfig.json @@ -0,0 +1,33 @@ +{ + "compilerOptions": { + "target": "ES2020", + "useDefineForClassFields": true, + "module": "ESNext", + "lib": ["ES2020", "DOM", "DOM.Iterable"], + "skipLibCheck": true, + + /* Bundler mode */ + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "resolveJsonModule": true, + "isolatedModules": true, + "noEmit": true, + + "strict": true, + "allowUnusedLabels": false, + "allowUnreachableCode": false, + "exactOptionalPropertyTypes": true, + "noFallthroughCasesInSwitch": true, + "noImplicitOverride": true, + "noImplicitReturns": true, + "noPropertyAccessFromIndexSignature": true, + "noUncheckedIndexedAccess": true, + "noUnusedLocals": true, + "noUnusedParameters": true, + "allowJs": false, + "esModuleInterop": true, + "forceConsistentCasingInFileNames": true + }, + "include": ["**/*"], + "exclude": ["tests/**/*", "public/**/*", "build/**/*"] +} diff --git a/task_2_ts/vite-env.d.ts b/task_2_ts/vite-env.d.ts new file mode 100644 index 0000000..11f02fe --- /dev/null +++ b/task_2_ts/vite-env.d.ts @@ -0,0 +1 @@ +/// diff --git a/task_2_ts/vite.config.js b/task_2_ts/vite.config.js new file mode 100644 index 0000000..4967025 --- /dev/null +++ b/task_2_ts/vite.config.js @@ -0,0 +1,7 @@ +export default { + server: { + host: '0.0.0.0', + port: 5173, + allowedHosts: true, + }, +} \ No newline at end of file