Skip to content

Landing Page Enhancement: SEO Architecture, Performance Optimization, Dark Mode, and Token Utility Section #128

Description

@5xbb

Summary

A comprehensive enhancement proposal for the Gibwork landing page covering four strategic areas currently unaddressed in the existing issue queue: (1) SEO architecture and rich results, (2) frontend performance optimization, (3) dark mode toggle and theme persistence, and (4) restoration of the $WORK token utility section. Together these changes improve organic discoverability, user experience, brand credibility, and conversion rates.


1. SEO Architecture and Structured Data (JSON-LD)

Problem: The landing page has minimal SEO metadata (only title and description in generateMetadata). There is no JSON-LD structured data, no WebSite/Organization schema, and no social preview customization beyond a single OG image. This limits organic traffic potential.

1a. Add JSON-LD Structured Data in layout.tsx

Add the following to the generateMetadata return in app/layout.tsx:

other: {
  "application/ld+json": JSON.stringify({
    "@context": "https://schema.org",
    "@type": "WebSite",
    name: "Gibwork",
    url: "https://gib.work",
    description: "Gibwork connects skilled professionals with freelance work opportunities.",
    potentialAction: {
      "@type": "SearchAction",
      target: "https://app.gib.work/search?q={search_term_string}",
      "query-input": "required name=search_term_string",
    },
  }),
},

1b. Add Organization and Social Profile Schema

const organizationSchema = {
  "@context": "https://schema.org",
  "@type": "Organization",
  name: "Gibwork",
  url: "https://gib.work",
  logo: "https://gib.work/work-logo.png",
  sameAs: [
    "https://twitter.com/gib_work",
    "https://discord.gg/TNXJjpRvqN",
    "https://www.youtube.com/@gibwork_",
  ],
};

1c. Enhance generateMetadata with Full Social Tags

return {
  metadataBase: new URL("https://gib.work"),
  title: {
    default: "Gibwork | Find Talent, Find Work in Crypto",
    template: "%s | Gibwork",
  },
  description:
    "Gibwork connects skilled professionals with freelance work opportunities, offering seamless integration with all Solana tokens for secure and efficient transactions.",
  keywords: [
    "crypto freelance", "solana jobs", "web3 work", "crypto bounties",
    "freelance crypto", "gibwork", "decentralized work",
  ],
  openGraph: {
    type: "website",
    locale: "en_US",
    siteName: "Gibwork",
    title: "Gibwork | Find Talent, Find Work in Crypto",
    description:
      "Join a community-driven platform for crypto bounties and paid Q&A.",
    url: "https://gib.work",
    images: [
      {
        url: "https://cdn.gib.work/metadata/default.png",
        width: 1200,
        height: 630,
        alt: "Gibwork -- Find Talent, Find Work",
      },
    ],
  },
  twitter: {
    card: "summary_large_image",
    site: "@gib_work",
    creator: "@gib_work",
    title: "Gibwork | Find Talent, Find Work",
    description:
      "Join a community-driven platform for crypto bounties and paid Q&A.",
    images: ["https://cdn.gib.work/metadata/default.png"],
  },
  robots: {
    index: true,
    follow: true,
    googleBot: {
      index: true,
      follow: true,
      "max-video-preview": -1,
      "max-image-preview": "large",
      "max-snippet": -1,
    },
  },
};

1d. Add sitemap.ts

// app/sitemap.ts
import { MetadataRoute } from "next";

export default function sitemap(): MetadataRoute.Sitemap {
  return [
    {
      url: "https://gib.work",
      lastModified: new Date(),
      changeFrequency: "weekly",
      priority: 1,
    },
    {
      url: "https://gib.work/tokenomics",
      lastModified: new Date(),
      changeFrequency: "monthly",
      priority: 0.5,
    },
  ];
}

Expected impact: Improved organic search visibility, rich snippet eligibility in SERP, higher click-through rates from social media embeds.


2. Frontend Performance Optimization

