diff --git a/.idea/.idea.NotNull/.idea/dataSources.xml b/.idea/.idea.NotNull/.idea/dataSources.xml
index 2d01e44..5a194dd 100644
--- a/.idea/.idea.NotNull/.idea/dataSources.xml
+++ b/.idea/.idea.NotNull/.idea/dataSources.xml
@@ -43,5 +43,12 @@
jdbc:postgresql://localhost:55394/?password=db8yXrm8kX0%7E2fchM%2BJ%2BBc&user=postgres
$ProjectFileDir$
+
+ postgresql
+ true
+ org.postgresql.Driver
+ jdbc:postgresql://localhost:56892/?password=db8yXrm8kX0%7E2fchM%2BJ%2BBc&user=postgres
+ $ProjectFileDir$
+
\ No newline at end of file
diff --git a/webapp/package-lock.json b/webapp/package-lock.json
index 44cd396..827c5c9 100644
--- a/webapp/package-lock.json
+++ b/webapp/package-lock.json
@@ -14,6 +14,7 @@
"date-fns": "^4.1.0",
"framer-motion": "^12.26.2",
"next": "16.1.3",
+ "next-auth": "^5.0.0-beta.30",
"next-themes": "^0.4.6",
"react": "19.2.3",
"react-dom": "19.2.3",
@@ -45,6 +46,35 @@
"url": "https://github.com/sponsors/sindresorhus"
}
},
+ "node_modules/@auth/core": {
+ "version": "0.41.0",
+ "resolved": "https://registry.npmjs.org/@auth/core/-/core-0.41.0.tgz",
+ "integrity": "sha512-Wd7mHPQ/8zy6Qj7f4T46vg3aoor8fskJm6g2Zyj064oQ3+p0xNZXAV60ww0hY+MbTesfu29kK14Zk5d5JTazXQ==",
+ "license": "ISC",
+ "dependencies": {
+ "@panva/hkdf": "^1.2.1",
+ "jose": "^6.0.6",
+ "oauth4webapi": "^3.3.0",
+ "preact": "10.24.3",
+ "preact-render-to-string": "6.5.11"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "nodemailer": "^6.8.0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/@babel/code-frame": {
"version": "7.28.6",
"resolved": "https://registry.npmjs.org/@babel/code-frame/-/code-frame-7.28.6.tgz",
@@ -2847,6 +2877,15 @@
"node": ">=12.4.0"
}
},
+ "node_modules/@panva/hkdf": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/@panva/hkdf/-/hkdf-1.2.1.tgz",
+ "integrity": "sha512-6oclG6Y3PiDFcoyk8srjLfVKyMfVCKJ27JwNPViuXziFpmdz+MZnZN/aKY0JGXgYuO/VghU0jcOAZgWXZ1Dmrw==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/@react-aria/breadcrumbs": {
"version": "3.5.30",
"resolved": "https://registry.npmjs.org/@react-aria/breadcrumbs/-/breadcrumbs-3.5.30.tgz",
@@ -7563,6 +7602,15 @@
"jiti": "lib/jiti-cli.mjs"
}
},
+ "node_modules/jose": {
+ "version": "6.2.2",
+ "resolved": "https://registry.npmjs.org/jose/-/jose-6.2.2.tgz",
+ "integrity": "sha512-d7kPDd34KO/YnzaDOlikGpOurfF0ByC2sEV4cANCtdqLlTfBlw2p14O/5d/zv40gJPbIQxfES3nSx1/oYNyuZQ==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/js-tokens": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/js-tokens/-/js-tokens-4.0.0.tgz",
@@ -8180,6 +8228,33 @@
}
}
},
+ "node_modules/next-auth": {
+ "version": "5.0.0-beta.30",
+ "resolved": "https://registry.npmjs.org/next-auth/-/next-auth-5.0.0-beta.30.tgz",
+ "integrity": "sha512-+c51gquM3F6nMVmoAusRJ7RIoY0K4Ts9HCCwyy/BRoe4mp3msZpOzYMyb5LAYc1wSo74PMQkGDcaghIO7W6Xjg==",
+ "license": "ISC",
+ "dependencies": {
+ "@auth/core": "0.41.0"
+ },
+ "peerDependencies": {
+ "@simplewebauthn/browser": "^9.0.1",
+ "@simplewebauthn/server": "^9.0.2",
+ "next": "^14.0.0-0 || ^15.0.0 || ^16.0.0",
+ "nodemailer": "^7.0.7",
+ "react": "^18.2.0 || ^19.0.0"
+ },
+ "peerDependenciesMeta": {
+ "@simplewebauthn/browser": {
+ "optional": true
+ },
+ "@simplewebauthn/server": {
+ "optional": true
+ },
+ "nodemailer": {
+ "optional": true
+ }
+ }
+ },
"node_modules/next-themes": {
"version": "0.4.6",
"resolved": "https://registry.npmjs.org/next-themes/-/next-themes-0.4.6.tgz",
@@ -8225,6 +8300,15 @@
"dev": true,
"license": "MIT"
},
+ "node_modules/oauth4webapi": {
+ "version": "3.8.5",
+ "resolved": "https://registry.npmjs.org/oauth4webapi/-/oauth4webapi-3.8.5.tgz",
+ "integrity": "sha512-A8jmyUckVhRJj5lspguklcl90Ydqk61H3dcU0oLhH3Yv13KpAliKTt5hknpGGPZSSfOwGyraNEFmofDYH+1kSg==",
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/panva"
+ }
+ },
"node_modules/object-assign": {
"version": "4.1.1",
"resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz",
@@ -8528,6 +8612,25 @@
"node": ">=4"
}
},
+ "node_modules/preact": {
+ "version": "10.24.3",
+ "resolved": "https://registry.npmjs.org/preact/-/preact-10.24.3.tgz",
+ "integrity": "sha512-Z2dPnBnMUfyQfSQ+GBdsGa16hz35YmLmtTLhM169uW944hYL6xzTYkJjC07j+Wosz733pMWx0fgON3JNw1jJQA==",
+ "license": "MIT",
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/preact"
+ }
+ },
+ "node_modules/preact-render-to-string": {
+ "version": "6.5.11",
+ "resolved": "https://registry.npmjs.org/preact-render-to-string/-/preact-render-to-string-6.5.11.tgz",
+ "integrity": "sha512-ubnauqoGczeGISiOh6RjX0/cdaF8v/oDXIjO85XALCQjwQP+SB4RDXXtvZ6yTYSjG+PC1QRP2AhPgCEsM2EvUw==",
+ "license": "MIT",
+ "peerDependencies": {
+ "preact": ">=10"
+ }
+ },
"node_modules/prelude-ls": {
"version": "1.2.1",
"resolved": "https://registry.npmjs.org/prelude-ls/-/prelude-ls-1.2.1.tgz",
diff --git a/webapp/package.json b/webapp/package.json
index 9c67756..bb88822 100644
--- a/webapp/package.json
+++ b/webapp/package.json
@@ -15,6 +15,7 @@
"date-fns": "^4.1.0",
"framer-motion": "^12.26.2",
"next": "16.1.3",
+ "next-auth": "^5.0.0-beta.30",
"next-themes": "^0.4.6",
"react": "19.2.3",
"react-dom": "19.2.3",
diff --git a/webapp/src/app/api/auth/[...nextauth]/route.ts b/webapp/src/app/api/auth/[...nextauth]/route.ts
new file mode 100644
index 0000000..7038c61
--- /dev/null
+++ b/webapp/src/app/api/auth/[...nextauth]/route.ts
@@ -0,0 +1,2 @@
+import { handlers } from "@/auth"
+export const { GET, POST } = handlers;
\ No newline at end of file
diff --git a/webapp/src/app/questions/QuestionCard.tsx b/webapp/src/app/questions/QuestionCard.tsx
index 9abd16d..8677ab3 100644
--- a/webapp/src/app/questions/QuestionCard.tsx
+++ b/webapp/src/app/questions/QuestionCard.tsx
@@ -1,86 +1,117 @@
'use client'
-import {Question} from "@/lib/types";
+import { Question } from "@/lib/types";
import Link from "next/link";
-import {Chip} from "@heroui/chip";
-import {Avatar} from "@heroui/avatar";
+import { Chip } from "@heroui/chip";
+import { Avatar } from "@heroui/avatar";
import clsx from "clsx";
-import {CheckIcon} from "@heroicons/react/24/outline";
+import { CheckIcon } from "@heroicons/react/24/outline";
import { timeAgo } from "@/lib/util";
type Props = {
question: Question;
}
-export default function QuestionCard({question}: Props) {
+export default function QuestionCard({ question }: Props) {
return (
-
-
-
{question.votes}
-
{question.votes === 1 ? 'vote' : 'votes'}
+
+ {/* Stats column */}
+
+
+ {/* Votes */}
+
+
+ {question.votes}
+
+
+ {question.votes === 1 ? 'vote' : 'votes'}
+
-
0 && !question.hasAcceptedAnswer,
- 'bg-success-500 text-white shadow-md': question.hasAcceptedAnswer,
- 'bg-default-100': question.answerCount === 0
- })}
- >
-
+ {/* Answers */}
+
0 && !question.hasAcceptedAnswer,
+ 'bg-default-100 dark:bg-white/5 text-default-500': question.answerCount === 0,
+ }
+ )}>
+
{question.hasAcceptedAnswer && (
-
+
)}
- {question.answerCount}
+ {question.answerCount}
-
{question.answerCount === 1 ? 'answer' : 'answers'}
+
+ {question.answerCount === 1 ? 'answer' : 'answers'}
+
-
-
{question.viewCount}
-
{question.viewCount === 1 ? 'view' : 'views'}
+ {/* Views */}
+
+
+ {question.viewCount}
+
+
+ {question.viewCount === 1 ? 'view' : 'views'}
+
-
-
+
+ {/* Main content */}
+
{question.title}
-
- {/* Tags */}
-
+ {/* Footer: tags + author */}
+
+
{question.tagSlugs.map(tag => (
{tag}
))}
-
+
{question.askerDisplayName}
diff --git a/webapp/src/app/questions/QuestionsHeader.tsx b/webapp/src/app/questions/QuestionsHeader.tsx
index e8d34ce..edd8e8c 100644
--- a/webapp/src/app/questions/QuestionsHeader.tsx
+++ b/webapp/src/app/questions/QuestionsHeader.tsx
@@ -1,9 +1,9 @@
'use client';
-import {Button} from "@heroui/button";
+import { Button } from "@heroui/button";
import Link from "next/link";
-import {Tab, Tabs} from "@heroui/tabs";
-import {useTagStore} from "@/lib/UseTagStore";
+import { Tab, Tabs } from "@heroui/tabs";
+import { useTagStore } from "@/lib/UseTagStore";
type Props = {
tag?: string;
@@ -11,63 +11,80 @@ type Props = {
}
export default function QuestionsHeader({ tag, total }: Props) {
-
const selectedTag = useTagStore((state) => state.getTagBySlug(tag ?? ''));
-
-
+
const tabs = [
- {key: 'newest', label: 'Newest'},
- {key: 'active', label: 'Active'},
- {key: 'unanswered', label: 'Unanswered'},
+ { key: 'newest', label: 'Newest' },
+ { key: 'active', label: 'Active' },
+ { key: 'unanswered', label: 'Unanswered' },
];
return (
-
-
-
-
-
- {tag ? (
-
- Questions tagged [{tag}]
-
- ) : (
- 'All Questions'
- )}
-
-
- {selectedTag?.description}
+
+
+ {/* Top bar */}
+
+
+
+ {tag ? (
+ <>
+ Questions tagged{' '}
+
+ {tag}
+
+ >
+ ) : (
+ 'All Questions'
+ )}
+
+
+ {selectedTag?.description && (
+
+ {selectedTag.description}
-
-
+ )}
+
+
{total.toLocaleString()} {total === 1 ? 'question' : 'questions'}
{/* Filter tabs */}
-
+
{tabs.map(tab => (
-
+
))}
diff --git a/webapp/src/app/questions/[id]/AnswerContent.tsx b/webapp/src/app/questions/[id]/AnswerContent.tsx
index bf82d08..eed86a5 100644
--- a/webapp/src/app/questions/[id]/AnswerContent.tsx
+++ b/webapp/src/app/questions/[id]/AnswerContent.tsx
@@ -1,19 +1,33 @@
-import {Answer} from "@/lib/types";
+import { Answer } from "@/lib/types";
import VotingButtons from "@/app/questions/[id]/VotingButtons";
import AnswerFooter from "@/app/questions/[id]/AnswerFooter";
-type Props = {
- answer: Answer;
-}
-
-export default function AnswerContent({answer}: {answer: Answer}) {
+export default function AnswerContent({ answer }: { answer: Answer }) {
return (
-
+
-
+
+
diff --git a/webapp/src/app/questions/[id]/AnswerFooter.tsx b/webapp/src/app/questions/[id]/AnswerFooter.tsx
index 148006c..d63f809 100644
--- a/webapp/src/app/questions/[id]/AnswerFooter.tsx
+++ b/webapp/src/app/questions/[id]/AnswerFooter.tsx
@@ -1,26 +1,30 @@
-import {Answer} from "@/lib/types";
+import { Answer } from "@/lib/types";
import { timeAgo } from "@/lib/util";
-import {Avatar} from "@heroui/avatar";
+import { Avatar } from "@heroui/avatar";
import Link from "next/link";
-export default function AnswerFooter({answer}: {answer: Answer}) {
+export default function AnswerFooter({ answer }: { answer: Answer }) {
return (
-
-
-
-
answered {timeAgo(answer.createdAt)}
-
-
- {answer.userDisplayName}
-
-
+
+
+
+ answered {timeAgo(answer.createdAt)}
+
+
+
+ {answer.userDisplayName}
+
);
diff --git a/webapp/src/app/questions/[id]/AnswersHeader.tsx b/webapp/src/app/questions/[id]/AnswersHeader.tsx
index bf469cf..b76737b 100644
--- a/webapp/src/app/questions/[id]/AnswersHeader.tsx
+++ b/webapp/src/app/questions/[id]/AnswersHeader.tsx
@@ -1,25 +1,30 @@
'use client'
-import {Select, SelectItem} from "@heroui/select";
-type Props = {
- answerCount: number;
-}
+import { Select, SelectItem } from "@heroui/select";
-export default function AnswersHeader({ answerCount }: Props) {
+export default function AnswersHeader({ answerCount }: { answerCount: number }) {
return (
-
-
+
+
{answerCount} {answerCount === 1 ? 'Answer' : 'Answers'}
-
-
-
-
+
+
+
);
-}
-
+}
\ No newline at end of file
diff --git a/webapp/src/app/questions/[id]/QuestionContent.tsx b/webapp/src/app/questions/[id]/QuestionContent.tsx
index d57f049..1b9e81e 100644
--- a/webapp/src/app/questions/[id]/QuestionContent.tsx
+++ b/webapp/src/app/questions/[id]/QuestionContent.tsx
@@ -8,35 +8,71 @@ import { timeAgo } from "@/lib/util";
export default function QuestionContent({ question }: { question: Question }) {
return (
-
-
+
+
-
-
-
+ {/* Content box */}
+
-
-
-
-
- asked {timeAgo(question.createdAt)}
-
+
+ {/* Author card */}
+
+
+
+ asked
+
+ {timeAgo(question.createdAt)}
+
+
+
+
{question.askerDisplayName}
diff --git a/webapp/src/app/questions/[id]/QuestionDetailedHeader.tsx b/webapp/src/app/questions/[id]/QuestionDetailedHeader.tsx
index 77abb81..df4077b 100644
--- a/webapp/src/app/questions/[id]/QuestionDetailedHeader.tsx
+++ b/webapp/src/app/questions/[id]/QuestionDetailedHeader.tsx
@@ -1,46 +1,50 @@
-import {Question} from "@/lib/types";
-import {Button} from "@heroui/button";
-import {LinkComponent} from "@/components/nav/LinkComponent";
-import {fuzzyTimeAgo} from "@/lib/util";
+import { Question } from "@/lib/types";
+import { Button } from "@heroui/button";
+import { LinkComponent } from "@/components/nav/LinkComponent";
+import { fuzzyTimeAgo } from "@/lib/util";
-type Props = {
- question: Question;
-}
-
-export default function QuestionDetailedHeader({question}: Props) {
+export default function QuestionDetailedHeader({ question }: { question: Question }) {
return (
-
-
-
+
+
+
{question.title}
-
-
+
+
Asked
- {fuzzyTimeAgo(question.createdAt)}
+
+ {fuzzyTimeAgo(question.createdAt)}
+
-
{question.updatedAt && (
-
+
Modified
- {fuzzyTimeAgo(question.updatedAt)}
+
+ {fuzzyTimeAgo(question.updatedAt)}
+
)}
-
-
+
Viewed
- {question.viewCount + 1} times
+
+ {question.viewCount + 1} times
+
diff --git a/webapp/src/app/questions/[id]/QuestionFooter.tsx b/webapp/src/app/questions/[id]/QuestionFooter.tsx
index 26be2cd..5f8fcf5 100644
--- a/webapp/src/app/questions/[id]/QuestionFooter.tsx
+++ b/webapp/src/app/questions/[id]/QuestionFooter.tsx
@@ -1,28 +1,27 @@
-import {Question} from "@/lib/types";
-import {Chip} from "@heroui/chip";
-import {Avatar} from "@heroui/avatar";
+import { Question } from "@/lib/types";
+import { Chip } from "@heroui/chip";
+import { Avatar } from "@heroui/avatar";
import { LinkComponent } from "@/components/nav/LinkComponent";
-
-type Props = {
- question: Question;
-}
-export default function QuestionFooter({question}: Props) {
+export default function QuestionFooter({ question }: { question: Question }) {
return (
-
-
-
- {question.tagSlugs.map((tag: string) => (
-
- {tag}
-
- ))}
-
+
+ {/* Tags */}
+
+ {question.tagSlugs.map((tag: string) => (
+
+ {tag}
+
+ ))}
);
diff --git a/webapp/src/app/questions/[id]/VotingButtons.tsx b/webapp/src/app/questions/[id]/VotingButtons.tsx
index 2ef0f38..00b2152 100644
--- a/webapp/src/app/questions/[id]/VotingButtons.tsx
+++ b/webapp/src/app/questions/[id]/VotingButtons.tsx
@@ -1,43 +1,49 @@
-import {Button} from "@heroui/button";
-import {ArrowDownCircleIcon, ArrowUpCircleIcon} from "@heroicons/react/24/outline";
-import {CheckBadgeIcon} from "@heroicons/react/24/solid";
+import { Button } from "@heroui/button";
+import { ArrowDownCircleIcon, ArrowUpCircleIcon } from "@heroicons/react/24/outline";
+import { CheckBadgeIcon } from "@heroicons/react/24/solid";
type Props = {
accepted?: boolean;
}
-export default function VotingButtons({accepted}: Props){
+export default function VotingButtons({ accepted }: Props) {
return (
-
+
-
-
0
+
+
+ 0
+
+
{accepted && (
-
diff --git a/webapp/src/auth.ts b/webapp/src/auth.ts
new file mode 100644
index 0000000..0d6162c
--- /dev/null
+++ b/webapp/src/auth.ts
@@ -0,0 +1,12 @@
+import NextAuth from "next-auth";
+import KeycloakProvider from "next-auth/providers/keycloak";
+
+export const { handlers, signIn, signOut, auth } = NextAuth({
+ providers: [
+ KeycloakProvider({
+ clientId: process.env.KEYCLOAK_ID,
+ clientSecret: process.env.KEYCLOAK_SECRET,
+ issuer: process.env.KEYCLOAK_ISSUER,
+ })
+ ],
+})
diff --git a/webapp/src/components/nav/LoginButton.tsx b/webapp/src/components/nav/LoginButton.tsx
new file mode 100644
index 0000000..cc21e16
--- /dev/null
+++ b/webapp/src/components/nav/LoginButton.tsx
@@ -0,0 +1,22 @@
+'use client';
+
+import { Button } from "@heroui/react";
+import { signIn } from "next-auth/react";
+
+export default function LoginButton() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/webapp/src/components/nav/SearchInput.tsx b/webapp/src/components/nav/SearchInput.tsx
index 916ca22..b77b3dd 100644
--- a/webapp/src/components/nav/SearchInput.tsx
+++ b/webapp/src/components/nav/SearchInput.tsx
@@ -19,10 +19,8 @@ export default function SearchInput() {
if (timeoutRef.current) clearTimeout(timeoutRef.current);
if (!query) {
- timeoutRef.current = setTimeout(() => {
- setResults(null);
- setShowDropdown(false);
- }, 0);
+ setResults(null);
+ setShowDropdown(false);
return;
}
@@ -60,35 +58,65 @@ export default function SearchInput() {
- :
+ ?
+ :
}
type="search"
placeholder="Search questions..."
value={query}
onChange={(e) => setQuery(e.target.value)}
onFocus={() => results && setShowDropdown(true)}
+ classNames={{
+ inputWrapper: [
+ 'border border-default-200 dark:border-white/10',
+ 'bg-gray-50 dark:bg-white/5',
+ 'hover:border-purple-300 dark:hover:border-purple-700',
+ 'group-data-[focus=true]:border-purple-500 dark:group-data-[focus=true]:border-purple-400',
+ 'shadow-none',
+ 'transition-colors duration-150',
+ ].join(' '),
+ }}
/>
{showDropdown && results && (
-
+
{results.length === 0 ? (
-
- No results for{' '}
-
- “{query}”
-
+
+
+
+ No results for{' '}
+
+ “{query}”
+
+
) : (
<>
-
- {results.length} result{results.length !== 1 ? 's' : ''} found
+ {/* Header do dropdown */}
+
+
+ {results.length} result{results.length !== 1 ? 's' : ''} found
+
+
+ ↵ to select
+
+
{(question) => (
0
- ? 'border-success text-success bg-success/10'
- : 'border-default-300 text-default-400'
- }`}
- >
- {question.answerCount}
- answers
+ 0
+ ? 'border-emerald-300 dark:border-emerald-700 text-emerald-600 dark:text-emerald-400 bg-emerald-50 dark:bg-emerald-950/40'
+ : 'border-default-200 dark:border-white/10 text-default-400 bg-default-50 dark:bg-white/5'
+ }
+ `}>
+
+ {question.answerCount}
+
+
+ ans
+
}
>
-
{question.title}
+
+ {question.title}
+
{question.content}
diff --git a/webapp/src/components/nav/SideMenu.tsx b/webapp/src/components/nav/SideMenu.tsx
index ee2cf76..a676fc7 100644
--- a/webapp/src/components/nav/SideMenu.tsx
+++ b/webapp/src/components/nav/SideMenu.tsx
@@ -1,40 +1,54 @@
'use client'
-import {HomeIcon, QuestionMarkCircleIcon, TagIcon, UserIcon} from "@heroicons/react/24/solid";
-import {Listbox, ListboxItem} from "@heroui/listbox";
+import { HomeIcon, QuestionMarkCircleIcon, TagIcon, UserIcon } from "@heroicons/react/24/solid";
import { usePathname } from "next/navigation";
+import Link from "next/link";
+
+const navLinks = [
+ { key: 'home', icon: HomeIcon, text: 'Home', href: '/' },
+ { key: 'questions', icon: QuestionMarkCircleIcon, text: 'Questions', href: '/questions' },
+ { key: 'tags', icon: TagIcon, text: 'Tags', href: '/tags' },
+ { key: 'session', icon: UserIcon, text: 'User Session', href: '/session' },
+];
export default function SideMenu() {
-
- const pathname = usePathname();
-
- const navLinks = [
- {key: 'home', icon: HomeIcon, text: 'Home', href: '/'},
- {key: 'questions', icon: QuestionMarkCircleIcon, text: 'Questions', href: '/questions'},
- {key: 'tags', icon: TagIcon, text: 'Tags', href: '/tags'},
- {key: 'session', icon: UserIcon, text: 'User Session', href: '/session'},
-
- ]
-
+ const pathname = usePathname();
+
return (
-
- {({key, href, icon: Icon, text}) => (
- }
- classNames={{
- base: pathname === href ? 'text-secondary' : '',
- title: 'text-lg'
- }}
- >
+
+ {text}
+
+ );
+ })}
+
);
-}
-
+}
\ No newline at end of file
diff --git a/webapp/src/components/nav/SignUpButton.tsx b/webapp/src/components/nav/SignUpButton.tsx
new file mode 100644
index 0000000..afe158b
--- /dev/null
+++ b/webapp/src/components/nav/SignUpButton.tsx
@@ -0,0 +1,22 @@
+// src/components/nav/SignUpButton.tsx
+'use client';
+
+import { Button } from "@heroui/react";
+
+export default function SignUpButton() {
+ return (
+
+ );
+}
\ No newline at end of file
diff --git a/webapp/src/components/nav/TopNav.tsx b/webapp/src/components/nav/TopNav.tsx
index 79747ff..cd34129 100644
--- a/webapp/src/components/nav/TopNav.tsx
+++ b/webapp/src/components/nav/TopNav.tsx
@@ -1,73 +1,111 @@
-"use client";
-
-import Link from "next/link";
-import { CommandLineIcon, MagnifyingGlassIcon, BellIcon, UserCircleIcon } from "@heroicons/react/24/outline";
-import { Button, Input, Badge } from "@heroui/react";
+import Link from "next/link";
+import { CommandLineIcon } from "@heroicons/react/24/outline";
import ThemeToggle from "@/components/nav/ThemeToggle";
import SearchInput from "@/components/nav/SearchInput";
+import LoginButton from "./LoginButton";
+import SignUpButton from "@/components/nav/SignUpButton";
+import { getCurrentUser } from "@/lib/actions/auth-actions";
+
+const navLinks = [
+ { href: '/questions', label: 'Questions' },
+ { href: '/tags', label: 'Tags' },
+ { href: '/users', label: 'Users' },
+];
+
+export default async function TopNav() {
+ const user = await getCurrentUser();
-export default function TopNav() {
return (
-