first commit

This commit is contained in:
martin 2026-01-05 16:03:44 +01:00
commit 9805c18dd5
223 changed files with 24265 additions and 0 deletions

3
.gitignore vendored Normal file
View File

@ -0,0 +1,3 @@
node_modules
.env
.vscode/*

49
Dockerfile Normal file
View File

@ -0,0 +1,49 @@
# Stage 1: Build (Erstellung des Produktionsbundles)
FROM node:20-alpine AS build
# Setze das Arbeitsverzeichnis
WORKDIR /usr/src/app
# Kopiere package.json und package-lock.json und installiere die Abhängigkeiten
COPY package.json ./
RUN npm install --force && npm cache clean --force
# Kopiere die weiteren wichtigen Projektdateien
COPY components.json .
COPY eslint.config.js .
COPY index.html .
COPY postcss.config.js .
COPY tailwind.config.ts .
COPY tsconfig.app.json .
COPY tsconfig.json .
COPY tsconfig.node.json .
COPY vite.config.ts .
COPY src ./src
COPY public ./public
COPY .env .
# Baue das Projekt für die Produktion
RUN npm run build
# Stage 2: Production (Einfacher Webserver für die bereitgestellten Dateien)
FROM node:20-alpine AS production
# Setze das Arbeitsverzeichnis
WORKDIR /usr/src/app
# Installiere ein einfaches Static File Hosting Tool (wie serve)
RUN npm install -g serve
# Kopiere die gebauten Dateien aus der Build-Phase
COPY --from=build /usr/src/app/dist ./dist
# Kopiere die generierte index.html aus dem Build-Ordner (aus der Build-Phase)
COPY --from=build /usr/src/app/index.html ./index.html
# Baue die TypeScript API
#RUN npm install && npx tsc api.ts
# Exponiere den Port, auf dem der Server läuft
EXPOSE 5030
# Starte den Server auf Port 5000 (dieser wird dann über den Nginx-Reverse-Proxy weitergeleitet)
CMD ["serve", "-s", "dist", "-l", "5030"]

218
api_doku.md Normal file
View File

@ -0,0 +1,218 @@
# REST API Übersicht (aus Client-Calls im Projekt abgeleitet)
- **Base URL**: `VITE_WEBHOOK_URL` (siehe `src/lib/config.ts -> getWebhookUrl()`)
- **Auth**:
- Cookies werden standardmäßig mitgesendet (`credentials: 'include'`)
- Falls vorhanden wird `Authorization: Bearer <token>` gesetzt (siehe `apiFetch`)
- Bei `401` wird automatisch Refresh versucht über `/auth/rnjwt`
## Auth
- **POST /auth_login**
- Headers: `Content-Type: application/json`
- Body:
```json
{ "email": "string", "password": "string" }
```
- Response:
```json
{ "token": "string", "user": { ... } }
```
- **GET /auth/rnjwt**
- Zweck: JWT Refresh
- Response:
```json
{ "token": "string" }
```
## Events
- **POST /event/new_manual**
- Headers: `Content-Type: application/json`
- Body:
```json
{
"name": "string",
"description": "string?",
"location": "string?",
"url": "string?",
"image": "string?",
"manager_name": "string?",
"manager_email": "string?",
"begin_date": "YYYY-MM-DD?",
"end_date": "YYYY-MM-DD?"
}
```
- Response: beliebiges Event-Objekt
- **GET /events/get_current**
- Response: `Event[]` oder ein einzelnes Event-Objekt
- **GET /events**
- Response: `Event[]` oder ein einzelnes Event-Objekt
- **POST /event/new_fromurl**
- Headers: `Content-Type: application/json`
- Body:
```json
{ "url": "string", "command": "eventmodus_extract_from_url" }
```
- Response: `data.message_from_ai` oder Roh-Response
## Blog
- **GET /blog/new_blog**
- Response:
```json
{ "id": "string" } // oder { "blog_id": "string" }
```
- **POST /blog/publish**
- Headers: `Content-Type: application/json`
- Body:
```json
{
"blog_id": "string",
"publish_date": "YYYY-MM-DD",
"publish_socialmedia": true,
"socialmedia_channels": ["string"],
"socialmedia_languages": ["string"]
}
```
- Response: beliebige Publikations-Infos
- **POST /blog/update**
- Headers: `Content-Type: application/json`
- Body:
```json
{
"blog_id": "string",
"content": { ... }
}
```
- Response: Update-Ergebnis
- **POST /blog/generate**
- Headers: `Content-Type: application/json`
- Body:
```json
{
"blog_Id": "string",
"topic": "string",
"tonality": "string",
"languages": ["string"]
}
```
- Response: generierter Blog-Content
- **GET /blog/topic_suggestion**
- Response:
```json
{ "topics": ["string", ...] } | ["string", ...]
```
## Dateien & Medien
- **POST /file_upload_blog**
- Body (FormData):
- `file`: File
- `blog_id`: string
- Response:
```json
{ "url": "string", ... }
```
- **POST /file_upload_event**
- Body (FormData):
- `file`: File
- `event_id`: string
- Response:
```json
{ "url": "string", ... }
```
- **POST /upload_tmp**
- Body (FormData):
- `file`: File
- Response:
```json
{ "url": "string", ... }
```
- **POST /media/image_generator**
- Headers: `Content-Type: application/json`
- Body:
```json
{ "blog_id": "string", "title": "string" }
```
- Response:
```json
{ "url": "string" } // oder { "imageUrl": "string" }
```
- Hinweis: `generateAIImage` ruft aktuell
- **POST /file_upload**
- Headers: `Content-Type: application/json`
- Body:
```json
{ "prompt": "string" }
```
- Response:
```json
{ "imageUrl": "string", ... }
```
- Anmerkung: Endpoint-Name wirkt untypisch für Image-Generation.
## Tools
- **POST /tools/speech2text**
- Body (FormData):
- `file`: Audio-Datei
- Response:
```json
{ "transcription": "string" } // oder "text", "result"
```
## Social Media
- **POST /socialmedia/post2event**
- Headers: `Content-Type: application/json`
- Body: frei, je nach Nutzungsfall (Payload für Generierung)
- Response: generierte Posts
- **POST /socialmedia/publish_post**
- Headers: `Content-Type: application/json`
- Body:
```json
{
"postId": "string",
"posts": { ... },
"images": { ... },
"scheduledTime": "string"
}
```
- Response: Veröffentlichungs-Ergebnis
## Gemeinsame Aspekte
- **Headers**
- `Content-Type: application/json` bei JSON-Requests
- FormData-Uploads ohne explizites `Content-Type` (Browser setzt MultiPart)
- **Auth**
- Cookies via `credentials: 'include'`
- Optionaler Bearer-Token via `Authorization`
- Auto-Refresh bei 401 über `/auth/rnjwt`, danach Retry
- **Statuscodes**
- Client erwartet `response.ok === true` bei Erfolg, sonst Fehlerwurf
- **Variabilität**
- Einige Responses sind polymorph (Array oder Objekt). Umgang entsprechend im Client.
# Beispiel: apiFetch Verhalten
- Sendet automatisch Cookies
- Fügt `Authorization: Bearer <token>` hinzu, wenn verfügbar
- Bei 401:
- versucht `GET /auth/rnjwt`
- wiederholt Request mit neuem Token
- bei erneutem 401: Logout und Fehlermeldung

20
components.json Normal file
View File

@ -0,0 +1,20 @@
{
"$schema": "https://ui.shadcn.com/schema.json",
"style": "default",
"rsc": false,
"tsx": true,
"tailwind": {
"config": "tailwind.config.ts",
"css": "src/index.css",
"baseColor": "slate",
"cssVariables": true,
"prefix": ""
},
"aliases": {
"components": "@/components",
"utils": "@/lib/utils",
"ui": "@/components/ui",
"lib": "@/lib",
"hooks": "@/hooks"
}
}

23
deploy.sh Normal file
View File

@ -0,0 +1,23 @@
#!/bin/bash
# Setze die Docker-Compose-Datei
COMPOSE_FILE="/home/martin/docker/apps/kimaschine.assistent/docker-compose.yml"
# Docker-Container herunterfahren
echo "🛑 Stopping Docker containers..."
docker-compose -f $COMPOSE_FILE down --remove-orphans
# Git-Pull mit Benutzername und Passwort
echo "📂 Pulling latest changes from Git..."
git pull
# Docker-Image neu bauen
echo "🔨 Rebuilding Docker image without cache..."
docker-compose -f $COMPOSE_FILE build --no-cache
# Docker-Container wieder hochfahren
echo "🚀 Starting Docker containers..."
docker-compose -f $COMPOSE_FILE up -d
echo "✅ Workflow completed!"

BIN
dist/Logo.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

191
dist/assets/index-CzGVSrN-.js vendored Normal file

File diff suppressed because one or more lines are too long

1
dist/assets/index-DHgMgX29.css vendored Normal file

File diff suppressed because one or more lines are too long

BIN
dist/default_event.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

BIN
dist/favicon/android-icon-144x144.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
dist/favicon/android-icon-192x192.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

BIN
dist/favicon/android-icon-36x36.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

BIN
dist/favicon/android-icon-48x48.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
dist/favicon/android-icon-72x72.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
dist/favicon/android-icon-96x96.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
dist/favicon/apple-icon-114x114.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

BIN
dist/favicon/apple-icon-120x120.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

BIN
dist/favicon/apple-icon-144x144.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
dist/favicon/apple-icon-152x152.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

BIN
dist/favicon/apple-icon-180x180.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

BIN
dist/favicon/apple-icon-57x57.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

BIN
dist/favicon/apple-icon-60x60.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

BIN
dist/favicon/apple-icon-72x72.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

BIN
dist/favicon/apple-icon-76x76.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

BIN
dist/favicon/apple-icon-precomposed.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

BIN
dist/favicon/apple-icon.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

2
dist/favicon/browserconfig.xml vendored Normal file
View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

BIN
dist/favicon/favicon-16x16.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
dist/favicon/favicon-32x32.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
dist/favicon/favicon-96x96.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
dist/favicon/favicon.ico vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

41
dist/favicon/manifest.json vendored Normal file
View File

@ -0,0 +1,41 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

BIN
dist/favicon/ms-icon-144x144.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

BIN
dist/favicon/ms-icon-150x150.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

BIN
dist/favicon/ms-icon-310x310.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

BIN
dist/favicon/ms-icon-70x70.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
dist/images/ITTools.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

BIN
dist/images/robo/robo_blogauthor.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

BIN
dist/images/robo/robo_event.png vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
dist/images/sales.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
dist/images/webhero.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

93
dist/index.html vendored Normal file
View File

@ -0,0 +1,93 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>K.I. Maschine</title>
<meta name="description" content="KIMaschine.de" />
<meta name="author" content="KIMaschine.de" />
<meta property="og:title" content="K.I. Maschine.de" />
<meta property="og:description" content="KImaschine automates your website, blog, and social media content using advanced AI. Save time, boost efficiency, and stay ahead in the digital competition." />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://kimaschine.de/logo.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@KIMaschine_de" />
<meta name="twitter:image" content="https://kimaschine.de/logo.png" />
<!-- Favicon links -->
<link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="36x36" href="/favicon/android-icon-36x36.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon/android-icon-48x48.png">
<link rel="icon" type="image/png" sizes="72x72" href="/favicon/android-icon-72x72.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/android-icon-96x96.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon/android-icon-144x144.png">
<link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
<link rel="shortcut icon" href="/favicon/favicon.ico">
<link rel="manifest" href="/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
<script type="module" crossorigin src="/assets/index-CzGVSrN-.js"></script>
<link rel="stylesheet" crossorigin href="/assets/index-DHgMgX29.css">
</head>
<body>
<div id="root"></div>
<!-- IMPORTANT: DO NOT REMOVE THIS SCRIPT TAG OR THIS VERY COMMENT! -->
<!-- <script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script> -->
<!-- Metricool Tracking -->
<!-- <script>
function loadScript(a){
var b=document.getElementsByTagName("head")[0],
c=document.createElement("script");
c.type="text/javascript",
c.src="https://tracker.metricool.com/resources/be.js",
c.onreadystatechange=a,
c.onload=a,
b.appendChild(c)
}
loadScript(function(){
beTracker.t({hash:"9496eca8438c4d21471232f7b1bf962f"})
});
</script> -->
</body>
</html>
<meta property="og:title" content="KIMaschine.de" />
<meta property="og:description" content="KIMaschine.de" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://kimaschinede.vercel.app/logo.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@KIMaschine_de" />
<meta name="twitter:image" content="https://kimaschinede.vercel.app/logo.png" />
<link rel="apple-touch-icon" sizes="57x57" href="favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="favicon/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon/favicon-16x16.png">
<link rel="manifest" href="/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
dist/martin.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
dist/miguel.jpeg vendored Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

1
dist/placeholder.svg vendored Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

14
dist/robots.txt vendored Normal file
View File

@ -0,0 +1,14 @@
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Twitterbot
Allow: /
User-agent: facebookexternalhit
Allow: /
User-agent: *
Allow: /

0
dist/test.svg vendored Normal file
View File

29
eslint.config.js Normal file
View File

@ -0,0 +1,29 @@
import js from "@eslint/js";
import globals from "globals";
import reactHooks from "eslint-plugin-react-hooks";
import reactRefresh from "eslint-plugin-react-refresh";
import tseslint from "typescript-eslint";
export default tseslint.config(
{ ignores: ["dist"] },
{
extends: [js.configs.recommended, ...tseslint.configs.recommended],
files: ["**/*.{ts,tsx}"],
languageOptions: {
ecmaVersion: 2020,
globals: globals.browser,
},
plugins: {
"react-hooks": reactHooks,
"react-refresh": reactRefresh,
},
rules: {
...reactHooks.configs.recommended.rules,
"react-refresh/only-export-components": [
"warn",
{ allowConstantExport: true },
],
"@typescript-eslint/no-unused-vars": "off",
},
}
);

