enzostvs HF staff commited on
Commit
3c7c2dc
1 Parent(s): 0af17ad

add og image

Browse files
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 border-b border-zinc-200 pb-5">
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
+ };