Skip to content
Open
2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
"devDependencies": {
"@next/eslint-plugin-next": "^14.0.3",
"@types/eslint": "^8.44.7",
"@types/node": "^18.17.0",
"@types/node": "^18.19.34",
"@types/react": "^18.2.37",
"@types/react-dom": "^18.2.15",
"@typescript-eslint/eslint-plugin": "^6.11.0",
Expand Down
1,289 changes: 682 additions & 607 deletions pnpm-lock.yaml

Large diffs are not rendered by default.

48 changes: 44 additions & 4 deletions src/app/api/og/compare/route.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
/* eslint-disable @next/next/no-img-element */
import { ImageResponse } from "next/og";
import { GitTweetBars } from "../../../../components/ui/git-tweet-bars";
import { getPageUrl, getRatioText } from "../../../../lib/utils";
import { getUserTagline, getPageUrl, getRatioText } from "../../../../lib/utils";
export const runtime = "edge";

export async function GET(req: Request) {
Expand All @@ -11,15 +11,28 @@ export async function GET(req: Request) {
const twitter = parsed.get("twitter");
const commitsS = parsed.get("commits");
const tweetsS = parsed.get("tweets");
const followers = parsed.get("followers");
const twitterAvatarUrl = parsed.get("avatar");
const displayName = parsed.get("displayName");
if (!github || !twitter || !commitsS || !tweetsS || !displayName) {
if (
!github ||
!twitter ||
!commitsS ||
!tweetsS ||
!displayName ||
!followers
) {
return new Response("Missing parameters", { status: 400 });
}
const commits = Number(commitsS);
const tweets = Number(tweetsS);
const txt = getRatioText({ tweets, commits, displayName });

const tagLine = getUserTagline({
tweets,
commits,
displayName,
twitterFollowerCount: Number(followers),
});
const UserMetadata = () => (
<div
style={{
Expand All @@ -28,7 +41,18 @@ export async function GET(req: Request) {
fontSize: "25px",
}}
>
<h1>{displayName}</h1>
<div
style={{
display: "flex",
flexDirection: "row",
alignItems: "center",
justifyContent: "flex-start",
gap: "10px",
}}
>
<h1>{displayName}</h1>
<UserTag />
</div>
<div
style={{
display: "flex",
Expand Down Expand Up @@ -133,6 +157,22 @@ export async function GET(req: Request) {
<UserMetadata />
</div>
);
const UserTag = () => {
return (
<div
style={{
backgroundColor: "#a855f7",
padding: "0.3rem 0.75rem",
fontSize: "2rem",
fontWeight: "semibold",
color: "white",
borderRadius: "9999px",
}}
>
{tagLine}
</div>
);
};

const url = `shiptalkers.dev${getPageUrl({
github,
Expand Down
3 changes: 2 additions & 1 deletion src/app/compare/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ import { db } from "../../server/db";
import { users } from "../../server/db/schema";
export const revalidate = 3600; // revalidate at most every hour

async function getPageDataInternal(props: Props) {
export async function getPageDataInternal(props: Props) {
const { github, twitter } = parse(props);
const user = await getCachedUserData({
githubName: github,
Expand Down Expand Up @@ -93,6 +93,7 @@ export async function generateMetadata(props: Props): Promise<Metadata> {
twitter: user.twitterName,
commits: user.commitsMade.toString(),
tweets: user.tweetsSent.toString(),
followers:Math.max(user.twitterFollowerCount, user.githubFollowerCount).toString()
});
if (user.twitterAvatarUrl) {
ogUrl.set("avatar", user.twitterAvatarUrl);
Expand Down
20 changes: 19 additions & 1 deletion src/app/compare/profile-no-heatmap.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
import { RatioPie } from "./pie";
import type { PageData } from "../../server/api/routers/get-data";
import {
getUserTagline,
getMatchPageUrl,
getPageUrl,
getRatioText,
Expand All @@ -25,6 +26,7 @@ import {
import Link from "next/link";
import { LinkButton } from "../../components/ui/link-button";
import ShimmerButton from "../../components/ui/shimmer-button";
import Tag from "../../components/custom/Tag";

function StreamingCTAs() {
return (
Expand Down Expand Up @@ -92,13 +94,13 @@ export function Profile(props: {

const totalCommits = commitsMade;
const totalTweets = tweetsSent;

const ogUrl = new URLSearchParams({
github: githubName,
displayName: twitterDisplayName,
twitter: twitterName,
commits: totalCommits.toString(),
tweets: totalTweets.toString(),
followers:Math.max(twitterFollowerCount, githubFollowerCount).toString()
});
if (pageData.user.twitterAvatarUrl) {
ogUrl.set("avatar", pageData.user.twitterAvatarUrl);
Expand All @@ -111,6 +113,12 @@ export function Profile(props: {
github: githubName,
twitter: twitterName,
})}`;
const tagline = getUserTagline({
tweets: totalTweets,
commits: totalCommits,
displayName: twitterDisplayName,
twitterFollowerCount: twitterFollowerCount,
});
return (
<div className="mx-auto flex w-full max-w-screen-xl flex-grow flex-col items-center py-8">
<div className="flex w-full flex-row items-center justify-between gap-4 md:mx-auto">
Expand All @@ -119,6 +127,16 @@ export function Profile(props: {
<div className="flex flex-col justify-between gap-4 py-4">
<div className="flex flex-col">
<div className="flex flex-col">
<TooltipProvider>
<Tooltip delayDuration={100}>
<TooltipTrigger className="flex flex-row items-center gap-1">
<Tag tagline={tagline} className="text-base py-0"/>
</TooltipTrigger>
<TooltipContent className="max-w-[260px]">
{tagline} 😃
</TooltipContent>
</Tooltip>
</TooltipProvider>
<div className="flex flex-row items-center gap-1">
<TwitterIcon size={20} />
<a
Expand Down
24 changes: 20 additions & 4 deletions src/app/components.client.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,12 +6,14 @@ import { Github, LoaderIcon, Twitter } from "lucide-react";
import type { HeatmaplessUser, User } from "../server/db/schema";

import { useQuery } from "@tanstack/react-query";
import { ChangeEvent, useEffect, useState } from "react";
import { GithubMetadata } from "../server/lib/github";
import { type ChangeEvent, useEffect, useState } from "react";
import { type GithubMetadata } from "../server/lib/github";
import { GitTweetBars } from "../components/ui/git-tweet-bars";
import { TwitterAvatar } from "../components/ui/twitter-avatar";
import { getMatchPageUrl, getPageUrl } from "../lib/utils";
import { getMatchPercentRelative, getMatchPercentTotal } from "./utils";
import { getUserTagline } from "../lib/utils";
import Tag from "../components/custom/Tag";

// Debounce function
// eslint-disable-next-line @typescript-eslint/ban-types
Expand Down Expand Up @@ -148,6 +150,12 @@ export function CompareInput(props: {

export function ComparisonCard(props: { user: HeatmaplessUser }) {
const { user } = props;
const tagLine = getUserTagline({
tweets: user.tweetsSent,
commits: user.commitsMade,
displayName: user.twitterDisplayName,
twitterFollowerCount: user.twitterFollowerCount,
});
return (
<a
className="flex flex-row items-center justify-between rounded-md border-2 bg-white p-4 drop-shadow-sm transition-all hover:scale-105 hover:border-blue-500 hover:shadow-lg"
Expand All @@ -159,9 +167,10 @@ export function ComparisonCard(props: { user: HeatmaplessUser }) {
<div className="flex flex-row items-start justify-center gap-4">
<TwitterAvatar user={user} className="size-24 min-w-24" />
<div className="flex h-full flex-col justify-start gap-2 text-start">
<h3 className="line-clamp-2 h-full max-w-56 text-wrap text-lg font-bold leading-5">
<h3 className="line-clamp-2 flex h-full max-w-56 items-center gap-2 text-lg font-bold leading-5">
{user.twitterDisplayName}
</h3>
<Tag tagline={tagLine} />
<div className="flex flex-row items-end justify-between gap-4">
<div className="flex h-full flex-col items-start justify-start text-start">
<span className="text-sm text-gray-500">@{user.twitterName}</span>
Expand Down Expand Up @@ -196,6 +205,12 @@ export function ViewAnotherMatchCardSuggestion(props: {
relative: boolean;
}) {
const { suggestedUser, rootUser } = props;
const tagline = getUserTagline({
tweets: suggestedUser.tweetsSent,
commits: suggestedUser.commitsMade,
displayName: suggestedUser.twitterDisplayName,
twitterFollowerCount: suggestedUser.twitterFollowerCount,
});
return (
<a
className="flex flex-row items-center justify-between rounded-md border-2 p-4 drop-shadow-sm transition-all hover:scale-105 hover:border-blue-500 hover:shadow-lg"
Expand All @@ -210,8 +225,9 @@ export function ViewAnotherMatchCardSuggestion(props: {
<div className="flex flex-row items-center justify-center gap-4">
<TwitterAvatar user={suggestedUser} className="size-24 min-w-24" />
<div className="flex h-full flex-col justify-start gap-2 text-start">
<h3 className="line-clamp-2 h-full max-w-56 text-wrap text-lg font-bold leading-5">
<h3 className="line-clamp-2 flex h-full max-w-56 flex-col gap-1 text-wrap text-lg font-bold leading-5">
{suggestedUser.twitterDisplayName}
<Tag tagline={tagline} />
</h3>
<div className="flex flex-row items-end justify-between gap-4">
<div className="flex h-full flex-col items-start justify-start text-start">
Expand Down
17 changes: 15 additions & 2 deletions src/app/match/hero.tsx
Original file line number Diff line number Diff line change
@@ -1,17 +1,24 @@
import { GithubIcon, TwitterIcon } from "lucide-react";
import {GithubIcon, TwitterIcon } from "lucide-react";
import { TwitterAvatar } from "../../components/ui/twitter-avatar";
import type { HeatmaplessUser } from "../../server/db/schema";
import type { MatchedUser } from "./utils";
import Link from "next/link";
import { cn, getPageUrl } from "../../lib/utils";
import { cn, getUserTagline, getPageUrl } from "../../lib/utils";
import { GitTweetBars } from "../../components/ui/git-tweet-bars";
import { getMatchPercentRelative, getMatchPercentTotal } from "../utils";
import { Switch } from "../../components/ui/switch";
import { Label } from "../../components/ui/label";
import { ToggleRelative } from "./toggle-relative";
import Tag from "../../components/custom/Tag";

function Stats(props: { user: HeatmaplessUser; className?: string }) {
const { user } = props;
const tagline = getUserTagline({
tweets: user.tweetsSent,
commits: user.commitsMade,
displayName: user.twitterDisplayName,
twitterFollowerCount: user.twitterFollowerCount,
});
return (
<div className={cn("flex flex-col md:w-[300px]", props.className)}>
<Link
Expand All @@ -23,6 +30,7 @@ function Stats(props: { user: HeatmaplessUser; className?: string }) {
>
{user.twitterDisplayName}
</Link>
<Tag tagline={tagline} />
<div className="flex items-center gap-2">
<TwitterIcon className="h-5 w-5 text-gray-600 dark:text-gray-400" />
<Link
Expand Down Expand Up @@ -69,6 +77,11 @@ function Bio(props: {
const total = user.tweetsSent + user.commitsMade;
const percentTweets = (user.tweetsSent / total) * 100;
const percentCommits = (user.commitsMade / total) * 100;
const tagline = getUserTagline({
tweets: user.tweetsSent,
commits: user.commitsMade,
displayName: user.twitterDisplayName,
});
return (
<div
className={cn(
Expand Down
23 changes: 23 additions & 0 deletions src/components/custom/Tag.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
import React from "react";
import { cn } from "../../lib/utils";
const Tag = ({
tagline,
className,
}: {
tagline: string;
className?: string;
}) => {
return (
<div
className={cn(
"relative mb-1 inline-flex w-fit animate-spin-around items-center rounded-full bg-gradient-to-r from-purple-500 to-pink-500 px-3 py-1 text-xs font-semibold text-white",
className,
)}
>
<span className="relative z-10">{tagline}</span>
<div className="absolute left-0 top-0 h-full animate-ping rounded-full bg-gradient-to-r from-purple-500 to-pink-500 opacity-30 blur-sm"></div>
</div>
);
};

export default Tag;
29 changes: 28 additions & 1 deletion src/lib/utils.ts
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,6 @@ export function getRatioText(input: {
if (tweets === commits) {
return `${displayName}'s life is perfectly balanced, as all things should be`;
}

const percentageTweets = Math.abs((tweets / commits) * 100 - 100).toFixed();
const percentageCommits = Math.abs((commits / tweets) * 100 - 100).toFixed();
const txt =
Expand Down Expand Up @@ -116,3 +115,31 @@ export function getMatchPageOgImageUrl(args: {
export function isVerifiedUser(user: Pick<User, "twitterInGithubBio" | "twitterName" | "githubName">): boolean {
return user.twitterInGithubBio || user.twitterName === user.githubName;
}
export function getUserTagline(input: {
tweets: number,
commits: number,
displayName: string,
twitterFollowerCount?: number,
}): string {
const { tweets, commits, twitterFollowerCount } = input;
const ratio = (commits / tweets);
if (twitterFollowerCount && twitterFollowerCount > 100000) return "Popular";
switch (true) {
case (ratio >= 5):
return "No life";
case (ratio >= 3 && ratio < 5):
return "Nerd";
case (ratio >= 2 && ratio < 3):
return "Builder";
case (ratio >= 1 && ratio < 2):
return "Load Balancer";
case (ratio >= 0.5 && ratio < 1):
return "Shiposter";
case (ratio >= 0.333 && ratio < 0.5):
return "Indie Hacker";
case (ratio >= 0.25 && ratio < 0.333):
return "Reply Guy";
default:
return "Influencer";
}
}
2 changes: 1 addition & 1 deletion tsconfig.json
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@
"**/*.ts",
"**/*.tsx",
".next/types/**/*.ts"
],
, "src/env.js" ],
"exclude": [
"node_modules"
]
Expand Down