diff --git a/app/contact/page.tsx b/app/contact/page.tsx
new file mode 100644
index 0000000..5c748ff
--- /dev/null
+++ b/app/contact/page.tsx
@@ -0,0 +1,208 @@
+import { PageContainer } from "@/components/layout/PageContainer";
+import { QRCodeDisplay } from "@/components/contact/QRCodeDisplay";
+import { JsonLd } from "@/components/seo/JsonLd";
+import { Heading } from "@/components/ui/Heading";
+
+import { SITE_URL } from "@/lib/constants";
+import {
+ createBreadcrumbList,
+ createSchemaGraph,
+} from "@/lib/seo";
+import { paths, urls } from "@/lib/utils/urls";
+
+export async function generateMetadata() {
+ return {
+ title: "Contact | Builder Vancouver",
+ description:
+ "Connect with Builder Vancouver. Follow us on X, Nostr, and Luma. Scan our QR code to share our website.",
+ keywords: ["contact", "builder vancouver", "bitcoin", "connect"],
+ };
+}
+
+/**
+ * Contact page with real-time QR code and social links
+ * Optimized for mobile sharing and showcasing work
+ */
+export default function ContactPage() {
+ // Use SITE_URL as fallback, QRCodeDisplay will update with actual URL on client
+ const fallbackUrl = `${SITE_URL}${paths.contact()}`;
+
+ const breadcrumbSchema = createBreadcrumbList([
+ { name: "Home", url: urls.home() },
+ { name: "Contact" },
+ ]);
+
+ const structuredData = createSchemaGraph(breadcrumbSchema);
+
+ // Social links - update these with actual URLs
+ const socialLinks = [
+ {
+ name: "X (Twitter)",
+ href: "https://x.com/builder_van", // Update with actual URL
+ icon: (
+
+ ),
+ color: "hover:text-neutral-100",
+ },
+ {
+ name: "Nostr",
+ href: "https://nostr.com/builder_van", // Update with actual Nostr profile URL or npub
+ icon: (
+
+ ),
+ color: "hover:text-orange-400",
+ },
+ {
+ name: "Luma",
+ href: "https://lu.ma/builder-vancouver", // Update with actual Luma URL
+ icon: (
+
+ ),
+ color: "hover:text-blue-400",
+ },
+ ];
+
+ return (
+ <>
+
+ Join the Builder Vancouver community
+
+ Scan the QR code or follow us on social media
+
+ Connect on {social.name}
+
+ Email us at{" "}
+
+ bitcoinbuildervan@gmail.com
+
+
+ We typically respond within 48 hours
+
+ Learn about Bitcoin, Lightning Network, and Layer 2 solutions
+ through our educational sessions and workshops.
+
+ Join our regular meetups, presentations, and networking events
+ in Vancouver.
+
+ Contribute to Bitcoin-related projects and collaborate with
+ builders in the ecosystem.
+
+ Access presentations, slides, recaps, and educational materials
+ from our community.
+
+ Follow Us
+
+
+ {social.name}
+
+
+ Get In Touch
+
+
+ What We Do
+
+
+ Bitcoin Education
+
+
+ Community Events
+
+
+ Open Source
+
+
+ Resources
+
+
+ Current URL: +
++ {currentUrl} +
+Builder Vancouver
Bitcoin Meetups & Education
diff --git a/components/layout/Navbar.tsx b/components/layout/Navbar.tsx index 146cf3e..e727b18 100644 --- a/components/layout/Navbar.tsx +++ b/components/layout/Navbar.tsx @@ -60,6 +60,7 @@ export function Navbar() { const navItems: NavItem[] = [ { href: "/", label: "Home" }, + { href: "/contact", label: "Contact" }, { label: "About", children: [ @@ -116,6 +117,7 @@ export function Navbar() { { href: "/sponsors", label: "Sponsors" }, { href: "/members", label: "Members" }, { href: "/get-involved", label: "Get Involved" }, + { href: "/contact", label: "Contact" }, ], }, ]; diff --git a/lib/utils/urls.ts b/lib/utils/urls.ts index 2475273..e1ed557 100644 --- a/lib/utils/urls.ts +++ b/lib/utils/urls.ts @@ -94,6 +94,7 @@ export const urls = { }, faq: () => buildUrl("/faq"), + contact: () => buildUrl("/contact"), page: (slug: string) => buildUrl(`/${slug}`), } as const; @@ -169,6 +170,7 @@ export const paths = { }, faq: () => "/faq", + contact: () => "/contact", page: (slug: string) => `/${slug}`, } as const; diff --git a/package-lock.json b/package-lock.json index f620fef..2b4af1c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -10,6 +10,7 @@ "dependencies": { "leaflet": "^1.9.4", "next": "16.0.3", + "qrcode.react": "^4.2.0", "react": "19.2.0", "react-dom": "19.2.0", "react-leaflet": "^5.0.0", @@ -6831,6 +6832,15 @@ "node": ">=6" } }, + "node_modules/qrcode.react": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/qrcode.react/-/qrcode.react-4.2.0.tgz", + "integrity": "sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==", + "license": "ISC", + "peerDependencies": { + "react": "^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0" + } + }, "node_modules/queue-microtask": { "version": "1.2.3", "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", diff --git a/package.json b/package.json index 333eb0f..c765023 100644 --- a/package.json +++ b/package.json @@ -19,6 +19,7 @@ "dependencies": { "leaflet": "^1.9.4", "next": "16.0.3", + "qrcode.react": "^4.2.0", "react": "19.2.0", "react-dom": "19.2.0", "react-leaflet": "^5.0.0", diff --git a/pnpm-lock.yaml b/pnpm-lock.yaml index 9318211..3d2452e 100644 --- a/pnpm-lock.yaml +++ b/pnpm-lock.yaml @@ -14,6 +14,9 @@ importers: next: specifier: 16.0.3 version: 16.0.3(@babel/core@7.28.5)(react-dom@19.2.0(react@19.2.0))(react@19.2.0) + qrcode.react: + specifier: ^4.2.0 + version: 4.2.0(react@19.2.0) react: specifier: 19.2.0 version: 19.2.0 @@ -2017,6 +2020,11 @@ packages: resolution: {integrity: sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg==} engines: {node: '>=6'} + qrcode.react@4.2.0: + resolution: {integrity: sha512-QpgqWi8rD9DsS9EP3z7BT+5lY5SFhsqGjpgW5DY/i3mK4M9DTBNz3ErMi8BWYEfI3L0d8GIbGmcdFAS1uIRGjA==} + peerDependencies: + react: ^16.8.0 || ^17.0.0 || ^18.0.0 || ^19.0.0 + queue-microtask@1.2.3: resolution: {integrity: sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==} @@ -4375,6 +4383,10 @@ snapshots: punycode@2.3.1: {} + qrcode.react@4.2.0(react@19.2.0): + dependencies: + react: 19.2.0 + queue-microtask@1.2.3: {} react-dom@19.2.0(react@19.2.0):