From c5c9cc37af4d43c15e3e98508426ee319ed542b9 Mon Sep 17 00:00:00 2001 From: Dominik Natter Date: Wed, 26 Mar 2025 17:41:46 +0100 Subject: [PATCH] basic search working --- package.json | 8 +- pnpm-lock.yaml | 75 +++++++++++ .../_components/DiplomarbeitSearch.tsx | 29 +++++ src/app/(frontend)/_components/Footer.tsx | 15 +++ src/app/(frontend)/_components/Header.tsx | 27 ++++ .../(frontend)/_components/SignInButton.tsx | 3 +- .../(frontend)/_components/SignOutButton.tsx | 5 +- src/app/(frontend)/globals.css | 123 ++++++++++++++++++ src/app/(frontend)/htld.svg | 43 ++++++ src/app/(frontend)/layout.tsx | 22 ++-- src/app/(frontend)/page.tsx | 31 ++++- src/app/(payload)/api/diplomarbeiten/route.ts | 32 +++++ src/collections/Papers.ts | 11 ++ 13 files changed, 406 insertions(+), 18 deletions(-) create mode 100644 src/app/(frontend)/_components/DiplomarbeitSearch.tsx create mode 100644 src/app/(frontend)/_components/Footer.tsx create mode 100644 src/app/(frontend)/_components/Header.tsx create mode 100644 src/app/(frontend)/htld.svg create mode 100644 src/app/(payload)/api/diplomarbeiten/route.ts diff --git a/package.json b/package.json index 4fdaa04..f763071 100644 --- a/package.json +++ b/package.json @@ -19,10 +19,14 @@ "@payloadcms/next": "latest", "@payloadcms/payload-cloud": "latest", "@payloadcms/richtext-lexical": "latest", + "@radix-ui/react-slot": "^1.1.2", "@tailwindcss/postcss": "^4.0.17", "auth": "^1.2.3", + "class-variance-authority": "^0.7.1", + "clsx": "^2.1.1", "cross-env": "^7.0.3", "graphql": "^16.8.1", + "lucide-react": "^0.484.0", "next": "15.2.3", "next-auth": "5.0.0-beta.25", "payload": "latest", @@ -31,7 +35,9 @@ "react": "19.0.0", "react-dom": "19.0.0", "sharp": "0.32.6", - "tailwindcss": "^4.0.17" + "tailwind-merge": "^3.0.2", + "tailwindcss": "^4.0.17", + "tw-animate-css": "^1.2.4" }, "devDependencies": { "@eslint/eslintrc": "^3.2.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 961a5de..406193f 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -20,18 +20,30 @@ importers: '@payloadcms/richtext-lexical': specifier: latest version: 3.31.0(@faceless-ui/modal@3.0.0-beta.2(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@faceless-ui/scroll-info@2.0.0(react-dom@19.0.0(react@19.0.0))(react@19.0.0))(@payloadcms/next@3.31.0(@types/react@19.0.12)(graphql@16.10.0)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3))(@types/react@19.0.12)(monaco-editor@0.52.2)(next@15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4))(payload@3.31.0(graphql@16.10.0)(typescript@5.7.3))(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(typescript@5.7.3)(yjs@13.6.24) + '@radix-ui/react-slot': + specifier: ^1.1.2 + version: 1.1.2(@types/react@19.0.12)(react@19.0.0) '@tailwindcss/postcss': specifier: ^4.0.17 version: 4.0.17 auth: specifier: ^1.2.3 version: 1.2.3 + class-variance-authority: + specifier: ^0.7.1 + version: 0.7.1 + clsx: + specifier: ^2.1.1 + version: 2.1.1 cross-env: specifier: ^7.0.3 version: 7.0.3 graphql: specifier: ^16.8.1 version: 16.10.0 + lucide-react: + specifier: ^0.484.0 + version: 0.484.0(react@19.0.0) next: specifier: 15.2.3 version: 15.2.3(react-dom@19.0.0(react@19.0.0))(react@19.0.0)(sass@1.77.4) @@ -56,9 +68,15 @@ importers: sharp: specifier: 0.32.6 version: 0.32.6 + tailwind-merge: + specifier: ^3.0.2 + version: 3.0.2 tailwindcss: specifier: ^4.0.17 version: 4.0.17 + tw-animate-css: + specifier: ^1.2.4 + version: 1.2.4 devDependencies: '@eslint/eslintrc': specifier: ^3.2.0 @@ -1391,6 +1409,24 @@ packages: react: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 react-dom: ^19.0.0 || ^19.0.0-rc-65a56d0e-20241020 + '@radix-ui/react-compose-refs@1.1.1': + resolution: {integrity: sha512-Y9VzoRDSJtgFMUCoiZBDVo084VQ5hfpXxVE+NgkdNsjiDBByiImMZKKhxMwCbdHvhlENG6a833CbFkOQvTricw==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + + '@radix-ui/react-slot@1.1.2': + resolution: {integrity: sha512-YAKxaiGsSQJ38VzKH86/BPRC4rh+b1Jpa+JneA5LRE7skmLPNAyeG8kPJj/oo4STLvlrs8vkf/iYyc3A5stYCQ==} + peerDependencies: + '@types/react': '*' + react: ^16.8 || ^17.0 || ^18.0 || ^19.0 || ^19.0.0-rc + peerDependenciesMeta: + '@types/react': + optional: true + '@rtsao/scc@1.1.0': resolution: {integrity: sha512-zt6OdqaDoOnJ1ZYsCYGt9YmWzDXl4vQdKTyJev62gFhRGKdx7mcT54V9KIjg+d2wi9EXsPvAPKe7i7WjfVWB8g==} @@ -2151,6 +2187,9 @@ packages: resolution: {integrity: sha512-cYY9mypksY8NRqgDB1XD1RiJL338v/551niynFTGkZOO2LHuB2OmOYxDIe/ttN9AHwrqdum1360G3ald0W9kCg==} engines: {node: '>=8'} + class-variance-authority@0.7.1: + resolution: {integrity: sha512-Ka+9Trutv7G8M6WT6SeiRWz792K5qEqIGEGzXKhAE6xOWAY6pPH8U+9IY3oCMv6kqTmLsv7Xh/2w2RigkePMsg==} + classnames@2.5.1: resolution: {integrity: sha512-saHYOzhIQs6wy2sVxTM6bUDsQO4F50V9RQ22qBpEdCW+I+/Wmke2HOl6lS6dTpdxVhb88/I6+Hs+438c3lfUow==} @@ -3294,6 +3333,11 @@ packages: resolution: {integrity: sha512-lyuxPGr/Wfhrlem2CL/UcnUc1zcqKAImBDzukY7Y5F/yQiNdko6+fRLevlw1HgMySw7f611UIY408EtxRSoK3Q==} hasBin: true + lucide-react@0.484.0: + resolution: {integrity: sha512-oZy8coK9kZzvqhSgfbGkPtTgyjpBvs3ukLgDPv14dSOZtBtboryWF5o8i3qen7QbGg7JhiJBz5mK1p8YoMZTLQ==} + peerDependencies: + react: ^16.5.1 || ^17.0.0 || ^18.0.0 || ^19.0.0 + math-intrinsics@1.1.0: resolution: {integrity: sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g==} engines: {node: '>= 0.4'} @@ -4134,6 +4178,9 @@ packages: tabbable@6.2.0: resolution: {integrity: sha512-Cat63mxsVJlzYvN51JmVXIgNoUokrIaT2zLclCXjRd8boZ0004U4KCs/sToJ75C6sdlByWxpYnb5Boif1VSFew==} + tailwind-merge@3.0.2: + resolution: {integrity: sha512-l7z+OYZ7mu3DTqrL88RiKrKIqO3NcpEO8V/Od04bNpvk0kiIFndGEoqfuzvj4yuhRkHKjRkII2z+KS2HfPcSxw==} + tailwindcss@4.0.17: resolution: {integrity: sha512-OErSiGzRa6rLiOvaipsDZvLMSpsBZ4ysB4f0VKGXUrjw2jfkJRd6kjRKV2+ZmTCNvwtvgdDam5D7w6WXsdLJZw==} @@ -4222,6 +4269,9 @@ packages: tunnel-agent@0.6.0: resolution: {integrity: sha512-McnNiV1l8RYeY8tBgEpuodCC1mLUdbSN+CYBL7kJsJNInOP8UjDDEwdk6Mw60vdLLrr5NHKZhMAOSrR2NZuQ+w==} + tw-animate-css@1.2.4: + resolution: {integrity: sha512-yt+HkJB41NAvOffe4NweJU6fLqAlVx/mBX6XmHRp15kq0JxTtOKaIw8pVSWM1Z+n2nXtyi7cW6C9f0WG/F/QAQ==} + type-check@0.4.0: resolution: {integrity: sha512-XleUoc9uwGXqjWwXaUTZAmzMcFZ5858QA2vvx1Ur5xIcixXIP+8LnFDgRplU30us6teqdlskFfu+ae4K79Ooew==} engines: {node: '>= 0.8.0'} @@ -6163,6 +6213,19 @@ snapshots: - supports-color - typescript + '@radix-ui/react-compose-refs@1.1.1(@types/react@19.0.12)(react@19.0.0)': + dependencies: + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.12 + + '@radix-ui/react-slot@1.1.2(@types/react@19.0.12)(react@19.0.0)': + dependencies: + '@radix-ui/react-compose-refs': 1.1.1(@types/react@19.0.12)(react@19.0.0) + react: 19.0.0 + optionalDependencies: + '@types/react': 19.0.12 + '@rtsao/scc@1.1.0': {} '@rushstack/eslint-patch@1.11.0': {} @@ -7059,6 +7122,10 @@ snapshots: ci-info@4.2.0: {} + class-variance-authority@0.7.1: + dependencies: + clsx: 2.1.1 + classnames@2.5.1: {} cli-cursor@5.0.0: @@ -8265,6 +8332,10 @@ snapshots: dependencies: js-tokens: 4.0.0 + lucide-react@0.484.0(react@19.0.0): + dependencies: + react: 19.0.0 + math-intrinsics@1.1.0: {} md5@2.3.0: @@ -9374,6 +9445,8 @@ snapshots: tabbable@6.2.0: {} + tailwind-merge@3.0.2: {} + tailwindcss@4.0.17: {} tapable@2.2.1: {} @@ -9481,6 +9554,8 @@ snapshots: dependencies: safe-buffer: 5.2.1 + tw-animate-css@1.2.4: {} + type-check@0.4.0: dependencies: prelude-ls: 1.2.1 diff --git a/src/app/(frontend)/_components/DiplomarbeitSearch.tsx b/src/app/(frontend)/_components/DiplomarbeitSearch.tsx new file mode 100644 index 0000000..487ad32 --- /dev/null +++ b/src/app/(frontend)/_components/DiplomarbeitSearch.tsx @@ -0,0 +1,29 @@ +"use client"; +import { useState, useEffect } from 'react'; +import { Input } from '@/components/ui/input'; + +export default function DiplomarbeitSearch() { + const [search, setSearch] = useState(''); + const [results, setResults] = useState([]); + + useEffect(() => { + const timeoutId = setTimeout(async () => { + const response = await fetch(`/api/diplomarbeiten?search=${search}`); + const data = await response.json(); + setResults(data.titles || []); + }, 500); // 500ms cooldown period + + return () => clearTimeout(timeoutId); + }, [search]); + + return ( +
+ setSearch(e.target.value)} className="w-full" /> + {results.map((title, index) => ( +
+

{title}

+
+ ))} +
+ ); +} diff --git a/src/app/(frontend)/_components/Footer.tsx b/src/app/(frontend)/_components/Footer.tsx new file mode 100644 index 0000000..9da372a --- /dev/null +++ b/src/app/(frontend)/_components/Footer.tsx @@ -0,0 +1,15 @@ +import React from 'react' + + +export default function Footer() { + return ( +
+
+

HTL Dornbirn

+
+
+

© 2021 HTL Dornbirn

+
+
+ ) +} diff --git a/src/app/(frontend)/_components/Header.tsx b/src/app/(frontend)/_components/Header.tsx new file mode 100644 index 0000000..a53334b --- /dev/null +++ b/src/app/(frontend)/_components/Header.tsx @@ -0,0 +1,27 @@ +import Image from 'next/image' +import HTLDLogo from '@/app/(frontend)/htld.svg' +import { SignOutButton } from '@/app/(frontend)/_components/SignOutButton' +import { SignInButton } from '@/app/(frontend)/_components/SignInButton' +import React from 'react' +import { getPayloadSession } from 'payload-authjs' + + +export default async function Header(){ + const session = await getPayloadSession(); + return ( +
+
+ {"HTL +

Diplom- und Abschlussarbeiten

+
+
+ {session ? : } +
+ +
+ ) +} diff --git a/src/app/(frontend)/_components/SignInButton.tsx b/src/app/(frontend)/_components/SignInButton.tsx index cbb9eac..de4ba3c 100644 --- a/src/app/(frontend)/_components/SignInButton.tsx +++ b/src/app/(frontend)/_components/SignInButton.tsx @@ -1,4 +1,5 @@ import { signIn } from "@/auth"; +import { Button } from '@/components/ui/button' export function SignInButton() { return ( @@ -8,7 +9,7 @@ export function SignInButton() { await signIn("github"); }} > - + ); } diff --git a/src/app/(frontend)/_components/SignOutButton.tsx b/src/app/(frontend)/_components/SignOutButton.tsx index 801a403..9ba896b 100644 --- a/src/app/(frontend)/_components/SignOutButton.tsx +++ b/src/app/(frontend)/_components/SignOutButton.tsx @@ -1,6 +1,7 @@ "use client"; import type { CollectionSlug } from "payload"; +import { Button } from '@/components/ui/button' export function SignOutButton({ userCollectionSlug = "users", @@ -8,7 +9,7 @@ export function SignOutButton({ userCollectionSlug?: CollectionSlug; }) { return ( - + ); } diff --git a/src/app/(frontend)/globals.css b/src/app/(frontend)/globals.css index f1d8c73..6833c8e 100644 --- a/src/app/(frontend)/globals.css +++ b/src/app/(frontend)/globals.css @@ -1 +1,124 @@ @import "tailwindcss"; +@import "tw-animate-css"; + +@theme { + --color-htl-red: #e4534dff; +} + +@custom-variant dark (&:is(.dark *)); + +:root { + --radius: 0.625rem; + --background: oklch(1 0 0); + --foreground: oklch(0.145 0 0); + --card: oklch(1 0 0); + --card-foreground: oklch(0.145 0 0); + --popover: oklch(1 0 0); + --popover-foreground: oklch(0.145 0 0); + --primary: oklch(0.205 0 0); + --primary-foreground: oklch(0.985 0 0); + --secondary: oklch(0.97 0 0); + --secondary-foreground: oklch(0.205 0 0); + --muted: oklch(0.97 0 0); + --muted-foreground: oklch(0.556 0 0); + --accent: oklch(0.97 0 0); + --accent-foreground: oklch(0.205 0 0); + --destructive: oklch(0.577 0.245 27.325); + --border: oklch(0.922 0 0); + --input: oklch(0.922 0 0); + --ring: oklch(0.708 0 0); + --chart-1: oklch(0.646 0.222 41.116); + --chart-2: oklch(0.6 0.118 184.704); + --chart-3: oklch(0.398 0.07 227.392); + --chart-4: oklch(0.828 0.189 84.429); + --chart-5: oklch(0.769 0.188 70.08); + --sidebar: oklch(0.985 0 0); + --sidebar-foreground: oklch(0.145 0 0); + --sidebar-primary: oklch(0.205 0 0); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.97 0 0); + --sidebar-accent-foreground: oklch(0.205 0 0); + --sidebar-border: oklch(0.922 0 0); + --sidebar-ring: oklch(0.708 0 0); +} + +.dark { + --background: oklch(0.145 0 0); + --foreground: oklch(0.985 0 0); + --card: oklch(0.205 0 0); + --card-foreground: oklch(0.985 0 0); + --popover: oklch(0.205 0 0); + --popover-foreground: oklch(0.985 0 0); + --primary: oklch(0.922 0 0); + --primary-foreground: oklch(0.205 0 0); + --secondary: oklch(0.269 0 0); + --secondary-foreground: oklch(0.985 0 0); + --muted: oklch(0.269 0 0); + --muted-foreground: oklch(0.708 0 0); + --accent: oklch(0.269 0 0); + --accent-foreground: oklch(0.985 0 0); + --destructive: oklch(0.704 0.191 22.216); + --border: oklch(1 0 0 / 10%); + --input: oklch(1 0 0 / 15%); + --ring: oklch(0.556 0 0); + --chart-1: oklch(0.488 0.243 264.376); + --chart-2: oklch(0.696 0.17 162.48); + --chart-3: oklch(0.769 0.188 70.08); + --chart-4: oklch(0.627 0.265 303.9); + --chart-5: oklch(0.645 0.246 16.439); + --sidebar: oklch(0.205 0 0); + --sidebar-foreground: oklch(0.985 0 0); + --sidebar-primary: oklch(0.488 0.243 264.376); + --sidebar-primary-foreground: oklch(0.985 0 0); + --sidebar-accent: oklch(0.269 0 0); + --sidebar-accent-foreground: oklch(0.985 0 0); + --sidebar-border: oklch(1 0 0 / 10%); + --sidebar-ring: oklch(0.556 0 0); +} + +@theme inline { + --radius-sm: calc(var(--radius) - 4px); + --radius-md: calc(var(--radius) - 2px); + --radius-lg: var(--radius); + --radius-xl: calc(var(--radius) + 4px); + --color-background: var(--background); + --color-foreground: var(--foreground); + --color-card: var(--card); + --color-card-foreground: var(--card-foreground); + --color-popover: var(--popover); + --color-popover-foreground: var(--popover-foreground); + --color-primary: var(--primary); + --color-primary-foreground: var(--primary-foreground); + --color-secondary: var(--secondary); + --color-secondary-foreground: var(--secondary-foreground); + --color-muted: var(--muted); + --color-muted-foreground: var(--muted-foreground); + --color-accent: var(--accent); + --color-accent-foreground: var(--accent-foreground); + --color-destructive: var(--destructive); + --color-border: var(--border); + --color-input: var(--input); + --color-ring: var(--ring); + --color-chart-1: var(--chart-1); + --color-chart-2: var(--chart-2); + --color-chart-3: var(--chart-3); + --color-chart-4: var(--chart-4); + --color-chart-5: var(--chart-5); + --color-sidebar: var(--sidebar); + --color-sidebar-foreground: var(--sidebar-foreground); + --color-sidebar-primary: var(--sidebar-primary); + --color-sidebar-primary-foreground: var(--sidebar-primary-foreground); + --color-sidebar-accent: var(--sidebar-accent); + --color-sidebar-accent-foreground: var(--sidebar-accent-foreground); + --color-sidebar-border: var(--sidebar-border); + --color-sidebar-ring: var(--sidebar-ring); +} + +@layer base { + * { + @apply border-border outline-ring/50; + } + body { + @apply bg-background text-foreground; + } +} diff --git a/src/app/(frontend)/htld.svg b/src/app/(frontend)/htld.svg new file mode 100644 index 0000000..6b85f2a --- /dev/null +++ b/src/app/(frontend)/htld.svg @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/app/(frontend)/layout.tsx b/src/app/(frontend)/layout.tsx index e96343e..66bb9b5 100644 --- a/src/app/(frontend)/layout.tsx +++ b/src/app/(frontend)/layout.tsx @@ -1,19 +1,23 @@ -import React from 'react' -import './globals.css' +import React from "react"; +import "./globals.css"; +import Header from "@/app/(frontend)/_components/Header"; +import Footer from "@/app/(frontend)/_components/Footer"; export const metadata = { - description: 'A blank template using Payload in a Next.js app.', - title: 'Payload Blank Template', -} + description: "A blank template using Payload in a Next.js app.", + title: "Payload Blank Template", +}; export default async function RootLayout(props: { children: React.ReactNode }) { - const { children } = props + const { children } = props; return ( - - + + +
{children}
+