View File

@ -0,0 +1 @@
google-site-verification: google0a5a3eb63f61c0ea.html

92
index.html Normal file
View File

@ -0,0 +1,92 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8" />
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
<title>K.I. Maschine</title>
<meta name="description" content="KIMaschine.de" />
<meta name="author" content="KIMaschine.de" />
<meta property="og:title" content="K.I. Maschine.de" />
<meta property="og:description" content="KImaschine automates your website, blog, and social media content using advanced AI. Save time, boost efficiency, and stay ahead in the digital competition." />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://kimaschine.de/logo.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@KIMaschine_de" />
<meta name="twitter:image" content="https://kimaschine.de/logo.png" />
<!-- Favicon links -->
<link rel="apple-touch-icon" sizes="57x57" href="/favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="/favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="/favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="/favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="/favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="/favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="/favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="/favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="/favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="36x36" href="/favicon/android-icon-36x36.png">
<link rel="icon" type="image/png" sizes="48x48" href="/favicon/android-icon-48x48.png">
<link rel="icon" type="image/png" sizes="72x72" href="/favicon/android-icon-72x72.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/android-icon-96x96.png">
<link rel="icon" type="image/png" sizes="144x144" href="/favicon/android-icon-144x144.png">
<link rel="icon" type="image/png" sizes="192x192" href="/favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="16x16" href="/favicon/favicon-16x16.png">
<link rel="icon" type="image/png" sizes="32x32" href="/favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="/favicon/favicon-96x96.png">
<link rel="shortcut icon" href="/favicon/favicon.ico">
<link rel="manifest" href="/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="/favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">
</head>
<body>
<div id="root"></div>
<!-- IMPORTANT: DO NOT REMOVE THIS SCRIPT TAG OR THIS VERY COMMENT! -->
<!-- <script src="https://cdn.gpteng.co/gptengineer.js" type="module"></script> -->
<script type="module" src="/src/main.tsx"></script>
<!-- Metricool Tracking -->
<!-- <script>
function loadScript(a){
var b=document.getElementsByTagName("head")[0],
c=document.createElement("script");
c.type="text/javascript",
c.src="https://tracker.metricool.com/resources/be.js",
c.onreadystatechange=a,
c.onload=a,
b.appendChild(c)
}
loadScript(function(){
beTracker.t({hash:"9496eca8438c4d21471232f7b1bf962f"})
});
</script> -->
</body>
</html>
<meta property="og:title" content="KIMaschine.de" />
<meta property="og:description" content="KIMaschine.de" />
<meta property="og:type" content="website" />
<meta property="og:image" content="https://kimaschinede.vercel.app/logo.png" />
<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@KIMaschine_de" />
<meta name="twitter:image" content="https://kimaschinede.vercel.app/logo.png" />
<link rel="apple-touch-icon" sizes="57x57" href="favicon/apple-icon-57x57.png">
<link rel="apple-touch-icon" sizes="60x60" href="favicon/apple-icon-60x60.png">
<link rel="apple-touch-icon" sizes="72x72" href="favicon/apple-icon-72x72.png">
<link rel="apple-touch-icon" sizes="76x76" href="favicon/apple-icon-76x76.png">
<link rel="apple-touch-icon" sizes="114x114" href="favicon/apple-icon-114x114.png">
<link rel="apple-touch-icon" sizes="120x120" href="favicon/apple-icon-120x120.png">
<link rel="apple-touch-icon" sizes="144x144" href="favicon/apple-icon-144x144.png">
<link rel="apple-touch-icon" sizes="152x152" href="favicon/apple-icon-152x152.png">
<link rel="apple-touch-icon" sizes="180x180" href="favicon/apple-icon-180x180.png">
<link rel="icon" type="image/png" sizes="192x192" href="favicon/android-icon-192x192.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicon/favicon-32x32.png">
<link rel="icon" type="image/png" sizes="96x96" href="favicon/favicon-96x96.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicon/favicon-16x16.png">
<link rel="manifest" href="/favicon/manifest.json">
<meta name="msapplication-TileColor" content="#ffffff">
<meta name="msapplication-TileImage" content="favicon/ms-icon-144x144.png">
<meta name="theme-color" content="#ffffff">

