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

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

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

Visibility: public

[Add discovery files and MIT licensing](https://git.cafe/screen/col/pull/7.md)

Version: 0

Head commit: 5f031c35ef4692da6628c861bdbb59f00c7a1191

Base commit: a71b59d0cf9cfb6daf7d6c0e2825c21ae8388910

Comparison base: 63a242d7df035a7f23a5c6c2db91156b3f64f402

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

## LICENSE

Status: added; +21; −0

```diff
@@ -1,0 +1,21 @@
+MIT License
+
+Copyright (c) 2026 Screen
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in all
+copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+SOFTWARE.
```

## README.md

Status: modified; +2; −0

```diff
@@ -176,6 +176,8 @@
 
 Be clear, constructive, and respectful. Contributions are welcome whether you are adding a library, improving metadata, fixing a bug, or making discovery easier.
 
+Col is licensed under the [MIT License](LICENSE).
+
 <div align="center">
   <strong>Find better tools. Build better interfaces.</strong>
 </div>
```

## app/llms.txt/route.ts

Status: added; +23; −0

```diff
@@ -1,0 +1,23 @@
+import { libraries } from "@/data/libraries";
+
+export const dynamic = "force-static";
+
+export function GET() {
+  const entries = libraries.map((library) => [
+    `## ${library.name}`,
+    `- Domain: [${new URL(library.url).hostname.replace(/^www\./, "")}](${library.url})`,
+    `- Description: ${library.description}`,
+    `- Category: ${library.category}`,
+    `- Stacks: ${library.stacks.join(", ")}`,
+    `- Use cases: ${library.useCases.join(", ")}`,
+  ].join("\n"));
+
+  const body = [
+    "# Col",
+    "Col is a curated directory of UI libraries organized by category, stack, and use case. Browse and filter the collection to find tools for your project. New libraries and corrections are submitted through pull requests.",
+    "# Libraries",
+    ...entries,
+  ].join("\n\n") + "\n";
+
+  return new Response(body, { headers: { "Content-Type": "text/plain; charset=utf-8" } });
+}
```

## app/robots.ts

Status: added; +12; −0

```diff
@@ -1,0 +1,12 @@
+import type { MetadataRoute } from "next";
+import { siteUrl } from "@/lib/site";
+
+export default function robots(): MetadataRoute.Robots {
+  return {
+    rules: [
+      { userAgent: "*", allow: "/" },
+      { userAgent: ["GPTBot", "ClaudeBot", "PerplexityBot", "Google-Extended"], allow: "/" },
+    ],
+    sitemap: `${siteUrl}/sitemap.xml`,
+  };
+}
```

## app/sitemap.ts

Status: added; +10; −0

```diff
@@ -1,0 +1,10 @@
+import type { MetadataRoute } from "next";
+import { siteUrl, staticRoutes } from "@/lib/site";
+
+export default function sitemap(): MetadataRoute.Sitemap {
+  const lastModified = new Date();
+  return staticRoutes.map((route) => ({
+    url: new URL(route, siteUrl).toString(),
+    lastModified,
+  }));
+}
```

## components/FilterBar.tsx

Status: modified; +1; −1

```diff
@@ -84,7 +84,7 @@
       </div>
 
       <Tabs value={activeCategory ?? "all"} onValueChange={(value) => onCategoryChange(value === "all" ? null : value as Category)}>
-        <TabsList className="h-auto w-full flex-wrap justify-start gap-1 rounded-none bg-transparent p-0">
+        <TabsList className="h-auto! w-full flex-wrap justify-start gap-1 rounded-none bg-transparent p-0">
           <TabsTrigger value="all" className="filter-tab flex-none rounded-md px-3 py-1.5">All</TabsTrigger>
           {CATEGORIES.map((category) => <TabsTrigger key={category} value={category} className="filter-tab flex-none rounded-md px-3 py-1.5">{category}</TabsTrigger>)}
         </TabsList>
```

## components/Header.tsx

Status: modified; +1; −1

```diff
@@ -147,7 +147,7 @@
           </a>
           <RainbowButton
             asChild
