Skip to content

Commit 3ef6613

Browse files
nearestnaborstorresmateoclaudegithub-actions[bot]
authored
Add example apps page to docs (#615)
* add example apps page * Adding an examples page with all the repos suggested so far in #tech-assets * Add submission guidelines * Update app/en/home/_meta.tsx Co-authored-by: Mateo Torres <[email protected]> * feat: enhance SampleAppCard with date support and improved styling - Add optional date prop to display creation dates - Update styling to match MCP Server tiles exactly - Add color-coded tags for languages (green), frameworks (blue), and integrations (yellow) - Remove thumbnail images and motion animations for cleaner design - Improve responsive layout and hover effects 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat: expand example apps with dates and submission guidelines - Add 8 new sample applications from ArcadeAI repositories - Include creation dates fetched from GitHub API for all apps - Sort examples chronologically (newest first) - Add "Submit your app" section with clear guidelines for community contributions - Update grid layout to 2-column responsive design - Enhance tag categorization for new frameworks and integrations New apps include: - OpenAI SDK MCP Gateway (Nov 2025) - Agent Kitchen Sink (Nov 2025) - Arcade Custom Verifier Next (Aug 2025) - Agency Tutorial with Stytch (Aug 2025) - CLI Agent Template (Jul 2025) - Megaforce (Jul 2025) - Framework Showdown (May 2025) - Agent Templates (Dec 2025) - Baseball dugout (Dec 2025) 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * feat: add automated repository date updating workflow - Create GitHub Actions workflow to update example app dates weekly - Auto-discover repositories from MDX file, no hardcoded lists needed - Fetch creation dates from GitHub API for accurate information - Create pull requests for review when dates change - Self-maintaining system - adding new SampleAppCard automatically includes it Workflow features: - Runs every Monday at 00:00 UTC + manual dispatch - Parses SampleAppCard components for GitHub URLs - Updates dates based on repository creation timestamps - Sorts apps chronologically after updates - Creates descriptive PRs with change summaries Script capabilities: - Regex-based MDX parsing for repository discovery - GitHub API integration with proper authentication - Robust error handling and logging - Smart date formatting (MMM YYYY) - Safe file updates with change detection 🤖 Generated with [Claude Code](https://claude.ai/code) Co-Authored-By: Claude <[email protected]> * 🤖 Regenerate LLMs.txt --------- Co-authored-by: Rachel Lee Nabors <[email protected]> Co-authored-by: Mateo Torres <[email protected]> Co-authored-by: Claude <[email protected]> Co-authored-by: github-actions[bot] <github-actions[bot]@users.noreply.github.com>
1 parent 46e5949 commit 3ef6613

File tree

6 files changed

+437
-37
lines changed

6 files changed

+437
-37
lines changed
Lines changed: 150 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,150 @@
1+
#!/usr/bin/env node
2+
3+
const fs = require("fs");
4+
const path = require("path");
5+
6+
function parseRepositoriesFromMDX(content) {
7+
const repositories = [];
8+
9+
// Regex to find all SampleAppCard components with title and href
10+
const sampleAppCardRegex = /<SampleAppCard\s+([^>]+)>/g;
11+
12+
let match;
13+
while ((match = sampleAppCardRegex.exec(content)) !== null) {
14+
const propsString = match[1];
15+
16+
// Extract title and href from props
17+
const titleMatch = propsString.match(/title="([^"]+)"/);
18+
const hrefMatch = propsString.match(/href="([^"]+)"/);
19+
20+
if (titleMatch && hrefMatch) {
21+
const title = titleMatch[1];
22+
const href = hrefMatch[1];
23+
24+
// Check if it's a GitHub URL and extract repo name
25+
const githubMatch = href.match(/https:\/\/github\.com\/([^/]+\/[^/]+)/);
26+
27+
if (githubMatch) {
28+
const repoName = githubMatch[1];
29+
repositories.push({
30+
title,
31+
repo: repoName,
32+
href,
33+
});
34+
}
35+
}
36+
}
37+
38+
return repositories;
39+
}
40+
41+
async function fetchRepoData(repoInfo) {
42+
const url = `https://api.github.com/repos/${repoInfo.repo}`;
43+
44+
try {
45+
const response = await fetch(url, {
46+
headers: {
47+
Authorization: `token ${process.env.GITHUB_TOKEN}`,
48+
"User-Agent": "arcade-docs-updater",
49+
},
50+
});
51+
52+
if (!response.ok) {
53+
throw new Error(`HTTP error! status: ${response.status}`);
54+
}
55+
56+
const data = await response.json();
57+
return {
58+
repo: repoInfo.repo,
59+
title: repoInfo.title,
60+
href: repoInfo.href,
61+
createdAt: new Date(data.created_at),
62+
updatedAt: new Date(data.updated_at),
63+
};
64+
} catch (error) {
65+
console.error(`Error fetching data for ${repoInfo.repo}:`, error);
66+
return null;
67+
}
68+
}
69+
70+
function formatDate(date) {
71+
const months = [
72+
"Jan",
73+
"Feb",
74+
"Mar",
75+
"Apr",
76+
"May",
77+
"Jun",
78+
"Jul",
79+
"Aug",
80+
"Sep",
81+
"Oct",
82+
"Nov",
83+
"Dec",
84+
];
85+
86+
return `${months[date.getMonth()]} ${date.getFullYear()}`;
87+
}
88+
89+
async function updateExampleDates() {
90+
console.log("Parsing repositories from MDX file...");
91+
92+
// Read the current MDX file
93+
const mdxPath = path.join(__dirname, "../../app/en/home/examples/page.mdx");
94+
let content = fs.readFileSync(mdxPath, "utf8");
95+
96+
// Parse repositories from the MDX file
97+
const repositories = parseRepositoriesFromMDX(content);
98+
console.log(
99+
"Found repositories:",
100+
repositories.map((r) => `${r.title} (${r.repo})`)
101+
);
102+
103+
if (repositories.length === 0) {
104+
console.log("No GitHub repositories found in MDX file.");
105+
return;
106+
}
107+
108+
console.log("Fetching repository data from GitHub API...");
109+
110+
// Fetch data for all repositories
111+
const repoDataPromises = repositories.map(fetchRepoData);
112+
const repoData = (await Promise.all(repoDataPromises)).filter(Boolean);
113+
114+
// Sort by creation date (newest first)
115+
repoData.sort((a, b) => b.createdAt - a.createdAt);
116+
117+
console.log(
118+
"Repository dates:",
119+
repoData.map((r) => `${r.title}: ${formatDate(r.createdAt)}`)
120+
);
121+
122+
// Update dates for each repository
123+
repoData.forEach((repo) => {
124+
// Find the SampleAppCard with this title and update its date
125+
const titleRegex = new RegExp(
126+
`(title="${repo.title.replace(/[.*+?^${}()|[\]\\]/g, "\\$&")}"[\\s\\S]*?)date="[^"]*"`,
127+
"g"
128+
);
129+
const newDate = formatDate(repo.createdAt);
130+
131+
const before = content;
132+
content = content.replace(titleRegex, `$1date="${newDate}"`);
133+
134+
if (content !== before) {
135+
console.log(`Updated date for "${repo.title}" to ${newDate}`);
136+
} else {
137+
console.warn(`Could not find or update date for "${repo.title}"`);
138+
}
139+
});
140+
141+
// Write the updated content back
142+
fs.writeFileSync(mdxPath, content, "utf8");
143+
console.log("Successfully updated example dates!");
144+
}
145+
146+
// Run the update
147+
updateExampleDates().catch((error) => {
148+
console.error("Error updating example dates:", error);
149+
process.exit(1);
150+
});
Lines changed: 59 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
name: Update Example App Dates
2+
3+
on:
4+
schedule:
5+
# Run every Monday at 00:00 UTC
6+
- cron: '0 0 * * 1'
7+
workflow_dispatch: # Allow manual triggering
8+
9+
jobs:
10+
update-dates:
11+
runs-on: ubuntu-latest
12+
13+
steps:
14+
- name: Checkout repository
15+
uses: actions/checkout@v4
16+
with:
17+
token: ${{ secrets.GITHUB_TOKEN }}
18+
fetch-depth: 1
19+
20+
- name: Setup Node.js
21+
uses: actions/setup-node@v4
22+
with:
23+
node-version: '22.x'
24+
25+
- name: Update repository dates
26+
env:
27+
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
28+
run: |
29+
node .github/scripts/update-example-dates.js
30+
31+
- name: Check for changes
32+
id: check-changes
33+
run: |
34+
if [ -n "$(git status --porcelain)" ]; then
35+
echo "changes=true" >> $GITHUB_OUTPUT
36+
else
37+
echo "changes=false" >> $GITHUB_OUTPUT
38+
fi
39+
40+
- name: Create Pull Request
41+
if: steps.check-changes.outputs.changes == 'true'
42+
uses: peter-evans/create-pull-request@v6
43+
with:
44+
token: ${{ secrets.GITHUB_TOKEN }}
45+
commit-message: "chore: update example app dates [skip ci]"
46+
title: "🤖 Update example app repository dates"
47+
body: |
48+
This PR contains automated updates to the example app creation/update dates.
49+
50+
**Generated on:** ${{ github.event_name == 'workflow_dispatch' && 'Manual trigger' || 'Scheduled run' }}
51+
**Triggered by:** ${{ github.actor }}
52+
53+
The script has fetched the latest repository information from GitHub API and updated the dates accordingly.
54+
branch: chore/update-example-dates-${{ github.run_id }}
55+
delete-branch: true
56+
labels: |
57+
automated
58+
examples
59+
assignees: rachelnabors
Lines changed: 79 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,5 @@
11
"use client";
22
import { Card, CardContent } from "@arcadeai/design-system";
3-
import { motion } from "motion/react";
4-
import Image from "next/image";
53
import Link from "next/link";
64

