diff --git a/app/components/Avatar.js b/app/components/Avatar.js
new file mode 100644
index 0000000..7ceeda4
--- /dev/null
+++ b/app/components/Avatar.js
@@ -0,0 +1,17 @@
+export default function Avatar({
+ src,
+ alt,
+ size = "small",
+ className = "",
+ ...props
+}) {
+ // Size styles - avatars scale to fit inside the 60px container
+ const sizeStyles = {
+ small: "w-4 h-4", // 16px x 16px to fit in 60px container
+ // Add more sizes as needed: medium, large, xlarge
+ };
+
+ const baseStyles = `rounded-[var(--radius-measures-radius-full)] object-cover ${sizeStyles[size]} ${className}`;
+
+ return
;
+}
diff --git a/app/components/AvatarContainer.js b/app/components/AvatarContainer.js
new file mode 100644
index 0000000..608b4d2
--- /dev/null
+++ b/app/components/AvatarContainer.js
@@ -0,0 +1,20 @@
+export default function AvatarContainer({
+ children,
+ size = "small",
+ className = "",
+ ...props
+}) {
+ // Size styles - container sizes to fit content, not fixed dimensions
+ const sizeStyles = {
+ small: "flex -space-x-2", // Just flex with -8px spacing, no fixed width/height
+ // Add more sizes as needed: medium, large, xlarge
+ };
+
+ const baseStyles = `items-center ${sizeStyles[size]} ${className}`;
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/components/Button.js b/app/components/Button.js
new file mode 100644
index 0000000..1294952
--- /dev/null
+++ b/app/components/Button.js
@@ -0,0 +1,86 @@
+export default function Button({
+ children,
+ variant = "default",
+ size = "xsmall",
+ className = "",
+ disabled = false,
+ type = "button",
+ onClick,
+ href,
+ target,
+ rel,
+ ariaLabel,
+ ...props
+}) {
+ // Size styles
+ const sizeStyles = {
+ xsmall:
+ "px-[var(--spacing-scale-006)] py-[var(--spacing-scale-004)] gap-[var(--spacing-scale-001)]",
+ small:
+ "px-[var(--spacing-measures-spacing-008)] py-[var(--spacing-measures-spacing-008)] gap-[var(--spacing-scale-004)]",
+ // Add more sizes as needed: medium, large, xlarge
+ };
+
+ // Font styles based on size
+ const fontStyles = {
+ xsmall:
+ "font-['Inter'] text-[10px] leading-[12px] font-medium tracking-[0%]",
+ small:
+ "font-['Inter'] text-[10px] leading-[12.5px] font-medium tracking-[0%]",
+ };
+
+ // Variant styles
+ const variantStyles = {
+ default:
+ "bg-[var(--color-surface-inverse-primary)] text-[var(--color-content-inverse-primary)] border-2 border-transparent hover:bg-[var(--color-surface-inverse-primary)] hover:text-[var(--color-content-inverse-brand-primary)] hover:border-[var(--border-color-default-brandprimary)] active:bg-[var(--color-surface-inverse-brand-primary)] active:text-[var(--color-content-inverse-primary)] active:border-[var(--border-color-default-brandprimary)] focus:bg-[var(--color-surface-inverse-primary)] focus:text-[var(--color-content-inverse-primary)] focus:shadow-[0_0_10px_#FFFDD2] focus:outline-none disabled:bg-[var(--color-surface-default-secondary)] disabled:text-[var(--color-content-inverse-tertiary)] disabled:cursor-not-allowed disabled:opacity-50",
+ secondary:
+ "bg-transparent text-[var(--color-content-default-primary)] border-2 border-[var(--color-content-default-primary)] hover:bg-[var(--color-surface-default-tertiary)] hover:text-[var(--color-content-default-primary)] active:bg-[var(--color-surface-default-secondary)] active:text-[var(--color-content-default-primary)] focus:bg-transparent focus:text-[var(--color-content-default-primary)] focus:shadow-[0_0_10px_#FFFDD2] focus:outline-none disabled:bg-[var(--color-surface-default-tertiary)] disabled:text-[var(--color-content-default-tertiary)] disabled:border-[var(--color-content-default-tertiary)] disabled:cursor-not-allowed disabled:opacity-50",
+ };
+
+ const baseStyles = `inline-flex items-center justify-start ${sizeStyles[size]} rounded-[var(--radius-measures-radius-full)] ${fontStyles[size]} transition-all duration-200 cursor-pointer`;
+
+ // Determine which variant to use
+ let finalVariant = variant;
+ if (disabled) {
+ finalVariant = "default"; // The disabled state is handled by disabled: utilities
+ }
+
+ const combinedStyles = `${baseStyles} ${variantStyles[finalVariant]} ${className}`;
+
+ // Accessibility attributes
+ const accessibilityProps = {
+ ...(ariaLabel && { "aria-label": ariaLabel }),
+ ...(disabled && { "aria-disabled": true }),
+ ...(onClick && { role: "button", tabIndex: 0 }),
+ };
+
+ // If href is provided, render as anchor tag
+ if (href && !disabled) {
+ return (
+
+ {children}
+
+ );
+ }
+
+ // Render as button
+ return (
+
+ );
+}
diff --git a/app/components/Header.js b/app/components/Header.js
new file mode 100644
index 0000000..43962c9
--- /dev/null
+++ b/app/components/Header.js
@@ -0,0 +1,63 @@
+import Logo from "./Logo";
+import NavigationItem from "./NavigationItem";
+import Button from "./Button";
+import AvatarContainer from "./AvatarContainer";
+import Avatar from "./Avatar";
+
+export default function Header() {
+ return (
+
+
+ {/* Logo */}
+
+
+ {/* Navigation */}
+
+
+
+
+
+
+
+ );
+}
diff --git a/app/components/Logo.js b/app/components/Logo.js
index e26070f..585fa0a 100644
--- a/app/components/Logo.js
+++ b/app/components/Logo.js
@@ -1,4 +1,4 @@
-export default function Logo({ size = "default" }) {
+export default function Logo({ size = "default", showText = true }) {
// Size configurations
const sizes = {
default: {
@@ -8,6 +8,20 @@ export default function Logo({ size = "default" }) {
lineHeight: "leading-[27.05px]",
iconSize: "w-[27.05px] h-[27.05px]",
},
+ header: {
+ containerHeight: "h-[14.24px]",
+ gap: "gap-[2.11px]",
+ textSize: "text-[18px]",
+ lineHeight: "leading-[22px]",
+ iconSize: "w-[22px] h-[22px]",
+ },
+ headerLg: {
+ containerHeight: "h-[36px]",
+ gap: "gap-[7px]",
+ textSize: "text-[20px]",
+ lineHeight: "leading-[24px]",
+ iconSize: "w-[24px] h-[24px]",
+ },
footer: {
containerHeight: "h-[calc(40px*1.37)]",
gap: "gap-[calc(8px*1.37)]",
@@ -25,7 +39,11 @@ export default function Logo({ size = "default" }) {
};
const config =
- size === "footer"
+ size === "header"
+ ? sizes.header
+ : size === "headerLg"
+ ? sizes.headerLg
+ : size === "footer"
? sizes.footer
: size === "footerLg"
? sizes.footerLg
@@ -33,14 +51,18 @@ export default function Logo({ size = "default" }) {
return (
- {/* Logo Text */}
-
- CommunityRule
-
+ {/* Logo Text - only show if showText is true */}
+ {showText && (
+
+ CommunityRule
+
+ )}
{/* Vector Icon */}
![]()
+ {children}
+
+ );
+ }
+
+ return (
+
+ {children}
+
+ );
+}
diff --git a/app/globals.css b/app/globals.css
index f1d8c73..d13c9fc 100644
--- a/app/globals.css
+++ b/app/globals.css
@@ -1 +1,4 @@
-@import "tailwindcss";
+@import "./tailwind.css";
+@tailwind base;
+@tailwind components;
+@tailwind utilities;
diff --git a/app/layout.js b/app/layout.js
index 668759b..20c7983 100644
--- a/app/layout.js
+++ b/app/layout.js
@@ -1,11 +1,11 @@
import { Inter, Bricolage_Grotesque } from "next/font/google";
import "./globals.css";
-import "./tailwind.css";
+import Header from "./components/Header";
import Footer from "./components/Footer";
const inter = Inter({
subsets: ["latin"],
- weight: ["400"],
+ weight: ["400", "500"],
variable: "--font-inter",
});
@@ -20,6 +20,7 @@ export default function RootLayout({ children }) {
+
{children}
diff --git a/package-lock.json b/package-lock.json
index 46d0cfe..7205d1a 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -18,6 +18,7 @@
"@tailwindcss/postcss": "^4.1.11",
"eslint": "^9",
"eslint-config-next": "15.2.4",
+ "postcss": "^8.5.6",
"tailwindcss": "^4.0.0"
}
},
diff --git a/package.json b/package.json
index 3669805..ac880e0 100644
--- a/package.json
+++ b/package.json
@@ -19,6 +19,7 @@
"@tailwindcss/postcss": "^4.1.11",
"eslint": "^9",
"eslint-config-next": "15.2.4",
+ "postcss": "^8.5.6",
"tailwindcss": "^4.0.0"
}
}
diff --git a/postcss.config.mjs b/postcss.config.mjs
index c7bcb4b..2df6729 100644
--- a/postcss.config.mjs
+++ b/postcss.config.mjs
@@ -1,5 +1,6 @@
-const config = {
- plugins: ["@tailwindcss/postcss"],
+/** @type {import('postcss-load-config').Config} */
+export default {
+ plugins: {
+ "@tailwindcss/postcss": {},
+ },
};
-
-export default config;
diff --git a/public/assets/Avatar_1.png b/public/assets/Avatar_1.png
new file mode 100644
index 0000000..30ab710
Binary files /dev/null and b/public/assets/Avatar_1.png differ
diff --git a/public/assets/Avatar_2.png b/public/assets/Avatar_2.png
new file mode 100644
index 0000000..2127a01
Binary files /dev/null and b/public/assets/Avatar_2.png differ
diff --git a/public/assets/Avatar_3.png b/public/assets/Avatar_3.png
new file mode 100644
index 0000000..bcb56a6
Binary files /dev/null and b/public/assets/Avatar_3.png differ