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 {alt}; +} 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