Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 2 additions & 3 deletions public/favicon.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 3 additions & 3 deletions public/llms.txt
Original file line number Diff line number Diff line change
Expand Up @@ -7,18 +7,18 @@ tightknit.dev is the landing page for tightknit's open source repos. The repo gr
## Featured repos

- [block-kitchen](https://github.com/tightknitai/block-kitchen): Compose Slack Block Kit messages with a React-style API.
- [slack-hono](https://github.com/tightknitai/slack-hono): Build Slack apps on Hono. Works on Workers, Bun, Node.
- [slack-block-kit-validator](https://github.com/tightknitai/slack-block-kit-validator): Validate Slack Block Kit payloads before you send them.
- [slack-hono](https://github.com/tightknitai/slack-hono): Build Slack apps on Hono — works on Workers, Bun, Node.
- [slack-hono-template](https://github.com/tightknitai/slack-hono-template): Starter template for shipping a Slack app with slack-hono on Cloudflare Workers.

## Principles

- **Made to be forked.** Every repo is MIT (or compatible). Lift it, mod it, ship it.
- **TypeScript first.** Strict mode on, types as docs, end-to-end inference where possible. Runtimes: Node, Bun, Cloudflare Workers.
- **Built in public.** Roadmaps in GitHub issues, releases on a real changelog, maintainers read PRs.
- **From the Tightknit team.** Built by the team behind Tightknit, the #1 community platform on Slack. These are the libraries and patterns we reach for when shipping Slack apps, open sourced for yours.

## Links

- [GitHub org (tightknitai)](https://github.com/tightknitai): Source of truth for all open source repos.
- [tightknit.ai](https://tightknit.ai): The company behind these toolscommunity platform for developer-facing teams.
- [tightknit.ai](https://tightknit.ai): The company behind these tools. The #1 community platform on Slack.
- [tightknit.dev source](https://github.com/TightknitAI/tightknit.dev): Source code for this landing page (Astro 5, Tailwind v4, Cloudflare Workers).
2 changes: 1 addition & 1 deletion public/og.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
10 changes: 5 additions & 5 deletions src/components/Footer.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ const year = new Date().getFullYear();
---

<footer class="bg-cream-dim border-ink relative overflow-hidden border-t-[3px]">
<!-- Giant brand wordmark SVG auto-fits to viewport width -->
<!-- Giant brand wordmark; SVG auto-fits to viewport width -->
<div
class="pointer-events-none px-4 pt-12 select-none sm:px-6 lg:px-10 lg:pt-16"
aria-hidden="true"
Expand Down Expand Up @@ -49,7 +49,7 @@ const year = new Date().getFullYear();
</li>
<li>
<a href="#repos" class="hover:text-pink decoration-2 underline-offset-4 hover:underline"
>all repos </a
>all repos </a
>
</li>
</ul>
Expand All @@ -70,10 +70,10 @@ const year = new Date().getFullYear();
</li>
<li>
<a
href="https://tightknit.ai/blog"
href="https://community.tightknit.ai"
target="_blank"
rel="noopener"
class="hover:text-pink decoration-2 underline-offset-4 hover:underline">blog →</a
class="hover:text-pink decoration-2 underline-offset-4 hover:underline">community →</a
>
</li>
</ul>
Expand Down Expand Up @@ -116,7 +116,7 @@ const year = new Date().getFullYear();
class="border-ink/15 text-ink/60 flex flex-col gap-4 border-t-2 pt-6 font-mono text-[12px] tracking-[0.12em] uppercase sm:flex-row sm:items-center sm:justify-between"
>
<div>
© {year} tightknit made with <Heart
© {year} tightknit · made with <Heart
class="mx-0.5 inline-block h-3.5 w-3.5 align-[-3px]"
/> in public
</div>
Expand Down
4 changes: 2 additions & 2 deletions src/components/Heart.astro
Original file line number Diff line number Diff line change
Expand Up @@ -18,12 +18,12 @@ const {
{
shadow && (
<polygon
points="21,9 33,9 33,27 39,27 39,9 51,9 51,15 57,15 57,21 63,21 63,39 57,39 57,45 51,45 51,51 45,51 45,57 39,57 39,63 33,63 33,57 27,57 27,51 21,51 21,45 15,45 15,39 9,39 9,21 15,21 15,15 21,15"
points="15,9 33,9 33,21 39,21 39,9 57,9 57,15 63,15 63,39 57,39 57,45 51,45 51,51 45,51 45,57 39,57 39,63 33,63 33,57 27,57 27,51 21,51 21,45 15,45 15,39 9,39 9,15 15,15"
fill={shadowFill}
/>
)
}
<polygon
points="17,5 29,5 29,23 35,23 35,5 47,5 47,11 53,11 53,17 59,17 59,35 53,35 53,41 47,41 47,47 41,47 41,53 35,53 35,59 29,59 29,53 23,53 23,47 17,47 17,41 11,41 11,35 5,35 5,17 11,17 11,11 17,11"
points="11,5 29,5 29,17 35,17 35,5 53,5 53,11 59,11 59,35 53,35 53,41 47,41 47,47 41,47 41,53 35,53 35,59 29,59 29,53 23,53 23,47 17,47 17,41 11,41 11,35 5,35 5,11 11,11"
fill={fill}></polygon>
</svg>
7 changes: 2 additions & 5 deletions src/components/Hero.astro
Original file line number Diff line number Diff line change
@@ -1,8 +1,5 @@
---
interface Props {
repoCount: number;
}
const { repoCount } = Astro.props;

---

<section class="border-ink relative overflow-hidden border-b-[3px]">
Expand Down Expand Up @@ -49,7 +46,7 @@ const { repoCount } = Astro.props;
<div class="mb-8 inline-flex items-center gap-3">
<span class="bg-pink inline-block h-2.5 w-2.5 animate-pulse"></span>
<span class="text-ink/70 font-mono text-[12px] tracking-[0.18em] uppercase">
{repoCount} open source repos · maintained in public
for teams building on slack · open source
</span>
</div>

Expand Down
4 changes: 2 additions & 2 deletions src/components/Manifesto.astro
Original file line number Diff line number Diff line change
Expand Up @@ -12,8 +12,8 @@ const items = [
},
{
n: '03',
title: 'Built in public.',
body: 'Roadmaps in GitHub issues, releases on a real changelog, and the maintainers actually read PRs.',
title: 'From the Tightknit team.',
body: 'Built by the team behind Tightknit, the #1 community platform on Slack. These are the libraries and patterns we reach for when shipping Slack apps, open sourced for yours.',
},
];
---
Expand Down
15 changes: 10 additions & 5 deletions src/components/RepoCard.astro
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ const dividerColor = isInverse ? 'border-cream/25' : 'border-ink/15';
}

<div
class={`flex items-center gap-4 pt-4 border-t-2 ${dividerColor} font-mono text-[12px] uppercase tracking-[0.08em]`}
class={`flex flex-wrap items-center gap-x-4 gap-y-1 pt-4 border-t-2 ${dividerColor} font-mono text-[12px] uppercase tracking-[0.08em]`}
>
{
repo.language && (
Expand All @@ -73,10 +73,15 @@ const dividerColor = isInverse ? 'border-cream/25' : 'border-ink/15';
</span>
)
}
<span class="flex items-center gap-1">
<span aria-hidden="true">★</span>
{repo.stars}
</span>
{repo.license && <span class="opacity-70">{repo.license}</span>}
{
repo.stars >= 10 && (
<span class="flex items-center gap-1">
<span aria-hidden="true">★</span>
{repo.stars}
</span>
)
}
<span class="ml-auto opacity-70">{formatRelativeTime(repo.pushedAt)}</span>
</div>
</a>
7 changes: 4 additions & 3 deletions src/components/RepoGrid.astro
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ interface Props {
const { repos } = Astro.props;

// Hand-pick the headline projects; remaining repos sort by stars (already sorted upstream).
const FEATURED_NAMES = ['block-kitchen', 'slack-block-kit-validator', 'slack-hono'];
const FEATURED_NAMES = ['block-kitchen', 'slack-hono', 'slack-block-kit-validator'];
const featured = FEATURED_NAMES.map((name) => repos.find((r) => r.name === name)).filter(
(r): r is Repo => r !== undefined,
);
Expand All @@ -32,12 +32,13 @@ const featuredVariants = ['yellow', 'pink', 'cyan'] as const;
</h2>
</div>
<p class="text-ink/70 max-w-md font-mono text-sm leading-relaxed">
Auto-synced from <a
Block Kit tooling, app frameworks, and validators we use to ship Slack apps faster. Open
sourced on <a
href="https://github.com/tightknitai"
class="decoration-pink hover:text-pink underline decoration-2 underline-offset-2"
target="_blank"
rel="noopener">github.com/tightknitai</a
> at build time. Sorted by stars.
>.
</p>
</div>

Expand Down
4 changes: 2 additions & 2 deletions src/layouts/Layout.astro
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ interface Props {
}

const {
title = 'tightknit.dev open source tools for Slack apps & AI agents',
title = 'tightknit.dev · open source tools for Slack apps & AI agents',
description = 'Open source TypeScript libraries, agents, and developer tools for building Slack apps and AI agents. Built and maintained in public by the team at tightknit.ai.',
image = '/og.png',
jsonLd = [],
Expand Down Expand Up @@ -76,7 +76,7 @@ const allJsonLd = [organizationLd, websiteLd, ...jsonLd];
<meta property="og:image" content={ogImageUrl} />
<meta property="og:image:width" content="1200" />
<meta property="og:image:height" content="630" />
<meta property="og:image:alt" content="tightknit.dev tools for Slack + agents" />
<meta property="og:image:alt" content="tightknit.dev · tools for Slack + agents" />

<meta name="twitter:card" content="summary_large_image" />
<meta name="twitter:site" content="@tightknitai" />
Expand Down
12 changes: 10 additions & 2 deletions src/lib/github.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ export interface Repo {
stars: number;
forks: number;
language: string | null;
license: string | null;
topics: string[];
pushedAt: string;
archived: boolean;
Expand All @@ -22,6 +23,7 @@ interface GitHubRepoApi {
stargazers_count: number;
forks_count: number;
language: string | null;
license: { spdx_id: string | null; name: string | null } | null;
topics: string[];
pushed_at: string;
archived: boolean;
Expand Down Expand Up @@ -105,12 +107,14 @@ export async function getOrgRepos(org: string): Promise<Repo[]> {
(r): Repo => ({
name: r.name,
fullName: r.full_name,
description: r.description,
description: r.description ? r.description.replace(/\s*—\s*/g, ', ') : null,
url: r.html_url,
homepage: r.homepage,
stars: r.stargazers_count,
forks: r.forks_count,
language: r.language,
license:
r.license?.spdx_id && r.license.spdx_id !== 'NOASSERTION' ? r.license.spdx_id : null,
topics: sortTopics(r.topics ?? []),
pushedAt: r.pushed_at,
archived: r.archived,
Expand All @@ -130,6 +134,7 @@ const FALLBACK_REPOS: Repo[] = [
stars: 0,
forks: 0,
language: 'TypeScript',
license: 'MIT',
topics: ['slack', 'block-kit'],
pushedAt: new Date().toISOString(),
archived: false,
Expand All @@ -144,6 +149,7 @@ const FALLBACK_REPOS: Repo[] = [
stars: 0,
forks: 0,
language: 'TypeScript',
license: 'MIT',
topics: ['slack', 'block-kit', 'validation'],
pushedAt: new Date().toISOString(),
archived: false,
Expand All @@ -152,12 +158,13 @@ const FALLBACK_REPOS: Repo[] = [
{
name: 'slack-hono',
fullName: 'tightknitai/slack-hono',
description: 'Build Slack apps on Hono — works on Workers, Bun, Node.',
description: 'Build Slack apps on Hono. Works on Workers, Bun, Node.',
url: 'https://github.com/tightknitai/slack-hono',
homepage: null,
stars: 0,
forks: 0,
language: 'TypeScript',
license: 'MIT',
topics: ['slack', 'hono', 'cloudflare-workers'],
pushedAt: new Date().toISOString(),
archived: false,
Expand All @@ -179,6 +186,7 @@ const MANUAL_REPOS: Repo[] = [
stars: 0,
forks: 0,
language: 'TypeScript',
license: 'MIT',
topics: ['slack', 'hono', 'cloudflare-workers', 'template'],
pushedAt: new Date().toISOString(),
archived: false,
Expand Down
4 changes: 2 additions & 2 deletions src/pages/404.astro
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ import Nav from '../components/Nav.astro';
import Footer from '../components/Footer.astro';
---

<Layout title="404 tightknit.dev" description="Page not found.">
<Layout title="404 · tightknit.dev" description="Page not found.">
<Nav />
<main class="border-ink relative overflow-hidden border-b-[3px]">
<div class="grid-bg pointer-events-none absolute inset-0 opacity-90"></div>
Expand All @@ -20,7 +20,7 @@ import Footer from '../components/Footer.astro';
404.
</h1>
<p class="text-ink/85 mt-10 max-w-xl text-lg font-medium">
That page doesn't exist (yet). The repos live below or head back to{' '}
That page doesn't exist (yet). The repos live below, or head back to{' '}
<a
href="/"
class="decoration-pink hover:text-pink underline decoration-[3px] underline-offset-4"
Expand Down
4 changes: 2 additions & 2 deletions src/pages/index.astro
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,7 @@ import { loadRepos } from '../lib/github';
const { repos, usedFallback } = await loadRepos('tightknitai');

if (usedFallback) {
console.warn('[index] using fallback repos — set GITHUB_TOKEN to fetch live data');
console.warn('[index] using fallback repos. Set GITHUB_TOKEN to fetch live data');
}

const itemListLd = {
Expand Down Expand Up @@ -47,7 +47,7 @@ const itemListLd = {
<Layout jsonLd={[itemListLd]}>
<Nav />
<main>
<Hero repoCount={repos.length} />
<Hero />
<RepoGrid repos={repos} />
<Manifesto />
</main>
Expand Down
17 changes: 9 additions & 8 deletions src/pages/index.md.ts
Original file line number Diff line number Diff line change
@@ -1,17 +1,18 @@
import type { APIRoute } from 'astro';
import { formatRelativeTime, loadRepos, type Repo } from '../lib/github';

const FEATURED_NAMES = ['block-kitchen', 'slack-block-kit-validator', 'slack-hono'];
const FEATURED_NAMES = ['block-kitchen', 'slack-hono', 'slack-block-kit-validator'];

function repoLine(repo: Repo): string {
const meta = [
repo.language,
repo.stars > 0 ? `★ ${repo.stars}` : null,
repo.license,
repo.stars >= 10 ? `★ ${repo.stars}` : null,
`updated ${formatRelativeTime(repo.pushedAt)}`,
]
.filter(Boolean)
.join(' · ');
const desc = repo.description ? ` ${repo.description}` : '';
const desc = repo.description ? `: ${repo.description}` : '';
return `- [${repo.name}](${repo.url})${desc} _(${meta})_`;
}

Expand All @@ -26,13 +27,13 @@ export const GET: APIRoute = async () => {
const sections: string[] = [
'# tightknit.dev',
'',
`> Tools for Slack + agents. ${repos.length} open source repos, maintained in public.`,
'> Tools for Slack + agents. For teams building on Slack · open source.',
'',
'Open source libraries, agents, and developer tools shipped by [tightknit.ai](https://tightknit.ai). Built in TypeScript. Made to be forked.',
'',
'## The stack',
'',
'Auto-synced from [github.com/tightknitai](https://github.com/tightknitai) at build time. Sorted by stars.',
'Block Kit tooling, app frameworks, and validators we use to ship Slack apps faster. Open sourced on [github.com/tightknitai](https://github.com/tightknitai).',
];

if (featured.length > 0) {
Expand All @@ -47,11 +48,11 @@ export const GET: APIRoute = async () => {
'',
'## Principles',
'',
"**01 Made to be forked.** Every repo is MIT (or compatible). Lift it, mod it, ship it. The point is that you don't have to ask.",
"**01 · Made to be forked.** Every repo is MIT (or compatible). Lift it, mod it, ship it. The point is that you don't have to ask.",
'',
'**02 TypeScript first.** Strict mode on, types as docs, end-to-end inference where possible. Runtimes: Node, Bun, Cloudflare Workers.',
'**02 · TypeScript first.** Strict mode on, types as docs, end-to-end inference where possible. Runtimes: Node, Bun, Cloudflare Workers.',
'',
'**03 — Built in public.** Roadmaps in GitHub issues, releases on a real changelog, and the maintainers actually read PRs.',
'**03 · From the Tightknit team.** Built by the team behind Tightknit, the #1 community platform on Slack. These are the libraries and patterns we reach for when shipping Slack apps, open sourced for yours.',
'',
'## Links',
'',
Expand Down
6 changes: 3 additions & 3 deletions src/styles/global.css
Original file line number Diff line number Diff line change
Expand Up @@ -75,13 +75,13 @@
.stacked-3d {
color: var(--color-pink);
text-shadow:
4px 4px 0 var(--color-ink),
8px 8px 0 var(--color-ink);
4px 4px 0 var(--color-yellow),
8px 8px 0 var(--color-cyan),
12px 12px 0 var(--color-ink);
}

.marquee {
display: flex;
gap: 3rem;
animation: marquee 30s linear infinite;
white-space: nowrap;
width: max-content;
Expand Down