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 ( -
-
-

- - - - - / - - {name} - -

-
- -
- ); + return ( +
+
+

+ + + + + / + + {name} + +

+
+ +
+ ); } 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 + } }