Skip to content

Commit

Permalink
Showing a condensed version of JSR link
Browse files Browse the repository at this point in the history
  • Loading branch information
taras committed Dec 15, 2024
1 parent 801aa2a commit a3e0746
Show file tree
Hide file tree
Showing 10 changed files with 364 additions and 172 deletions.
8 changes: 8 additions & 0 deletions www/assets/images/jsr-logo.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
32 changes: 32 additions & 0 deletions www/components/package/cicle-score.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
import { PackageDetailsResult } from "../../hooks/use-jsr-client.ts";

export function CircleScore({ details }: { details: PackageDetailsResult }) {
return (
<>
<h3 class="text-2xl flex justify-center">
<img src="/assets/images/jsr-logo.svg" alt="JSR Logo" class="mr-2" />
Score
</h3>
<div
class={`h-32 w-32 justify-center aspect-square rounded-full p-1.5 ${getScoreBgColorClass(
details.score,
)}`}
style="background-image: conic-gradient(transparent, transparent 100%, #e7e8e8 100%)"
>
<span class="rounded-full w-full h-full bg-white flex justify-center items-center text-center text-3xl font-bold">
{details.score}%
</span>
</div>
</>
);
}

/** @src https://github.com/jsr-io/jsr/blob/34603e996f56eb38e811619f8aebc6e5c4ad9fa7/frontend/utils/score_ring_color.ts */
export function getScoreBgColorClass(score: number): string {
if (score >= 90) {
return "bg-green-500";
} else if (score >= 60) {
return "bg-yellow-500";
}
return "bg-red-500";
}
4 changes: 4 additions & 0 deletions www/components/package/cross.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
<svg xmlns="http://www.w3.org/2000/svg" aria-hidden="true" stroke="currentColor" fill="none"
viewBox="0 0 24 24">
<path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path>
</svg>
38 changes: 38 additions & 0 deletions www/components/package/icons.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
// @ts-nocheck Property 'svg' does not exist on type 'JSX.IntrinsicElements'.

export function Check() {
return (
<svg
class="h-6 stroke-green-500 stroke-2 -mt-px"
aria-hidden="true"
viewBox="0 0 24 24"
stroke-width="2"
stroke="currentColor"
fill="none"
stroke-linecap="round"
stroke-linejoin="round"
>
<path stroke="none" d="M0 0h24v24H0z" fill="none"></path>
<path d="M5 12l5 5l10 -10"></path>
</svg>
);
}

export function Cross() {
return (
<svg
class="h-6 stroke-red-500 stroke-2 -mt-px"
aria-hidden="true"
stroke="currentColor"
fill="none"
viewBox="0 0 24 24"
>
<path
stroke-linecap="round"
stroke-linejoin="round"
stroke-width="2"
d="M6 18L18 6M6 6l12 12"
></path>
</svg>
);
}
128 changes: 128 additions & 0 deletions www/components/score-card.tsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,128 @@
import { Package, usePackage } from "../hooks/use-package.tsx";
import {
PackageDetailsResult,
type PackageScoreResult,
} from "../hooks/use-jsr-client.ts";
import { Check, Cross } from "./package/icons.tsx";

export function ScoreCard() {
return function* () {
const pkg = yield* usePackage();
const [details, score] = yield* pkg.jsrPackageDetails();

return (
<div class="flex flex-col items-center space-y-5 w-full border-2 border-cyan-100 rounded-lg p-8">
{details.success && details.data ? (
<>
<a class="flex text-lg space-x-2 font-semibold" href={`${pkg.jsr}`}>
<span>Available on</span>
<img
src="/assets/images/jsr-logo.svg"
alt="JSR Logo"
class="mr-2"
/>
</a>
<div class="flex flex-col md:flex-row gap-2 md:gap-8 items-between">
<div class="flex flex-row md:flex-col items-center md:items-end gap-2 md:gap-1.5 text-sm font-bold">
<div aria-hidden="true">Works with</div>
<div class="min-w-content font-semibold select-none">
<div class="flex items-center *:mx-0.5 flex-row-reverse"></div>
</div>
</div>
<a class="flex flex-row md:flex-col items-baseline md:items-end gap-2 md:gap-1.5 text-sm font-bold"
href={`${new URL('./score/', pkg.jsr)}`}
>
<div>JSR Score</div>
<div
class={`!leading-none md:text-xl ${getScoreTextColorClass(details.data.score)}`}
>
{details.data.score}%
</div>
</a>
</div>
{score.success && score.data ? (
<ScoreDescription score={score.data} pkg={pkg} />
) : (
<></>
)}
</>
) : (
<></>
)}
</div>
);
};
}

function ScoreDescription({
score,
pkg,
}: {
score: PackageScoreResult;
pkg: Package;
}) {
const {
percentageDocumentedSymbols: _percentageDocumentedSymbols,
total: _total,
...flags
} = score;

const SCORE_MAP = {
hasReadme: "Has a readme or module doc",
hasReadmeExamples: "Has examples in the readme or module doc",
allEntrypointsDocs: "Has module docs in all entrypoints",
allFastCheck: (
<>
No{" "}
<a class="underline" href="https://jsr.io/docs/about-slow-types">
slow types
</a>{" "}
are used
</>
),
hasProvenance: "Has provenance",
hasDescription: (
<>
Has a{" "}
<a
class="underline"
href={`${new URL("./settings#description", pkg.jsr)}`}
>
description
</a>
</>
),
atLeastOneRuntimeCompatible: "At least one runtime is marked as compatible",
multipleRuntimesCompatible:
"At least two runtimes are marked as compatible",
};

return (
<details>
<summary class="text-gray-500 text-sm">
The JSR score is a measure of the overall quality of a package, expand
for more detail.
</summary>
<ul class="flex flex-col divide-y-1 w-full pt-5 px-2">
<>
{Object.entries(flags).map(([key, value]) => (
<li class="grid grid-cols-[auto_1fr_auto] gap-x-3 py-3 first:pt-0 items-start">
{value ? <Check /> : <Cross />}
<span>{SCORE_MAP[key as keyof typeof flags]}</span>
</li>
))}
</>
</ul>
</details>
);
}