10453
package-lock.json generated Normal file

File diff suppressed because it is too large Load Diff

101
package.json Normal file
View File

@ -0,0 +1,101 @@
{
"name": "vite_react_shadcn_ts",
"private": true,
"version": "0.0.0",
"type": "module",
"scripts": {
"dev": "vite",
"build": "vite build",
"build:dev": "vite build --mode development",
"lint": "eslint .",
"preview": "vite preview",
"test": "vitest",
"test:watch": "vitest --watch",
"coverage": "vitest run --coverage"
},
"dependencies": {
"@hookform/resolvers": "^3.9.0",
"@radix-ui/react-accordion": "^1.2.0",
"@radix-ui/react-alert-dialog": "^1.1.1",
"@radix-ui/react-aspect-ratio": "^1.1.0",
"@radix-ui/react-avatar": "^1.1.0",
"@radix-ui/react-checkbox": "^1.1.1",
"@radix-ui/react-collapsible": "^1.1.0",
"@radix-ui/react-context-menu": "^2.2.1",
"@radix-ui/react-dialog": "^1.1.2",
"@radix-ui/react-dropdown-menu": "^2.1.1",
"@radix-ui/react-hover-card": "^1.1.1",
"@radix-ui/react-icons": "^1.3.2",
"@radix-ui/react-label": "^2.1.0",
"@radix-ui/react-menubar": "^1.1.1",
"@radix-ui/react-navigation-menu": "^1.2.0",
"@radix-ui/react-popover": "^1.1.1",
"@radix-ui/react-progress": "^1.1.0",
"@radix-ui/react-radio-group": "^1.2.0",
"@radix-ui/react-scroll-area": "^1.1.0",
"@radix-ui/react-select": "^2.1.1",
"@radix-ui/react-separator": "^1.1.0",
"@radix-ui/react-slider": "^1.2.0",
"@radix-ui/react-slot": "^1.1.0",
"@radix-ui/react-switch": "^1.1.0",
"@radix-ui/react-tabs": "^1.1.12",
"@radix-ui/react-toast": "^1.2.1",
"@radix-ui/react-toggle": "^1.1.0",
"@radix-ui/react-toggle-group": "^1.1.0",
"@radix-ui/react-tooltip": "^1.1.4",
"@tanstack/react-query": "^5.56.2",
"@types/react-dropzone": "^4.2.2",
"class-variance-authority": "^0.7.1",
"clsx": "^2.1.1",
"cmdk": "^1.0.0",
"date-fns": "^3.6.0",
"embla-carousel-react": "^8.3.0",
"input-otp": "^1.2.4",
"lucide-react": "^0.462.0",
"next-themes": "^0.3.0",
"react": "^18.3.1",
"react-day-picker": "^9.7.0",
"react-dom": "^18.3.1",
"react-dropzone": "^14.3.8",
"react-easy-crop": "^5.5.6",
"react-helmet-async": "^2.0.5",
"react-hook-form": "^7.53.0",
"react-markdown": "^10.1.0",
"react-quill": "^2.0.0",
"react-resizable-panels": "^2.1.3",
"react-router-dom": "^6.26.2",
"react-swipeable": "^7.0.2",
"recharts": "^2.12.7",
"sonner": "^1.5.0",
"tailwind-merge": "^2.5.2",
"tailwindcss-animate": "^1.0.7",
"vaul": "^0.9.3",
"zod": "^3.23.8"
},
"devDependencies": {
"@eslint/js": "^9.9.0",
"@tailwindcss/typography": "^0.5.15",
"@testing-library/jest-dom": "^6.6.3",
"@testing-library/react": "^16.0.1",
"@testing-library/user-event": "^14.5.2",
"@types/node": "^22.5.5",
"@types/react": "^18.3.23",
"@types/react-dom": "^18.3.7",
"@vitejs/plugin-react": "^4.5.0",
"@vitejs/plugin-react-swc": "^3.5.0",
"@vitest/coverage-v8": "^2.1.9",
"autoprefixer": "^10.4.20",
"eslint": "^9.9.0",
"eslint-plugin-react-hooks": "^5.1.0-rc.0",
"eslint-plugin-react-refresh": "^0.4.9",
"globals": "^15.9.0",
"jsdom": "^25.0.1",
"lovable-tagger": "^1.1.7",
"postcss": "^8.4.47",
"tailwindcss": "^3.4.11",
"typescript": "^5.5.3",
"typescript-eslint": "^8.0.1",
"vite": "^5.4.1",
"vitest": "^2.1.1"
}
}

