From d1bed0edc9567c24774c731761ef38d2e2acb917 Mon Sep 17 00:00:00 2001 From: Thanan Traiongthawon <95660+nullcoder@users.noreply.github.com> Date: Sat, 7 Jun 2025 09:33:29 -0700 Subject: [PATCH 1/2] feat: implement Footer component (#70) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Add Footer component with branding and navigation links - Include Ghost icon and copyright notice with dynamic year - Implement responsive layout (horizontal desktop, stacked mobile) - Add navigation links for GitHub, Privacy, and Terms - Support optional build/version info display - Create FooterWithBuildInfo variant that reads from env vars - Add comprehensive tests and demo page - Ensure proper semantic HTML and accessibility 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude --- app/demo/footer/page.tsx | 158 +++++++++++++++++++++++++++++++++++++ components/footer.test.tsx | 130 ++++++++++++++++++++++++++++++ components/footer.tsx | 92 +++++++++++++++++++++ 3 files changed, 380 insertions(+) create mode 100644 app/demo/footer/page.tsx create mode 100644 components/footer.test.tsx create mode 100644 components/footer.tsx diff --git a/app/demo/footer/page.tsx b/app/demo/footer/page.tsx new file mode 100644 index 0000000..e18c8b2 --- /dev/null +++ b/app/demo/footer/page.tsx @@ -0,0 +1,158 @@ +"use client"; + +import * as React from "react"; +import { Footer, FooterWithBuildInfo } from "@/components/footer"; +import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; +import { Tabs, TabsContent, TabsList, TabsTrigger } from "@/components/ui/tabs"; + +export default function FooterDemo() { + return ( +
+
+

Footer Component Demo

+ + + + Basic Footer + With Build Info + Custom Styling + + + + + + Basic Footer + + +

+ The default footer with branding and navigation links. +

+
+
+
+
+
+
+ + + + + Footer with Build Information + + +

+ Footer displaying build ID for version tracking. +

+
+
+
+
+
+ +
+
+
+
+
+ + + + + Custom Styled Footer + + +

+ Footer with custom background and styling. +

+
+
+
+
+
+
+
+
+
+
+
+
+ + + + Responsive Behavior + + +

+ The footer adapts to different screen sizes. Try resizing your + browser window to see the responsive layout in action. +

+
+

+ • Desktop (≥768px): Horizontal layout with + left-aligned branding and right-aligned navigation +

+

+ • Mobile (<768px): Stacked layout with + centered content +

+
+
+
+ + + + Usage Example + + +
+              {`// Basic footer
+
+ +// Footer with build ID +
+ +// Footer with environment-based build ID + + +// Footer with custom styling +
`} +
+
+
+ + + + Features + + +

+ ✓ Responsive layout (horizontal on desktop, stacked on mobile) +

+

✓ Branding with Ghost icon and company name

+

✓ Copyright notice with current year

+

✓ Navigation links (GitHub, Privacy, Terms)

+

✓ Optional build/version display

+

✓ Proper semantic HTML structure

+

✓ Accessible navigation with ARIA labels

+

✓ Theme-aware styling

+

✓ External links open in new tab with security attributes

+
+
+
+ + {/* Example of footer at page bottom */} +
+
+
+
+ ); +} diff --git a/components/footer.test.tsx b/components/footer.test.tsx new file mode 100644 index 0000000..fdc3f70 --- /dev/null +++ b/components/footer.test.tsx @@ -0,0 +1,130 @@ +import { render, screen } from "@testing-library/react"; +import { describe, expect, it, vi, beforeEach, afterEach } from "vitest"; +import { Footer, FooterWithBuildInfo } from "./footer"; + +// Mock next/link +vi.mock("next/link", () => ({ + default: ({ + children, + ...props + }: React.PropsWithChildren< + React.AnchorHTMLAttributes + >) => {children}, +})); + +describe("Footer", () => { + it("renders branding elements", () => { + render(