Problem: The landing page exhibits several performance anti-patterns:

  • No dynamic imports for heavy components (ClientTweetCard, Ripple)
  • Framer Motion imported eagerly in every section (7+ client components)
  • No image optimization for CDN-hosted assets (missing width/height, no loading="lazy")
  • No bundle analysis or code splitting
  • No PWA readiness

2a. Dynamic Import Heavy Components

// In testimonial.tsx -- dynamic import ClientTweetCard
import dynamic from "next/dynamic";
const ClientTweetCard = dynamic(
  () => import("@/components/ui/client-tweet-card"),
  {
    ssr: false,
    loading: () => <div className="h-48 animate-pulse bg-muted rounded-lg" />,
  }
);

2b. Consolidate Framer Motion Imports

Create a single client wrapper for scroll animations to reduce duplication and bundle size:

// components/animated-section.tsx
"use client";
import { motion } from "framer-motion";
import { FADE_UP_ANIMATION_VARIANTS } from "@/lib/framer-variants";
import { ReactNode } from "react";

export function AnimatedSection({
  children,
  className,
  id,
}: {
  children: ReactNode;
  className?: string;
  id?: string;
}) {
  return (
    <motion.section
      id={id}
      initial="hidden"
      whileInView="show"
      viewport={{ once: true }}
      variants={{
        hidden: {},
        show: { transition: { staggerChildren: 0.15 } },
      }}
      className={className}
    >
      {children}
    </motion.section>
  );
}

2c. Image Optimization

  • Add explicit width/height to all CDN images from https://cdn.gib.work/
  • Set loading="lazy" for below-fold images
  • Set priority on the hero dashboard screenshot (above the fold)
  • Convert static images in public/ to AVIF or WebP where possible

2d. next.config.js Optimizations

const nextConfig = {
  images: {
    formats: ["image/avif", "image/webp"],
    remotePatterns: [
      { protocol: "https", hostname: "cdn.gib.work" },
      { protocol: "https", hostname: "ucarecdn.com" },
    ],
  },
  experimental: {
    optimizePackageImports: [
      "lucide-react",
      "@tabler/icons-react",
      "framer-motion",
    ],
  },
};

2e. Add PWA Support

Update public/site.webmanifest with a complete icon set, theme colors, and display: standalone. Add a <link rel="manifest"> to layout.tsx.

Expected impact: 40-60% reduction in initial JavaScript bundle, 15-25 point improvement in Lighthouse performance score, improved Core Web Vitals (LCP under 2.5 seconds).


3. Dark Mode Toggle with Theme Persistence

Problem: The globals.css already defines complete .dark CSS custom properties, but there is no theme toggle UI and no persistence mechanism. Users cannot switch themes manually, and there is no system preference detection.

3a. Create Theme Provider

// components/providers/theme-provider.tsx
"use client";
import { createContext, useContext, useEffect, useState } from "react";

type Theme = "light" | "dark";
const ThemeContext = createContext<{
  theme: Theme;
  toggleTheme: () => void;
}>({ theme: "light", toggleTheme: () => {} });

export function ThemeProvider({ children }: { children: React.ReactNode }) {
  const [theme, setTheme] = useState<Theme>("light");
  const [mounted, setMounted] = useState(false);

  useEffect(() => {
    setMounted(true);
    const stored = localStorage.getItem("theme") as Theme | null;
    if (stored) {
      setTheme(stored);
      document.documentElement.classList.toggle("dark", stored === "dark");
    } else {
      const prefersDark = window.matchMedia("(prefers-color-scheme: dark)").matches;
      setTheme(prefersDark ? "dark" : "light");
      document.documentElement.classList.toggle("dark", prefersDark);
    }
  }, []);

  const toggleTheme = () => {
    const next = theme === "light" ? "dark" : "light";
    setTheme(next);
    localStorage.setItem("theme", next);
    document.documentElement.classList.toggle("dark", next === "dark");
  };

  if (!mounted) return <>{children}</>;
  return (
    <ThemeContext.Provider value={{ theme, toggleTheme }}>
      {children}
    </ThemeContext.Provider>
  );
}

