Skip to content

Commit 4aad95c

Browse files
committed
seo optimization
1 parent 4854d23 commit 4aad95c

File tree

11 files changed

+134
-24
lines changed

11 files changed

+134
-24
lines changed

app/badge/builder/[[...login]]/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,9 +4,9 @@ import { Header } from '@/components/header/header';
44
import { Page } from '@/components/page/page';
55

66
export const metadata: Metadata = {
7-
title: 'GitRanks · GitHub Profile Analytics & Rankings',
7+
title: 'Badge Builder · GitRanks',
88
description:
9-
'Explore ranks based on stars, followers, contributions, and more. Dive into dynamic leaderboards and find out how you measure up against developers worldwide.',
9+
'Generate custom GitHub badges with GitRanks. Show your global and country rankings, percentile, monthly changes, and progress toward the next tier.',
1010
};
1111

1212
export default function BadgeLayout({ children }: Readonly<{ children: React.ReactNode }>) {

app/badge/page.tsx

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
import { redirect } from 'next/navigation';
2+
3+
export default async function BadgePage() {
4+
redirect(`/badge/gallery`);
5+
}

app/by/[rankingType]/layout.tsx

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3,21 +3,31 @@
33
import type { Metadata } from 'next';
44
import { unstable_cacheLife as cacheLife } from 'next/cache';
55

6+
import { RANK_NAME } from '@/badge/badge.consts';
67
import { Header } from '@/components/header/header';
78
import { Page } from '@/components/page/page';
89
import { RankingHeaderSection } from '@/components/ranking-header-section/ranking-header-section';
910
import { RankingTypeClient } from '@/types/ranking.types';
11+
import { getRankPropByType } from '@/utils/get-rank-prop-by-ranking-type';
1012

1113
type GlobalRankingProps = {
1214
children: React.ReactNode;
1315
params: Promise<{ rankingType: RankingTypeClient; page: string }>;
1416
};
1517

16-
export const metadata: Metadata = {
17-
title: 'GitRanks · GitHub Profile Analytics & Rankings',
18-
description:
19-
'Explore ranks based on stars, followers, contributions, and more. Dive into dynamic leaderboards and find out how you measure up against developers worldwide.',
20-
};
18+
export async function generateMetadata({ params }: GlobalRankingProps): Promise<Metadata> {
19+
const { rankingType, page: pageParam } = await params;
20+
21+
const rankProp = getRankPropByType(rankingType);
22+
const rankName = RANK_NAME[rankProp];
23+
const page = parseInt(pageParam ?? '1', 10);
24+
25+
return {
26+
title: `${rankName}ing · Page ${page} · GitRanks`,
27+
description:
28+
'Explore ranks based on stars, followers, contributions, and more. Dive into dynamic leaderboards and find out how you measure up against developers worldwide.',
29+
};
30+
}
2131

2232
export async function generateStaticParams() {
2333
const page = '1';

app/countries/[orderBy]/[page]/layout.tsx

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,31 @@
11
import { FlameIcon } from 'lucide-react';
22
import type { Metadata } from 'next';
33

4+
import { RANK_NAME } from '@/badge/badge.consts';
45
import { Header } from '@/components/header/header';
56
import { Page } from '@/components/page/page';
67
import { Badge } from '@/components/ui/badge';
78
import { CountrySummaryOrder } from '@/types/generated/graphql';
9+
import { UserRankProp } from '@/types/ranking.types';
810

911
import { CountryOrderSwitcher } from './components/country-order-switcher';
1012

11-
export const metadata: Metadata = {
12-
title: 'Country Rankings · GitRanks · GitHub Profile Analytics & Rankings',
13-
description:
14-
'Explore ranks based on stars, followers, contributions, and more. Dive into dynamic leaderboards and find out how you measure up against developers worldwide.',
13+
type CountriesLayoutProps = {
14+
children: React.ReactNode;
15+
params: Promise<{ orderBy: CountrySummaryOrder; page: string }>;
1516
};
1617

17-
type CountriesLayoutProps = Readonly<{ children: React.ReactNode; params: Promise<{ orderBy: CountrySummaryOrder }> }>;
18+
export async function generateMetadata({ params }: CountriesLayoutProps): Promise<Metadata> {
19+
const { orderBy, page } = await params;
20+
21+
const rankProp = orderBy.slice(0, 1) as UserRankProp;
22+
23+
return {
24+
title: `Country ${RANK_NAME[rankProp]}ing · Page ${page} · GitRanks`,
25+
description:
26+
'Discover GitHub country rankings. Compare stars, contributions, and followers by nation, updated monthly. See where your country ranks.',
27+
};
28+
}
1829

1930
export default async function CountriesLayout({ children, params }: CountriesLayoutProps) {
2031
const { orderBy } = await params;
@@ -41,13 +52,13 @@ export default async function CountriesLayout({ children, params }: CountriesLay
4152
</p>
4253
<ul className="list-disc pl-6 mb-4">
4354
<li>
44-
<strong>User Stars</strong> stars on repos owned by developers from this country
55+
<strong>User Stars</strong> - stars on repos owned by developers from this country
4556
</li>
4657
<li>
47-
🔀 <strong>Contrib Stars</strong> stars on external repos where they’ve merged PRs
58+
🔀 <strong>Contrib Stars</strong> - stars on external repos where they’ve merged PRs
4859
</li>
4960
<li>
50-
👥 <strong>Followers</strong> combined GitHub followers of those developers
61+
👥 <strong>Followers</strong> - combined GitHub followers of those developers
5162
</li>
5263
</ul>
5364
<p>

app/country/[name]/[rankingType]/[page]/layout.tsx

Lines changed: 16 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,34 @@
11
'use cache';
22

3-
import type { Metadata } from 'next';
3+
import { Metadata } from 'next';
44
import { unstable_cacheLife as cacheLife } from 'next/cache';
55

6+
import { RANK_NAME } from '@/badge/badge.consts';
67
import { Header } from '@/components/header/header';
78
import { Page } from '@/components/page/page';
89
import { RankingHeaderSection } from '@/components/ranking-header-section/ranking-header-section';
910
import { fetchCountries } from '@/graphql/helpers/fetch-countries';
1011
import { RankingTypeClient } from '@/types/ranking.types';
12+
import { getRankPropByType } from '@/utils/get-rank-prop-by-ranking-type';
1113

1214
type CountryRankingProps = {
1315
children: React.ReactNode;
1416
params: Promise<{ name: string; rankingType: RankingTypeClient; page: string }>;
1517
};
1618

17-
export const metadata: Metadata = {
18-
title: 'GitRanks · GitHub Profile Analytics & Rankings',
19-
description:
20-
'Explore ranks based on stars, followers, contributions, and more. Dive into dynamic leaderboards and find out how you measure up against developers worldwide.',
21-
};
19+
export async function generateMetadata({ params }: CountryRankingProps): Promise<Metadata> {
20+
const { rankingType, page: pageParam, name } = await params;
21+
22+
const rankProp = getRankPropByType(rankingType);
23+
const rankName = RANK_NAME[rankProp];
24+
const page = parseInt(pageParam, 10);
25+
26+
return {
27+
title: `${decodeURIComponent(name)} ${rankName}ing · Page ${page} · GitRanks`,
28+
description:
29+
'Discover GitHub profile rankings by country with GitRanks. See the top developers ranked by stars, contributions, and followers - refreshed daily.',
30+
};
31+
}
2232

2333
export async function generateStaticParams() {
2434
const countries = await fetchCountries();

app/country/sitemap.ts

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
import { fetchCountries } from '@/graphql/helpers/fetch-countries';
2+
3+
export default async function sitemap() {
4+
const pagesToParse = 10;
5+
const pages = Array.from({ length: pagesToParse }, (_, i) => i + 1);
6+
const rankingTypes = ['contributions', 'followers', 'stars'] as const;
7+
const countries = await fetchCountries();
8+
const countryNames = countries.slice(0, 100).map((country) => country.name);
9+
10+
return pages.flatMap((page) => {
11+
const priority = 0.9 - (page / pagesToParse) * 0.5;
12+
return countryNames.flatMap((name) => {
13+
return rankingTypes.map((rankingType) => ({
14+
url: `${process.env.NEXT_PUBLIC_URI}/country/${name}/${rankingType}/${page}`,
15+
changeFrequency: 'monthly',
16+
priority,
17+
}));
18+
});
19+
});
20+
}

app/profile/[login]/layout.tsx

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ export async function generateMetadata({ params }: { params: Promise<{ login: st
2525
const { s, c, f } = user.rankGlobal ?? {};
2626

2727
return {
28-
title: `${login} · GitHub Profile Analytics · GitRanks`,
29-
description: `Explore GitHub profile analytics for ${login} ranked #${s} by stars, #${c} by contributions, and #${f} by followers.`,
28+
title: `${login} · GitRanks · GitHub Profile Analytics`,
29+
description: `Explore GitHub profile analytics for ${login} - ranked #${s} by stars, #${c} by contributions, and #${f} by followers.`,
3030
openGraph: {
3131
images: [user.avatarUrl!],
3232
},

app/sitemap.ts

Lines changed: 40 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
export default async function sitemap() {
2+
const priority = 1;
3+
return [
4+
{
5+
url: `${process.env.NEXT_PUBLIC_URI}`,
6+
changeFrequency: 'monthly',
7+
priority,
8+
},
9+
{
10+
url: `${process.env.NEXT_PUBLIC_URI}/countries/stars/1`,
11+
changeFrequency: 'monthly',
12+
priority,
13+
},
14+
{
15+
url: `${process.env.NEXT_PUBLIC_URI}/countries/contributions/1`,
16+
changeFrequency: 'monthly',
17+
priority,
18+
},
19+
{
20+
url: `${process.env.NEXT_PUBLIC_URI}/countries/followers/1`,
21+
changeFrequency: 'monthly',
22+
priority,
23+
},
24+
{
25+
url: `${process.env.NEXT_PUBLIC_URI}/countries/users/1`,
26+
changeFrequency: 'monthly',
27+
priority,
28+
},
29+
{
30+
url: `${process.env.NEXT_PUBLIC_URI}/badge/gallery`,
31+
changeFrequency: 'monthly',
32+
priority,
33+
},
34+
{
35+
url: `${process.env.NEXT_PUBLIC_URI}/badge/builder`,
36+
changeFrequency: 'monthly',
37+
priority,
38+
},
39+
];
40+
}

badge/badge.consts.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,4 +6,5 @@ export const RANK_NAME = {
66
[UserRankProp.s]: 'Stars Rank',
77
[UserRankProp.c]: 'Contributor Rank',
88
[UserRankProp.f]: 'Followers Rank',
9+
u: 'Users Rank',
910
};

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
"standalone": "dotenv -e .env.local node .next/standalone/server.js",
1313
"icons": "pnpm dlx @svgr/cli --out-dir components/icons --filename-case kebab --typescript --no-dimensions --replace-attr-values \"#000=currentColor\" -- public/icons",
1414
"figma:icons": "tsc lib/figma/download-icons.ts --outDir dist && dotenv -e .env.local node dist/download-icons.js && pnpm run icons",
15-
"indexnow": "tsx lib/indexnow/indexnow-submit.ts --sitemap=https://gitranks.com/profile/login/sitemap.xml --host=gitranks.com --key=ef3b3dfb08554fce864bebfc1702134c --keyLocation=https://gitranks.com/ef3b3dfb08554fce864bebfc1702134c.txt"
15+
"indexnow:profile": "tsx lib/indexnow/indexnow-submit.ts"
1616
},
1717
"dependencies": {
1818
"@auth/mongodb-adapter": "^3.10.0",

0 commit comments

Comments
 (0)