6
postcss.config.js Normal file
View File

@ -0,0 +1,6 @@
export default {
plugins: {
tailwindcss: {},
autoprefixer: {},
},
}

BIN
public/Logo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
public/default_event.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 33 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 17 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 25 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 32 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.9 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.7 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 34 KiB

View File

@ -0,0 +1,2 @@
<?xml version="1.0" encoding="utf-8"?>
<browserconfig><msapplication><tile><square70x70logo src="/ms-icon-70x70.png"/><square150x150logo src="/ms-icon-150x150.png"/><square310x310logo src="/ms-icon-310x310.png"/><TileColor>#ffffff</TileColor></tile></msapplication></browserconfig>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 12 KiB

BIN
public/favicon/favicon.ico Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

View File

@ -0,0 +1,41 @@
{
"name": "App",
"icons": [
{
"src": "\/android-icon-36x36.png",
"sizes": "36x36",
"type": "image\/png",
"density": "0.75"
},
{
"src": "\/android-icon-48x48.png",
"sizes": "48x48",
"type": "image\/png",
"density": "1.0"
},
{
"src": "\/android-icon-72x72.png",
"sizes": "72x72",
"type": "image\/png",
"density": "1.5"
},
{
"src": "\/android-icon-96x96.png",
"sizes": "96x96",
"type": "image\/png",
"density": "2.0"
},
{
"src": "\/android-icon-144x144.png",
"sizes": "144x144",
"type": "image\/png",
"density": "3.0"
},
{
"src": "\/android-icon-192x192.png",
"sizes": "192x192",
"type": "image\/png",
"density": "4.0"
}
]
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 23 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 74 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.4 KiB

BIN
public/images/ITTools.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 157 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 130 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 186 KiB

BIN
public/images/sales.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

BIN
public/images/webhero.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 177 KiB

BIN
public/kgblogo.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 107 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 61 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 68 KiB

BIN
public/martin.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 36 KiB

BIN
public/miguel.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 40 KiB

1
public/placeholder.svg Normal file
View File

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="1200" height="1200" fill="none"><rect width="1200" height="1200" fill="#EAEAEA" rx="3"/><g opacity=".5"><g opacity=".5"><path fill="#FAFAFA" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 736.5c-75.454 0-136.621-61.167-136.621-136.62 0-75.454 61.167-136.621 136.621-136.621 75.453 0 136.62 61.167 136.62 136.621 0 75.453-61.167 136.62-136.62 136.62Z"/></g><path stroke="url(#a)" stroke-width="2.418" d="M0-1.209h553.581" transform="scale(1 -1) rotate(45 1163.11 91.165)"/><path stroke="url(#b)" stroke-width="2.418" d="M404.846 598.671h391.726"/><path stroke="url(#c)" stroke-width="2.418" d="M599.5 795.742V404.017"/><path stroke="url(#d)" stroke-width="2.418" d="m795.717 796.597-391.441-391.44"/><path fill="#fff" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/><g clip-path="url(#e)"><path fill="#666" fill-rule="evenodd" d="M616.426 586.58h-31.434v16.176l3.553-3.554.531-.531h9.068l.074-.074 8.463-8.463h2.565l7.18 7.181V586.58Zm-15.715 14.654 3.698 3.699 1.283 1.282-2.565 2.565-1.282-1.283-5.2-5.199h-6.066l-5.514 5.514-.073.073v2.876a2.418 2.418 0 0 0 2.418 2.418h26.598a2.418 2.418 0 0 0 2.418-2.418v-8.317l-8.463-8.463-7.181 7.181-.071.072Zm-19.347 5.442v4.085a6.045 6.045 0 0 0 6.046 6.045h26.598a6.044 6.044 0 0 0 6.045-6.045v-7.108l1.356-1.355-1.282-1.283-.074-.073v-17.989h-38.689v23.43l-.146.146.146.147Z" clip-rule="evenodd"/></g><path stroke="#C9C9C9" stroke-width="2.418" d="M600.709 656.704c-31.384 0-56.825-25.441-56.825-56.824 0-31.384 25.441-56.825 56.825-56.825 31.383 0 56.824 25.441 56.824 56.825 0 31.383-25.441 56.824-56.824 56.824Z"/></g><defs><linearGradient id="a" x1="554.061" x2="-.48" y1=".083" y2=".087" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="b" x1="796.912" x2="404.507" y1="599.963" y2="599.965" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="c" x1="600.792" x2="600.794" y1="403.677" y2="796.082" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><linearGradient id="d" x1="404.85" x2="796.972" y1="403.903" y2="796.02" gradientUnits="userSpaceOnUse"><stop stop-color="#C9C9C9" stop-opacity="0"/><stop offset=".208" stop-color="#C9C9C9"/><stop offset=".792" stop-color="#C9C9C9"/><stop offset="1" stop-color="#C9C9C9" stop-opacity="0"/></linearGradient><clipPath id="e"><path fill="#fff" d="M581.364 580.535h38.689v38.689h-38.689z"/></clipPath></defs></svg>

After

Width:  |  Height:  |  Size: 3.2 KiB

14
public/robots.txt Normal file
View File

@ -0,0 +1,14 @@
User-agent: Googlebot
Allow: /
User-agent: Bingbot
Allow: /
User-agent: Twitterbot
Allow: /
User-agent: facebookexternalhit
Allow: /
User-agent: *
Allow: /

0
public/test.svg Normal file
View File

42
src/App.css Normal file
View File

@ -0,0 +1,42 @@
#root {
max-width: 1280px;
margin: 0 auto;
padding: 2rem;
text-align: center;
}
.logo {
height: 6em;
padding: 1.5em;
will-change: filter;
transition: filter 300ms;
}
.logo:hover {
filter: drop-shadow(0 0 2em #646cffaa);
}
.logo.react:hover {
filter: drop-shadow(0 0 2em #61dafbaa);
}
@keyframes logo-spin {
from {
transform: rotate(0deg);
}
to {
transform: rotate(360deg);
}
}
@media (prefers-reduced-motion: no-preference) {
a:nth-of-type(2) .logo {
animation: logo-spin infinite 20s linear;
}
}
.card {
padding: 2em;
}
.read-the-docs {
color: #888;
}

48
src/App.tsx Normal file
View File

@ -0,0 +1,48 @@
import { Toaster } from "@/components/ui/toaster";
import { Toaster as Sonner } from "@/components/ui/sonner";
import { TooltipProvider } from "@/components/ui/tooltip";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import { BrowserRouter, Routes, Route } from "react-router-dom";
import { HelmetProvider } from "react-helmet-async";
import { LanguageProvider } from "@/contexts/LanguageContext";
import { AuthProvider, useAuth } from "@/contexts/AuthContext";
import Main from "./components/app/Main";
import LoginContainer from "./components/auth/LoginContainer";
import ArtistCollabForm from "@/features/event/components/ArtistCollabForm";
const queryClient = new QueryClient();
const AppContent = () => {
const { user } = useAuth();
return (
<Routes>
<Route path="/collab/:token" element={<ArtistCollabForm />} />
<Route
path="/*"
element={user ? <Main /> : <LoginContainer />}
/>
</Routes>
);
};
const App = () => (
<HelmetProvider>
<QueryClientProvider client={queryClient}>
<TooltipProvider>
<LanguageProvider>
<AuthProvider>
<Toaster />
<Sonner />
<BrowserRouter>
<AppContent />
</BrowserRouter>
</AuthProvider>
</LanguageProvider>
</TooltipProvider>
</QueryClientProvider>
</HelmetProvider>
);
export default App;

108
src/components/app/Main.tsx Normal file
View File

@ -0,0 +1,108 @@
import React, { useState, useEffect } from 'react';
import { Button } from "@/components/ui/button";
import { LogOut, Menu } from 'lucide-react';
import { useAuth } from '@/contexts/AuthContext';
import { useNavigate } from 'react-router-dom';
import DashboardContainer from '../dashboard/DashboardContainer';
import { cn } from '@/lib/utils';
const Main: React.FC = () => {
const { user, logout } = useAuth();
const navigate = useNavigate();
const [hasActiveEvent, setHasActiveEvent] = useState(false);
const [isMobileMenuOpen, setIsMobileMenuOpen] = useState(false);
// Check for active events - This will be replaced with actual API call
useEffect(() => {
// TODO: Replace with actual API call to check for active events
const checkActiveEvents = async () => {
try {
// const response = await fetch('/api/events/active');
// const data = await response.json();
// setHasActiveEvent(data.hasActiveEvent);
// For now, we'll set it to false
setHasActiveEvent(false);
} catch (error) {
console.error('Error checking active events:', error);
}
};
checkActiveEvents();
}, []);
const handleAction = (action: string) => {
console.log('Selected action:', action);
// Handle navigation or other actions based on the selected card
switch (action) {
case 'event':
// Navigate to events page or open event form
break;
case 'blog':
// Navigate to blog page or open blog form
break;
case 'quick-post':
// Open quick post dialog
break;
default:
break;
}
};
return (
<div className="min-h-screen bg-background">
{/* Header */}
<header className="sticky top-0 z-40 border-b bg-background/95 backdrop-blur supports-[backdrop-filter]:bg-background/60">
<div className="container flex h-16 items-center justify-between px-4">
<div className="flex items-center gap-2">
<Button
variant="ghost"
size="icon"
className="md:hidden"
onClick={() => setIsMobileMenuOpen(!isMobileMenuOpen)}
>
<Menu className="h-5 w-5" />
<span className="sr-only">Toggle menu</span>
</Button>
<div
className="flex items-center gap-2 cursor-pointer"
onClick={() => navigate('/')}
>
<img
src="/Logo.png"
alt="Logo"
className="h-10 w-auto object-contain"
/>
</div>
</div>
<div className="flex items-center gap-2">
<div className="hidden md:block text-sm text-muted-foreground">
Hallo, {user?.name?.split(' ')[0] || 'Benutzer'}
</div>
<Button
variant="outline"
size="sm"
className="gap-1.5 text-sm"
onClick={logout}
>
<LogOut className="h-4 w-4" />
<span className="hidden sm:inline">Abmelden</span>
</Button>
</div>
</div>
</header>
{/* Main Content */}
<main className="container py-6 px-0 md:px-4">
<div className="mx-auto md:max-w-5xl">
<DashboardContainer
onActionClick={handleAction}
hasActiveEvent={hasActiveEvent}
/>
</div>
</main>
</div>
);
};
export default Main;

Some files were not shown because too many files have changed in this diff Show More