Refactor GitHub fork status behavior

This commit is contained in:
Sam Becker 2025-01-31 18:31:35 -06:00
parent c41d178301
commit ba32f4e8f7
7 changed files with 61 additions and 40 deletions

View File

@ -1,5 +1,7 @@
import { htmlHasBrParagraphBreaks, safelyParseFormattedHtml } from '@/utility/html'; import {
import { parameterize } from '@/utility/string'; htmlHasBrParagraphBreaks,
safelyParseFormattedHtml,
} from '@/utility/html';
describe('HTML', () => { describe('HTML', () => {
it('safely parses', () => { it('safely parses', () => {

View File

@ -1,14 +1,12 @@
import { Suspense } from 'react'; import { Suspense } from 'react';
import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient'; import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient';
import GitHubForkStatusBadgeServer from './GitHubForkStatusBadgeServer'; import GitHubForkStatusBadgeServer from './GitHubForkStatusBadgeServer';
import { IS_DEVELOPMENT, IS_VERCEL_GIT_PROVIDER_GITHUB } from '@/site/config'; import { IS_DEVELOPMENT } from '@/site/config';
export default function GitHubForkStatusBadge() { export default function GitHubForkStatusBadge() {
return IS_DEVELOPMENT return IS_DEVELOPMENT
? <GitHubForkStatusBadgeClient label="Local" /> ? <GitHubForkStatusBadgeClient label="Local" />
: IS_VERCEL_GIT_PROVIDER_GITHUB : <Suspense>
? <Suspense> <GitHubForkStatusBadgeServer />
<GitHubForkStatusBadgeServer /> </Suspense>;
</Suspense>
: null;
} }

View File

@ -38,10 +38,11 @@ export default function GitHubForkStatusBadgeClient({
}; };
const className = clsx( const className = clsx(
'opacity-0 transition-opacity animate-fade-in',
'inline-flex items-center gap-2', 'inline-flex items-center gap-2',
'border transition-colors', 'border transition-colors',
url ? 'hover:underline' : 'select-none', url ? 'hover:underline' : 'select-none',
'pl-[4.5px] pr-2 py-[3px]', 'pl-[4.5px] pr-2.5 py-[3px]',
'rounded-full shadow-sm', 'rounded-full shadow-sm',
classNameForStyle(), classNameForStyle(),
); );

View File

@ -1,5 +1,6 @@
import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient'; import GitHubForkStatusBadgeClient from './GitHubForkStatusBadgeClient';
import { import {
VERCEL_GIT_BRANCH,
VERCEL_GIT_REPO_OWNER, VERCEL_GIT_REPO_OWNER,
VERCEL_GIT_REPO_SLUG, VERCEL_GIT_REPO_SLUG,
} from '@/site/config'; } from '@/site/config';
@ -8,29 +9,32 @@ import { getGitHubMeta } from '.';
export default async function GitHubForkStatusBadgeServer() { export default async function GitHubForkStatusBadgeServer() {
const owner = VERCEL_GIT_REPO_OWNER; const owner = VERCEL_GIT_REPO_OWNER;
const repo = VERCEL_GIT_REPO_SLUG; const repo = VERCEL_GIT_REPO_SLUG;
const branch = VERCEL_GIT_BRANCH;
const { const {
url, url,
isForkedFromBase,
label, label,
title, title,
isBehind, isBehind,
} = await getGitHubMeta({ owner, repo }) } = await getGitHubMeta({ owner, repo, branch })
.catch(() => { .catch(() => {
console.log('Error getting GitHub meta', { owner, repo }); console.error('Error retrieving GitHub meta', { owner, repo, branch });
return { return {
url: undefined, url: undefined,
isForkedFromBase: false,
label: undefined, label: undefined,
title: undefined, title: undefined,
isBehind: false, isBehind: undefined,
}; };
}); });
return ( return isForkedFromBase
<GitHubForkStatusBadgeClient {...{ ? <GitHubForkStatusBadgeClient {...{
url, url,
label, label,
title, title,
style: isBehind ? 'warning' : 'mono', style: isBehind ? 'warning' : 'mono',
}} /> }} />
); : null;
} }

View File

@ -1,7 +1,10 @@
import { VERCEL_BRANCH } from '@/site/config'; import {
TEMPLATE_BASE_OWNER,
TEMPLATE_BASE_REPO,
TEMPLATE_BASE_BRANCH,
} from '@/site/config';
const BASE_OWNER = 'sambecker'; const DEFAULT_BRANCH = 'main';
const BASE_REPO = 'exif-photo-blog';
interface RepoParams { interface RepoParams {
owner?: string owner?: string
@ -9,31 +12,42 @@ interface RepoParams {
branch?: string branch?: string
}; };
// Urls // Website urls
const getGitHubRepoUrl = ({ const getGitHubRepoUrl = ({
owner = BASE_OWNER, owner = TEMPLATE_BASE_OWNER,
repo = BASE_REPO, repo = TEMPLATE_BASE_REPO,
}: RepoParams = {}) => }: RepoParams = {}) =>
`https://github.com/${owner}/${repo}`; `https://github.com/${owner}/${repo}`;
export const getGitHubCompareUrl = ({
owner,
repo,
branch = DEFAULT_BRANCH,
}: RepoParams = {}) =>
// eslint-disable-next-line max-len
`${getGitHubRepoUrl({ owner, repo })}/compare/${branch}...${TEMPLATE_BASE_OWNER}:${TEMPLATE_BASE_REPO}:${TEMPLATE_BASE_BRANCH}`;
// API urls
const getGitHubApiRepoUrl = ({ const getGitHubApiRepoUrl = ({
owner = BASE_OWNER, owner = TEMPLATE_BASE_OWNER,
repo = BASE_REPO, repo = TEMPLATE_BASE_REPO,
}: RepoParams = {}) => }: RepoParams = {}) =>
`https://api.github.com/repos/${owner}/${repo}`; `https://api.github.com/repos/${owner}/${repo}`;
const getGitHubApiCommitsUrl = (params?: RepoParams) => const getGitHubApiCommitsUrl = (params?: RepoParams) =>
`${getGitHubApiRepoUrl(params)}/commits/main`; `${getGitHubApiRepoUrl(params)}/commits/main`;
// Fetching
const getGitHubApiCompareUrl = ({ const getGitHubApiCompareUrl = ({
owner, owner,
repo, repo,
branch = 'main', branch = 'main',
}: RepoParams = {}) => }: RepoParams = {}) =>
`${getGitHubApiRepoUrl()}/compare/main...${owner}:${repo}:${branch}`; // eslint-disable-next-line max-len
`${getGitHubApiRepoUrl()}/compare/${TEMPLATE_BASE_BRANCH}...${owner}:${repo}:${branch}`;
// Requests
const getLatestBaseRepoCommitSha = async () => { const getLatestBaseRepoCommitSha = async () => {
const response = await fetch(getGitHubApiCommitsUrl()); const response = await fetch(getGitHubApiCommitsUrl());
@ -44,21 +58,21 @@ const getLatestBaseRepoCommitSha = async () => {
const getIsRepoForkedFromBase = async (params: RepoParams) => { const getIsRepoForkedFromBase = async (params: RepoParams) => {
const response = await fetch(getGitHubApiRepoUrl(params)); const response = await fetch(getGitHubApiRepoUrl(params));
const data = await response.json(); const data = await response.json();
return data.fork && data.source?.full_name === `${BASE_OWNER}/${BASE_REPO}`; return (
Boolean(data.fork) &&
data.source?.full_name === `${TEMPLATE_BASE_OWNER}/${TEMPLATE_BASE_REPO}`
);
}; };
const getGitHubCommitsBehind = async (params?: RepoParams) => { const getGitHubCommitsBehind = async (params?: RepoParams) => {
const response = await fetch(getGitHubApiCompareUrl({ const response = await fetch(getGitHubApiCompareUrl(params));
...params,
branch: VERCEL_BRANCH,
}));
const data = await response.json(); const data = await response.json();
return data.behind_by as number; return data.behind_by as number;
}; };
const isRepoBaseRepo = async ({ owner, repo }: RepoParams) => const isRepoBaseRepo = async ({ owner, repo }: RepoParams) =>
owner?.toLowerCase() === BASE_OWNER && owner?.toLowerCase() === TEMPLATE_BASE_OWNER &&
repo?.toLowerCase() === BASE_REPO; repo?.toLowerCase() === TEMPLATE_BASE_REPO;
export const getGitHubMeta = async (params: RepoParams) => { export const getGitHubMeta = async (params: RepoParams) => {
const [ const [

View File

@ -3,23 +3,26 @@ import type { StorageType } from '@/services/storage';
import { makeUrlAbsolute, shortenUrl } from '@/utility/url'; import { makeUrlAbsolute, shortenUrl } from '@/utility/url';
// HARD-CODED GLOBAL CONFIGURATION // HARD-CODED GLOBAL CONFIGURATION
export const SHOULD_PREFETCH_ALL_LINKS: boolean | undefined = undefined; export const SHOULD_PREFETCH_ALL_LINKS: boolean | undefined = undefined;
export const SHOULD_DEBUG_SQL = false; export const SHOULD_DEBUG_SQL = false;
// META / SOURCE / DOMAINS // META / SOURCE / DOMAINS
export const SITE_TITLE = export const SITE_TITLE =
process.env.NEXT_PUBLIC_SITE_TITLE || process.env.NEXT_PUBLIC_SITE_TITLE ||
'Photo Blog'; 'Photo Blog';
// SOURCE // SOURCE
export const TEMPLATE_BASE_OWNER = 'sambecker';
export const TEMPLATE_BASE_REPO = 'exif-photo-blog';
export const TEMPLATE_BASE_BRANCH = 'main';
export const VERCEL_GIT_PROVIDER = export const VERCEL_GIT_PROVIDER =
process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER; process.env.NEXT_PUBLIC_VERCEL_GIT_PROVIDER;
export const VERCEL_GIT_REPO_OWNER = export const VERCEL_GIT_REPO_OWNER =
process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER; process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_OWNER;
export const VERCEL_GIT_REPO_SLUG = export const VERCEL_GIT_REPO_SLUG =
process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG; process.env.NEXT_PUBLIC_VERCEL_GIT_REPO_SLUG;
export const VERCEL_GIT_BRANCH = process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF;
export const VERCEL_GIT_COMMIT_MESSAGE = export const VERCEL_GIT_COMMIT_MESSAGE =
process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE; process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_MESSAGE;
export const VERCEL_GIT_COMMIT_SHA = export const VERCEL_GIT_COMMIT_SHA =
@ -37,10 +40,9 @@ export const VERCEL_ENV = process.env.NEXT_PUBLIC_VERCEL_ENV;
export const VERCEL_PRODUCTION_URL = process.env.VERCEL_PROJECT_PRODUCTION_URL; export const VERCEL_PRODUCTION_URL = process.env.VERCEL_PROJECT_PRODUCTION_URL;
export const VERCEL_DEPLOYMENT_URL = process.env.NEXT_PUBLIC_VERCEL_URL; export const VERCEL_DEPLOYMENT_URL = process.env.NEXT_PUBLIC_VERCEL_URL;
export const VERCEL_BRANCH_URL = process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL; export const VERCEL_BRANCH_URL = process.env.NEXT_PUBLIC_VERCEL_BRANCH_URL;
export const VERCEL_BRANCH = process.env.NEXT_PUBLIC_VERCEL_GIT_COMMIT_REF;
// Last resort: cannot be used reliably // Last resort: cannot be used reliably
export const VERCEL_PROJECT_URL = VERCEL_BRANCH_URL && VERCEL_BRANCH export const VERCEL_PROJECT_URL = VERCEL_BRANCH_URL && VERCEL_GIT_BRANCH
? `${VERCEL_BRANCH_URL.split(`-git-${VERCEL_BRANCH}-`)[0]}.vercel.app` ? `${VERCEL_BRANCH_URL.split(`-git-${VERCEL_GIT_BRANCH}-`)[0]}.vercel.app`
: undefined; : undefined;
export const IS_PRODUCTION = process.env.NODE_ENV === 'production' && ( export const IS_PRODUCTION = process.env.NODE_ENV === 'production' && (

View File

@ -29,7 +29,7 @@ module.exports = {
'rotate-pulse': 'rotate-pulse':
'rotate-pulse 0.75s linear infinite normal both running', 'rotate-pulse 0.75s linear infinite normal both running',
'fade-in': 'fade-in':
'fade-in 0.5s linear', 'fade-in 0.5s linear both running',
'hover-drift': 'hover-drift':
'hover-drift 8s linear infinite', 'hover-drift 8s linear infinite',
'hover-wobble': 'hover-wobble':