# Files changed · PR \#5 · screen/col

[View on GitCafe](https://git.cafe/screen/col/pull/5/diffs)

Repository: [screen/col](https://git.cafe/screen/col)

Visibility: public

[Add docs, contributors, and refreshed site branding](https://git.cafe/screen/col/pull/5.md)

Version: 0

Head commit: b88f5ee023b27f7c1e3d842d16ee068444c2a7ac

Base commit: d7b9d82c47618c6b44cdc6faa77b85da40919cef

Comparison base: d7b9d82c47618c6b44cdc6faa77b85da40919cef

Showing up to 20 entries from this revision. If the pull request changes, reopen the first page before continuing.

## PRODUCT.md

Status: added; +45; −0

```diff
@@ -1,0 +1,45 @@
+# Product
+
+<!-- impeccable:product-schema 1 -->
+
+## Platform
+
+web
+
+## Users
+
+Frontend developers and product designers comparing UI libraries for an active project, plus contributors maintaining the directory.
+
+## Product Purpose
+
+Col is a community-maintained directory for finding, filtering, and comparing UI libraries without opening many disconnected sources.
+
+## Positioning
+
+Col combines a curated library registry with practical stack and use-case filters, then sends users to the official source for each library.
+
+## Operating Context
+
+Visitors search from the homepage, refine results in the library directory, save useful entries locally, and use GitHub issues or pull requests to improve the catalog.
+
+## Capabilities and Constraints
+
+- Catalog libraries rather than individual components.
+- Keep library metadata factual and link to canonical project sources.
+- Preserve light and dark themes, keyboard access, responsive behavior, and reduced-motion support.
+- Only maintainers merge changes to the protected default branch.
+
+## Brand Commitments
+
+The product is named Col and uses the line “Sol could not do it himself, so we made Col.” The visual identity is minimal, high-contrast, and uses `#0800FF` as its primary accent.
+
+## Evidence on Hand
+
+The curated registry lives in `data/libraries.ts`; contribution rules live in `README.md`, `CONTRIBUTING.md`, and `.github/` issue templates.
+
+## Product Principles
+
+- Reduce the time it takes to find a suitable UI library.
+- Prefer clear filters and factual metadata over promotional copy.
+- Keep contributions focused, reviewable, and easy to verify.
+- Send users to official project sources for installation and documentation.
```

## app/contributors/page.tsx

Status: added; +84; −0

```diff
@@ -1,0 +1,84 @@
+import type { Metadata } from "next";
+import { ArrowUpRight } from "lucide-react";
+import { Header } from "@/components/Header";
+import { SiteFooter } from "@/components/SiteFooter";
+
+export const metadata: Metadata = {
+  title: "Contributors — Col",
+  description: "Meet the people contributing to Col.",
+};
+
+type GitHubContributor = {
+  id: number;
+  login: string;
+  avatar_url: string;
+  html_url: string;
+  contributions: number;
+  type: string;
+};
+
+async function getContributors(): Promise<GitHubContributor[]> {
+  try {
+    const contributors: GitHubContributor[] = [];
+    let page = 1;
+
+    while (true) {
+      const response = await fetch(`https://api.github.com/repos/screen-gd/Col/contributors?per_page=100&page=${page}`, {
+        headers: { Accept: "application/vnd.github+json", "User-Agent": "Col-directory" },
+        next: { revalidate: 3600 },
+      });
+      if (!response.ok) return [];
+      const batch = await response.json() as GitHubContributor[];
+      contributors.push(...batch);
+      if (batch.length < 100) break;
+      page += 1;
+    }
+
+    return contributors.filter((contributor) => contributor.type === "User");
+  } catch {
+    return [];
+  }
+}
+
+export default async function ContributorsPage() {
+  const contributors = await getContributors();
+
+  return (
+    <>
+      <Header />
+      <main className="w-full max-w-full overflow-x-hidden">
+        <div className="mx-auto min-h-screen max-w-7xl px-5 pt-36 pb-28 sm:px-8 sm:pt-44">
+        <div className="flex flex-col gap-8 sm:flex-row sm:items-end sm:justify-between">
+          <div>
+            <h1 className="theme-text text-5xl font-semibold tracking-[-0.04em] sm:text-7xl">Built by people.</h1>
+            <p className="theme-muted mt-6 max-w-2xl text-lg leading-8">The contributors keeping Col useful, accurate, and open.</p>
+          </div>
+          <a href="https://github.com/screen-gd/Col/graphs/contributors" target="_blank" rel="noopener noreferrer" className="theme-text inline-flex items-center gap-2 text-sm font-medium">View on GitHub <ArrowUpRight className="size-4" aria-hidden /></a>
+        </div>
+
+        {contributors.length ? (
+          <ul className="theme-border mt-20 grid grid-cols-2 border-t sm:grid-cols-3 lg:grid-cols-5">
+            {contributors.map((contributor) => (
+              <li key={contributor.id} className="theme-border border-b p-4 sm:p-6 lg:border-r">
+                <a href={contributor.html_url} target="_blank" rel="noopener noreferrer" className="group block" aria-label={`View ${contributor.login} on GitHub`}>
+                  <img src={contributor.avatar_url} alt="" width="240" height="240" loading="lazy" className="aspect-square w-full bg-neutral-900 object-cover" />
+                  <div className="mt-4 flex items-start justify-between gap-3">
+                    <div><p className="theme-text font-medium">{contributor.login}</p><p className="theme-muted mt-1 text-xs tabular-nums">{contributor.contributions} {contributor.contributions === 1 ? "contribution" : "contributions"}</p></div>
+                    <ArrowUpRight className="theme-muted mt-1 size-4 shrink-0" aria-hidden />
+                  </div>
+                </a>
+              </li>
+            ))}
+          </ul>
+        ) : (
+          <div className="theme-border mt-20 border-y py-16">
+            <p className="theme-text text-xl font-medium">Contributors could not be loaded right now.</p>
+            <a href="https://github.com/screen-gd/Col/graphs/contributors" target="_blank" rel="noopener noreferrer" className="theme-muted mt-3 inline-flex items-center gap-2 text-sm">View the contributor graph on GitHub <ArrowUpRight className="size-4" aria-hidden /></a>
+          </div>
+        )}
+        </div>
+      </main>
+      <SiteFooter />
+    </>
+  );
+}
```

## app/docs/page.tsx

Status: added; +82; −0

```diff
@@ -1,0 +1,82 @@
+import type { Metadata } from "next";
+import { ArrowUpRight } from "lucide-react";
+import { Header } from "@/components/Header";
+import { SiteFooter } from "@/components/SiteFooter";
+
+export const metadata: Metadata = {
+  title: "Docs — Col",
+  description: "Learn how to use and contribute to Col.",
+};
+
+const sections = [
+  ["overview", "Overview"],
+  ["find", "Find a library"],
+  ["request", "Request a library"],
+  ["issues", "Report issues"],
+  ["pull-requests", "Open a pull request"],
+] as const;
+
+export default function DocsPage() {
+  return (
+    <>
+      <Header />
+      <main className="w-full max-w-full overflow-x-hidden">
+        <div className="mx-auto min-h-screen max-w-7xl px-5 pt-36 pb-28 sm:px-8 sm:pt-44">
+        <div className="max-w-3xl">
+          <h1 className="theme-text text-5xl font-semibold tracking-[-0.04em] sm:text-7xl">Documentation</h1>
+          <p className="theme-muted mt-6 max-w-2xl text-lg leading-8">Find a library, request what is missing, or contribute an improvement to the directory.</p>
+        </div>
+
+        <div className="mt-20 grid gap-16 lg:grid-cols-[14rem_minmax(0,1fr)]">
+          <nav aria-label="Documentation" className="theme-border border-t pt-5 lg:sticky lg:top-28 lg:h-fit">
+            <ul className="space-y-3 text-sm">
+              {sections.map(([id, label]) => <li key={id}><a className="theme-muted hover:underline" href={`#${id}`}>{label}</a></li>)}
+            </ul>
+          </nav>
+
+          <article className="docs-copy max-w-[72ch]">
+            <DocSection id="overview" title="What Col does">
+              <p>Col organizes UI libraries by category, stack, and use case. It catalogs libraries rather than individual components, and every listing points back to the project’s official source.</p>
+            </DocSection>
+
+            <DocSection id="find" title="Find a library">
+              <p>Search by name, keyword, category, stack, or use case. The homepage search opens the directory with your query applied, where you can refine the results and save useful entries locally.</p>
+              <DocLink href="/libraries">Browse all libraries</DocLink>
+            </DocSection>
+
+            <DocSection id="request" title="Request a library">
+              <p>Search the directory, existing issues, and open pull requests first. If the library is missing, include its official URL, supported stacks, category, use cases, and a short explanation of who it helps.</p>
+              <DocLink href="https://github.com/screen-gd/Col/issues/new?template=library-request.yml">Open a library request</DocLink>
+            </DocSection>
+
+            <DocSection id="issues" title="Report bugs and request features">
+              <p>Keep one outcome per issue. Bug reports should include the failing page or action, reproduction steps, expected and actual behavior, browser details, and supporting screenshots or console errors. Feature requests should lead with the problem and expected outcome.</p>
+              <div className="flex flex-wrap gap-x-6 gap-y-3">
+                <DocLink href="https://github.com/screen-gd/Col/issues/new?template=bug-report.yml">Report a bug</DocLink>
+                <DocLink href="https://github.com/screen-gd/Col/issues/new?template=feature-request.yml">Request a feature</DocLink>
+              </div>
+            </DocSection>
+
+            <DocSection id="pull-requests" title="Open a pull request">
+              <p>Fork the repository, create a focused branch, and keep unrelated changes out. Library additions belong in <code>data/libraries.ts</code> with a unique kebab-case slug, canonical URL, factual description, and existing taxonomy values where possible.</p>
+              <pre><code>{`npm install\nnpm run dev\nnpm run build`}</code></pre>
+              <p>Explain what changed, why it changed, and how you verified it. Include screenshots for visible interface changes.</p>
+              <DocLink href="https://github.com/screen-gd/Col/blob/main/CONTRIBUTING.md">Read the contribution guide</DocLink>
+            </DocSection>
+          </article>
+          </div>
+        </div>
+      </main>
+      <SiteFooter />
+    </>
+  );
+}
+
+function DocSection({ id, title, children }: { id: string; title: string; children: React.ReactNode }) {
+  return <section id={id} className="theme-border scroll-mt-28 border-t py-10 first:border-t-0 first:pt-0"><h2 className="theme-text text-2xl font-semibold tracking-[-0.025em]">{title}</h2><div className="theme-muted mt-4 space-y-5 leading-7">{children}</div></section>;
+}
+
+function DocLink({ href, children }: { href: string; children: React.ReactNode }) {
+  const external = href.startsWith("https://");
+  return <a href={href} {...(external ? { target: "_blank", rel: "noopener noreferrer" } : {})} className="theme-text inline-flex items-center gap-2 font-medium underline decoration-current underline-offset-4">{children}<ArrowUpRight className="size-4" aria-hidden /></a>;
+}
```

## app/globals.css

Status: modified; +50; −5

```diff
@@ -34,7 +34,7 @@
 }
 
 :root {
-  --col-red: #ff6257;
+  --col-brand: #0800ff;
   --col-blue: #69a9ff;
   --col-green: #3ddc97;
 }
@@ -78,11 +78,55 @@
 html.light .hero-registers { opacity: 0.07; filter: invert(1); }
 html.light .brand-mark { filter: invert(1); }
 
+.hero-accent-text { color: var(--col-brand); }
+
+html.light .hero-accent-text { color: var(--col-brand); }
+
+.site-footer-panel { background: #07152f; color: #fff; }
+.footer-icon-link {
+  display: inline-flex;
+  width: 2.75rem;
+  height: 2.75rem;
+  align-items: center;
+  justify-content: center;
+  border: 1px solid rgba(255, 255, 255, 0.16);
+  border-radius: 0.625rem;
+  background-color: rgba(255, 255, 255, 0.08);
+  color: #fff;
+  transition: background-color 160ms ease, border-color 160ms ease;
+}
+.footer-icon-link:hover { border-color: rgba(255, 255, 255, 0.32); background-color: rgba(255, 255, 255, 0.14); }
+.footer-icon-link--primary { border-color: #0800ff; background-color: #0800ff; }
+.footer-icon-link--primary:hover { border-color: #241eff; background-color: #241eff; }
+.footer-link { display: flex; align-items: center; justify-content: space-between; gap: 1rem; max-width: 20rem; color: rgba(255, 255, 255, 0.72); transition: color 160ms ease; }
+.footer-link:hover { color: #fff; }
+.site-footer-wordmark {
+  margin-bottom: -0.16em;
+  color: transparent;
+  font-size: clamp(10rem, 32vw, 30rem);
+  font-weight: 700;
+  line-height: 0.8;
+  letter-spacing: -0.04em;
+  text-align: center;
+  -webkit-text-stroke: 1px rgba(255, 255, 255, 0.22);
+}
+
+.docs-copy code {
+  font-family: var(--font-geist-mono), ui-monospace, monospace;
+  font-size: 0.9em;
+}
+
+.docs-copy pre {
+  overflow-x: auto;
+  padding: 1.25rem 0;
+  border-block: 1px solid rgba(255, 255, 255, 0.12);
+  color: #fff;
+}
-.hero-accent-text,
-.footer-wordmark { color: var(--col-red); }
 
+html.light .docs-copy pre {
-html.light .hero-accent-text,
+  border-color: rgba(17, 17, 17, 0.14);
-html.light .footer-wordmark { color: #c92f36; }
+  color: #111;
+}
 
 .gooey-surface {
   background: #090909;
@@ -257,6 +301,7 @@
 html.light .library-chip { border-color: rgba(17,17,17,.12); background: rgba(17,17,17,.045); color: rgba(17,17,17,.72); }
 
 html.light [class~="text-white"] { color: #111; }
+html.light .site-footer-panel [class~="text-white"] { color: #fff; }
 html.light [class~="bg-black"] { background-color: #fff; }
 html.light [class~="bg-black/90"] { background-color: rgba(255,255,255,.9); }
 html.light [class~="border-white/10"],
```

## app/libraries/page.tsx

Status: modified; +5; −3

```diff
@@ -5,9 +5,11 @@
   const { q = "" } = await searchParams;
 
   return (
-    <main className="w-full max-w-full overflow-x-hidden">
+    <>
       <Header />
-      <DirectoryExplorer initialQuery={q} />
-    </main>
+      <main className="w-full max-w-full overflow-x-hidden">
+        <DirectoryExplorer initialQuery={q} />
+      </main>
+    </>
   );
 }
```

## app/page.tsx

Status: modified; +7; −38

```diff
@@ -1,46 +1,15 @@
-import { ArrowUpRight } from "lucide-react";
-import Image from "next/image";
 import { LibraryExplorer } from "@/components/LibraryExplorer";
 import { Header } from "@/components/Header";
+import { SiteFooter } from "@/components/SiteFooter";
 
 export default function Home() {
   return (
-    <main className="w-full max-w-full overflow-x-hidden">
+    <>
       <Header />
-
+      <main className="w-full max-w-full overflow-x-hidden">
+        <LibraryExplorer />
-      <LibraryExplorer />
+      </main>
+      <SiteFooter />
+    </>
-
-      <footer className="theme-border border-t">
-        <div className="mx-auto max-w-7xl px-5 py-32 sm:px-8 sm:py-40">
-          <h2 className="theme-text mt-6 max-w-3xl text-[clamp(2.5rem,5.5vw,4.5rem)] leading-[1.05] font-semibold tracking-tight">
-            Know one we missed?
-          </h2>
-          <a
-            href="https://github.com/screen-gd/Col"
-            target="_blank"
-            rel="noopener noreferrer"
-            className="primary-invert-button group mt-10 inline-flex items-center gap-2.5 rounded-xl px-7 py-3.5 text-sm font-semibold transition-opacity duration-200 hover:opacity-85"
-          >
-            Contribute on GitHub
-            <ArrowUpRight
-              className="size-4 transition-transform duration-200 group-hover:translate-x-0.5 group-hover:-translate-y-0.5"
-              aria-hidden
-            />
-          </a>
-        </div>
-        <div className="theme-border border-t">
-          <div className="theme-muted mx-auto flex max-w-7xl flex-col items-start justify-between gap-5 px-5 py-8 text-xs sm:flex-row sm:items-center sm:px-8">
-            <div className="flex items-center gap-3">
-              <Image src="/brand/col-mark.png" alt="" width={30} height={30} className="brand-mark size-[30px] object-contain" />
-              <div>
-                <p className="footer-wordmark text-base font-bold tracking-[-0.03em]">Col</p>
-                <p className="mt-0.5">Sol could not do it himself so we made Col</p>
-              </div>
-            </div>
-            <p>Built with Next.js, TypeScript & Tailwind CSS</p>
-          </div>
-        </div>
-      </footer>
-    </main>
   );
 }
```

## components/Header.tsx

Status: modified; +11; −5

```diff
@@ -51,10 +51,16 @@
           <Image src="/brand/col-mark.png" alt="" width={28} height={28} className="brand-mark size-7 object-contain" priority />
           <span className="brand-wordmark text-base font-bold tracking-[-0.03em]">Col</span>
         </a>
-        <a href="/libraries" className="absolute left-1/2 hidden -translate-x-1/2 text-sm text-white lg:block">
-          Libraries
-        </a>
-        <nav className="flex items-center gap-5">
+        <nav aria-label="Primary" className="absolute left-1/2 hidden -translate-x-1/2 items-center gap-7 text-sm text-white lg:flex">
+          <a href="/libraries">Libraries</a>
+          <a href="/docs">Docs</a>
+          <a href="/contributors">Contributors</a>
+        </nav>
+        <nav aria-label="Actions" className="flex items-center gap-4 sm:gap-5">
+          <div className="flex items-center gap-4 text-sm text-white lg:hidden">
+            <a href="/docs">Docs</a>
+            <a href="/contributors">People</a>
+          </div>
           <ThemeToggle />
           <a href="/#hero-search" aria-label="Search libraries" className="hidden text-white sm:block">
             <Search className="size-4" aria-hidden />
@@ -72,7 +78,7 @@
             target="_blank"
             rel="noopener noreferrer"
             aria-label={`Contribute on GitHub${stars === null ? "" : `, ${stars} stars`}`}
-            className="flex items-center gap-2 rounded-xl border border-white/15 px-4 py-2 text-sm text-white transition-colors hover:border-white/30"
+            className="hidden items-center gap-2 rounded-xl border border-white/15 px-4 py-2 text-sm text-white transition-colors hover:border-white/30 md:flex"
           >
             <GitFork className="size-4" aria-hidden />
             <span>Contribute</span>
```

## components/SiteFooter.tsx

Status: added; +66; −0

```diff
@@ -1,0 +1,66 @@
+import Image from "next/image";
+import { ArrowUpRight, BookOpen, GitFork, MessageSquarePlus } from "lucide-react";
+
+const linkIcon = <ArrowUpRight className="size-4" aria-hidden />;
+
+export function SiteFooter() {
+  return (
+    <footer className="theme-border border-t">
+      <div className="site-footer-panel overflow-hidden px-5 pt-14 sm:px-8 sm:pt-20">
+        <div className="mx-auto max-w-7xl">
+          <div className="grid gap-12 sm:grid-cols-2">
+            <div className="max-w-sm">
+              <div className="flex items-center gap-3">
+                <Image src="/brand/col-mark.png" alt="" width={40} height={40} className="size-10 object-contain" />
+                <span className="text-3xl font-semibold tracking-[-0.035em] text-white">Col</span>
+              </div>
+              <p className="mt-5 text-sm leading-6 text-white/60">Sol could not do it himself, so we made Col.</p>
+            </div>
+
+            <div className="sm:justify-self-end sm:pr-24">
+              <h2 className="text-lg font-medium text-white">Explore the project</h2>
+              <div className="mt-5 flex gap-2.5">
+                <a className="footer-icon-link footer-icon-link--primary" href="https://github.com/screen-gd/Col" target="_blank" rel="noopener noreferrer" aria-label="View Col on GitHub">
+                  <GitFork className="size-5" aria-hidden />
+                </a>
+                <a className="footer-icon-link" href="/docs" aria-label="Read the Col documentation">
+                  <BookOpen className="size-5" aria-hidden />
+                </a>
+                <a className="footer-icon-link" href="https://github.com/screen-gd/Col/issues/new/choose" target="_blank" rel="noopener noreferrer" aria-label="Contribute to Col">
+                  <MessageSquarePlus className="size-5" aria-hidden />
+                </a>
+              </div>
+            </div>
+          </div>
+
+          <div className="mt-24 grid gap-14 sm:grid-cols-3 sm:gap-10 lg:mt-32">
+            <FooterLinks title="Discover" links={[["All libraries", "/libraries"], ["Search", "/#hero-search"], ["Contributors", "/contributors"]]} />
+            <FooterLinks title="Contribute" links={[["Request a library", "https://github.com/screen-gd/Col/issues/new?template=library-request.yml"], ["Request a feature", "https://github.com/screen-gd/Col/issues/new?template=feature-request.yml"], ["Report a bug", "https://github.com/screen-gd/Col/issues/new?template=bug-report.yml"]]} external />
+            <FooterLinks title="Project" links={[["Docs", "/docs"], ["GitHub", "https://github.com/screen-gd/Col"], ["Contributing", "https://github.com/screen-gd/Col/blob/main/CONTRIBUTING.md"]]} />
+          </div>
+
+          <div className="mt-20 flex flex-col gap-3 border-b border-white/15 pb-6 text-xs text-white/55 sm:flex-row sm:items-center sm:justify-between">
+            <p>© {new Date().getFullYear()} Col. All rights reserved.</p>
+            <p>Open source. Community maintained.</p>
+          </div>
+
+          <p className="site-footer-wordmark" aria-hidden>Col</p>
+        </div>
+      </div>
+    </footer>
+  );
+}
+
+function FooterLinks({ title, links, external = false }: { title: string; links: readonly (readonly [string, string])[]; external?: boolean }) {
+  return (
+    <nav aria-label={title}>
+      <h3 className="text-xs font-medium tracking-[0.12em] text-white/45 uppercase">{title}</h3>
+      <div className="mt-5 flex flex-col gap-3 text-lg">
+        {links.map(([label, href]) => {
+          const opensNewTab = external || href.startsWith("https://");
+          return <a key={href} className="footer-link" href={href} {...(opensNewTab ? { target: "_blank", rel: "noopener noreferrer" } : {})}><span>{label}</span>{linkIcon}</a>;
+        })}
+      </div>
+    </nav>
+  );
+}
```

## public/brand/col-brand-kit.png

Status: added; +0; −0

File exceeds the inline diff size limit; patch omitted.

## public/brand/concepts/col-logo-01-modular-c.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-02-shelf-c.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-03-layered-cards.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-04-bracket-core.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-05-custom-wordmark.png

Status: added; +0; −0

File exceeds the inline diff size limit; patch omitted.

## public/brand/concepts/col-logo-06-acid-aperture.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-07-index-tabs.png

Status: added; +0; −0

Binary file; no text patch.

## public/brand/concepts/col-logo-08-path-c.png

Status: added; +0; −0

File exceeds the inline diff size limit; patch omitted.
