Skip to content

Commit 2c05b7e

Browse files
committed
Add error page
1 parent 25fdc6c commit 2c05b7e

File tree

7 files changed

+187
-59
lines changed

7 files changed

+187
-59
lines changed

main.ts

Lines changed: 12 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import { Hono } from "hono";
22
import { listAllFeatures } from "./endpoints/features.ts";
33
import { minBrowserVersion } from "./endpoints/min-browser-version-for-feature.ts";
4+
import { RenderError } from "./rendering/error.tsx";
45

56
const app = new Hono();
67

@@ -26,22 +27,20 @@ if (Deno.env.get("DEBUG") !== "true") {
2627
console.log("Debug mode is enabled. CORS headers will not be set.");
2728
}
2829

29-
//app.onError((err, c) => {
30-
// console.error(`error throwing returning image ${err}`)
31-
// return c.body(
32-
// `<svg xmlns="http://www.w3.org/2000/svg" width="600" height="30">
33-
// <rect width="800" height="600" fill="#f0f0f0" stroke="#ccc"/>
34-
// <text x="10" y="20" font-family="Arial" font-size="16" fill="#333">Error ${err.message}</text>
35-
// </svg>`,
36-
// 500,
37-
// { 'Content-Type': 'image/svg+xml' }
38-
// );
39-
// });
40-
41-
// http://localhost:8000/min-browser-version?features=AmbientLightSensor&filter=chrome&filter=firefox
30+
app.onError((err, c) => {
31+
console.error(`error throwing returning image ${err}`);
32+
return c.body(
33+
RenderError({ error: err.message }),
34+
500,
35+
{ "Content-Type": "image/svg+xml" },
36+
);
37+
});
4238

4339
app.get("/all-features", listAllFeatures);
4440
app.get("/min-browser-version", minBrowserVersion);
41+
app.get("/", (c) => {
42+
return c.text("Welcome to the Can I Use Embed API. Use /all-features to get a list of all features.");
43+
});
4544

