diff --git a/.prettierrc b/.prettierrc
deleted file mode 100644
index a8d69b6..0000000
--- a/.prettierrc
+++ /dev/null
@@ -1,13 +0,0 @@
-{
- "singleQuote": true,
- "bracketSpacing": false,
- "useTabs": true,
- "overrides": [
- {
- "files": ["*.yml"],
- "options": {
- "singleQuote": false
- }
- }
- ]
-}
diff --git a/.vscode/settings.json b/.vscode/settings.json
index d9b23cb..9165da4 100644
--- a/.vscode/settings.json
+++ b/.vscode/settings.json
@@ -1,5 +1,5 @@
{
- "editor.tabSize": 2,
- "typescript.tsdk": "node_modules/typescript/lib",
- "typescript.enablePromptUseWorkspaceTsdk": true
+ "editor.tabSize": 2,
+ "typescript.tsdk": "node_modules/typescript/lib",
+ "typescript.enablePromptUseWorkspaceTsdk": true
}
diff --git a/package.json b/package.json
index 3d4db59..976aafe 100644
--- a/package.json
+++ b/package.json
@@ -14,7 +14,7 @@
"react": "^18.2.0",
"react-dom": "^18.2.0",
"remotion": "^4.0.0",
- "zod": "^3.21.4"
+ "zod": "3.22.3"
},
"devDependencies": {
"@remotion/eslint-config": "^4.0.0",
diff --git a/remotion.config.ts b/remotion.config.ts
index bc54c19..f702024 100644
--- a/remotion.config.ts
+++ b/remotion.config.ts
@@ -1,9 +1,9 @@
-import {Config} from '@remotion/cli/config';
+import { Config } from "@remotion/cli/config";
/**
* Note: When using the Node.JS APIs, the config file
* doesn't apply. Instead, pass options directly to the APIs
*/
-Config.setVideoImageFormat('jpeg');
+Config.setVideoImageFormat("jpeg");
Config.setDelayRenderTimeoutInMilliseconds(1200000);
diff --git a/src/Content.tsx b/src/Content.tsx
index 12be441..fc382d7 100644
--- a/src/Content.tsx
+++ b/src/Content.tsx
@@ -1,162 +1,162 @@
-import {Img, useVideoConfig} from 'remotion';
-import {Stargazer} from './cache';
-import {RepoHeader} from './repo-header';
+import { Img, useVideoConfig } from "remotion";
+import { Stargazer } from "./cache";
+import { RepoHeader } from "./repo-header";
const W = 1280 / 2.5;
const H = 720 / 2.5;
export function Content({
- stargazers,
- repoOrg,
- repoName,
- progress,
+ stargazers,
+ repoOrg,
+ repoName,
+ progress,
}: {
- stargazers: Stargazer[];
- repoOrg: string;
- repoName: string;
- progress: number;
+ stargazers: Stargazer[];
+ repoOrg: string;
+ repoName: string;
+ progress: number;
}) {
- const gap = 102;
- const startY = 76 - gap;
- const dy = progress * gap;
- const {width} = useVideoConfig();
+ const gap = 102;
+ const startY = 76 - gap;
+ const dy = progress * gap;
+ const { width } = useVideoConfig();
- return (
-
- {stargazers.map((stargazer, index) => {
- const isHidden = Math.abs(index - progress) > 3;
- const grow = 0;
- const opacity = Math.min(0.1 + progress - index, 1);
- return isHidden ? null : (
-
- );
- })}
+ return (
+
+ {stargazers.map((stargazer, index) => {
+ const isHidden = Math.abs(index - progress) > 3;
+ const grow = 0;
+ const opacity = Math.min(0.1 + progress - index, 1);
+ return isHidden ? null : (
+
+ );
+ })}
-
-
- );
+
+
+ );
}
function StarBox({
- avatarUrl,
- name,
- date,
- repoName,
- y,
- starNumber,
- grow,
- opacity,
+ avatarUrl,
+ name,
+ date,
+ repoName,
+ y,
+ starNumber,
+ grow,
+ opacity,
}: {
- avatarUrl: string;
- name: string;
- date: string;
- repoName: string;
- y: number;
- starNumber: number;
- grow: number;
- opacity: number;
+ avatarUrl: string;
+ name: string;
+ date: string;
+ repoName: string;
+ y: number;
+ starNumber: number;
+ grow: number;
+ opacity: number;
}) {
- const d = new Date(date);
- const dateString = d.toLocaleDateString('en-US', {
- month: 'short',
- day: '2-digit',
- year: 'numeric',
- });
+ const d = new Date(date);
+ const dateString = d.toLocaleDateString("en-US", {
+ month: "short",
+ day: "2-digit",
+ year: "numeric",
+ });
- return (
-
-
-
-
- {name}
-
-
- starred {repoName}{' '}
- on {dateString}
-
-
-
-
Star
-
- #
- {starNumber}
-
-
-
- );
+ return (
+
+
+
+
+ {name}
+
+
+ starred {repoName}{" "}
+ on {dateString}
+
+
+
+
Star
+
+ #
+ {starNumber}
+
+
+
+ );
}
diff --git a/src/Main.tsx b/src/Main.tsx
index fa41db5..cdfb9ad 100644
--- a/src/Main.tsx
+++ b/src/Main.tsx
@@ -1,45 +1,45 @@
-import {useCurrentFrame, useVideoConfig} from 'remotion';
-import {z} from 'zod';
-import {Stargazer} from './cache';
-import {Content} from './Content';
-import {getProgress} from './utils';
+import { useCurrentFrame, useVideoConfig } from "remotion";
+import { z } from "zod";
+import { Stargazer } from "./cache";
+import { Content } from "./Content";
+import { getProgress } from "./utils";
export const mainSchema = z.object({
- repoOrg: z.string(),
- repoName: z.string(),
- starCount: z.number().step(1),
- duration: z.number().step(1),
+ repoOrg: z.string(),
+ repoName: z.string(),
+ starCount: z.number().step(1),
+ duration: z.number().step(1),
});
type SchemaProps = z.infer;
export type MainProps = SchemaProps & {
- stargazers: Stargazer[] | null;
+ stargazers: Stargazer[] | null;
};
-export function Main({repoOrg, repoName, stargazers}: MainProps) {
- const frame = useCurrentFrame();
- const {fps, durationInFrames} = useVideoConfig();
-
- const extraEnding = fps;
-
- if (!stargazers) {
- return null;
- }
-
- const progress = getProgress(
- frame,
- durationInFrames - extraEnding,
- stargazers.length,
- fps,
- );
-
- return (
-
- );
+export function Main({ repoOrg, repoName, stargazers }: MainProps) {
+ const frame = useCurrentFrame();
+ const { fps, durationInFrames } = useVideoConfig();
+
+ const extraEnding = fps;
+
+ if (!stargazers) {
+ return null;
+ }
+
+ const progress = getProgress(
+ frame,
+ durationInFrames - extraEnding,
+ stargazers.length,
+ fps,
+ );
+
+ return (
+
+ );
}
diff --git a/src/Root.tsx b/src/Root.tsx
index 684b2e8..0f6cece 100644
--- a/src/Root.tsx
+++ b/src/Root.tsx
@@ -1,51 +1,51 @@
-import {useCallback} from 'react';
-import {CalculateMetadataFunction, Composition} from 'remotion';
-import {fetchStargazers} from './fetch/fetch-data';
-import {Main, MainProps, mainSchema} from './Main';
-import {waitForNoInput} from './wait-for-no-input';
+import { useCallback } from "react";
+import { CalculateMetadataFunction, Composition } from "remotion";
+import { fetchStargazers } from "./fetch/fetch-data";
+import { Main, MainProps, mainSchema } from "./Main";
+import { waitForNoInput } from "./wait-for-no-input";
const FPS = 30;
export const RemotionRoot = () => {
- const calculateMetadata: CalculateMetadataFunction = useCallback(
- async ({props, abortSignal}) => {
- await waitForNoInput(abortSignal, 500);
+ const calculateMetadata: CalculateMetadataFunction = useCallback(
+ async ({ props, abortSignal }) => {
+ await waitForNoInput(abortSignal, 500);
- const stargazers = await fetchStargazers({
- repoOrg: props.repoOrg,
- repoName: props.repoName,
- starCount: props.starCount,
- abortSignal,
- });
+ const stargazers = await fetchStargazers({
+ repoOrg: props.repoOrg,
+ repoName: props.repoName,
+ starCount: props.starCount,
+ abortSignal,
+ });
- return {
- props: {
- ...props,
- stargazers,
- },
- durationInFrames: props.duration * FPS,
- };
- },
- [],
- );
+ return {
+ props: {
+ ...props,
+ stargazers,
+ },
+ durationInFrames: props.duration * FPS,
+ };
+ },
+ [],
+ );
- return (
-
- );
+ return (
+
+ );
};
diff --git a/src/cache.ts b/src/cache.ts
index 2bf11f3..20c4304 100644
--- a/src/cache.ts
+++ b/src/cache.ts
@@ -1,68 +1,68 @@
export type QueryResult = {
- cursor: string;
- results: Stargazer[];
+ cursor: string;
+ results: Stargazer[];
};
export type Stargazer = {
- avatarUrl: string;
- name: string;
- date: string;
- login: string;
+ avatarUrl: string;
+ name: string;
+ date: string;
+ login: string;
};
const makeKey = ({
- count,
- cursor,
- repoName,
- repoOrg,
+ count,
+ cursor,
+ repoName,
+ repoOrg,
}: {
- repoOrg: string;
- repoName: string;
- count: number;
- cursor: string | null;
+ repoOrg: string;
+ repoName: string;
+ count: number;
+ cursor: string | null;
}) => {
- return ['__stargazer', repoOrg, repoName, count, cursor].join('-');
+ return ["__stargazer", repoOrg, repoName, count, cursor].join("-");
};
export const saveResult = ({
- count,
- cursor,
- repoName,
- repoOrg,
- result,
+ count,
+ cursor,
+ repoName,
+ repoOrg,
+ result,
}: {
- repoOrg: string;
- repoName: string;
- count: number;
- cursor: string | null;
- result: QueryResult;
+ repoOrg: string;
+ repoName: string;
+ count: number;
+ cursor: string | null;
+ result: QueryResult;
}) => {
- try {
- const key = makeKey({count, cursor, repoName, repoOrg});
- window.localStorage.setItem(key, JSON.stringify(result));
- } catch (err) {
- // If quota is exceeded, don't cache
- if (!(err as Error).message.toLowerCase().includes('quota')) {
- throw err;
- }
- }
+ try {
+ const key = makeKey({ count, cursor, repoName, repoOrg });
+ window.localStorage.setItem(key, JSON.stringify(result));
+ } catch (err) {
+ // If quota is exceeded, don't cache
+ if (!(err as Error).message.toLowerCase().includes("quota")) {
+ throw err;
+ }
+ }
};
export const getFromCache = ({
- count,
- cursor,
- repoName,
- repoOrg,
+ count,
+ cursor,
+ repoName,
+ repoOrg,
}: {
- repoOrg: string;
- repoName: string;
- count: number;
- cursor: string | null;
+ repoOrg: string;
+ repoName: string;
+ count: number;
+ cursor: string | null;
}): QueryResult | null => {
- const key = makeKey({count, cursor, repoName, repoOrg});
- const value = window.localStorage.getItem(key);
- if (!value) {
- return null;
- }
- return JSON.parse(value);
+ const key = makeKey({ count, cursor, repoName, repoOrg });
+ const value = window.localStorage.getItem(key);
+ if (!value) {
+ return null;
+ }
+ return JSON.parse(value);
};
diff --git a/src/fetch/fetch-data.ts b/src/fetch/fetch-data.ts
index 7fdf2e8..d2295e4 100644
--- a/src/fetch/fetch-data.ts
+++ b/src/fetch/fetch-data.ts
@@ -1,71 +1,71 @@
-import {QueryResult, Stargazer} from '../cache';
-import {fetchViaGraphQl} from './via-graphql';
-import {fetchPageViaRest, REST_PER_PAGE} from './via-rest';
+import { QueryResult, Stargazer } from "../cache";
+import { fetchViaGraphQl } from "./via-graphql";
+import { fetchPageViaRest, REST_PER_PAGE } from "./via-rest";
export async function fetchStargazers({
- repoOrg,
- repoName,
- starCount,
- abortSignal,
+ repoOrg,
+ repoName,
+ starCount,
+ abortSignal,
}: {
- repoOrg: string;
- repoName: string;
- starCount: number;
- abortSignal: AbortSignal;
+ repoOrg: string;
+ repoName: string;
+ starCount: number;
+ abortSignal: AbortSignal;
}) {
- let allStargazers: Stargazer[] = [];
+ let allStargazers: Stargazer[] = [];
- console.log('Fetching stars...');
- if (!process.env.REMOTION_GITHUB_TOKEN) {
- console.error(
- 'No REMOTION_GITHUB_TOKEN environment variable found. Using the GitHub REST API instead of GraphQL, which has a lower rate-limit and does not have GitHub display names.',
- );
+ console.log("Fetching stars...");
+ if (!process.env.REMOTION_GITHUB_TOKEN) {
+ console.error(
+ "No REMOTION_GITHUB_TOKEN environment variable found. Using the GitHub REST API instead of GraphQL, which has a lower rate-limit and does not have GitHub display names.",
+ );
- let page = 0;
+ let page = 0;
- for (let i = 0; i < Math.ceil(starCount / REST_PER_PAGE); i++) {
- const stars = await fetchPageViaRest({
- abortSignal,
- page,
- repoName,
- repoOrg,
- });
- if (stars.length === 0) {
- break;
- }
- allStargazers = [...allStargazers, ...stars];
- console.log(`Fetched ${allStargazers.length} stars`);
- if (allStargazers.length >= starCount) {
- allStargazers = allStargazers.slice(0, starCount);
- break;
- }
- page++;
- }
- return allStargazers;
- }
- let starsLeft = starCount;
- let cursor = null;
+ for (let i = 0; i < Math.ceil(starCount / REST_PER_PAGE); i++) {
+ const stars = await fetchPageViaRest({
+ abortSignal,
+ page,
+ repoName,
+ repoOrg,
+ });
+ if (stars.length === 0) {
+ break;
+ }
+ allStargazers = [...allStargazers, ...stars];
+ console.log(`Fetched ${allStargazers.length} stars`);
+ if (allStargazers.length >= starCount) {
+ allStargazers = allStargazers.slice(0, starCount);
+ break;
+ }
+ page++;
+ }
+ return allStargazers;
+ }
+ let starsLeft = starCount;
+ let cursor = null;
- while (starsLeft > 0) {
- const count = Math.min(starsLeft, 100);
- const result = (await fetchViaGraphQl({
- repoOrg,
- repoName,
- count,
- cursor,
- abortSignal,
- })) as QueryResult;
+ while (starsLeft > 0) {
+ const count = Math.min(starsLeft, 100);
+ const result = (await fetchViaGraphQl({
+ repoOrg,
+ repoName,
+ count,
+ cursor,
+ abortSignal,
+ })) as QueryResult;
- const {cursor: newCursor, results} = result;
- allStargazers = [...allStargazers, ...results];
- console.log(`Fetched ${allStargazers.length} stars`);
- cursor = newCursor;
- if (results.length < count) {
- starsLeft = 0;
- } else {
- starsLeft -= results.length;
- }
- }
+ const { cursor: newCursor, results } = result;
+ allStargazers = [...allStargazers, ...results];
+ console.log(`Fetched ${allStargazers.length} stars`);
+ cursor = newCursor;
+ if (results.length < count) {
+ starsLeft = 0;
+ } else {
+ starsLeft -= results.length;
+ }
+ }
- return allStargazers;
+ return allStargazers;
}
diff --git a/src/fetch/via-graphql.ts b/src/fetch/via-graphql.ts
index 4ccdec3..e3b34de 100644
--- a/src/fetch/via-graphql.ts
+++ b/src/fetch/via-graphql.ts
@@ -1,59 +1,59 @@
-import {QueryResult, Stargazer, getFromCache, saveResult} from '../cache';
+import { QueryResult, Stargazer, getFromCache, saveResult } from "../cache";
type Edge = {
- starredAt: string;
- node: {
- avatarUrl: string;
- name?: string;
- login: string;
- };
- cursor: string;
+ starredAt: string;
+ node: {
+ avatarUrl: string;
+ name?: string;
+ login: string;
+ };
+ cursor: string;
};
type ApiError =
- | {
- type: 'RATE_LIMITED';
- message: string;
- }
- | {
- type: string;
- message: string;
- };
+ | {
+ type: "RATE_LIMITED";
+ message: string;
+ }
+ | {
+ type: string;
+ message: string;
+ };
type GitHubApiResponse =
- | {
- data: {
- repository: {
- stargazers: {
- edges: Edge[];
- };
- };
- };
- }
- | {
- errors: ApiError[];
- };
+ | {
+ data: {
+ repository: {
+ stargazers: {
+ edges: Edge[];
+ };
+ };
+ };
+ }
+ | {
+ errors: ApiError[];
+ };
export const fetchViaGraphQl = async ({
- count,
- cursor,
- repoName,
- repoOrg,
- abortSignal,
+ count,
+ cursor,
+ repoName,
+ repoOrg,
+ abortSignal,
}: {
- repoOrg: string;
- repoName: string;
- count: number;
- cursor: string | null;
- abortSignal: AbortSignal;
+ repoOrg: string;
+ repoName: string;
+ count: number;
+ cursor: string | null;
+ abortSignal: AbortSignal;
}): Promise => {
- const cache = getFromCache({repoOrg, repoName, count, cursor});
- if (cache) {
- return cache;
- }
- const query = `{
+ const cache = getFromCache({ repoOrg, repoName, count, cursor });
+ if (cache) {
+ return cache;
+ }
+ const query = `{
repository(owner: "${repoOrg}", name: "${repoName}") {
- stargazers(first: ${count}${cursor ? `, after: "${cursor}"` : ''}) {
+ stargazers(first: ${count}${cursor ? `, after: "${cursor}"` : ""}) {
edges {
starredAt
node {
@@ -67,48 +67,48 @@ export const fetchViaGraphQl = async ({
}
}`;
- const res = await fetch('https://api.github.com/graphql', {
- method: 'POST',
- headers: {
- 'Content-Type': 'application/json',
- authorization: `token ${process.env.REMOTION_GITHUB_TOKEN}`,
- },
- signal: abortSignal,
- body: JSON.stringify({query}),
- });
+ const res = await fetch("https://api.github.com/graphql", {
+ method: "POST",
+ headers: {
+ "Content-Type": "application/json",
+ authorization: `token ${process.env.REMOTION_GITHUB_TOKEN}`,
+ },
+ signal: abortSignal,
+ body: JSON.stringify({ query }),
+ });
- if (!res.ok) {
- const textResponse = await res.text();
- throw Error(`HTTP ${res.status} ${res.statusText}: ${textResponse}`);
- }
+ if (!res.ok) {
+ const textResponse = await res.text();
+ throw Error(`HTTP ${res.status} ${res.statusText}: ${textResponse}`);
+ }
- const json = (await res.json()) as GitHubApiResponse;
+ const json = (await res.json()) as GitHubApiResponse;
- if ('errors' in json) {
- if (json.errors[0].type === 'RATE_LIMITED') {
- console.error('Rate limit exceeded, waiting 1 minute...');
- await new Promise((resolve) => {
- setTimeout(resolve, 60 * 1000);
- });
- return fetchViaGraphQl({repoOrg, repoName, count, cursor, abortSignal});
- }
- throw new Error(JSON.stringify(json.errors));
- }
+ if ("errors" in json) {
+ if (json.errors[0].type === "RATE_LIMITED") {
+ console.error("Rate limit exceeded, waiting 1 minute...");
+ await new Promise((resolve) => {
+ setTimeout(resolve, 60 * 1000);
+ });
+ return fetchViaGraphQl({ repoOrg, repoName, count, cursor, abortSignal });
+ }
+ throw new Error(JSON.stringify(json.errors));
+ }
- const {edges} = json.data.repository.stargazers;
- const lastCursor = edges[edges.length - 1].cursor;
+ const { edges } = json.data.repository.stargazers;
+ const lastCursor = edges[edges.length - 1].cursor;
- const page: Stargazer[] = edges.map((edge) => {
- return {
- avatarUrl: edge.node.avatarUrl,
- date: edge.starredAt,
- name: edge.node.name || edge.node.login,
- login: edge.node.login,
- };
- });
+ const page: Stargazer[] = edges.map((edge) => {
+ return {
+ avatarUrl: edge.node.avatarUrl,
+ date: edge.starredAt,
+ name: edge.node.name || edge.node.login,
+ login: edge.node.login,
+ };
+ });
- const result = {cursor: lastCursor, results: page};
- saveResult({repoOrg, repoName, count, cursor, result});
+ const result = { cursor: lastCursor, results: page };
+ saveResult({ repoOrg, repoName, count, cursor, result });
- return result;
+ return result;
};
diff --git a/src/fetch/via-rest.ts b/src/fetch/via-rest.ts
index 2f50f2d..5ea8316 100644
--- a/src/fetch/via-rest.ts
+++ b/src/fetch/via-rest.ts
@@ -1,55 +1,55 @@
-import {Stargazer} from '../cache';
+import { Stargazer } from "../cache";
export const REST_PER_PAGE = 100;
type GitHubApiResponse = {
- starred_at: string;
- user: {
- login: string;
- avatar_url: string;
- };
+ starred_at: string;
+ user: {
+ login: string;
+ avatar_url: string;
+ };
}[];
export const fetchPageViaRest = async ({
- abortSignal,
- page,
- repoName,
- repoOrg,
+ abortSignal,
+ page,
+ repoName,
+ repoOrg,
}: {
- repoOrg: string;
- repoName: string;
- page: number;
- abortSignal: AbortSignal;
+ repoOrg: string;
+ repoName: string;
+ page: number;
+ abortSignal: AbortSignal;
}): Promise => {
- const url = `https://api.github.com/repos/${repoOrg}/${repoName}/stargazers?per_page=${REST_PER_PAGE}&page=${page}`;
- const res = await fetch(url, {
- headers: {
- Accept: 'application/vnd.github.v3.star+json',
- ...(process.env.REMOTION_GITHUB_TOKEN && {
- Authorization: `Bearer ${process.env.REMOTION_GITHUB_TOKEN}`,
- }),
- },
- signal: abortSignal,
- });
- const rateLimitHit = res.status === 403 || res.status === 429;
- if (rateLimitHit) {
- console.error('GitHub REST API rate limit hit. Waiting 1 minute...');
- await new Promise((resolve) => {
- setTimeout(resolve, 60 * 1000);
- });
- return fetchPageViaRest({repoOrg, repoName, page, abortSignal});
- }
+ const url = `https://api.github.com/repos/${repoOrg}/${repoName}/stargazers?per_page=${REST_PER_PAGE}&page=${page}`;
+ const res = await fetch(url, {
+ headers: {
+ Accept: "application/vnd.github.v3.star+json",
+ ...(process.env.REMOTION_GITHUB_TOKEN && {
+ Authorization: `Bearer ${process.env.REMOTION_GITHUB_TOKEN}`,
+ }),
+ },
+ signal: abortSignal,
+ });
+ const rateLimitHit = res.status === 403 || res.status === 429;
+ if (rateLimitHit) {
+ console.error("GitHub REST API rate limit hit. Waiting 1 minute...");
+ await new Promise((resolve) => {
+ setTimeout(resolve, 60 * 1000);
+ });
+ return fetchPageViaRest({ repoOrg, repoName, page, abortSignal });
+ }
- const json = (await res.json()) as GitHubApiResponse;
- if (!res.ok) {
- throw new Error(`HTTP ${res.status} ${res.statusText} (${url})`);
- }
- return json.map((item) => {
- return {
- avatarUrl: item.user.avatar_url,
- login: item.user.login,
- name: item.user.login,
- date: item.starred_at,
- };
- });
+ const json = (await res.json()) as GitHubApiResponse;
+ if (!res.ok) {
+ throw new Error(`HTTP ${res.status} ${res.statusText} (${url})`);
+ }
+ return json.map((item) => {
+ return {
+ avatarUrl: item.user.avatar_url,
+ login: item.user.login,
+ name: item.user.login,
+ date: item.starred_at,
+ };
+ });
};
diff --git a/src/gh-styles.css b/src/gh-styles.css
index e21f631..7732b69 100644
--- a/src/gh-styles.css
+++ b/src/gh-styles.css
@@ -1,174 +1,174 @@
.break-word {
- word-break: break-word;
- word-wrap: break-word;
- overflow-wrap: break-word;
+ word-break: break-word;
+ word-wrap: break-word;
+ overflow-wrap: break-word;
}
.text-normal {
- font-weight: 400;
+ font-weight: 400;
}
.f3 {
- font-size: 20px !important;
+ font-size: 20px !important;
}
.octicon-repo {
- width: 0.8em;
- height: 0.8em;
+ width: 0.8em;
+ height: 0.8em;
}
.mrx {
- margin-right: 0.4em;
+ margin-right: 0.4em;
}
.flex-items-center {
- align-items: center !important;
+ align-items: center !important;
}
.flex-wrap {
- flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
}
.flex-self-stretch {
- align-self: stretch !important;
+ align-self: stretch !important;
}
.mx-1 {
- margin-right: 4px !important;
- margin-left: 4px !important;
+ margin-right: 4px !important;
+ margin-left: 4px !important;
}
.flex-self-stretch {
- align-self: stretch !important;
+ align-self: stretch !important;
}
.color-text-secondary {
- color: #586069 !important;
+ color: #586069 !important;
}
.mr-2 {
- margin-right: 8px !important;
+ margin-right: 8px !important;
}
.flex-self-stretch {
- align-self: stretch !important;
+ align-self: stretch !important;
}
b,
strong {
- font-weight: 600;
+ font-weight: 600;
}
a {
- color: #0366d6;
- text-decoration: none;
+ color: #0366d6;
+ text-decoration: none;
}
.d-flex {
- display: flex !important;
+ display: flex !important;
}
.flex-items-center {
- align-items: center !important;
+ align-items: center !important;
}
.flex-wrap {
- flex-wrap: wrap !important;
+ flex-wrap: wrap !important;
}
svg:not(:root) {
- overflow: hidden;
+ overflow: hidden;
}
.mr-2 {
- margin-right: 8px !important;
+ margin-right: 8px !important;
}
.color-text-secondary {
- color: #586069 !important;
+ color: #586069 !important;
}
.octicon {
- display: inline-block;
- overflow: visible !important;
- vertical-align: text-bottom;
- fill: currentColor;
+ display: inline-block;
+ overflow: visible !important;
+ vertical-align: text-bottom;
+ fill: currentColor;
}
body:not(.full-width) div.application-main main > div.hide-full-screen > * > * {
- margin-left: 0px !important;
+ margin-left: 0px !important;
}
.mr-3 {
- margin-right: 16px !important;
+ margin-right: 16px !important;
}
.min-width-0 {
- min-width: 0 !important;
+ min-width: 0 !important;
}
.width-fit {
- max-width: 100% !important;
+ max-width: 100% !important;
}
.flex-auto {
- flex: auto !important;
+ flex: auto !important;
}
* {
- box-sizing: border-box;
+ box-sizing: border-box;
}
.flex-shrink-0 {
- flex-shrink: 0 !important;
+ flex-shrink: 0 !important;
}
.d-md-inline {
- display: inline !important;
+ display: inline !important;
}
.pagehead-actions > li:last-child {
- margin-right: 0;
+ margin-right: 0;
}
.pagehead-actions > li {
- float: left;
- margin: 0 10px 0 0;
- font-size: 11px;
- color: var(--color-text-primary);
- list-style-type: none;
+ float: left;
+ margin: 0 10px 0 0;
+ font-size: 11px;
+ color: var(--color-text-primary);
+ list-style-type: none;
}
.d-block {
- display: block !important;
+ display: block !important;
}
form {
- display: block;
- margin-top: 0em;
+ display: block;
+ margin-top: 0em;
}
button {
- cursor: pointer;
- border-radius: 0;
+ cursor: pointer;
+ border-radius: 0;
}
button,
input,
select,
textarea {
- font-family: inherit;
- font-size: inherit;
- line-height: inherit;
+ font-family: inherit;
+ font-size: inherit;
+ line-height: inherit;
}
button,
select {
- text-transform: none;
+ text-transform: none;
}
button,
input {
- overflow: visible;
+ overflow: visible;
}
button,
input,
select,
textarea {
- font: inherit;
- margin: 0;
+ font: inherit;
+ margin: 0;
}
ol,
ul {
- padding-left: 0;
- margin-top: 0;
- margin-bottom: 0;
+ padding-left: 0;
+ margin-top: 0;
+ margin-bottom: 0;
}
h1 {
- display: block;
- font-size: 2em;
- margin-block-start: 0.67em;
- margin-block-end: 0.67em;
- margin-inline-start: 0px;
- margin-inline-end: 0px;
- font-weight: bold;
+ display: block;
+ font-size: 2em;
+ margin-block-start: 0.67em;
+ margin-block-end: 0.67em;
+ margin-inline-start: 0px;
+ margin-inline-end: 0px;
+ font-weight: bold;
}
h1,
h2,
@@ -176,115 +176,115 @@ h3,
h4,
h5,
h6 {
- margin-top: 0;
- margin-bottom: 0;
+ margin-top: 0;
+ margin-bottom: 0;
}
.starring-container.on .starred,
.starring-container .unstarred {
- display: block;
+ display: block;
}
.btn-sm .octicon {
- vertical-align: text-top;
+ vertical-align: text-top;
}
.btn .octicon {
- margin-right: 4px;
- color: var(--color-text-tertiary);
- vertical-align: text-bottom;
+ margin-right: 4px;
+ color: var(--color-text-tertiary);
+ vertical-align: text-bottom;
}
svg:not(:root) {
- overflow: hidden;
+ overflow: hidden;
}
.mr-1 {
- margin-right: 4px !important;
+ margin-right: 4px !important;
}
.social-count {
- position: relative;
- float: left;
- padding: 3px 12px;
- font-size: 12px;
- font-weight: 600;
- line-height: 20px;
- color: var(--color-text-primary);
- vertical-align: middle;
- background-color: var(--color-social-count-bg);
- border: 1px solid var(--color-btn-border);
- border-left: 0;
- border-top-right-radius: 6px;
- border-bottom-right-radius: 6px;
- box-shadow: var(--color-shadow-small), var(--color-shadow-highlight);
- font-variant-numeric: tabular-nums;
+ position: relative;
+ float: left;
+ padding: 3px 12px;
+ font-size: 12px;
+ font-weight: 600;
+ line-height: 20px;
+ color: var(--color-text-primary);
+ vertical-align: middle;
+ background-color: var(--color-social-count-bg);
+ border: 1px solid var(--color-btn-border);
+ border-left: 0;
+ border-top-right-radius: 6px;
+ border-bottom-right-radius: 6px;
+ box-shadow: var(--color-shadow-small), var(--color-shadow-highlight);
+ font-variant-numeric: tabular-nums;
}
.btn {
- position: relative;
- display: inline-block;
- padding: 5px 16px;
- font-size: 14px;
- font-weight: 500;
- line-height: 20px;
- white-space: nowrap;
- vertical-align: middle;
- cursor: pointer;
- -webkit-user-select: none;
- -moz-user-select: none;
- -ms-user-select: none;
- user-select: none;
- border: 1px solid;
- border-radius: 6px;
- -webkit-appearance: none;
- -moz-appearance: none;
- appearance: none;
+ position: relative;
+ display: inline-block;
+ padding: 5px 16px;
+ font-size: 14px;
+ font-weight: 500;
+ line-height: 20px;
+ white-space: nowrap;
+ vertical-align: middle;
+ cursor: pointer;
+ -webkit-user-select: none;
+ -moz-user-select: none;
+ -ms-user-select: none;
+ user-select: none;
+ border: 1px solid;
+ border-radius: 6px;
+ -webkit-appearance: none;
+ -moz-appearance: none;
+ appearance: none;
}
.btn {
- color: var(--color-btn-text);
- background-color: var(--color-btn-bg);
- border-color: var(--color-btn-border);
- box-shadow: var(--color-btn-shadow), var(--color-btn-inset-shadow);
- transition: 0.2s cubic-bezier(0.3, 0, 0.5, 1);
- transition-property: color, background-color, border-color;
+ color: var(--color-btn-text);
+ background-color: var(--color-btn-bg);
+ border-color: var(--color-btn-border);
+ box-shadow: var(--color-btn-shadow), var(--color-btn-inset-shadow);
+ transition: 0.2s cubic-bezier(0.3, 0, 0.5, 1);
+ transition-property: color, background-color, border-color;
}
.btn-sm {
- padding: 3px 12px;
- font-size: 12px;
- line-height: 20px;
+ padding: 3px 12px;
+ font-size: 12px;
+ line-height: 20px;
}
.btn-with-count {
- float: left;
- border-top-right-radius: 0;
- border-bottom-right-radius: 0;
+ float: left;
+ border-top-right-radius: 0;
+ border-bottom-right-radius: 0;
}
.btn .octicon {
- margin-right: 4px;
- color: var(--color-text-tertiary);
- vertical-align: text-bottom;
+ margin-right: 4px;
+ color: var(--color-text-tertiary);
+ vertical-align: text-bottom;
}
.btn-sm .octicon {
- vertical-align: text-top;
+ vertical-align: text-top;
}
body {
- font-family:
- -apple-system,
- BlinkMacSystemFont,
- Segoe UI,
- Arial,
- Noto Sans,
- Noto Sans CJK SC,
- sans-serif,
- Apple Color Emoji,
- Segoe UI Emoji,
- Noto Color Emoji;
- line-height: 1.5;
- --color-text-primary: #24292e;
- --color-text-tertiary: #6a737d;
- --color-social-count-bg: #ffff;
- --color-btn-border: #1b1f2326;
- --color-btn-text: #24292e;
- --color-btn-bg: #fafbfc;
- --color-shadow-small: 0 1px 0 rgba(27, 31, 35, 0.04);
- --color-shadow-highlight: inset 0 1px 0 hsla(0, 0%, 100%, 0.25);
- --color-border-secondary: #ebedef;
- background-color: #f6f8fa;
+ font-family:
+ -apple-system,
+ BlinkMacSystemFont,
+ Segoe UI,
+ Arial,
+ Noto Sans,
+ Noto Sans CJK SC,
+ sans-serif,
+ Apple Color Emoji,
+ Segoe UI Emoji,
+ Noto Color Emoji;
+ line-height: 1.5;
+ --color-text-primary: #24292e;
+ --color-text-tertiary: #6a737d;
+ --color-social-count-bg: #ffff;
+ --color-btn-border: #1b1f2326;
+ --color-btn-text: #24292e;
+ --color-btn-bg: #fafbfc;
+ --color-shadow-small: 0 1px 0 rgba(27, 31, 35, 0.04);
+ --color-shadow-highlight: inset 0 1px 0 hsla(0, 0%, 100%, 0.25);
+ --color-border-secondary: #ebedef;
+ background-color: #f6f8fa;
}
diff --git a/src/index.ts b/src/index.ts
index d831f7b..f31c790 100644
--- a/src/index.ts
+++ b/src/index.ts
@@ -1,4 +1,4 @@
-import {registerRoot} from 'remotion';
-import {RemotionRoot} from './Root';
+import { registerRoot } from "remotion";
+import { RemotionRoot } from "./Root";
registerRoot(RemotionRoot);
diff --git a/src/repo-header.tsx b/src/repo-header.tsx
index f861852..e64d3db 100644
--- a/src/repo-header.tsx
+++ b/src/repo-header.tsx
@@ -1,112 +1,112 @@
-import './gh-styles.css';
+import "./gh-styles.css";
export function RepoHeader({
- stars,
- org,
- name,
+ stars,
+ org,
+ name,
}: {
- stars: number;
- org: string;
- name: string;
+ stars: number;
+ org: string;
+ name: string;
}) {
- return (
-
- );
+ return (
+
+ );
}
diff --git a/src/utils.ts b/src/utils.ts
index a126849..1c42fc8 100644
--- a/src/utils.ts
+++ b/src/utils.ts
@@ -1,96 +1,96 @@
-const {sqrt, exp, sin, cos} = Math;
+const { sqrt, exp, sin, cos } = Math;
export function getProgress(
- frame: number,
- totalFrames: number,
- totalStars: number,
- fps: number,
+ frame: number,
+ totalFrames: number,
+ totalStars: number,
+ fps: number,
) {
- const table = getTable(totalFrames, totalStars, fps);
- if (frame >= table.length - 1) {
- return totalStars;
- }
- return table[frame][2];
+ const table = getTable(totalFrames, totalStars, fps);
+ if (frame >= table.length - 1) {
+ return totalStars;
+ }
+ return table[frame][2];
}
function getTable(totalFrames: number, totalStars: number, fps: number) {
- const table = [];
- let px = 0;
- let pv = 0;
- for (let frame = 0; frame < totalFrames; frame++) {
- const target = Math.ceil(
- easeInOutCubic(frame / (totalFrames - 1)) * totalStars,
- );
- const {x, v} = customSpring({
- x0: px,
- v0: pv,
- t0: 0,
- t: 1000 / fps,
- k: 170, // Stiffness
- c: 26, // Damping
- m: 1, // Mass
- X: target,
- });
- px = x;
- pv = v;
- table.push([frame, target, x]);
- }
- return table;
+ const table = [];
+ let px = 0;
+ let pv = 0;
+ for (let frame = 0; frame < totalFrames; frame++) {
+ const target = Math.ceil(
+ easeInOutCubic(frame / (totalFrames - 1)) * totalStars,
+ );
+ const { x, v } = customSpring({
+ x0: px,
+ v0: pv,
+ t0: 0,
+ t: 1000 / fps,
+ k: 170, // Stiffness
+ c: 26, // Damping
+ m: 1, // Mass
+ X: target,
+ });
+ px = x;
+ pv = v;
+ table.push([frame, target, x]);
+ }
+ return table;
}
function easeInOutCubic(x: number) {
- return x < 0.5 ? 4 * x * x * x : 1 - (-2 * x + 2) ** 3 / 2;
+ return x < 0.5 ? 4 * x * x * x : 1 - (-2 * x + 2) ** 3 / 2;
}
// From https://github.com/pomber/use-spring/blob/master/src/spring.ts
function customSpring({
- x0,
- v0,
- t0,
- t,
- k,
- c,
- m,
- X,
+ x0,
+ v0,
+ t0,
+ t,
+ k,
+ c,
+ m,
+ X,
}: {
- x0: number;
- v0: number;
- t0: number;
- t: number;
- k: number;
- c: number;
- m: number;
- X: number;
+ x0: number;
+ v0: number;
+ t0: number;
+ t: number;
+ k: number;
+ c: number;
+ m: number;
+ X: number;
}) {
- const dx = x0 - X;
- const dt = (t - t0) / 1000;
- const radicand = c * c - 4 * k * m;
- if (radicand > 0) {
- const rp = (-c + sqrt(radicand)) / (2 * m);
- const rn = (-c - sqrt(radicand)) / (2 * m);
- const a = (dx * rp - v0) / (rp - rn);
- const b = (v0 - dx * rn) / (rp - rn);
- return {
- x: X + a * exp(rn * dt) + b * exp(rp * dt),
- v: a * rn * exp(rn * dt) + b * rp * exp(rp * dt),
- };
- }
- if (radicand < 0) {
- const r = -c / (2 * m);
- const s = sqrt(-radicand) / (2 * m);
- const a = dx;
- const b = (v0 - r * dx) / s;
- return {
- x: X + exp(r * dt) * (a * cos(s * dt) + b * sin(s * dt)),
- v:
- exp(r * dt) *
- ((b * s + a * r) * cos(s * dt) - (a * s - b * r) * sin(s * dt)),
- };
- }
- const r = -c / (2 * m);
- const a = dx;
- const b = v0 - r * dx;
- return {
- x: X + (a + b * dt) * exp(r * dt),
- v: (b + a * r + b * r * dt) * exp(r * dt),
- };
+ const dx = x0 - X;
+ const dt = (t - t0) / 1000;
+ const radicand = c * c - 4 * k * m;
+ if (radicand > 0) {
+ const rp = (-c + sqrt(radicand)) / (2 * m);
+ const rn = (-c - sqrt(radicand)) / (2 * m);
+ const a = (dx * rp - v0) / (rp - rn);
+ const b = (v0 - dx * rn) / (rp - rn);
+ return {
+ x: X + a * exp(rn * dt) + b * exp(rp * dt),
+ v: a * rn * exp(rn * dt) + b * rp * exp(rp * dt),
+ };
+ }
+ if (radicand < 0) {
+ const r = -c / (2 * m);
+ const s = sqrt(-radicand) / (2 * m);
+ const a = dx;
+ const b = (v0 - r * dx) / s;
+ return {
+ x: X + exp(r * dt) * (a * cos(s * dt) + b * sin(s * dt)),
+ v:
+ exp(r * dt) *
+ ((b * s + a * r) * cos(s * dt) - (a * s - b * r) * sin(s * dt)),
+ };
+ }
+ const r = -c / (2 * m);
+ const a = dx;
+ const b = v0 - r * dx;
+ return {
+ x: X + (a + b * dt) * exp(r * dt),
+ v: (b + a * r + b * r * dt) * exp(r * dt),
+ };
}
diff --git a/src/wait-for-no-input.ts b/src/wait-for-no-input.ts
index 2fa0671..7d30a2d 100644
--- a/src/wait-for-no-input.ts
+++ b/src/wait-for-no-input.ts
@@ -1,25 +1,25 @@
-import {getRemotionEnvironment} from 'remotion';
+import { getRemotionEnvironment } from "remotion";
export const waitForNoInput = (signal: AbortSignal, ms: number) => {
- // Don't wait during rendering
- if (getRemotionEnvironment().isRendering) {
- return Promise.resolve();
- }
+ // Don't wait during rendering
+ if (getRemotionEnvironment().isRendering) {
+ return Promise.resolve();
+ }
- if (signal.aborted) {
- return Promise.reject(new Error('stale'));
- }
+ if (signal.aborted) {
+ return Promise.reject(new Error("stale"));
+ }
- return Promise.race([
- new Promise((_, reject) => {
- signal.addEventListener('abort', () => {
- reject(new Error('stale'));
- });
- }),
- new Promise((resolve) => {
- setTimeout(() => {
- resolve();
- }, ms);
- }),
- ]);
+ return Promise.race([
+ new Promise((_, reject) => {
+ signal.addEventListener("abort", () => {
+ reject(new Error("stale"));
+ });
+ }),
+ new Promise((resolve) => {
+ setTimeout(() => {
+ resolve();
+ }, ms);
+ }),
+ ]);
};
diff --git a/tsconfig.json b/tsconfig.json
index 970257f..9009904 100644
--- a/tsconfig.json
+++ b/tsconfig.json
@@ -1,16 +1,16 @@
{
- "compilerOptions": {
- "target": "ES2018",
- "module": "commonjs",
- "jsx": "react-jsx",
- "outDir": "./dist",
- "strict": true,
- "noEmit": true,
- "lib": ["es2015", "DOM"],
- "esModuleInterop": true,
- "skipLibCheck": true,
- "forceConsistentCasingInFileNames": true,
- "strictNullChecks": true,
- "noUnusedLocals": true
- }
+ "compilerOptions": {
+ "target": "ES2018",
+ "module": "commonjs",
+ "jsx": "react-jsx",
+ "outDir": "./dist",
+ "strict": true,
+ "noEmit": true,
+ "lib": ["es2015", "DOM"],
+ "esModuleInterop": true,
+ "skipLibCheck": true,
+ "forceConsistentCasingInFileNames": true,
+ "strictNullChecks": true,
+ "noUnusedLocals": true
+ }
}