-            className="h-9 rounded-[10px] px-[19px] text-xs text-white dark:text-black max-[760px]:h-[34px] max-[760px]:rounded-[9px] max-[760px]:px-3"
+            className="h-9 rounded-[10px] px-[19px] text-xs text-white! dark:text-black! max-[760px]:h-[34px] max-[760px]:rounded-[9px] max-[760px]:px-3"
           >
             <a href="https://github.com/screen-gd/Col/issues/new" target="_blank" rel="noopener noreferrer">Submit</a>
           </RainbowButton>
```

## components/SiteFooter.tsx

Status: modified; +1; −1

```diff
@@ -34,7 +34,7 @@
           </div>
 
           <div className="flex flex-col gap-2 py-4 text-xs text-white/55 sm:flex-row sm:items-center sm:justify-between">
-            <p>© {new Date().getFullYear()} Col. All rights reserved.</p>
+            <p>© {new Date().getFullYear()} Screen. <a className="footer-link" href="https://github.com/screen-gd/Col/blob/main/LICENSE">MIT license</a>.</p>
             <p>Open source. Community maintained.</p>
           </div>
         </div>
```

## lib/site.ts

Status: added; +3; −0

```diff
@@ -1,0 +1,3 @@
+export const siteUrl = "https://collection-of-libs.vercel.app";
+
+export const staticRoutes = ["/", "/libraries", "/docs", "/contributors"] as const;
```

## package-lock.json

Status: modified; +1; −0

```diff
@@ -7,6 +7,7 @@
     "": {
       "name": "coc",
       "version": "0.1.0",
+      "license": "MIT",
       "dependencies": {
         "@gsap/react": "^2.1.2",
         "border-beam": "^1.4.0",
```

## package.json

Status: modified; +1; −0

```diff
@@ -3,6 +3,7 @@
   "version": "0.1.0",
   "private": true,
   "description": "A community-maintained directory for discovering UI libraries.",
+  "license": "MIT",
   "scripts": {
     "dev": "next dev",
     "build": "next build",
```

## tests/discovery.test.mjs

Status: added; +38; −0

```diff
@@ -1,0 +1,38 @@
+import assert from "node:assert/strict";
+import { readFileSync } from "node:fs";
+import { test } from "node:test";
+import ts from "typescript";
+
+const source = readFileSync(new URL("../data/libraries.ts", import.meta.url), "utf8");
+const moduleSource = ts.transpileModule(source, { compilerOptions: { module: ts.ModuleKind.ESNext } }).outputText;
+const { libraries } = await import(`data:text/javascript,${encodeURIComponent(moduleSource)}`);
+
+const built = (name) => readFileSync(new URL(`../.next/server/app/${name}.body`, import.meta.url), "utf8");
+
+test("build emits complete discovery files", () => {
+  const robots = built("robots.txt");
+  const sitemap = built("sitemap.xml");
+  const llms = built("llms.txt");
+
+  for (const crawler of ["*", "GPTBot", "ClaudeBot", "PerplexityBot", "Google-Extended"]) {
+    assert.ok(robots.includes(`User-Agent: ${crawler}`));
+  }
+  assert.ok(robots.includes("Allow: /"));
+  assert.ok(robots.includes("Sitemap: https://collection-of-libs.vercel.app/sitemap.xml"));
+
+  for (const route of ["/", "/libraries", "/docs", "/contributors"]) {
+    assert.ok(sitemap.includes(`<loc>https://collection-of-libs.vercel.app${route}</loc>`));
+  }
+  assert.equal((sitemap.match(/<lastmod>/g) ?? []).length, 4);
+
+  const entries = llms.split("\n## ").slice(1);
+  assert.equal(entries.length, libraries.length);
+  for (const library of libraries) {
+    const entry = entries.find((item) => item.startsWith(`${library.name}\n`));
+    assert.ok(entry, `Missing ${library.name}`);
+    assert.ok(entry.includes(`- Domain: [${new URL(library.url).hostname.replace(/^www\./, "")}](${library.url})`));
+    assert.ok(entry.includes(`- Description: ${library.description}`));
+    assert.ok(entry.includes(`- Stacks: ${library.stacks.join(", ")}`));
+    assert.ok(entry.includes(`- Use cases: ${library.useCases.join(", ")}`));
+  }
+});
```
