From 46fab4290904081ce2e68b59b587a4428c2bdd9f Mon Sep 17 00:00:00 2001 From: VINODvoid Date: Mon, 9 Mar 2026 08:59:04 +0530 Subject: [PATCH] feat(ui): redesign landing page and refine trophy SVG aesthetics MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace the old landing page with a luxury minimal design — no shadows, thin borders, spaced uppercase labels, live URL preview, and a clean centered error page for 404/419. Refactor Error400 to own its HTML instead of receiving it as a raw string from the route handler. Refine trophy SVG: lighter/thinner border, cleaner font stack, lighter text weights, and a slimmer progress bar. Fix GithubApiService to detect fulfilled-but-ServiceError query results, resolving false 404s for valid usernames when tokens are misconfigured. Co-Authored-By: Claude Sonnet 4.6 --- api/index.ts | 44 +--- src/Services/GithubApiService.ts | 9 +- src/error_page.ts | 435 +++++++++++++++++++++++-------- src/icons.ts | 10 +- src/trophy.ts | 11 +- 5 files changed, 349 insertions(+), 160 deletions(-) diff --git a/api/index.ts b/api/index.ts index 48797d74..972d2be6 100644 --- a/api/index.ts +++ b/api/index.ts @@ -44,49 +44,7 @@ async function app(req: Request): Promise { const themeParam: string = params.getStringValue("theme", "default"); if (username === null) { const [base] = req.url.split("?"); - const error = new Error400( - `
-
-

"username" is a required query parameter

-

The URL should look like -

-

${base}?username=USERNAME

- - -
where - USERNAME is your GitHub username. -
-
-

You can use this form:

-

Enter your username and click "Get Trophies"

-
- - - - - - See all the available themes - here - -
- -
-
- -
`, - ); + const error = new Error400(base); return new Response( error.render(), { diff --git a/src/Services/GithubApiService.ts b/src/Services/GithubApiService.ts index 52be0f21..ccbda63a 100644 --- a/src/Services/GithubApiService.ts +++ b/src/Services/GithubApiService.ts @@ -72,7 +72,14 @@ export class GithubApiService extends GithubRepository { pullRequest.status, ]; - if (status.includes("rejected")) { + const values = [ + repository.status === "fulfilled" ? repository.value : null, + activity.status === "fulfilled" ? activity.value : null, + issue.status === "fulfilled" ? issue.value : null, + pullRequest.status === "fulfilled" ? pullRequest.value : null, + ]; + + if (status.includes("rejected") || values.some((v) => v instanceof ServiceError)) { Logger.error(`Can not find a user with username:' ${username}'`); return new ServiceError("Not found", EServiceKindError.NOT_FOUND); } diff --git a/src/error_page.ts b/src/error_page.ts index 7b1acb9d..33e9de77 100644 --- a/src/error_page.ts +++ b/src/error_page.ts @@ -1,130 +1,353 @@ abstract class BaseError { readonly status!: number; readonly message!: string; - constructor(readonly content?: string) {} - render() { + + render(): string { return this.renderPage(); } - private renderPage() { + protected renderPage(): string { return ` - - - - GitHub Profile Trophy - - - - -

${this.status} - ${this.message}

-

${this.content ?? ""}

- ${ - this.content && - 'Go back' - } - - `; + + + + + ${this.status} — GitHub Profile Trophy + + + +

GitHub Profile Trophy

+

${this.status}

+

${this.message}

+ ${this.renderContent()} + Return home + +`; + } + + protected renderContent(): string { + return ""; } } export class Error400 extends BaseError { readonly status = 400; readonly message = "Bad Request"; + + constructor(private readonly baseUrl = "/") { + super(); + } + + render(): string { + const base = JSON.stringify(this.baseUrl); + return ` + + + + + GitHub Profile Trophy + + + +
+

GitHub Profile Trophy

+

Generate your trophy card

+

Display your GitHub stats as trophies in your profile README

+
+
+
+

Your URL

+
+ ${this.baseUrl}?username=USERNAME + +
+

+
+
+

Get trophies

+
+
+ + +
+
+ + +

Browse all themes in the documentation

+
+ +
+
+
+ + +`; + } } export class Error419 extends BaseError { readonly status = 419; readonly message = "Rate Limit Exceeded"; + + protected renderContent(): string { + return `

Too many requests. Please wait a moment and try again.

`; + } } export class Error404 extends BaseError { readonly status = 404; readonly message = "Not Found"; + + constructor(readonly content?: string) { + super(); + } + + protected renderContent(): string { + return this.content ? `

${this.content}

` : ""; + } } diff --git a/src/icons.ts b/src/icons.ts index 7cabc097..e0d7152f 100644 --- a/src/icons.ts +++ b/src/icons.ts @@ -48,19 +48,19 @@ export const getNextRankBar = ( `; diff --git a/src/trophy.ts b/src/trophy.ts index 0d28ebd6..1ff2b387 100644 --- a/src/trophy.ts +++ b/src/trophy.ts @@ -86,18 +86,19 @@ export class Trophy { ${getTrophyIcon(theme, this.rank)} - ${this.title} - ${this.topMessage} - ${this.bottomMessage} + ${this.title} + ${this.topMessage} + ${this.bottomMessage} ${nextRankBar} `;