Initial commit
This commit is contained in:
commit
2736d33be0
27 files changed
+4899
No files matched your search
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"extraKnownMarketplaces": {
|
||||||
|
"ep-plugins": {
|
||||||
|
"source": { "source": "git", "url": "ssh://[email protected]:2222/EP-Intern/Projekt-Referenz.git" }
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"enabledPlugins": { "prodi@ep-plugins": true },
|
||||||
|
"permissions": {
|
||||||
|
"defaultMode": "plan",
|
||||||
|
"allow": [
|
||||||
|
"Bash(git status:*)", "Bash(git diff:*)", "Bash(git log:*)", "Bash(git fetch:*)",
|
||||||
|
"Bash(git pull:*)", "Bash(git switch main:*)",
|
||||||
|
"Bash(git switch -c feat/:*)", "Bash(git switch -c fix/:*)", "Bash(git switch -c chore/:*)",
|
||||||
|
"Bash(git add:*)"
|
||||||
|
],
|
||||||
|
"ask": ["Bash(git commit:*)", "Bash(git push:*)"],
|
||||||
|
"deny": [
|
||||||
|
"Bash(git push origin main:*)", "Bash(git push origin HEAD:main:*)",
|
||||||
|
"Bash(git push --force:*)", "Bash(git push -f:*)", "Bash(git push --force-with-lease:*)",
|
||||||
|
"Bash(git merge:*)", "Bash(git rebase:*)", "Bash(git reset:*)",
|
||||||
|
"Bash(git branch -D:*)", "Bash(git branch -d:*)",
|
||||||
|
"Read(./.env*)", "Read(**/.env*)", "Read(~/.claude/projects/**)"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,45 @@
|
|||||||
|
{
|
||||||
|
"name": "webapp",
|
||||||
|
"image": "mcr.microsoft.com/devcontainers/typescript-node:1-22-bookworm",
|
||||||
|
"runArgs": ["--env-file", "${localEnv:HOME}/.config/ep-dev/devcontainer.env"],
|
||||||
|
"mounts": [
|
||||||
|
"source=claude-config-${devcontainerId},target=/home/node/.claude,type=volume",
|
||||||
|
"source=${localEnv:HOME}/.ssh/config,target=/home/node/.ssh/config,type=bind,readonly",
|
||||||
|
"source=${localEnv:HOME}/.ssh/known_hosts,target=/home/node/.ssh/known_hosts,type=bind,readonly",
|
||||||
|
"source=npm-cache,target=/home/node/.npm,type=volume"
|
||||||
|
],
|
||||||
|
"forwardPorts": [3000],
|
||||||
|
"containerEnv": {
|
||||||
|
"NEXT_TELEMETRY_DISABLED": "1",
|
||||||
|
"NPM_CONFIG_UPDATE_NOTIFIER": "false",
|
||||||
|
"DISABLE_AUTOUPDATER": "1",
|
||||||
|
"ENABLE_CLAUDEAI_MCP_SERVERS": "false"
|
||||||
|
},
|
||||||
|
"portsAttributes": {
|
||||||
|
"3000": { "label": "App", "onAutoForward": "openBrowser" }
|
||||||
|
},
|
||||||
|
"postCreateCommand": "sudo chown -R node:node /home/node/.claude /home/node/.npm && npm install -g @anthropic-ai/[email protected] && cd frontend-starter && npm install",
|
||||||
|
"postStartCommand": "cd frontend-starter && npm install --no-audit --no-fund",
|
||||||
|
"postAttachCommand": "cd frontend-starter && npx -y kill-port 3000 && npm run dev",
|
||||||
|
"customizations": {
|
||||||
|
"vscode": {
|
||||||
|
"settings": {
|
||||||
|
"extensions.autoUpdate": false,
|
||||||
|
"extensions.autoCheckUpdates": false,
|
||||||
|
"git.branchProtection": ["main"],
|
||||||
|
"git.branchProtectionPrompt": "alwaysCommitToNewBranch",
|
||||||
|
"git.branchPrefix": "feat/",
|
||||||
|
"git.branchRandomName.enable": true,
|
||||||
|
"git.postCommitCommand": "push",
|
||||||
|
"git.autofetch": true,
|
||||||
|
"json.schemaDownload.trustedDomains": { "https://ui.shadcn.com": true },
|
||||||
|
},
|
||||||
|
"extensions": [
|
||||||
|
"[email protected]",
|
||||||
|
"dbaeumer.vscode-eslint",
|
||||||
|
"esbenp.prettier-vscode",
|
||||||
|
"bradlc.vscode-tailwindcss"
|
||||||
|
]
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
**/node_modules
|
||||||
|
**/.next
|
||||||
|
.git
|
||||||
|
.gitea
|
||||||
|
.devcontainer
|
||||||
|
.claude
|
||||||
|
**/.env*
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
* text=auto eol=lf
|
||||||
|
*.woff2 binary
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
## Was und warum
|
||||||
|
|
||||||
|
## So testest du es
|
||||||
|
|
||||||
|
## Checkliste
|
||||||
|
- [ ] Läuft lokal
|
||||||
|
- [ ] Keine Passwörter oder Tokens im Code
|
||||||
|
- [ ] Neue Umgebungsvariablen sind dem Owner mitgeteilt
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
node_modules/
|
||||||
|
.next/
|
||||||
|
.env
|
||||||
|
.env.*
|
||||||
|
!.env.local.example
|
||||||
|
data/
|
||||||
|
.claude/settings.local.json
|
||||||
|
next-env.d.ts
|
||||||
|
frontend-starter/public/ep-logo.svg
|
||||||
|
frontend-starter/public/favicon.svg
|
||||||
@@ -0,0 +1,10 @@
|
|||||||
|
# test-app
|
||||||
|
|
||||||
|
- Owner: <name>
|
||||||
|
- n8n-Ordner (Staging und Live): <Bereich> → test-app
|
||||||
|
- Datenbank: SQLite in der App
|
||||||
|
- Webseite: Next.js im Ordner `frontend-starter`; npm-Befehle dort ausführen
|
||||||
|
- Port: immer 3000. Dockerfile, Port und `output: "standalone"` nicht ändern.
|
||||||
|
|
||||||
|
Arbeitsweise, Git-Ablauf, n8n-Regeln und UI-Richtlinien kommen aus dem Plugin `prodi`.
|
||||||
|
Der Steckbrief liegt in `docs/steckbrief.md`.
|
||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
FROM node:22-bookworm-slim AS deps
|
||||||
|
WORKDIR /app
|
||||||
|
ARG GITEA_NPM_TOKEN
|
||||||
|
COPY frontend-starter/package.json frontend-starter/package-lock.json frontend-starter/.npmrc ./
|
||||||
|
RUN GITEA_NPM_TOKEN=$GITEA_NPM_TOKEN npm ci
|
||||||
|
|
||||||
|
FROM node:22-bookworm-slim AS build
|
||||||
|
WORKDIR /app
|
||||||
|
COPY --from=deps /app/node_modules ./node_modules
|
||||||
|
COPY frontend-starter/ ./
|
||||||
|
ENV NEXT_TELEMETRY_DISABLED=1
|
||||||
|
RUN npm run build
|
||||||
|
|
||||||
|
FROM node:22-bookworm-slim AS run
|
||||||
|
WORKDIR /app
|
||||||
|
ENV NODE_ENV=production NEXT_TELEMETRY_DISABLED=1 PORT=3000 HOSTNAME=0.0.0.0
|
||||||
|
COPY --from=build /app/.next/standalone ./
|
||||||
|
COPY --from=build /app/.next/static ./.next/static
|
||||||
|
COPY --from=build /app/public ./public
|
||||||
|
USER node
|
||||||
|
EXPOSE 3000
|
||||||
|
CMD ["node", "server.js"]
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# test-app
|
||||||
|
|
||||||
|
Erreichbar unter: https://test-app.ep-reisen.app
|
||||||
|
|
||||||
|
## Arbeitsweise
|
||||||
|
- Niemand committet direkt auf `main`.
|
||||||
|
- Jede Änderung über Claude in VS-Code: Branch anlegen, Pull Request öffnen, Owner gibt frei.
|
||||||
|
- Jeder Merge auf `main` wird automatisch über Coolify deployt.
|
||||||
@@ -0,0 +1,16 @@
|
|||||||
|
# Steckbrief: test-app
|
||||||
|
|
||||||
|
- **Owner:**
|
||||||
|
- **Team:**
|
||||||
|
- **Zweck:**
|
||||||
|
- **n8n-Ordner:**
|
||||||
|
- **Datenbank:**
|
||||||
|
- **Webseite:** ja / nein
|
||||||
|
|
||||||
|
## Idee
|
||||||
|
|
||||||
|
## Ablauf
|
||||||
|
|
||||||
|
## Zugänge
|
||||||
|
|
||||||
|
## Offene Punkte
|
||||||
@@ -0,0 +1,2 @@
|
|||||||
|
@ep:registry=http://192.168.20.70:3002/api/packages/EP-Intern/npm/
|
||||||
|
//192.168.20.70:3002/api/packages/EP-Intern/npm/:_authToken=${GITEA_NPM_TOKEN}
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
# App
|
||||||
|
|
||||||
|
Dies ist die Next.js-App des Projekts.
|
||||||
|
|
||||||
|
- Starten: `npm run dev` in diesem Ordner, läuft immer auf Port 3000.
|
||||||
|
- Änderungen nur auf einem eigenen Branch, nie auf `main`.
|
||||||
|
- Committen und pushen nur nach ausdrücklicher Zustimmung des Nutzers.
|
||||||
|
- Deployt wird automatisch, wenn der Owner einen Pull Request nach `main` mergt.
|
||||||
@@ -0,0 +1,8 @@
|
|||||||
|
@import "tailwindcss";
|
||||||
|
@import "tw-animate-css";
|
||||||
|
@import "shadcn/tailwind.css";
|
||||||
|
@import "@ep/ui/theme.css";
|
||||||
|
@source "../node_modules/@ep/ui/dist";
|
||||||
|
|
||||||
|
/* E&P-Farben, Schriften und Bausteine (ep-karte, ep-knopf, …) kommen aus @ep/ui/theme.css.
|
||||||
|
* Hier nur app-eigene Regeln ergänzen. */
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
import type { Metadata, Viewport } from "next";
|
||||||
|
import { EpFuss, EpKopf } from "@ep/ui";
|
||||||
|
import "./globals.css";
|
||||||
|
import { APP_BESCHREIBUNG, APP_TITEL } from "@/lib/app";
|
||||||
|
|
||||||
|
export const metadata: Metadata = {
|
||||||
|
title: `${APP_TITEL} · E&P Reisen`,
|
||||||
|
description: APP_BESCHREIBUNG,
|
||||||
|
robots: { index: false, follow: false },
|
||||||
|
icons: { icon: "/favicon.svg" },
|
||||||
|
};
|
||||||
|
|
||||||
|
export const viewport: Viewport = {
|
||||||
|
themeColor: "#ffffff",
|
||||||
|
colorScheme: "light",
|
||||||
|
};
|
||||||
|
|
||||||
|
// E&P-Layout für jede Seite: Kopf mit Logo, Inhalt, Fuß. Seiten liefern nur ihren Inhalt, kein eigenes <main>.
|
||||||
|
// Kopf, Fuß und die Hausschrift Lato kommen aus @ep/ui.
|
||||||
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
||||||
|
return (
|
||||||
|
<html lang="de" className="font-sans">
|
||||||
|
<body className="flex min-h-screen flex-col bg-ground text-ink">
|
||||||
|
<a href="#inhalt" className="skip-link">
|
||||||
|
Zum Inhalt springen
|
||||||
|
</a>
|
||||||
|
<EpKopf titel={APP_TITEL} />
|
||||||
|
<main id="inhalt" className="mx-auto w-full max-w-3xl flex-1 px-4 py-8 sm:px-6 sm:py-12">
|
||||||
|
{children}
|
||||||
|
</main>
|
||||||
|
<EpFuss />
|
||||||
|
</body>
|
||||||
|
</html>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,17 @@
|
|||||||
|
import { Card, CardContent, CardHeader } from "@/components/ui/card";
|
||||||
|
import { APP_BESCHREIBUNG, APP_TITEL } from "@/lib/app";
|
||||||
|
|
||||||
|
// Startseite im E&P-Layout. Kopf und Fuß kommen aus app/layout.tsx,
|
||||||
|
// Farben und Bausteine (ep-karte, ep-ueberschrift, …) aus @ep/ui/theme.css.
|
||||||
|
export default function Home() {
|
||||||
|
return (
|
||||||
|
<Card className="ep-karte rounded-none shadow-none ring-0">
|
||||||
|
<CardHeader className="px-0">
|
||||||
|
<h1 className="ep-ueberschrift text-3xl">{APP_TITEL}</h1>
|
||||||
|
</CardHeader>
|
||||||
|
<CardContent className="px-0">
|
||||||
|
<p className="text-ink-muted">{APP_BESCHREIBUNG}</p>
|
||||||
|
</CardContent>
|
||||||
|
</Card>
|
||||||
|
);
|
||||||
|
}
|
||||||
@@ -0,0 +1,25 @@
|
|||||||
|
{
|
||||||
|
"$schema": "https://ui.shadcn.com/schema.json",
|
||||||
|
"style": "base-luma",
|
||||||
|
"rsc": true,
|
||||||
|
"tsx": true,
|
||||||
|
"tailwind": {
|
||||||
|
"config": "",
|
||||||
|
"css": "app/globals.css",
|
||||||
|
"baseColor": "neutral",
|
||||||
|
"cssVariables": true,
|
||||||
|
"prefix": ""
|
||||||
|
},
|
||||||
|
"iconLibrary": "lucide",
|
||||||
|
"rtl": false,
|
||||||
|
"aliases": {
|
||||||
|
"components": "@/components",
|
||||||
|
"utils": "@/lib/utils",
|
||||||
|
"ui": "@/components/ui",
|
||||||
|
"lib": "@/lib",
|
||||||
|
"hooks": "@/hooks"
|
||||||
|
},
|
||||||
|
"menuColor": "default",
|
||||||
|
"menuAccent": "subtle",
|
||||||
|
"registries": {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { Button as ButtonPrimitive } from "@base-ui/react/button"
|
||||||
|
import { cva, type VariantProps } from "class-variance-authority"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
const buttonVariants = cva(
|
||||||
|
"group/button inline-flex shrink-0 items-center justify-center rounded-4xl border border-transparent bg-clip-padding text-sm font-medium whitespace-nowrap transition-all outline-none select-none focus-visible:border-ring focus-visible:ring-3 focus-visible:ring-ring/30 active:not-aria-[haspopup]:translate-y-px disabled:pointer-events-none disabled:opacity-50 aria-invalid:border-destructive aria-invalid:ring-3 aria-invalid:ring-destructive/20 dark:aria-invalid:border-destructive/50 dark:aria-invalid:ring-destructive/40 [&_svg]:pointer-events-none [&_svg]:shrink-0 [&_svg:not([class*='size-'])]:size-4",
|
||||||
|
{
|
||||||
|
variants: {
|
||||||
|
variant: {
|
||||||
|
default: "bg-primary text-primary-foreground hover:bg-primary/80",
|
||||||
|
outline:
|
||||||
|
"border-border bg-background hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:bg-transparent dark:hover:bg-input/30",
|
||||||
|
secondary:
|
||||||
|
"bg-secondary text-secondary-foreground hover:bg-[color-mix(in_oklch,var(--secondary),var(--foreground)_5%)] aria-expanded:bg-secondary aria-expanded:text-secondary-foreground",
|
||||||
|
ghost:
|
||||||
|
"hover:bg-muted hover:text-foreground aria-expanded:bg-muted aria-expanded:text-foreground dark:hover:bg-muted/50",
|
||||||
|
destructive:
|
||||||
|
"bg-destructive/10 text-destructive hover:bg-destructive/20 focus-visible:border-destructive/40 focus-visible:ring-destructive/20 dark:bg-destructive/20 dark:hover:bg-destructive/30 dark:focus-visible:ring-destructive/40",
|
||||||
|
link: "text-primary underline-offset-4 hover:underline",
|
||||||
|
},
|
||||||
|
size: {
|
||||||
|
default:
|
||||||
|
"h-9 gap-1.5 px-3 has-data-[icon=inline-end]:pr-2.5 has-data-[icon=inline-start]:pl-2.5",
|
||||||
|
xs: "h-6 gap-1 px-2.5 text-xs has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2 [&_svg:not([class*='size-'])]:size-3",
|
||||||
|
sm: "h-8 gap-1 px-3 has-data-[icon=inline-end]:pr-2 has-data-[icon=inline-start]:pl-2",
|
||||||
|
lg: "h-10 gap-1.5 px-4 has-data-[icon=inline-end]:pr-3 has-data-[icon=inline-start]:pl-3",
|
||||||
|
icon: "size-9",
|
||||||
|
"icon-xs": "size-6 [&_svg:not([class*='size-'])]:size-3",
|
||||||
|
"icon-sm": "size-8",
|
||||||
|
"icon-lg": "size-10",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
defaultVariants: {
|
||||||
|
variant: "default",
|
||||||
|
size: "default",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
)
|
||||||
|
|
||||||
|
function Button({
|
||||||
|
className,
|
||||||
|
variant = "default",
|
||||||
|
size = "default",
|
||||||
|
...props
|
||||||
|
}: ButtonPrimitive.Props & VariantProps<typeof buttonVariants>) {
|
||||||
|
return (
|
||||||
|
<ButtonPrimitive
|
||||||
|
data-slot="button"
|
||||||
|
className={cn(buttonVariants({ variant, size, className }))}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export { Button, buttonVariants }
|
||||||
@@ -0,0 +1,99 @@
|
|||||||
|
import * as React from "react"
|
||||||
|
import { cn } from "@/lib/utils"
|
||||||
|
|
||||||
|
function Card({
|
||||||
|
className,
|
||||||
|
size = "default",
|
||||||
|
...props
|
||||||
|
}: React.ComponentProps<"div"> & { size?: "default" | "sm" }) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card"
|
||||||
|
data-size={size}
|
||||||
|
className={cn(
|
||||||
|
"group/card flex flex-col gap-(--card-spacing) overflow-hidden rounded-4xl bg-card py-(--card-spacing) text-sm text-card-foreground shadow-md ring-1 ring-foreground/5 [--card-spacing:--spacing(6)] has-[>img:first-child]:pt-0 data-[size=sm]:[--card-spacing:--spacing(4)] dark:ring-foreground/10 *:[img:first-child]:rounded-t-4xl *:[img:last-child]:rounded-b-4xl",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardHeader({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-header"
|
||||||
|
className={cn(
|
||||||
|
"group/card-header @container/card-header grid auto-rows-min items-start gap-1.5 rounded-t-4xl px-(--card-spacing) has-data-[slot=card-action]:grid-cols-[1fr_auto] has-data-[slot=card-description]:grid-rows-[auto_auto] [.border-b]:pb-(--card-spacing)",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardTitle({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-title"
|
||||||
|
className={cn("font-heading text-base font-medium", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardDescription({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-description"
|
||||||
|
className={cn("text-sm text-muted-foreground", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardAction({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-action"
|
||||||
|
className={cn(
|
||||||
|
"col-start-2 row-span-2 row-start-1 self-start justify-self-end",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardContent({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-content"
|
||||||
|
className={cn("px-(--card-spacing)", className)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
function CardFooter({ className, ...props }: React.ComponentProps<"div">) {
|
||||||
|
return (
|
||||||
|
<div
|
||||||
|
data-slot="card-footer"
|
||||||
|
className={cn(
|
||||||
|
"flex items-center rounded-b-4xl px-(--card-spacing) [.border-t]:pt-(--card-spacing)",
|
||||||
|
className
|
||||||
|
)}
|
||||||
|
{...props}
|
||||||
|
/>
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export {
|
||||||
|
Card,
|
||||||
|
CardHeader,
|
||||||
|
CardFooter,
|
||||||
|
CardTitle,
|
||||||
|
CardAction,
|
||||||
|
CardDescription,
|
||||||
|
CardContent,
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/**
|
||||||
|
* Name und Kurzbeschreibung der Oberfläche. Der Name steht im Kopf neben dem E&P-Logo
|
||||||
|
* und im Browser-Tab. Für jede neue Oberfläche passend setzen, zum Beispiel "Hotel-Steckbriefe".
|
||||||
|
*/
|
||||||
|
export const APP_TITEL = "Neue App";
|
||||||
|
export const APP_BESCHREIBUNG = "Interne Web-App von E&P";
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
import { clsx, type ClassValue } from "clsx"
|
||||||
|
import { twMerge } from "tailwind-merge"
|
||||||
|
|
||||||
|
export function cn(...inputs: ClassValue[]) {
|
||||||
|
return twMerge(clsx(inputs))
|
||||||
|
}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
/** @type {import('next').NextConfig} */
|
||||||
|
const nextConfig = {
|
||||||
|
output: "standalone",
|
||||||
|
};
|
||||||
|
|
||||||
|
export default nextConfig;
|
||||||
Generated
+4396
File diff suppressed because it is too large.
Load diff
@@ -0,0 +1,32 @@
|
|||||||
|
{
|
||||||
|
"name": "frontend-starter",
|
||||||
|
"version": "0.1.0",
|
||||||
|
"private": true,
|
||||||
|
"scripts": {
|
||||||
|
"assets": "mkdir -p public && cp node_modules/@ep/ui/assets/*.svg public/",
|
||||||
|
"dev": "npm run assets && next dev -p 3000",
|
||||||
|
"build": "npm run assets && next build",
|
||||||
|
"start": "next start -p 3000"
|
||||||
|
},
|
||||||
|
"dependencies": {
|
||||||
|
"@base-ui/react": "^1.9.0",
|
||||||
|
"@ep/ui": "^1.0.0",
|
||||||
|
"class-variance-authority": "^0.7.1",
|
||||||
|
"clsx": "^2.1.1",
|
||||||
|
"lucide-react": "^1.63.0",
|
||||||
|
"next": "^16.4.5",
|
||||||
|
"react": "^19.2.0",
|
||||||
|
"react-dom": "^19.2.0",
|
||||||
|
"shadcn": "^4.23.0",
|
||||||
|
"tailwind-merge": "^3.7.0",
|
||||||
|
"tw-animate-css": "^1.4.0"
|
||||||
|
},
|
||||||
|
"devDependencies": {
|
||||||
|
"@tailwindcss/postcss": "^4.3.0",
|
||||||
|
"@types/node": "^22.0.0",
|
||||||
|
"@types/react": "^19.2.0",
|
||||||
|
"@types/react-dom": "^19.2.0",
|
||||||
|
"tailwindcss": "^4.3.0",
|
||||||
|
"typescript": "^5.9.0"
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
export default {
|
||||||
|
plugins: {
|
||||||
|
"@tailwindcss/postcss": {},
|
||||||
|
},
|
||||||
|
};
|
||||||
@@ -0,0 +1,41 @@
|
|||||||
|
{
|
||||||
|
"compilerOptions": {
|
||||||
|
"lib": [
|
||||||
|
"dom",
|
||||||
|
"dom.iterable",
|
||||||
|
"esnext"
|
||||||
|
],
|
||||||
|
"allowJs": true,
|
||||||
|
"skipLibCheck": true,
|
||||||
|
"strict": true,
|
||||||
|
"noEmit": true,
|
||||||
|
"esModuleInterop": true,
|
||||||
|
"module": "esnext",
|
||||||
|
"moduleResolution": "bundler",
|
||||||
|
"resolveJsonModule": true,
|
||||||
|
"isolatedModules": true,
|
||||||
|
"jsx": "react-jsx",
|
||||||
|
"incremental": true,
|
||||||
|
"plugins": [
|
||||||
|
{
|
||||||
|
"name": "next"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"paths": {
|
||||||
|
"@/*": [
|
||||||
|
"./*"
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"target": "ES2017"
|
||||||
|
},
|
||||||
|
"include": [
|
||||||
|
"next-env.d.ts",
|
||||||
|
"**/*.ts",
|
||||||
|
"**/*.tsx",
|
||||||
|
".next/types/**/*.ts",
|
||||||
|
".next/dev/types/**/*.ts"
|
||||||
|
],
|
||||||
|
"exclude": [
|
||||||
|
"node_modules"
|
||||||
|
]
|
||||||
|
}
|
||||||
@@ -0,0 +1,5 @@
|
|||||||
|
# Zugänge, die die Workflows dieses Projekts brauchen (ohne Geheimnisse).
|
||||||
|
# - name: "Raumplanung SharePoint"
|
||||||
|
# typ: microsoftSharePointOAuth2Api
|
||||||
|
# zweck: Raumbelegung lesen
|
||||||
|
# klasse: gruen
|
||||||
Whitespace-only changes.
Reference in new issue
Block a user