75
type SampleAppCardProps = {
@@ -10,6 +8,8 @@ type SampleAppCardProps = {
108
image: string;
119
href: string;
1210
blank?: boolean;
11+
tags?: string[];
12+
date?: string;
1313
};
1414

1515
export function SampleAppCard({
@@ -18,38 +18,87 @@ export function SampleAppCard({
1818
image,
1919
href,
2020
blank = false,
21+
tags = [],
22+
date,
2123
}: SampleAppCardProps) {
2224
return (
23-
<motion.div
24-
whileHover={{
25-
scale: 1.02,
26-
boxShadow: "0 0 20px 0 rgba(238, 23, 94, 0.1)",
27-
}}
28-
whileTap={{ scale: 0.98 }}
29-
>
30-
<Link href={href} target={blank ? "_blank" : undefined}>
31-
<Card className="group h-full overflow-hidden border-gray-200 bg-white/90 backdrop-blur-xs transition-all hover:border-[#ee175e]/30 dark:border-gray-800 dark:bg-[rgba(17,17,17,0.8)]">
32-
<CardContent className="p-0">
33-
<div className="relative aspect-video overflow-hidden bg-gray-100 dark:bg-zinc-900">
34-
<Image
35-
alt={title}
36-
className="scale-110 object-cover transition-transform duration-300"
37-
fill
38-
sizes="(max-width: 768px) 100vw, (max-width: 1200px) 50vw, 33vw"
39-
src={image}
40-
/>
41-
</div>
42-
<div className="space-y-2 p-6">
43-
<h3 className="font-semibold text-gray-900 text-xl tracking-tight transition-colors group-hover:text-[#ee175e] dark:text-white">
25+
<Link href={href} target={blank ? "_blank" : undefined}>
26+
<Card className="flex h-full flex-col gap-1.5 border border-gray-600/20 bg-white/90 py-3 backdrop-blur-sm transition-all duration-300 hover:border-primary hover:bg-gray-600/[0.03] hover:shadow-lg dark:bg-gray-900/80">
27+
<CardContent className="p-0">
28+
<div className="space-y-2 p-6">
29+
<div className="flex items-start justify-between gap-2">
30+
<h3 className="font-semibold text-gray-900 text-xl tracking-tight dark:text-white">
4431
{title}
4532
</h3>
46-
<p className="text-gray-600 text-sm leading-relaxed dark:text-gray-300">
47-
{description}
48-
</p>
33+
{date && (
34+
<span className="whitespace-nowrap font-medium text-gray-500 text-xs dark:text-gray-400">
35+
{date}
36+
</span>
37+
)}
4938
</div>
50-
</CardContent>
51-
</Card>
52-
</Link>
53-
</motion.div>
39+
<p className="text-gray-600 text-sm leading-relaxed dark:text-gray-300">
40+
{description}
41+
</p>
42+
{tags.length > 0 && (
43+
<div className="flex flex-wrap gap-2 pt-2">
44+
{tags.map((tag, index) => {
45+
const getTagColor = (tag: string) => {
46+
const languages = [
47+
"JavaScript",
48+
"Python",
49+
"TypeScript",
50+
"Java",
51+
"Go",
52+
"Rust",
53+
];
54+
const frameworks = [
55+
"Langchain",
56+
"mastra",
57+
"CrewAI",
58+
"LangGraph",
59+
"OpenAI",
60+
"Anthropic",
61+
"Next.js",
62+
];
63+
const integrations = [
64+
"Slack",
65+
"GitHub",
66+
"Gmail",
67+
"Discord",
68+
"Notion",
69+
"Linear",
70+
"Jira",
71+
"Weaviate",
72+
"Email",
73+
"Stytch",
74+
];
75+
76+
if (languages.includes(tag)) {
77+
return "bg-gradient-to-br from-emerald-600 to-emerald-800";
78+
}
79+
if (frameworks.includes(tag)) {
80+
return "bg-gradient-to-br from-blue-600 to-blue-800";
81+
}
82+
if (integrations.includes(tag)) {
83+
return "bg-gradient-to-br from-yellow-600 to-yellow-800";
84+
}
85+
return "bg-gradient-to-br from-gray-600 to-gray-800";
86+
};
87+
88+
return (
89+
<span
90+
className={`inline-flex w-fit shrink-0 items-center justify-center overflow-hidden whitespace-nowrap rounded-md border-0 border-transparent px-2 py-1 font-semibold text-[0.725rem] text-white uppercase leading-4 tracking-wide shadow-md ${getTagColor(tag)}`}
91+
key={index}
92+
>
93+
{tag}
94+
</span>
95+
);
96+
})}
97+
</div>
98+
)}
99+
</div>
100+
</CardContent>
101+
</Card>
102+
</Link>
54103
);
55104
}

app/en/home/_meta.tsx

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,6 +51,9 @@ export const meta: MetaRecord = {
5151
"api-keys": {
5252
title: "Get an API key",
5353
},
54+
examples: {
55+
title: "Example agents",
56+
},
5457
"-- Authoring Tools": {
5558
type: "separator",
5659
title: "Authoring Tools",

0 commit comments

Comments
 (0)