/** @src https://github.com/jsr-io/jsr/blob/34603e996f56eb38e811619f8aebc6e5c4ad9fa7/frontend/utils/score_ring_color.ts */
export function getScoreTextColorClass(score: number): string {
if (score >= 90) {
return "text-green-600";
} else if (score >= 60) {
return "text-yellow-700";
}
return "text-red-500";
}
7 changes: 0 additions & 7 deletions www/components/score.tsx

This file was deleted.

89 changes: 23 additions & 66 deletions www/hooks/use-jsr-client.ts
Original file line number Diff line number Diff line change
Expand Up @@ -10,59 +10,54 @@ const PackageScore = z.object({
hasReadme: z.boolean(),
hasReadmeExamples: z.boolean(),
allEntrypointsDocs: z.boolean(),
percentageDocumentedSymbols: z.number().min(0).max(1),
allFastCheck: z.boolean(),
hasProvenance: z.boolean(),
hasDescription: z.boolean(),
atLeastOneRuntimeCompatible: z.boolean(),
multipleRuntimesCompatible: z.boolean(),
total: z.number().min(0).max(1),
percentageDocumentedSymbols: z.number().min(0).max(1),
total: z.number(),
});

const PackageDetails = z.object({
scope: z.string(),
name: z.string(),
description: z.string(),
runtimeCompat: z.object({
browser: z.boolean(),
deno: z.boolean(),
node: z.boolean(),
workerd: z.boolean(),
bun: z.boolean(),
browser: z.boolean().optional(),
deno: z.boolean().optional(),
node: z.boolean().optional(),
bun: z.boolean().optional(),
workerd: z.boolean().optional()
}),
createdAt: z.string().datetime({ precision: 3 }),
updatedAt: z.string().datetime({ precision: 3 }),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime(),
githubRepository: z.object({
id: z.number(),
owner: z.string(),
name: z.string(),
createdAt: z.string().datetime(),
updatedAt: z.string().datetime(),
}),
score: z.number().min(0).max(1),
score: z.number().min(0).max(100),
});

export type PackageScoreType = z.infer<typeof PackageScore>;
export type PackageDetailsType = z.infer<typeof PackageDetails>;
export type PackageScoreResult = z.infer<typeof PackageScore>;
export type PackageDetailsResult = z.infer<typeof PackageDetails>;

export interface JSRClient {
getPackageScore: (
params: GetPackageDetailsParams,
) => Operation<PackageScoreType>;
) => Operation<z.SafeParseReturnType<unknown, PackageScoreResult>>;
getPackageDetails: (
params: GetPackageDetailsParams,
) => Operation<PackageDetailsType>;
) => Operation<z.SafeParseReturnType<unknown, PackageDetailsResult>>;
}

const JSRClientContext = createContext<JSRClient>("jsr-client");

export function* initJSRClient({ token }: { token: string }) {
let client: JSRClient | undefined;
if (token === "example") {
console.info(
`JSR Client Context is using the example token; will return example data`,
);
client = createExampleJSRClient();
} else {
client = createJSRClient(token);
}
let client = createJSRClient(token);

return yield* JSRClientContext.set(client);
}
Expand All @@ -86,7 +81,8 @@ function createJSRClient(token: string): JSRClient {
);

if (response.ok) {
return PackageScore.parse(yield* call(() => response.json()));
const json = yield* call(() => response.json());
return yield* call(() => PackageScore.safeParseAsync(json));
}

throw new Error(`${response.status}: ${response.statusText}`);
Expand All @@ -104,50 +100,11 @@ function createJSRClient(token: string): JSRClient {
);

if (response.ok) {
return PackageDetails.parse(yield* call(() => response.json()));
const json = yield* call(() => response.json());
return yield* call(() => PackageDetails.safeParseAsync(json));
}

throw new Error(`${response.status}: ${response.statusText}`);
},
};
}

function createExampleJSRClient(): JSRClient {
return {
*getPackageScore() {
return {
hasReadme: true,
hasReadmeExamples: true,
allEntrypointsDocs: true,
percentageDocumentedSymbols: 1,
allFastCheck: true,
hasProvenance: true,
hasDescription: true,
atLeastOneRuntimeCompatible: true,
multipleRuntimesCompatible: true,
total: 1,
};
},
*getPackageDetails() {
return {
scope: "effection-contrib",
name: "websocket",
description: "Use the WebSocket API as an Effection resource.",
runtimeCompat: {
browser: true,
deno: true,
node: true,
workerd: true,
bun: true,
},
createdAt: "2024-12-15T02:18:26.624Z",
updatedAt: "2024-12-15T02:18:26.624Z",
githubRepository: {
owner: "thefrontside",
name: "effection-contribs",
},
score: 1,
};
},
};
}
}
Loading

0 comments on commit a3e0746

Please sign in to comment.