Skip to content

Commit 8afa7d1

Browse files
authored
fix: static routes (#2)
* fix: static routes * chore: tweaks * chore: up * chore: up * chore: up
1 parent 670a547 commit 8afa7d1

11 files changed

Lines changed: 127 additions & 50 deletions

File tree

‎.github/workflows/pull_request.yml‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -96,6 +96,7 @@ jobs:
9696
run: pnpm build
9797
env:
9898
CLOUDFLARE_ENV: preview
99+
GIT_SHA: ${{ github.event.pull_request.head.sha }}
99100

100101
- name: Deploy preview
101102
uses: cloudflare/wrangler-action@da0e0dfe58b7a431659754fdf3f186c529afbe65 # v3.14.1

‎.github/workflows/verify.yml‎

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -21,8 +21,13 @@ jobs:
2121
- name: Lint
2222
run: pnpm check
2323

24+
- name: Run migrations
25+
run: pnpm exec wrangler d1 migrations apply DB --local
26+
2427
- name: Generate types
25-
run: pnpm gen:types
28+
run: |
29+
pnpm gen:types
30+
pnpm db:codegen
2631
2732
- name: Check types
2833
run: pnpm check:types

‎AGENTS.md‎

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,3 +51,4 @@ App runs in Docker via `docker compose up`. Use these to debug:
5151

5252
- **Tailwind CSS v4** - Use `@import "tailwindcss"` in CSS; utility classes in components
5353
- Use logical properties for RTL/LTR support (e.g. `ms-4`/`me-4` instead of `ml-4`/`mr-4`, `start-2`/`end-2` instead of `left-2`/`right-2`)
54+
- Do NOT concatenate class names for conditional styles. Use `data-*` attributes with Tailwind's `data-[...]` variant instead (e.g., `data-[active]:bg-blue9` + `data-active={cond ? '' : undefined}`)

‎src/lib/db.gen.ts‎

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ type request = {
1111
country: string | null
1212
created_at: k.Generated<string>
1313
hostname: string
14-
id: string
14+
id: k.Generated<string>
1515
path: string
1616
query: string | null
1717
url: string

‎src/lib/known-md-sites.ts‎

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,28 @@ function appendMdWithIndex(url: URL): URL {
7676
return mdUrl
7777
}
7878

79+
const githubDocsLangs = new Set([
80+
'cn',
81+
'de',
82+
'en',
83+
'es',
84+
'fr',
85+
'ja',
86+
'ko',
87+
'pt',
88+
'ru',
89+
'zh',
90+
])
91+
7992
function githubDocsArticle(url: URL): MdUrlResult {
8093
const mdUrl = new URL(url.href)
8194
mdUrl.pathname = '/api/article'
82-
mdUrl.searchParams.set('pathname', url.pathname)
95+
const firstSegment = url.pathname.split('/')[1]
96+
const pathname =
97+
firstSegment && githubDocsLangs.has(firstSegment)
98+
? url.pathname
99+
: `/en${url.pathname}`
100+
mdUrl.searchParams.set('pathname', pathname)
83101
return {
84102
url: mdUrl,
85103
parse: (content) => {

‎src/routeTree.gen.ts‎

Lines changed: 21 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,17 @@
99
// Additionally, you should also exclude this file from your linter and/or formatter to prevent it from being checked or modified.
1010

1111
import { Route as rootRouteImport } from './routes/__root'
12+
import { Route as SkillsRouteImport } from './routes/skills'
1213
import { Route as McpRouteImport } from './routes/mcp'
1314
import { Route as LlmsDottxtRouteImport } from './routes/llms[.]txt'
1415
import { Route as SplatRouteImport } from './routes/$'
1516
import { Route as IndexRouteImport } from './routes/index'
1617

18+
const SkillsRoute = SkillsRouteImport.update({
19+
id: '/skills',
20+
path: '/skills',
21+
getParentRoute: () => rootRouteImport,
22+
} as any)
1723
const McpRoute = McpRouteImport.update({
1824
id: '/mcp',
1925
path: '/mcp',
@@ -40,37 +46,48 @@ export interface FileRoutesByFullPath {
4046
'/$': typeof SplatRoute
4147
'/llms.txt': typeof LlmsDottxtRoute
4248
'/mcp': typeof McpRoute
49+
'/skills': typeof SkillsRoute
4350
}
4451
export interface FileRoutesByTo {
4552
'/': typeof IndexRoute
4653
'/$': typeof SplatRoute
4754
'/llms.txt': typeof LlmsDottxtRoute
4855
'/mcp': typeof McpRoute
56+
'/skills': typeof SkillsRoute
4957
}
5058
export interface FileRoutesById {
5159
__root__: typeof rootRouteImport
5260
'/': typeof IndexRoute
5361
'/$': typeof SplatRoute
5462
'/llms.txt': typeof LlmsDottxtRoute
5563
'/mcp': typeof McpRoute
64+
'/skills': typeof SkillsRoute
5665
}
5766
export interface FileRouteTypes {
5867
fileRoutesByFullPath: FileRoutesByFullPath
59-
fullPaths: '/' | '/$' | '/llms.txt' | '/mcp'
68+
fullPaths: '/' | '/$' | '/llms.txt' | '/mcp' | '/skills'
6069
fileRoutesByTo: FileRoutesByTo
61-
to: '/' | '/$' | '/llms.txt' | '/mcp'
62-
id: '__root__' | '/' | '/$' | '/llms.txt' | '/mcp'
70+
to: '/' | '/$' | '/llms.txt' | '/mcp' | '/skills'
71+
id: '__root__' | '/' | '/$' | '/llms.txt' | '/mcp' | '/skills'
6372
fileRoutesById: FileRoutesById
6473
}
6574
export interface RootRouteChildren {
6675
IndexRoute: typeof IndexRoute
6776
SplatRoute: typeof SplatRoute
6877
LlmsDottxtRoute: typeof LlmsDottxtRoute
6978
McpRoute: typeof McpRoute
79+
SkillsRoute: typeof SkillsRoute
7080
}
7181

7282
declare module '@tanstack/react-router' {
7383
interface FileRoutesByPath {
84+
'/skills': {
85+
id: '/skills'
86+
path: '/skills'
87+
fullPath: '/skills'
88+
preLoaderRoute: typeof SkillsRouteImport
89+
parentRoute: typeof rootRouteImport
90+
}
7491
'/mcp': {
7592
id: '/mcp'
7693
path: '/mcp'
@@ -107,6 +124,7 @@ const rootRouteChildren: RootRouteChildren = {
107124
SplatRoute: SplatRoute,
108125
LlmsDottxtRoute: LlmsDottxtRoute,
109126
McpRoute: McpRoute,
127+
SkillsRoute: SkillsRoute,
110128
}
111129
export const routeTree = rootRouteImport
112130
._addFileChildren(rootRouteChildren)

‎src/routes/__root.tsx‎

Lines changed: 23 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -49,23 +49,40 @@ function RootComponent() {
4949
{theme}
5050
</button>
5151
)}
52+
{prNumber(__HOST__) && (
53+
<a
54+
className="hover:text-gray10"
55+
href={`https://github.com/wevm/curl.md/pull/${prNumber(__HOST__)}`}
56+
rel="noopener noreferrer"
57+
target="_blank"
58+
>
59+
#{prNumber(__HOST__)}
60+
</a>
61+
)}
5262
<a
5363
className="hover:text-gray10"
54-
href={
55-
__GIT_SHA__ === 'dev'
56-
? 'https://github.com/wevm/curl.md'
57-
: `https://github.com/wevm/curl.md/commit/${__GIT_SHA__}`
58-
}
64+
href={commitHref(__GIT_SHA__)}
5965
rel="noopener noreferrer"
6066
target="_blank"
6167
>
62-
{__GIT_SHA__}
68+
{__GIT_SHA__.slice(0, 7)}
6369
</a>
6470
</div>
6571
</>
6672
)
6773
}
6874

75+
function commitHref(sha: string) {
76+
if (sha === 'dev') return 'https://github.com/wevm/curl.md'
77+
const pr = prNumber(__HOST__)
78+
if (pr) return `https://github.com/wevm/curl.md/pull/${pr}/commits/${sha}`
79+
return `https://github.com/wevm/curl.md/commit/${sha}`
80+
}
81+
82+
function prNumber(host: string) {
83+
return host.match(/^pr(\d+)\./)?.[1]
84+
}
85+
6986
function RootDocument(props: React.PropsWithChildren) {
7087
const { children } = props
7188
return (

‎src/routes/index.tsx‎

Lines changed: 26 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,8 @@ function Home() {
2020
return (
2121
<>
2222
<header className="mb-10">
23-
<h1 className="text-base">
24-
<span className="font-bold">curl.md</span>
25-
<span className="ms-2 text-gray6">Fetch any URL as markdown</span>
26-
</h1>
23+
<h1 className="text-base font-bold">curl.md</h1>
24+
<p className="mt-1 text-base text-gray6">Fetch any URL as markdown</p>
2725
</header>
2826

2927
<h2 className="text-sm text-gray10">
@@ -38,14 +36,14 @@ function Home() {
3836
</CopyableCommand>
3937
<span className="block mt-3 text-gray8"># Focus output with query</span>
4038
<CopyableCommand
41-
command={`curl ${__HOST__}/react.dev?q=fullstack+support`}
39+
command={`curl ${__HOST__}/react.dev?q=fullstack+framework+support`}
4240
>
4341
curl {__HOST__}
4442
<span className="text-blue9">/react.dev</span>
4543
<span className="text-purple9">
4644
?q=
4745
<wbr />
48-
fullstack+support
46+
fullstack+framework+support
4947
</span>
5048
</CopyableCommand>
5149
</pre>
@@ -77,10 +75,10 @@ function Home() {
7775
}
7876

7977
const examples = [
80-
['react.dev', 'fullstack support'],
81-
['developer.mozilla.org/en-US/docs/Web/API/Fetch_API'],
82-
['en.wikipedia.org/wiki/Linux', 'kernel history'],
83-
['docs.github.com/en/rest', 'rate limiting'],
78+
['react.dev', 'fullstack framework support'],
79+
['developer.mozilla.org/docs/Web/API/Fetch_API', 'Response'],
80+
['wikipedia.org/wiki/Linux', 'kernel history'],
81+
['docs.github.com/en/actions', 'workflow syntax'],
8482
] as const
8583

8684
function Playground() {
@@ -189,9 +187,12 @@ function Playground() {
189187
<div className="bg-bg2">
190188
<div className="flex items-center gap-2 px-3 py-2 text-xs text-gray8">
191189
<span>{pending ? pendingDisplayUrl : result?.fetchedUrl}</span>
192-
{result && (
190+
{result && (!pending || refreshingRef.current) && (
193191
<button
194-
className={`hover:text-gray11 ${pending && refreshingRef.current ? 'animate-spin' : ''}`}
192+
className="hover:text-gray11 data-[spinning]:animate-spin"
193+
data-spinning={
194+
pending && refreshingRef.current ? '' : undefined
195+
}
195196
disabled={pending}
196197
onClick={() => {
197198
freshRef.current = true
@@ -221,7 +222,7 @@ function Playground() {
221222
<div className="mt-2 grid grid-cols-1 gap-1.5 text-xs sm:grid-cols-2">
222223
{examples.map(([url, q]) => (
223224
<button
224-
className="bg-bg2 px-3 py-2 text-start opacity-50 grayscale hover:opacity-100 hover:grayscale-0 focus:opacity-100 focus:grayscale-0"
225+
className="bg-bg2 px-3 py-2 text-start opacity-75 grayscale hover:opacity-100 hover:grayscale-0 focus:opacity-100 focus:grayscale-0 sm:opacity-50"
225226
key={`${url}${q ?? ''}`}
226227
onClick={() => {
227228
flushSync(() => {
@@ -234,20 +235,19 @@ function Playground() {
234235
>
235236
<span className="block truncate text-gray10">
236237
{url.split('/')[0]}
237-
{q && url.includes('/') && (
238-
<span className="text-blue9">
239-
/{url.split('/').slice(1).join('/')}
240-
</span>
241-
)}
242238
</span>
243-
{!q && url.includes('/') && (
244-
<span className="block truncate text-blue9">
245-
/{url.split('/').slice(1).join('/')}
246-
</span>
247-
)}
248-
{q && (
249-
<span className="block truncate text-purple9">
250-
?q={q.replace(/ /g, '+')}
239+
{(url.includes('/') || q) && (
240+
<span className="block truncate">
241+
{url.includes('/') && (
242+
<span className="text-blue9">
243+
/{url.split('/').slice(1).join('/')}
244+
</span>
245+
)}
246+
{q && (
247+
<span className="text-purple9">
248+
?q={q.replace(/ /g, '+')}
249+
</span>
250+
)}
251251
</span>
252252
)}
253253
</button>

‎src/routes/skills.ts‎

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
import { createFileRoute } from '@tanstack/react-router'
2+
3+
export const Route = createFileRoute('/skills')({
4+
server: {
5+
handlers: {
6+
GET: async (options) => {
7+
return Response.redirect(
8+
new URL('/skills/index.json', options.request.url).href,
9+
301,
10+
)
11+
},
12+
},
13+
},
14+
})

‎src/worker-configuration.d.ts‎

Lines changed: 4 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,10 @@
11
/* eslint-disable */
2-
// Generated by Wrangler by running `wrangler types src/worker-configuration.d.ts` (hash: d073ec20d62ef5917bc18501cc3fe4b4)
2+
// Generated by Wrangler by running `wrangler types src/worker-configuration.d.ts` (hash: d1210e4b995e995fd23441c43fe4c292)
33
// Runtime types generated with workerd@1.20260212.0 2026-02-12 nodejs_compat
44
declare namespace Cloudflare {
55
interface ProductionEnv {
66
KV: KVNamespace;
7+
DB: D1Database;
78
AI: Ai;
89
HOST: "curl.md";
910
CLOUDFLARE_ACCOUNT_ID: string;
@@ -12,6 +13,7 @@ declare namespace Cloudflare {
1213
}
1314
interface PreviewEnv {
1415
KV: KVNamespace;
16+
DB: D1Database;
1517
AI: Ai;
1618
HOST: "__PREVIEW_APEX__.curl.md";
1719
CLOUDFLARE_ACCOUNT_ID: string;
@@ -23,9 +25,9 @@ declare namespace Cloudflare {
2325
CLOUDFLARE_API_TOKEN: string;
2426
WRANGLER_SEND_METRICS: string;
2527
KV: KVNamespace;
28+
DB: D1Database;
2629
AI: Ai;
2730
HOST: "curl.md" | "__PREVIEW_APEX__.curl.md" | "curl.local";
28-
DB?: D1Database;
2931
}
3032
}
3133
interface Env extends Cloudflare.Env {}

0 commit comments

Comments
 (0)