Category metadata / icon support
This commit is contained in:
10
index.html
10
index.html
@@ -2,8 +2,9 @@
|
|||||||
<html lang="en">
|
<html lang="en">
|
||||||
<head>
|
<head>
|
||||||
<meta charset="UTF-8" />
|
<meta charset="UTF-8" />
|
||||||
<link rel="icon" type="image/svg+xml" href="/vite.svg" />
|
<link rel="icon" type="image/svg+xml" href="/aai-favicon.png" />
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||||
|
|
||||||
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
<link rel="preconnect" href="https://fonts.googleapis.com" />
|
||||||
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
<link rel="preconnect" href="https://fonts.gstatic.com" crossorigin />
|
||||||
<link rel="preconnect" href="https://rsms.me/" />
|
<link rel="preconnect" href="https://rsms.me/" />
|
||||||
@@ -12,7 +13,12 @@
|
|||||||
href="https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100..900;1,100..900&display=swap"
|
href="https://fonts.googleapis.com/css2?family=Work+Sans:ital,wght@0,100..900;1,100..900&display=swap"
|
||||||
rel="stylesheet"
|
rel="stylesheet"
|
||||||
/>
|
/>
|
||||||
<title>Vite + React</title>
|
<!-- Material Icons font -->
|
||||||
|
<link
|
||||||
|
rel="stylesheet"
|
||||||
|
href="https://fonts.googleapis.com/icon?family=Material+Icons"
|
||||||
|
/>
|
||||||
|
<title>AI Skills Framework</title>
|
||||||
</head>
|
</head>
|
||||||
<body>
|
<body>
|
||||||
<div id="root"></div>
|
<div id="root"></div>
|
||||||
|
|||||||
1165
package-lock.json
generated
1165
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@@ -10,9 +10,12 @@
|
|||||||
"preview": "vite preview"
|
"preview": "vite preview"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
|
"@emotion/styled": "^11.14.1",
|
||||||
|
"@mui/icons-material": "^7.2.0",
|
||||||
"d3": "^7.9.0",
|
"d3": "^7.9.0",
|
||||||
"react": "^19.1.0",
|
"react": "^19.1.0",
|
||||||
"react-dom": "^19.1.0"
|
"react-dom": "^19.1.0",
|
||||||
|
"sass": "^1.89.2"
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"@eslint/js": "^9.30.1",
|
"@eslint/js": "^9.30.1",
|
||||||
|
|||||||
BIN
public/aai-favicon.png
Normal file
BIN
public/aai-favicon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 5.7 KiB |
15
src/App.tsx
15
src/App.tsx
@@ -4,14 +4,20 @@ import Legend from "./components/Legend";
|
|||||||
import QRCode from "./components/QRCode";
|
import QRCode from "./components/QRCode";
|
||||||
import { QuestionGroupChart } from "./components/QuestionGroupChart";
|
import { QuestionGroupChart } from "./components/QuestionGroupChart";
|
||||||
import { config } from "./config";
|
import { config } from "./config";
|
||||||
import { getSampleData } from "./lib/data";
|
import { CategoryMetadata, fetchCategoryMetadata } from "./lib/metadata";
|
||||||
import { ResponseData } from "./lib/parser";
|
import { fetchGoogleSheet, ResponseData } from "./lib/parser";
|
||||||
|
|
||||||
function App() {
|
function App() {
|
||||||
const [data, setData] = useState<ResponseData[]>([]);
|
const [data, setData] = useState<ResponseData[]>([]);
|
||||||
|
const [categoryMetadata, setCategoryMetadata] = useState<CategoryMetadata[]>(
|
||||||
|
[]
|
||||||
|
);
|
||||||
|
|
||||||
useEffect(() => {
|
useEffect(() => {
|
||||||
// fetchGoogleSheet().then(setData);
|
fetchGoogleSheet().then(setData);
|
||||||
setData(getSampleData());
|
// setData(getSampleData());
|
||||||
|
|
||||||
|
fetchCategoryMetadata().then(setCategoryMetadata);
|
||||||
}, []);
|
}, []);
|
||||||
|
|
||||||
if (!data.length) return null;
|
if (!data.length) return null;
|
||||||
@@ -38,6 +44,7 @@ function App() {
|
|||||||
<QuestionGroupChart
|
<QuestionGroupChart
|
||||||
key={question}
|
key={question}
|
||||||
question={question}
|
question={question}
|
||||||
|
metadata={categoryMetadata.find((m) => m.category === question)}
|
||||||
groupData={groupData}
|
groupData={groupData}
|
||||||
responses={sortedResponses}
|
responses={sortedResponses}
|
||||||
xScale={xScale}
|
xScale={xScale}
|
||||||
|
|||||||
@@ -1,11 +1,15 @@
|
|||||||
|
import MaterialIcon from "@mui/material/Icon";
|
||||||
import * as d3 from "d3";
|
import * as d3 from "d3";
|
||||||
import { useEffect, useRef } from "react";
|
import { useEffect, useRef } from "react";
|
||||||
import { colorScheme, config } from "../config";
|
import { colorScheme, config } from "../config";
|
||||||
|
|
||||||
|
import { CategoryMetadata } from "../lib/metadata";
|
||||||
|
|
||||||
import "./Chart.css";
|
import "./Chart.css";
|
||||||
|
|
||||||
interface QuestionGroupChartProps {
|
interface QuestionGroupChartProps {
|
||||||
question: string;
|
question: string;
|
||||||
|
metadata?: CategoryMetadata;
|
||||||
groupData: { response: string }[];
|
groupData: { response: string }[];
|
||||||
responses: string[];
|
responses: string[];
|
||||||
xScale: d3.ScaleBand<string>;
|
xScale: d3.ScaleBand<string>;
|
||||||
@@ -38,6 +42,7 @@ function makeDot(
|
|||||||
|
|
||||||
export function QuestionGroupChart({
|
export function QuestionGroupChart({
|
||||||
question,
|
question,
|
||||||
|
metadata,
|
||||||
groupData,
|
groupData,
|
||||||
responses,
|
responses,
|
||||||
xScale,
|
xScale,
|
||||||
@@ -81,13 +86,11 @@ export function QuestionGroupChart({
|
|||||||
return (
|
return (
|
||||||
<div className="question-group">
|
<div className="question-group">
|
||||||
<svg ref={svgRef}></svg>
|
<svg ref={svgRef}></svg>
|
||||||
<div className="question-title">{question}</div>
|
<div className="question-title">
|
||||||
<p>
|
{metadata?.icon && <MaterialIcon>{metadata.icon}</MaterialIcon>}
|
||||||
Lorem ipsum dolor sit amet, consectetur adipiscing elit. Sed do eiusmod
|
{question}
|
||||||
tempor incididunt ut labore et dolore magna aliqua. Ut enim ad minim
|
</div>
|
||||||
veniam, quis nostrud exercitation ullamco laboris nisi ut aliquip ex ea
|
<p>{metadata?.description || question}</p>
|
||||||
commodo.
|
|
||||||
</p>
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -23,3 +23,6 @@ const aaiColors = [
|
|||||||
export const colorScheme = Object.fromEntries(
|
export const colorScheme = Object.fromEntries(
|
||||||
aaiColors.map((color, index) => [index, color])
|
aaiColors.map((color, index) => [index, color])
|
||||||
);
|
);
|
||||||
|
|
||||||
|
export const categoryMetadataUrl =
|
||||||
|
"https://docs.google.com/spreadsheets/d/e/2PACX-1vT6FQoV_8ET_pmEB5LGlI_ST9AAhsfiZrWydFwIB80G0Lr_kGwVJUzjM6fRPP9Yrx6iVZYMVAPTnLKq/pub?gid=0&single=true&output=csv";
|
||||||
|
|||||||
@@ -78,6 +78,8 @@ body {
|
|||||||
border: 1px solid #ddd;
|
border: 1px solid #ddd;
|
||||||
border-radius: 8px;
|
border-radius: 8px;
|
||||||
|
|
||||||
|
flex: 1 1 380px;
|
||||||
|
|
||||||
filter: drop-shadow(0 2px 2px hsl(202.5deg 20% 76.5%));
|
filter: drop-shadow(0 2px 2px hsl(202.5deg 20% 76.5%));
|
||||||
|
|
||||||
display: flex;
|
display: flex;
|
||||||
@@ -95,7 +97,6 @@ body {
|
|||||||
font-size: 14px;
|
font-size: 14px;
|
||||||
color: #666;
|
color: #666;
|
||||||
line-height: 1.4;
|
line-height: 1.4;
|
||||||
max-width: 40ch;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
.question-title {
|
.question-title {
|
||||||
|
|||||||
37
src/lib/metadata.ts
Normal file
37
src/lib/metadata.ts
Normal file
@@ -0,0 +1,37 @@
|
|||||||
|
import * as d3 from "d3";
|
||||||
|
|
||||||
|
export interface CategoryMetadata {
|
||||||
|
category: string;
|
||||||
|
description: string;
|
||||||
|
icon: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
const sampleMetadataCsv = `title,text,icon
|
||||||
|
Allgemeines KI-Wissen,Grundlegendes Wissen über Künstliche Intelligenz und deren Anwendung in Organisationen,school
|
||||||
|
KI-Innovation,"Fähigkeiten zur Entwicklung, Bewertung und Förderung von KI-Innovationen im Unternehmen",science
|
||||||
|
KI-Geschäftsstrategie,"Verstehen, wie KI strategisch in Geschäftsmodelle integriert und eingesetzt werden kann",business
|
||||||
|
Stakeholder-Landschaft,"Fähigkeit, relevante Stakeholder für KI-Initiativen zu identifizieren, einzubinden und zu koordinieren",people_alt
|
||||||
|
KI-Ethik,Kenntnisse über ethische Fragestellungen und verantwortungsvollen KI-Einsatz,local_police
|
||||||
|
KI-Regulation,Verständnis rechtlicher Rahmenbedingungen und Regulierungen rund um KI,gavel
|
||||||
|
Datenkompetenz,"Fähigkeit, Daten kritisch zu beurteilen, aufzubereiten und für KI nutzbar zu machen",equalizer
|
||||||
|
Python-Programmierung,Grundlegende Programmier-kenntnisse zur Umsetzung und Anpassung von KI-Lösungen,data_object
|
||||||
|
Software Design,"Gestaltung robuster, skalierbarer und wartbarer Softwarelösungen mit KI-Komponenten",code
|
||||||
|
Maschinelles Lernen,Kenntnisse in maschinellem Lernen zur Entwicklung datengetriebener Modelle,model_training
|
||||||
|
MLOps / Infrastruktur,Fähigkeiten zum produktiven Einsatz und Betrieb von KI-Systemen in Unternehmen,all_inclusive
|
||||||
|
GenAI-Kenntnisse,Verständnis generativer KI-Modelle (z. B. Large Language Models) und ihrer praktischen Nutzung,auto_awesome`;
|
||||||
|
|
||||||
|
export function fetchCategoryMetadata(): Promise<CategoryMetadata[]> {
|
||||||
|
const parseCsv = (csv: string): CategoryMetadata[] => {
|
||||||
|
const parsed = d3.csvParse(csv);
|
||||||
|
return parsed.map((row) => ({
|
||||||
|
category: row.title,
|
||||||
|
description: row.text,
|
||||||
|
icon: row.icon,
|
||||||
|
}));
|
||||||
|
};
|
||||||
|
|
||||||
|
/*return fetch(categoryMetadataUrl)
|
||||||
|
.then((response) => response.text())
|
||||||
|
.then(parseCsv);*/
|
||||||
|
return Promise.resolve(parseCsv(sampleMetadataCsv));
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user