Spaces:
Running
Running
add og image
Browse files- app/[roastId]/page.tsx +1 -1
- app/api/og/[slug]/route.tsx +88 -0
- app/page.tsx +1 -0
- package-lock.json +155 -3
- package.json +2 -1
- public/inter.ttf +0 -0
- utils/svg.ts +32 -0
app/[roastId]/page.tsx
CHANGED
@@ -23,7 +23,7 @@ export default async function Roast({
|
|
23 |
}
|
24 |
return (
|
25 |
<div>
|
26 |
-
<header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col
|
27 |
<Image
|
28 |
src={Logo}
|
29 |
alt="logo hugging face"
|
|
|
23 |
}
|
24 |
return (
|
25 |
<div>
|
26 |
+
<header className="flex items-start max-lg:gap-1 lg:items-center justify-between max-lg:flex-col mb-5">
|
27 |
<Image
|
28 |
src={Logo}
|
29 |
alt="logo hugging face"
|
app/api/og/[slug]/route.tsx
ADDED
@@ -0,0 +1,88 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
import { getRoast } from "@/app/actions/roast";
|
2 |
+
import { ImageResponse } from "next/og";
|
3 |
+
import { NextRequest } from "next/server";
|
4 |
+
// App router includes @vercel/og.
|
5 |
+
// No need to install it.
|
6 |
+
|
7 |
+
export async function GET(
|
8 |
+
request: NextRequest,
|
9 |
+
{ params }: { params: { slug: string } }
|
10 |
+
) {
|
11 |
+
const { slug } = params;
|
12 |
+
const roast = await getRoast({ id: slug });
|
13 |
+
|
14 |
+
if (!roast?.data) {
|
15 |
+
return undefined;
|
16 |
+
}
|
17 |
+
|
18 |
+
return new ImageResponse(
|
19 |
+
(
|
20 |
+
<div
|
21 |
+
style={{
|
22 |
+
fontSize: 40,
|
23 |
+
color: "black",
|
24 |
+
background: "white",
|
25 |
+
width: "100%",
|
26 |
+
height: "100%",
|
27 |
+
padding: "60px 60px",
|
28 |
+
textAlign: "left",
|
29 |
+
justifyContent: "center",
|
30 |
+
alignItems: "flex-start",
|
31 |
+
display: "flex",
|
32 |
+
position: "relative",
|
33 |
+
flexDirection: "column",
|
34 |
+
}}
|
35 |
+
>
|
36 |
+
<p
|
37 |
+
style={{
|
38 |
+
letterSpacing: 10,
|
39 |
+
fontSize: 26,
|
40 |
+
margin: 0,
|
41 |
+
marginBottom: 20,
|
42 |
+
color: "#71717a",
|
43 |
+
}}
|
44 |
+
>
|
45 |
+
HUGGER ROASTER
|
46 |
+
</p>
|
47 |
+
<p
|
48 |
+
style={{
|
49 |
+
fontSize: 40,
|
50 |
+
margin: 0,
|
51 |
+
lineHeight: 1.3,
|
52 |
+
color: "##27272a",
|
53 |
+
whiteSpace: "break-spaces",
|
54 |
+
lineClamp: 2,
|
55 |
+
}}
|
56 |
+
>
|
57 |
+
{roast.data.text}...
|
58 |
+
</p>
|
59 |
+
<p
|
60 |
+
style={{
|
61 |
+
position: "absolute",
|
62 |
+
bottom: -100,
|
63 |
+
right: -10,
|
64 |
+
fontSize: 240,
|
65 |
+
opacity: 0.5,
|
66 |
+
}}
|
67 |
+
>
|
68 |
+
🧨
|
69 |
+
</p>
|
70 |
+
<div
|
71 |
+
style={{
|
72 |
+
width: "100vw",
|
73 |
+
height: "200px",
|
74 |
+
background:
|
75 |
+
"linear-gradient(180deg, rgba(255, 255, 255, 0) 0%, white 100%)",
|
76 |
+
position: "absolute",
|
77 |
+
bottom: 0,
|
78 |
+
left: 0,
|
79 |
+
}}
|
80 |
+
></div>
|
81 |
+
</div>
|
82 |
+
),
|
83 |
+
{
|
84 |
+
width: 1200,
|
85 |
+
height: 630,
|
86 |
+
}
|
87 |
+
);
|
88 |
+
}
|
app/page.tsx
CHANGED
@@ -2,6 +2,7 @@
|
|
2 |
import { useState } from "react";
|
3 |
import Image from "next/image";
|
4 |
import classNames from "classnames";
|
|
|
5 |
|
6 |
import { roast } from "@/app/actions/roast";
|
7 |
import { share, ShareProps } from "@/app/actions/share";
|
|
|
2 |
import { useState } from "react";
|
3 |
import Image from "next/image";
|
4 |
import classNames from "classnames";
|
5 |
+
import satori from "satori";
|
6 |
|
7 |
import { roast } from "@/app/actions/roast";
|
8 |
import { share, ShareProps } from "@/app/actions/share";
|
package-lock.json
CHANGED
@@ -17,7 +17,8 @@
|
|
17 |
"prisma": "^5.19.0",
|
18 |
"react": "^18",
|
19 |
"react-dom": "^18",
|
20 |
-
"react-use": "^17.5.1"
|
|
|
21 |
},
|
22 |
"devDependencies": {
|
23 |
"@types/node": "^20",
|
@@ -579,6 +580,21 @@
|
|
579 |
"integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==",
|
580 |
"dev": true
|
581 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
582 |
"node_modules/@swc/counter": {
|
583 |
"version": "0.1.3",
|
584 |
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
@@ -1278,6 +1294,14 @@
|
|
1278 |
"node": ">= 6"
|
1279 |
}
|
1280 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1281 |
"node_modules/caniuse-lite": {
|
1282 |
"version": "1.0.30001653",
|
1283 |
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz",
|
@@ -1438,6 +1462,24 @@
|
|
1438 |
"node": ">= 8"
|
1439 |
}
|
1440 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1441 |
"node_modules/css-in-js-utils": {
|
1442 |
"version": "3.1.0",
|
1443 |
"resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
|
@@ -1446,6 +1488,16 @@
|
|
1446 |
"hyphenate-style-name": "^1.0.3"
|
1447 |
}
|
1448 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1449 |
"node_modules/css-tree": {
|
1450 |
"version": "1.1.3",
|
1451 |
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
@@ -1906,6 +1958,11 @@
|
|
1906 |
"url": "https://github.com/sponsors/ljharb"
|
1907 |
}
|
1908 |
},
|
|
|
|
|
|
|
|
|
|
|
1909 |
"node_modules/escape-string-regexp": {
|
1910 |
"version": "4.0.0",
|
1911 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
@@ -2417,6 +2474,11 @@
|
|
2417 |
"reusify": "^1.0.4"
|
2418 |
}
|
2419 |
},
|
|
|
|
|
|
|
|
|
|
|
2420 |
"node_modules/file-entry-cache": {
|
2421 |
"version": "6.0.1",
|
2422 |
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
@@ -2838,6 +2900,17 @@
|
|
2838 |
"node": ">= 0.4"
|
2839 |
}
|
2840 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
2841 |
"node_modules/hyphenate-style-name": {
|
2842 |
"version": "1.1.0",
|
2843 |
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
|
@@ -3507,6 +3580,23 @@
|
|
3507 |
"node": ">=10"
|
3508 |
}
|
3509 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
3510 |
"node_modules/lines-and-columns": {
|
3511 |
"version": "1.2.4",
|
3512 |
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
@@ -4032,6 +4122,11 @@
|
|
4032 |
"url": "https://github.com/sponsors/sindresorhus"
|
4033 |
}
|
4034 |
},
|
|
|
|
|
|
|
|
|
|
|
4035 |
"node_modules/parent-module": {
|
4036 |
"version": "1.0.1",
|
4037 |
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
@@ -4044,6 +4139,15 @@
|
|
4044 |
"node": ">=6"
|
4045 |
}
|
4046 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4047 |
"node_modules/path-exists": {
|
4048 |
"version": "4.0.0",
|
4049 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
@@ -4303,8 +4407,7 @@
|
|
4303 |
"node_modules/postcss-value-parser": {
|
4304 |
"version": "4.2.0",
|
4305 |
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
4306 |
-
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
4307 |
-
"dev": true
|
4308 |
},
|
4309 |
"node_modules/prebuild-install": {
|
4310 |
"version": "7.1.2",
|
@@ -4798,6 +4901,31 @@
|
|
4798 |
"url": "https://github.com/sponsors/ljharb"
|
4799 |
}
|
4800 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
4801 |
"node_modules/scheduler": {
|
4802 |
"version": "0.23.2",
|
4803 |
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
@@ -5163,6 +5291,11 @@
|
|
5163 |
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
5164 |
}
|
5165 |
},
|
|
|
|
|
|
|
|
|
|
|
5166 |
"node_modules/string.prototype.includes": {
|
5167 |
"version": "2.0.0",
|
5168 |
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz",
|
@@ -5489,6 +5622,11 @@
|
|
5489 |
"node": ">=10"
|
5490 |
}
|
5491 |
},
|
|
|
|
|
|
|
|
|
|
|
5492 |
"node_modules/to-regex-range": {
|
5493 |
"version": "5.0.1",
|
5494 |
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
@@ -5687,6 +5825,15 @@
|
|
5687 |
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
5688 |
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
5689 |
},
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
5690 |
"node_modules/uri-js": {
|
5691 |
"version": "4.4.1",
|
5692 |
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
@@ -5926,6 +6073,11 @@
|
|
5926 |
"funding": {
|
5927 |
"url": "https://github.com/sponsors/sindresorhus"
|
5928 |
}
|
|
|
|
|
|
|
|
|
|
|
5929 |
}
|
5930 |
}
|
5931 |
}
|
|
|
17 |
"prisma": "^5.19.0",
|
18 |
"react": "^18",
|
19 |
"react-dom": "^18",
|
20 |
+
"react-use": "^17.5.1",
|
21 |
+
"satori": "^0.10.14"
|
22 |
},
|
23 |
"devDependencies": {
|
24 |
"@types/node": "^20",
|
|
|
580 |
"integrity": "sha512-WJgX9nzTqknM393q1QJDJmoW28kUfEnybeTfVNcNAPnIx210RXm2DiXiHzfNPJNIUUb1tJnz/l4QGtJ30PgWmA==",
|
581 |
"dev": true
|
582 |
},
|
583 |
+
"node_modules/@shuding/opentype.js": {
|
584 |
+
"version": "1.4.0-beta.0",
|
585 |
+
"resolved": "https://registry.npmjs.org/@shuding/opentype.js/-/opentype.js-1.4.0-beta.0.tgz",
|
586 |
+
"integrity": "sha512-3NgmNyH3l/Hv6EvsWJbsvpcpUba6R8IREQ83nH83cyakCw7uM1arZKNfHwv1Wz6jgqrF/j4x5ELvR6PnK9nTcA==",
|
587 |
+
"dependencies": {
|
588 |
+
"fflate": "^0.7.3",
|
589 |
+
"string.prototype.codepointat": "^0.2.1"
|
590 |
+
},
|
591 |
+
"bin": {
|
592 |
+
"ot": "bin/ot"
|
593 |
+
},
|
594 |
+
"engines": {
|
595 |
+
"node": ">= 8.0.0"
|
596 |
+
}
|
597 |
+
},
|
598 |
"node_modules/@swc/counter": {
|
599 |
"version": "0.1.3",
|
600 |
"resolved": "https://registry.npmjs.org/@swc/counter/-/counter-0.1.3.tgz",
|
|
|
1294 |
"node": ">= 6"
|
1295 |
}
|
1296 |
},
|
1297 |
+
"node_modules/camelize": {
|
1298 |
+
"version": "1.0.1",
|
1299 |
+
"resolved": "https://registry.npmjs.org/camelize/-/camelize-1.0.1.tgz",
|
1300 |
+
"integrity": "sha512-dU+Tx2fsypxTgtLoE36npi3UqcjSSMNYfkqgmoEhtZrraP5VWq0K7FkWVTYa8eMPtnU/G2txVsfdCJTn9uzpuQ==",
|
1301 |
+
"funding": {
|
1302 |
+
"url": "https://github.com/sponsors/ljharb"
|
1303 |
+
}
|
1304 |
+
},
|
1305 |
"node_modules/caniuse-lite": {
|
1306 |
"version": "1.0.30001653",
|
1307 |
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001653.tgz",
|
|
|
1462 |
"node": ">= 8"
|
1463 |
}
|
1464 |
},
|
1465 |
+
"node_modules/css-background-parser": {
|
1466 |
+
"version": "0.1.0",
|
1467 |
+
"resolved": "https://registry.npmjs.org/css-background-parser/-/css-background-parser-0.1.0.tgz",
|
1468 |
+
"integrity": "sha512-2EZLisiZQ+7m4wwur/qiYJRniHX4K5Tc9w93MT3AS0WS1u5kaZ4FKXlOTBhOjc+CgEgPiGY+fX1yWD8UwpEqUA=="
|
1469 |
+
},
|
1470 |
+
"node_modules/css-box-shadow": {
|
1471 |
+
"version": "1.0.0-3",
|
1472 |
+
"resolved": "https://registry.npmjs.org/css-box-shadow/-/css-box-shadow-1.0.0-3.tgz",
|
1473 |
+
"integrity": "sha512-9jaqR6e7Ohds+aWwmhe6wILJ99xYQbfmK9QQB9CcMjDbTxPZjwEmUQpU91OG05Xgm8BahT5fW+svbsQGjS/zPg=="
|
1474 |
+
},
|
1475 |
+
"node_modules/css-color-keywords": {
|
1476 |
+
"version": "1.0.0",
|
1477 |
+
"resolved": "https://registry.npmjs.org/css-color-keywords/-/css-color-keywords-1.0.0.tgz",
|
1478 |
+
"integrity": "sha512-FyyrDHZKEjXDpNJYvVsV960FiqQyXc/LlYmsxl2BcdMb2WPx0OGRVgTg55rPSyLSNMqP52R9r8geSp7apN3Ofg==",
|
1479 |
+
"engines": {
|
1480 |
+
"node": ">=4"
|
1481 |
+
}
|
1482 |
+
},
|
1483 |
"node_modules/css-in-js-utils": {
|
1484 |
"version": "3.1.0",
|
1485 |
"resolved": "https://registry.npmjs.org/css-in-js-utils/-/css-in-js-utils-3.1.0.tgz",
|
|
|
1488 |
"hyphenate-style-name": "^1.0.3"
|
1489 |
}
|
1490 |
},
|
1491 |
+
"node_modules/css-to-react-native": {
|
1492 |
+
"version": "3.2.0",
|
1493 |
+
"resolved": "https://registry.npmjs.org/css-to-react-native/-/css-to-react-native-3.2.0.tgz",
|
1494 |
+
"integrity": "sha512-e8RKaLXMOFii+02mOlqwjbD00KSEKqblnpO9e++1aXS1fPQOpS1YoqdVHBqPjHNoxeF2mimzVqawm2KCbEdtHQ==",
|
1495 |
+
"dependencies": {
|
1496 |
+
"camelize": "^1.0.0",
|
1497 |
+
"css-color-keywords": "^1.0.0",
|
1498 |
+
"postcss-value-parser": "^4.0.2"
|
1499 |
+
}
|
1500 |
+
},
|
1501 |
"node_modules/css-tree": {
|
1502 |
"version": "1.1.3",
|
1503 |
"resolved": "https://registry.npmjs.org/css-tree/-/css-tree-1.1.3.tgz",
|
|
|
1958 |
"url": "https://github.com/sponsors/ljharb"
|
1959 |
}
|
1960 |
},
|
1961 |
+
"node_modules/escape-html": {
|
1962 |
+
"version": "1.0.3",
|
1963 |
+
"resolved": "https://registry.npmjs.org/escape-html/-/escape-html-1.0.3.tgz",
|
1964 |
+
"integrity": "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="
|
1965 |
+
},
|
1966 |
"node_modules/escape-string-regexp": {
|
1967 |
"version": "4.0.0",
|
1968 |
"resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz",
|
|
|
2474 |
"reusify": "^1.0.4"
|
2475 |
}
|
2476 |
},
|
2477 |
+
"node_modules/fflate": {
|
2478 |
+
"version": "0.7.4",
|
2479 |
+
"resolved": "https://registry.npmjs.org/fflate/-/fflate-0.7.4.tgz",
|
2480 |
+
"integrity": "sha512-5u2V/CDW15QM1XbbgS+0DfPxVB+jUKhWEKuuFuHncbk3tEEqzmoXL+2KyOFuKGqOnmdIy0/davWF1CkuwtibCw=="
|
2481 |
+
},
|
2482 |
"node_modules/file-entry-cache": {
|
2483 |
"version": "6.0.1",
|
2484 |
"resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-6.0.1.tgz",
|
|
|
2900 |
"node": ">= 0.4"
|
2901 |
}
|
2902 |
},
|
2903 |
+
"node_modules/hex-rgb": {
|
2904 |
+
"version": "4.3.0",
|
2905 |
+
"resolved": "https://registry.npmjs.org/hex-rgb/-/hex-rgb-4.3.0.tgz",
|
2906 |
+
"integrity": "sha512-Ox1pJVrDCyGHMG9CFg1tmrRUMRPRsAWYc/PinY0XzJU4K7y7vjNoLKIQ7BR5UJMCxNN8EM1MNDmHWA/B3aZUuw==",
|
2907 |
+
"engines": {
|
2908 |
+
"node": ">=6"
|
2909 |
+
},
|
2910 |
+
"funding": {
|
2911 |
+
"url": "https://github.com/sponsors/sindresorhus"
|
2912 |
+
}
|
2913 |
+
},
|
2914 |
"node_modules/hyphenate-style-name": {
|
2915 |
"version": "1.1.0",
|
2916 |
"resolved": "https://registry.npmjs.org/hyphenate-style-name/-/hyphenate-style-name-1.1.0.tgz",
|
|
|
3580 |
"node": ">=10"
|
3581 |
}
|
3582 |
},
|
3583 |
+
"node_modules/linebreak": {
|
3584 |
+
"version": "1.1.0",
|
3585 |
+
"resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
|
3586 |
+
"integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
|
3587 |
+
"dependencies": {
|
3588 |
+
"base64-js": "0.0.8",
|
3589 |
+
"unicode-trie": "^2.0.0"
|
3590 |
+
}
|
3591 |
+
},
|
3592 |
+
"node_modules/linebreak/node_modules/base64-js": {
|
3593 |
+
"version": "0.0.8",
|
3594 |
+
"resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
|
3595 |
+
"integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
|
3596 |
+
"engines": {
|
3597 |
+
"node": ">= 0.4"
|
3598 |
+
}
|
3599 |
+
},
|
3600 |
"node_modules/lines-and-columns": {
|
3601 |
"version": "1.2.4",
|
3602 |
"resolved": "https://registry.npmjs.org/lines-and-columns/-/lines-and-columns-1.2.4.tgz",
|
|
|
4122 |
"url": "https://github.com/sponsors/sindresorhus"
|
4123 |
}
|
4124 |
},
|
4125 |
+
"node_modules/pako": {
|
4126 |
+
"version": "0.2.9",
|
4127 |
+
"resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
|
4128 |
+
"integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
|
4129 |
+
},
|
4130 |
"node_modules/parent-module": {
|
4131 |
"version": "1.0.1",
|
4132 |
"resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz",
|
|
|
4139 |
"node": ">=6"
|
4140 |
}
|
4141 |
},
|
4142 |
+
"node_modules/parse-css-color": {
|
4143 |
+
"version": "0.2.1",
|
4144 |
+
"resolved": "https://registry.npmjs.org/parse-css-color/-/parse-css-color-0.2.1.tgz",
|
4145 |
+
"integrity": "sha512-bwS/GGIFV3b6KS4uwpzCFj4w297Yl3uqnSgIPsoQkx7GMLROXfMnWvxfNkL0oh8HVhZA4hvJoEoEIqonfJ3BWg==",
|
4146 |
+
"dependencies": {
|
4147 |
+
"color-name": "^1.1.4",
|
4148 |
+
"hex-rgb": "^4.1.0"
|
4149 |
+
}
|
4150 |
+
},
|
4151 |
"node_modules/path-exists": {
|
4152 |
"version": "4.0.0",
|
4153 |
"resolved": "https://registry.npmjs.org/path-exists/-/path-exists-4.0.0.tgz",
|
|
|
4407 |
"node_modules/postcss-value-parser": {
|
4408 |
"version": "4.2.0",
|
4409 |
"resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-4.2.0.tgz",
|
4410 |
+
"integrity": "sha512-1NNCs6uurfkVbeXG4S8JFT9t19m45ICnif8zWLd5oPSZ50QnwMfK+H3jv408d4jw/7Bttv5axS5IiHoLaVNHeQ=="
|
|
|
4411 |
},
|
4412 |
"node_modules/prebuild-install": {
|
4413 |
"version": "7.1.2",
|
|
|
4901 |
"url": "https://github.com/sponsors/ljharb"
|
4902 |
}
|
4903 |
},
|
4904 |
+
"node_modules/satori": {
|
4905 |
+
"version": "0.10.14",
|
4906 |
+
"resolved": "https://registry.npmjs.org/satori/-/satori-0.10.14.tgz",
|
4907 |
+
"integrity": "sha512-abovcqmwl97WKioxpkfuMeZmndB1TuDFY/R+FymrZyiGP+pMYomvgSzVPnbNMWHHESOPosVHGL352oFbdAnJcA==",
|
4908 |
+
"dependencies": {
|
4909 |
+
"@shuding/opentype.js": "1.4.0-beta.0",
|
4910 |
+
"css-background-parser": "^0.1.0",
|
4911 |
+
"css-box-shadow": "1.0.0-3",
|
4912 |
+
"css-to-react-native": "^3.0.0",
|
4913 |
+
"emoji-regex": "^10.2.1",
|
4914 |
+
"escape-html": "^1.0.3",
|
4915 |
+
"linebreak": "^1.1.0",
|
4916 |
+
"parse-css-color": "^0.2.1",
|
4917 |
+
"postcss-value-parser": "^4.2.0",
|
4918 |
+
"yoga-wasm-web": "^0.3.3"
|
4919 |
+
},
|
4920 |
+
"engines": {
|
4921 |
+
"node": ">=16"
|
4922 |
+
}
|
4923 |
+
},
|
4924 |
+
"node_modules/satori/node_modules/emoji-regex": {
|
4925 |
+
"version": "10.4.0",
|
4926 |
+
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-10.4.0.tgz",
|
4927 |
+
"integrity": "sha512-EC+0oUMY1Rqm4O6LLrgjtYDvcVYTy7chDnM4Q7030tP4Kwj3u/pR6gP9ygnp2CJMK5Gq+9Q2oqmrFJAz01DXjw=="
|
4928 |
+
},
|
4929 |
"node_modules/scheduler": {
|
4930 |
"version": "0.23.2",
|
4931 |
"resolved": "https://registry.npmjs.org/scheduler/-/scheduler-0.23.2.tgz",
|
|
|
5291 |
"url": "https://github.com/chalk/strip-ansi?sponsor=1"
|
5292 |
}
|
5293 |
},
|
5294 |
+
"node_modules/string.prototype.codepointat": {
|
5295 |
+
"version": "0.2.1",
|
5296 |
+
"resolved": "https://registry.npmjs.org/string.prototype.codepointat/-/string.prototype.codepointat-0.2.1.tgz",
|
5297 |
+
"integrity": "sha512-2cBVCj6I4IOvEnjgO/hWqXjqBGsY+zwPmHl12Srk9IXSZ56Jwwmy+66XO5Iut/oQVR7t5ihYdLB0GMa4alEUcg=="
|
5298 |
+
},
|
5299 |
"node_modules/string.prototype.includes": {
|
5300 |
"version": "2.0.0",
|
5301 |
"resolved": "https://registry.npmjs.org/string.prototype.includes/-/string.prototype.includes-2.0.0.tgz",
|
|
|
5622 |
"node": ">=10"
|
5623 |
}
|
5624 |
},
|
5625 |
+
"node_modules/tiny-inflate": {
|
5626 |
+
"version": "1.0.3",
|
5627 |
+
"resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
|
5628 |
+
"integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
|
5629 |
+
},
|
5630 |
"node_modules/to-regex-range": {
|
5631 |
"version": "5.0.1",
|
5632 |
"resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
|
|
|
5825 |
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.19.8.tgz",
|
5826 |
"integrity": "sha512-ve2KP6f/JnbPBFyobGHuerC9g1FYGn/F8n1LWTwNxCEzd6IfqTwUQcNXgEtmmQ6DlRrC1hrSrBnCZPokRrDHjw=="
|
5827 |
},
|
5828 |
+
"node_modules/unicode-trie": {
|
5829 |
+
"version": "2.0.0",
|
5830 |
+
"resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
|
5831 |
+
"integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
|
5832 |
+
"dependencies": {
|
5833 |
+
"pako": "^0.2.5",
|
5834 |
+
"tiny-inflate": "^1.0.0"
|
5835 |
+
}
|
5836 |
+
},
|
5837 |
"node_modules/uri-js": {
|
5838 |
"version": "4.4.1",
|
5839 |
"resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.4.1.tgz",
|
|
|
6073 |
"funding": {
|
6074 |
"url": "https://github.com/sponsors/sindresorhus"
|
6075 |
}
|
6076 |
+
},
|
6077 |
+
"node_modules/yoga-wasm-web": {
|
6078 |
+
"version": "0.3.3",
|
6079 |
+
"resolved": "https://registry.npmjs.org/yoga-wasm-web/-/yoga-wasm-web-0.3.3.tgz",
|
6080 |
+
"integrity": "sha512-N+d4UJSJbt/R3wqY7Coqs5pcV0aUj2j9IaQ3rNj9bVCLld8tTGKRa2USARjnvZJWVx1NDmQev8EknoczaOQDOA=="
|
6081 |
}
|
6082 |
}
|
6083 |
}
|
package.json
CHANGED
@@ -18,7 +18,8 @@
|
|
18 |
"prisma": "^5.19.0",
|
19 |
"react": "^18",
|
20 |
"react-dom": "^18",
|
21 |
-
"react-use": "^17.5.1"
|
|
|
22 |
},
|
23 |
"devDependencies": {
|
24 |
"@types/node": "^20",
|
|
|
18 |
"prisma": "^5.19.0",
|
19 |
"react": "^18",
|
20 |
"react-dom": "^18",
|
21 |
+
"react-use": "^17.5.1",
|
22 |
+
"satori": "^0.10.14"
|
23 |
},
|
24 |
"devDependencies": {
|
25 |
"@types/node": "^20",
|
public/inter.ttf
ADDED
Binary file (343 kB). View file
|
|
utils/svg.ts
ADDED
@@ -0,0 +1,32 @@
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
1 |
+
export const svgToPngURL = (svg: string) =>
|
2 |
+
new Promise<string>((resolve, reject) => {
|
3 |
+
const img = new Image();
|
4 |
+
img.onload = () => {
|
5 |
+
const canvas = document.createElement("canvas");
|
6 |
+
canvas.width = img.naturalWidth;
|
7 |
+
canvas.height = img.naturalHeight;
|
8 |
+
const ctx = canvas.getContext("2d");
|
9 |
+
ctx!.drawImage(img, 0, 0);
|
10 |
+
resolve(canvas.toDataURL("image/png"));
|
11 |
+
URL.revokeObjectURL(img.src);
|
12 |
+
};
|
13 |
+
img.onerror = (e) => {
|
14 |
+
reject(e);
|
15 |
+
URL.revokeObjectURL(img.src);
|
16 |
+
};
|
17 |
+
img.src = URL.createObjectURL(new Blob([svg], { type: "image/svg+xml" }));
|
18 |
+
});
|
19 |
+
|
20 |
+
export const downloadSvgAsPng = async (svg: string) => {
|
21 |
+
const pngURL = await svgToPngURL(svg);
|
22 |
+
try {
|
23 |
+
const a = document.createElement("a");
|
24 |
+
a.href = pngURL;
|
25 |
+
a.download = "Image.png";
|
26 |
+
document.body.appendChild(a);
|
27 |
+
a.click();
|
28 |
+
document.body.removeChild(a);
|
29 |
+
} finally {
|
30 |
+
URL.revokeObjectURL(pngURL);
|
31 |
+
}
|
32 |
+
};
|