export const useTheme = () => useContext(ThemeContext);

3b. Dark Mode Toggle Button

Add a toggle button in the Nav component (next to the social icons):

import { Moon, Sun } from "lucide-react";
import { useTheme } from "@/components/providers/theme-provider";

const { theme, toggleTheme } = useTheme();

<Button
  size="icon"
  variant="ghost"
  onClick={toggleTheme}
  aria-label={`Switch to ${theme === "light" ? "dark" : "light"} mode`}
>
  {theme === "light" ? <Moon className="size-5" /> : <Sun className="size-5" />}
</Button>

3c. System Preference Listener

Add a change event listener for prefers-color-scheme media query so the theme updates live when the user changes their OS setting, unless they have explicitly set a preference via the toggle.

Expected impact: Improved accessibility for users with light sensitivity, reduced eye strain in low-light environments.


4. Restore and Enhance $WORK Token Utility Section

Problem: The FAQ component has four token-related questions commented out (items covering fees, $WORK purpose, and how to acquire $WORK). The token page at /tokenomics exists but has no link from the main navigation. There is no dedicated token value proposition section on the landing page.

4a. Create a Token Utility Section

Add a new section between Testimonials and CTA that explains:

  1. What $WORK is: Governance token for the Gibwork ecosystem
  2. How to acquire $WORK: Jupiter swap, DEX listings
  3. Token benefits: Fee discounts, community voting, reward pool access
// components/token-utility.tsx
"use client";
import { motion } from "framer-motion";
import { FADE_UP_ANIMATION_VARIANTS } from "@/lib/framer-variants";
import { Button } from "@/components/ui/button";
import { ExternalLink } from "lucide-react";

const benefits = [
  {
    title: "Governance Rights",
    description: "Vote on platform decisions, fee structures, and community fund allocation.",
    icon: "gov",
  },
  {
    title: "Fee Discounts",
    description: "Pay reduced platform fees when using $WORK for transactions.",
    icon: "discount",
  },
  {
    title: "Reward Pool Access",
    description: "Earn a share of platform revenue through staked $WORK.",
    icon: "reward",
  },
];

export function TokenUtility() {
  return (
    <section className="relative py-24 sm:py-32 px-4 sm:px-6 w-full max-w-7xl mx-auto border-y">
      <motion.div
        initial="hidden"
        whileInView="show"
        viewport={{ once: true }}
        variants={{
          hidden: {},
          show: { transition: { staggerChildren: 0.15 } },
        }}
        className="text-center"
      >
        <motion.p variants={FADE_UP_ANIMATION_VARIANTS} className="text-primary font-semibold text-sm uppercase tracking-wider">
          Token
        </motion.p>
        <motion.h2 variants={FADE_UP_ANIMATION_VARIANTS} className="text-3xl sm:text-4xl font-semibold mt-2">
          The $WORK Token
        </motion.h2>
        <motion.p variants={FADE_UP_ANIMATION_VARIANTS} className="text-muted-foreground mt-2 max-w-2xl mx-auto">
          Powering the Gibwork ecosystem with governance, incentives, and rewards.
        </motion.p>
      </motion.div>

      <motion.div
        initial="hidden"
        whileInView="show"
        viewport={{ once: true }}
        variants={{
          hidden: {},
          show: { transition: { staggerChildren: 0.15 } },
        }}
        className="grid md:grid-cols-3 gap-6 mt-12"
      >
        {benefits.map((benefit) => (
          <motion.div
            key={benefit.title}
            variants={FADE_UP_ANIMATION_VARIANTS}
            className="rounded-lg border bg-card p-6 text-center"
          >
            <h3 className="font-semibold text-lg">{benefit.title}</h3>
            <p className="text-muted-foreground text-sm mt-2">{benefit.description}</p>
          </motion.div>
        ))}
      </motion.div>

      <motion.div
        variants={FADE_UP_ANIMATION_VARIANTS}
        initial="hidden"
        whileInView="show"
        viewport={{ once: true }}
        className="text-center mt-8"
      >
        <Button variant="outline" asChild>
          <a href="https://jup.ag/swap/SOL-WORK" target="_blank" rel="noopener noreferrer">
            Swap for $WORK <ExternalLink className="size-4 ml-2" />
          </a>
        </Button>
      </motion.div>
    </section>
  );
}