4645
Deno.serve({
4746
hostname: "0.0.0.0",

rendering/SvgLinkElement.tsx

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1 @@
1+
export const SvgA = <a {...{ "xlink:href": "test" } as any}></a>;

rendering/badge.tsx

Lines changed: 30 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@ import { Icon } from "./icon.tsx";
44
import { getTextWidth } from "./get-text-size.ts";
55
import { renderToString } from "preact-render-to-string";
66
import { loadEmbeddableFontSync } from "./load-font.ts";
7+
import { css } from "./css-fake-function.ts";
78

89
function getRenderBrowserWithCheckmarkWidth(
910
browserName: string,
@@ -117,38 +118,38 @@ export function Badges(
117118
>
118119
<defs>
119120
<style>
120-
{`
121-
@font-face {
122-
font-family: 'Roboto';
123-
src: url('${robotFont}') format('woff2');
124-
font-weight: normal;
125-
font-style: normal;
126-
}
121+
{css`
122+
@font-face {
123+
font-family: "Roboto";
124+
src: url("${robotFont}") format("woff2");
125+
font-weight: normal;
126+
font-style: normal;
127+
}
127128
128-
text {
129-
font-family: 'Roboto', 'Arial', sans-serif;
130-
}
129+
text {
130+
font-family: "Roboto", "Arial", sans-serif;
131+
}
131132
132-
:root {
133-
--badge-bg-color: #f8f9fa;
134-
--badge-border-color: #e9ecef;
135-
--badge-text-color: #000;
136-
--badge-text-color-light: #666;
137-
--badge-checkmark-color: #34A853;
138-
--badge-xmark-color: #EA4335;
139-
}
133+
:root {
134+
--badge-bg-color: #f8f9fa;
135+
--badge-border-color: #e9ecef;
136+
--badge-text-color: #000;
137+
--badge-text-color-light: #666;
138+
--badge-checkmark-color: #34a853;
139+
--badge-xmark-color: #ea4335;
140+
}
140141
141-
@media (prefers-color-scheme: dark) {
142-
:root {
143-
--badge-bg-color: #343a40;
144-
--badge-border-color: #495057;
145-
--badge-text-color: #f8f9fa;
146-
--badge-text-color-light: #adb5bd;
147-
--badge-checkmark-color: #28a745;
148-
--badge-xmark-color: #dc3545;
149-
}
150-
}
151-
`}
142+
@media (prefers-color-scheme: dark) {
143+
:root {
144+
--badge-bg-color: #343a40;
145+
--badge-border-color: #495057;
146+
--badge-text-color: #f8f9fa;
147+
--badge-text-color-light: #adb5bd;
148+
--badge-checkmark-color: #28a745;
149+
--badge-xmark-color: #dc3545;
150+
}
151+
}
152+
`}
152153
</style>
153154
</defs>
154155

rendering/css-fake-function.ts

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
export function css(strings: TemplateStringsArray, ...values: string[]): string {
2+
return strings.reduce((result, str, i) => {
3+
return result + str + (values[i] || "");
4+
}, "");
5+
}

rendering/error.tsx

Lines changed: 111 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,111 @@
1+
import { faExclamationTriangle } from "fa-solid";
2+
import { getTextWidth } from "./get-text-size.ts";
3+
import { renderToString } from "preact-render-to-string";
4+
import { loadEmbeddableFontSync } from "./load-font.ts";
5+
import { Icon } from "./icon.tsx";
6+
import { css } from "./css-fake-function.ts";
7+
8+
export function Error(
9+
{ error }: {
10+
error: string;
11+
},
12+
) {
13+
const title = "An error occurred while rendering the badge.";
14+
15+
const widgetWidth = Math.max(getTextWidth(title), getTextWidth(error, 14)) + 10 + 40; // 10px padding on each side
16+
const lineHeight = 60; // Height of each line in the SVG
17+
18+
const robotFont = loadEmbeddableFontSync(
19+
"./rendering/roboto/Roboto-VariableFont_wdth,wght.woff2",
20+
);
21+
22+
return (
23+
<svg
24+
xmlns="http://www.w3.org/2000/svg"
25+
xmlnsXlink="http://www.w3.org/1999/xlink"
26+
width={widgetWidth}
27+
height={lineHeight}
28+
>
29+
<defs>
30+
<style>
31+
{css`
32+
@font-face {
33+
font-family: "Roboto";
34+
src: url("${robotFont}") format("woff2");
35+
font-weight: normal;
36+
font-style: normal;
37+
}
38+
39+
text {
40+
font-family: "Roboto", "Arial", sans-serif;
41+
}
42+
43+
:root {
44+
--badge-bg-color: #f8f9fa;
45+
--badge-border-color: #e9ecef;
46+
--badge-text-color: #000;
47+
--badge-text-color-light: #666;
48+
--badge-checkmark-color: #34a853;
49+
--badge-xmark-color: #ea4335;
50+
--badge-error-color: #ff6961;
51+
}
52+
53+
@media (prefers-color-scheme: dark) {
54+
:root {
55+
--badge-bg-color: #343a40;
56+
--badge-border-color: #495057;
57+
--badge-text-color: #f8f9fa;
58+
--badge-text-color-light: #adb5bd;
59+
--badge-checkmark-color: #28a745;
60+
--badge-xmark-color: #dc3545;
61+
}
62+
}
63+
64+
a {
65+
text-decoration: none;
66+
}
67+
68+
a:hover {
69+
fill: #5a7d9f;
70+
text-decoration: underline;
71+
}
72+
`}
73+
</style>
74+
</defs>
75+
<rect
76+
width={widgetWidth}
77+
height={lineHeight}
78+
rx="8"
79+
ry="8"
80+
fill="var(--badge-bg-color)"
81+
stroke="var(--badge-border-color)"
82+
strokeWidth="1"
83+
/>
84+
<Icon icon={faExclamationTriangle} size={20} fill="var(--badge-error-color)" x={10} y={10} />
85+
<text
86+
x={40}
87+
y="25"
88+
fontSize="16"
89+
fill="var(--badge-text-color-light)"
90+
>
91+
<a href="https://github.com/K0IN/can-i-use-embed">
92+
{title}
93+
<title>Click to open the documentation.</title>
94+
</a>
95+
</text>
96+
97+
<text
98+
x={40}
99+
y="50"
100+
fontSize="14"
101+
fill="var(--badge-text-color-light)"
102+
>
103+
{error}
104+
</text>
105+
</svg>
106+
);
107+
}
108+
109+
export function RenderError(args: Parameters<typeof Error>[0]): string {
110+
return renderToString(<Error {...args} />);
111+
}

rendering/icon.tsx

Lines changed: 17 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -4,22 +4,22 @@ import { IconDefinition as SolidIconDefinition } from "fa-solid";
44
export type AnyIconDefinition = BrandIconDefinition | SolidIconDefinition;
55

66
export function Icon({ icon, size = 16, fill = "currentColor", ...props }: {
7-
icon: AnyIconDefinition;
8-
size?: number;
9-
fill?: string;
10-
x?: number;
11-
y?: number;
7+
icon: AnyIconDefinition;
8+
size?: number;
9+
fill?: string;
10+
x?: number;
11+
y?: number;
1212
}) {
13-
const [width, height, , , path] = icon.icon;
14-
const pathData = Array.isArray(path) ? path.join(" ") : path;
15-
return (
16-
<svg
17-
width={size}
18-
height={size}
19-
viewBox={`0 0 ${width} ${height}`}
20-
{...props}
21-
>
22-
<path d={pathData} fill={fill} />
23-
</svg>
24-
);
13+
const [width, height, , , path] = icon.icon;
14+
const pathData = Array.isArray(path) ? path.join(" ") : path;
15+
return (
16+
<svg
17+
width={size}
18+
height={size}
19+
viewBox={`0 0 ${width} ${height}`}
20+
{...props}
21+
>
22+
<path d={pathData} fill={fill} />
23+
</svg>
24+
);
2525
}

rendering/test-renders.tsx

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
import * as path from "@std/path";
22
import { RenderBadge } from "./badge.tsx";
33
import { faChrome, faFirefox, faSafari } from "fa-brands";
4+
import { RenderError } from "./error.tsx";
45

56
if (import.meta.main) {
67
{
@@ -36,4 +37,14 @@ if (import.meta.main) {
3637
new TextEncoder().encode(svgString),
3738
);
3839
}
40+
{
41+
const svgString = RenderError({
42+
error: "Loading the data failed and now im here thanks test 123.",
43+
tooltip: "This is a tooltip",
44+
});
45+
await Deno.writeFile(
46+
path.join(import.meta.dirname ?? "", "RenderError.svg"),
47+
new TextEncoder().encode(svgString),
48+
);
49+
}
3950
}

0 commit comments

Comments
 (0)