4b. Restore and Expand FAQ Token Questions

Uncomment and expand the token FAQ items in faq.tsx:

  • "Are there any fees for using Gibwork?" -- Explain the 5% service fee, with discounts for $WORK holders
  • "What is the purpose of the $WORK token?" -- Governance, staking, fee discounts
  • "Where can I get $WORK?" -- Jupiter swap link, DEX pairs, supported wallets

4c. Add Token Link to Navigation

Add a "Token" or "$WORK" link in the main navigation between FAQ and DOCS.

Expected impact: Increased token awareness, improved community engagement, clearer value proposition for token holders.


5. Code Quality and Maintenance

5a. Remove Unused Dependencies

flowbite-react is only used for Clipboard.WithIconText in a commented-out section of hero.tsx. Either complete and ship the CA copy feature, or remove the dependency to reclaim approximately 50KB from the bundle.

5b. Fix TypeScript Warnings

The generateMetadata function in app/layout.tsx uses any types:

export async function generateMetadata(
  { params, searchParams }: any,
  parent: ResolvingMetadata
): Promise<Metadata>

5c. Address Dead Code

The commented-out CA token copy section in hero.tsx (lines 80-104) should either be completed and shipped or removed. Dead code creates ongoing maintenance overhead.

5d. Add Error Boundaries for Tweet Embeds

The react-tweet ClientTweetCard component can fail silently (deleted tweet, rate limit, network error). Wrap each card in an error boundary to prevent blank spaces:

<ErrorBoundary fallback={<div className="h-48 bg-muted rounded-lg animate-pulse" />}>
  <ClientTweetCard id={id} />
</ErrorBoundary>

5e. Add loading="lazy" to Below-Fold Images

Images in the testimonial section and subsequent sections should use loading="lazy" for below-fold optimization.


Files to Modify

File Changes
app/layout.tsx Enhanced metadata, JSON-LD, Organization schema, manifest link
app/sitemap.ts New file with sitemap entries
app/globals.css Smooth theme transition for dark mode
next.config.js Enable optimizePackageImports, add remotePatterns
components/nav.tsx Add dark mode toggle, $WORK token link
components/providers/theme-provider.tsx New file
components/token-utility.tsx New file
components/animated-section.tsx New file
components/testimonial.tsx Dynamic imports, error boundaries
components/faq.tsx Uncomment and expand token FAQ items
All section components Refactor to use shared AnimatedSection
components/hero.tsx Remove or ship commented CA code
components/looking-for.tsx Fix image width/height props
public/site.webmanifest Complete PWA metadata

Priority Order

  1. Performance and SEO (highest impact, foundational -- enables discovery and conversion)
  2. Dark Mode (low effort, high polish -- approximately 2 hours)
  3. Token Utility (medium effort, strategic value -- approximately 4 hours)
  4. Code Quality (ongoing maintenance -- approximately 2 hours)

Total estimated effort: 2-3 days for a single developer familiar with the codebase.


Why This Issue Is Differentiated

While there are over 100 open issues on this repository, none systematically address:

  • JSON-LD structured data for rich Google search results
  • Frontend bundle optimization (dynamic imports, consolidated motion wrappers)
  • Dark mode with localStorage persistence and OS preference detection
  • Restoration of the commented-out $WORK token content
  • Image optimization for CDN-hosted assets
  • PWA readiness with a complete manifest

These gaps represent the next opportunity for the Gibwork landing page: moving beyond visual polish to technical excellence, discoverability, and token community growth.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Fields

    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions