@m1kapp/kit 0.0.2 → 0.0.4
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.d.mts +33 -181
- package/dist/index.d.ts +33 -181
- package/dist/index.js +4 -4
- package/dist/index.mjs +4 -4
- package/dist/ogimage.d.mts +175 -0
- package/dist/ogimage.d.ts +175 -0
- package/dist/ogimage.js +1 -0
- package/dist/ogimage.mjs +1 -0
- package/dist/server.d.mts +29 -10
- package/dist/server.d.ts +29 -10
- package/dist/server.js +1 -1
- package/dist/server.mjs +1 -1
- package/package.json +6 -1
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface OGConfig {
|
|
4
|
+
/** 앱 이름 (좌상단 로고) */
|
|
5
|
+
appName?: string;
|
|
6
|
+
/** 브랜드 색상 (hex) */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** 하단 도메인 */
|
|
9
|
+
domain?: string;
|
|
10
|
+
/** 배경 스타일 — "dark"(기본) | "gradient"(다크 오로라) | "blend"(라이트 파스텔 블렌드) */
|
|
11
|
+
bg?: "dark" | "gradient" | "blend";
|
|
12
|
+
/** 로고 이미지 URL (지정 시 appName 첫 글자 대신 이미지 표시) */
|
|
13
|
+
logoUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
interface OGDefaultTemplate {
|
|
16
|
+
type?: "default";
|
|
17
|
+
title: string;
|
|
18
|
+
sub?: string;
|
|
19
|
+
badge?: string;
|
|
20
|
+
}
|
|
21
|
+
interface OGMatchTemplate {
|
|
22
|
+
type: "match";
|
|
23
|
+
home: string;
|
|
24
|
+
away: string;
|
|
25
|
+
score?: string;
|
|
26
|
+
sub?: string;
|
|
27
|
+
badge?: string;
|
|
28
|
+
}
|
|
29
|
+
interface OGSquareTemplate {
|
|
30
|
+
type: "square";
|
|
31
|
+
title: string;
|
|
32
|
+
sub?: string;
|
|
33
|
+
badge?: string;
|
|
34
|
+
}
|
|
35
|
+
interface OGIconTemplate {
|
|
36
|
+
type: "icon";
|
|
37
|
+
/** 아이콘에 표시할 글자 (기본: appName 첫 글자) */
|
|
38
|
+
letter?: string;
|
|
39
|
+
/** 아이콘 모서리 둥글기 (기본: 96) */
|
|
40
|
+
radius?: number;
|
|
41
|
+
}
|
|
42
|
+
interface OGArticleTemplate {
|
|
43
|
+
type: "article";
|
|
44
|
+
title: string;
|
|
45
|
+
/** 작성자 */
|
|
46
|
+
author?: string;
|
|
47
|
+
/** 날짜 또는 발행일 */
|
|
48
|
+
date?: string;
|
|
49
|
+
/** 카테고리 / 태그 */
|
|
50
|
+
category?: string;
|
|
51
|
+
sub?: string;
|
|
52
|
+
}
|
|
53
|
+
interface OGStatTemplate {
|
|
54
|
+
type: "stat";
|
|
55
|
+
/** 강조할 숫자 또는 지표 */
|
|
56
|
+
stat: string;
|
|
57
|
+
/** 지표 설명 */
|
|
58
|
+
label: string;
|
|
59
|
+
sub?: string;
|
|
60
|
+
badge?: string;
|
|
61
|
+
}
|
|
62
|
+
interface OGProductTemplate {
|
|
63
|
+
type: "product";
|
|
64
|
+
title: string;
|
|
65
|
+
tagline?: string;
|
|
66
|
+
/** 핵심 특징 (최대 3개) */
|
|
67
|
+
features?: string[];
|
|
68
|
+
badge?: string;
|
|
69
|
+
}
|
|
70
|
+
type OGTemplate = OGDefaultTemplate | OGMatchTemplate | OGSquareTemplate | OGIconTemplate | OGArticleTemplate | OGStatTemplate | OGProductTemplate;
|
|
71
|
+
type OGProps = OGTemplate & OGConfig;
|
|
72
|
+
declare function OGImage(props: OGProps): react_jsx_runtime.JSX.Element;
|
|
73
|
+
|
|
74
|
+
/** @vercel/og (Satori) fonts 옵션에 넘길 수 있는 폰트 정의 */
|
|
75
|
+
interface OGFont {
|
|
76
|
+
name: string;
|
|
77
|
+
data: ArrayBuffer;
|
|
78
|
+
weight: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
|
|
79
|
+
style?: "normal" | "italic";
|
|
80
|
+
}
|
|
81
|
+
declare const PRETENDARD_WEIGHTS: {
|
|
82
|
+
readonly 400: "Pretendard-Regular.otf";
|
|
83
|
+
readonly 700: "Pretendard-Bold.otf";
|
|
84
|
+
readonly 900: "Pretendard-Black.otf";
|
|
85
|
+
};
|
|
86
|
+
type PretendardWeight = keyof typeof PRETENDARD_WEIGHTS;
|
|
87
|
+
/**
|
|
88
|
+
* Pretendard 폰트를 CDN에서 로드합니다.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { OG, loadPretendard } from "@m1kapp/seo";
|
|
93
|
+
* import { ImageResponse } from "next/og";
|
|
94
|
+
*
|
|
95
|
+
* export async function GET() {
|
|
96
|
+
* const fonts = await loadPretendard();
|
|
97
|
+
* return new ImageResponse(<OG type="default" title="Hello" />, {
|
|
98
|
+
* width: 1200, height: 630, fonts,
|
|
99
|
+
* });
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @param weights 로드할 weight 배열 (기본: [700, 900])
|
|
104
|
+
*/
|
|
105
|
+
declare function loadPretendard(weights?: PretendardWeight[]): Promise<OGFont[]>;
|
|
106
|
+
/**
|
|
107
|
+
* 임의의 URL에서 폰트를 로드합니다.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const fonts = await loadFont({
|
|
112
|
+
* name: "CustomFont",
|
|
113
|
+
* url: "https://example.com/CustomFont-Bold.otf",
|
|
114
|
+
* weight: 700,
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
declare function loadFont(opts: {
|
|
119
|
+
name: string;
|
|
120
|
+
url: string;
|
|
121
|
+
weight?: OGFont["weight"];
|
|
122
|
+
style?: OGFont["style"];
|
|
123
|
+
}): Promise<OGFont>;
|
|
124
|
+
/**
|
|
125
|
+
* Google Fonts에서 폰트를 로드합니다.
|
|
126
|
+
* CSS 응답을 파싱해 TTF/OTF URL을 자동 추출합니다.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* const fonts = await loadGoogleFont("Noto Sans KR", [400, 700]);
|
|
131
|
+
* return new ImageResponse(<OG ... />, { fonts });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
declare function loadGoogleFont(family: string, weights?: OGFont["weight"][]): Promise<OGFont[]>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @vercel/og ImageResponse에서 지원하는 이모지 스타일.
|
|
138
|
+
* ImageResponse 옵션의 `emoji` 필드에 넘기면 됩니다.
|
|
139
|
+
*/
|
|
140
|
+
type EmojiStyle = "twemoji" | "openmoji" | "noto" | "fluent" | "fluentFlat" | "blobmoji";
|
|
141
|
+
/**
|
|
142
|
+
* raw Satori의 `loadAdditionalAsset` 콜백을 생성합니다.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import satori from "satori";
|
|
147
|
+
* import { createEmojiLoader } from "@m1kapp/seo";
|
|
148
|
+
*
|
|
149
|
+
* const svg = await satori(<OG ... />, {
|
|
150
|
+
* width: 1200, height: 630,
|
|
151
|
+
* fonts: [...],
|
|
152
|
+
* loadAdditionalAsset: createEmojiLoader(),
|
|
153
|
+
* });
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
declare function createEmojiLoader(): (code: string, segment: string) => Promise<string | undefined>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* OG 이미지 URL의 캐시를 즉시 무효화할 버전 키를 반환합니다.
|
|
160
|
+
*
|
|
161
|
+
* Cache-Control로 CDN에 캐싱된 OG 이미지를 강제 갱신하고 싶을 때
|
|
162
|
+
* URL의 `v` 파라미터에 이 값을 넣으세요.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { getOGVersion } from "@m1kapp/seo";
|
|
167
|
+
*
|
|
168
|
+
* // OG 갱신 버튼 핸들러
|
|
169
|
+
* const freshUrl = `/og?title=${title}&v=${getOGVersion()}`;
|
|
170
|
+
* // → /og?title=...&v=20260415152347
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function getOGVersion(): string;
|
|
174
|
+
|
|
175
|
+
export { type EmojiStyle, type OGArticleTemplate, type OGConfig, type OGDefaultTemplate, type OGFont, type OGIconTemplate, OGImage, type OGMatchTemplate, type OGProductTemplate, type OGProps, type OGSquareTemplate, type OGStatTemplate, type OGTemplate, createEmojiLoader, getOGVersion, loadFont, loadGoogleFont, loadPretendard };
|
|
@@ -0,0 +1,175 @@
|
|
|
1
|
+
import * as react_jsx_runtime from 'react/jsx-runtime';
|
|
2
|
+
|
|
3
|
+
interface OGConfig {
|
|
4
|
+
/** 앱 이름 (좌상단 로고) */
|
|
5
|
+
appName?: string;
|
|
6
|
+
/** 브랜드 색상 (hex) */
|
|
7
|
+
color?: string;
|
|
8
|
+
/** 하단 도메인 */
|
|
9
|
+
domain?: string;
|
|
10
|
+
/** 배경 스타일 — "dark"(기본) | "gradient"(다크 오로라) | "blend"(라이트 파스텔 블렌드) */
|
|
11
|
+
bg?: "dark" | "gradient" | "blend";
|
|
12
|
+
/** 로고 이미지 URL (지정 시 appName 첫 글자 대신 이미지 표시) */
|
|
13
|
+
logoUrl?: string;
|
|
14
|
+
}
|
|
15
|
+
interface OGDefaultTemplate {
|
|
16
|
+
type?: "default";
|
|
17
|
+
title: string;
|
|
18
|
+
sub?: string;
|
|
19
|
+
badge?: string;
|
|
20
|
+
}
|
|
21
|
+
interface OGMatchTemplate {
|
|
22
|
+
type: "match";
|
|
23
|
+
home: string;
|
|
24
|
+
away: string;
|
|
25
|
+
score?: string;
|
|
26
|
+
sub?: string;
|
|
27
|
+
badge?: string;
|
|
28
|
+
}
|
|
29
|
+
interface OGSquareTemplate {
|
|
30
|
+
type: "square";
|
|
31
|
+
title: string;
|
|
32
|
+
sub?: string;
|
|
33
|
+
badge?: string;
|
|
34
|
+
}
|
|
35
|
+
interface OGIconTemplate {
|
|
36
|
+
type: "icon";
|
|
37
|
+
/** 아이콘에 표시할 글자 (기본: appName 첫 글자) */
|
|
38
|
+
letter?: string;
|
|
39
|
+
/** 아이콘 모서리 둥글기 (기본: 96) */
|
|
40
|
+
radius?: number;
|
|
41
|
+
}
|
|
42
|
+
interface OGArticleTemplate {
|
|
43
|
+
type: "article";
|
|
44
|
+
title: string;
|
|
45
|
+
/** 작성자 */
|
|
46
|
+
author?: string;
|
|
47
|
+
/** 날짜 또는 발행일 */
|
|
48
|
+
date?: string;
|
|
49
|
+
/** 카테고리 / 태그 */
|
|
50
|
+
category?: string;
|
|
51
|
+
sub?: string;
|
|
52
|
+
}
|
|
53
|
+
interface OGStatTemplate {
|
|
54
|
+
type: "stat";
|
|
55
|
+
/** 강조할 숫자 또는 지표 */
|
|
56
|
+
stat: string;
|
|
57
|
+
/** 지표 설명 */
|
|
58
|
+
label: string;
|
|
59
|
+
sub?: string;
|
|
60
|
+
badge?: string;
|
|
61
|
+
}
|
|
62
|
+
interface OGProductTemplate {
|
|
63
|
+
type: "product";
|
|
64
|
+
title: string;
|
|
65
|
+
tagline?: string;
|
|
66
|
+
/** 핵심 특징 (최대 3개) */
|
|
67
|
+
features?: string[];
|
|
68
|
+
badge?: string;
|
|
69
|
+
}
|
|
70
|
+
type OGTemplate = OGDefaultTemplate | OGMatchTemplate | OGSquareTemplate | OGIconTemplate | OGArticleTemplate | OGStatTemplate | OGProductTemplate;
|
|
71
|
+
type OGProps = OGTemplate & OGConfig;
|
|
72
|
+
declare function OGImage(props: OGProps): react_jsx_runtime.JSX.Element;
|
|
73
|
+
|
|
74
|
+
/** @vercel/og (Satori) fonts 옵션에 넘길 수 있는 폰트 정의 */
|
|
75
|
+
interface OGFont {
|
|
76
|
+
name: string;
|
|
77
|
+
data: ArrayBuffer;
|
|
78
|
+
weight: 100 | 200 | 300 | 400 | 500 | 600 | 700 | 800 | 900;
|
|
79
|
+
style?: "normal" | "italic";
|
|
80
|
+
}
|
|
81
|
+
declare const PRETENDARD_WEIGHTS: {
|
|
82
|
+
readonly 400: "Pretendard-Regular.otf";
|
|
83
|
+
readonly 700: "Pretendard-Bold.otf";
|
|
84
|
+
readonly 900: "Pretendard-Black.otf";
|
|
85
|
+
};
|
|
86
|
+
type PretendardWeight = keyof typeof PRETENDARD_WEIGHTS;
|
|
87
|
+
/**
|
|
88
|
+
* Pretendard 폰트를 CDN에서 로드합니다.
|
|
89
|
+
*
|
|
90
|
+
* @example
|
|
91
|
+
* ```ts
|
|
92
|
+
* import { OG, loadPretendard } from "@m1kapp/seo";
|
|
93
|
+
* import { ImageResponse } from "next/og";
|
|
94
|
+
*
|
|
95
|
+
* export async function GET() {
|
|
96
|
+
* const fonts = await loadPretendard();
|
|
97
|
+
* return new ImageResponse(<OG type="default" title="Hello" />, {
|
|
98
|
+
* width: 1200, height: 630, fonts,
|
|
99
|
+
* });
|
|
100
|
+
* }
|
|
101
|
+
* ```
|
|
102
|
+
*
|
|
103
|
+
* @param weights 로드할 weight 배열 (기본: [700, 900])
|
|
104
|
+
*/
|
|
105
|
+
declare function loadPretendard(weights?: PretendardWeight[]): Promise<OGFont[]>;
|
|
106
|
+
/**
|
|
107
|
+
* 임의의 URL에서 폰트를 로드합니다.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```ts
|
|
111
|
+
* const fonts = await loadFont({
|
|
112
|
+
* name: "CustomFont",
|
|
113
|
+
* url: "https://example.com/CustomFont-Bold.otf",
|
|
114
|
+
* weight: 700,
|
|
115
|
+
* });
|
|
116
|
+
* ```
|
|
117
|
+
*/
|
|
118
|
+
declare function loadFont(opts: {
|
|
119
|
+
name: string;
|
|
120
|
+
url: string;
|
|
121
|
+
weight?: OGFont["weight"];
|
|
122
|
+
style?: OGFont["style"];
|
|
123
|
+
}): Promise<OGFont>;
|
|
124
|
+
/**
|
|
125
|
+
* Google Fonts에서 폰트를 로드합니다.
|
|
126
|
+
* CSS 응답을 파싱해 TTF/OTF URL을 자동 추출합니다.
|
|
127
|
+
*
|
|
128
|
+
* @example
|
|
129
|
+
* ```ts
|
|
130
|
+
* const fonts = await loadGoogleFont("Noto Sans KR", [400, 700]);
|
|
131
|
+
* return new ImageResponse(<OG ... />, { fonts });
|
|
132
|
+
* ```
|
|
133
|
+
*/
|
|
134
|
+
declare function loadGoogleFont(family: string, weights?: OGFont["weight"][]): Promise<OGFont[]>;
|
|
135
|
+
|
|
136
|
+
/**
|
|
137
|
+
* @vercel/og ImageResponse에서 지원하는 이모지 스타일.
|
|
138
|
+
* ImageResponse 옵션의 `emoji` 필드에 넘기면 됩니다.
|
|
139
|
+
*/
|
|
140
|
+
type EmojiStyle = "twemoji" | "openmoji" | "noto" | "fluent" | "fluentFlat" | "blobmoji";
|
|
141
|
+
/**
|
|
142
|
+
* raw Satori의 `loadAdditionalAsset` 콜백을 생성합니다.
|
|
143
|
+
*
|
|
144
|
+
* @example
|
|
145
|
+
* ```ts
|
|
146
|
+
* import satori from "satori";
|
|
147
|
+
* import { createEmojiLoader } from "@m1kapp/seo";
|
|
148
|
+
*
|
|
149
|
+
* const svg = await satori(<OG ... />, {
|
|
150
|
+
* width: 1200, height: 630,
|
|
151
|
+
* fonts: [...],
|
|
152
|
+
* loadAdditionalAsset: createEmojiLoader(),
|
|
153
|
+
* });
|
|
154
|
+
* ```
|
|
155
|
+
*/
|
|
156
|
+
declare function createEmojiLoader(): (code: string, segment: string) => Promise<string | undefined>;
|
|
157
|
+
|
|
158
|
+
/**
|
|
159
|
+
* OG 이미지 URL의 캐시를 즉시 무효화할 버전 키를 반환합니다.
|
|
160
|
+
*
|
|
161
|
+
* Cache-Control로 CDN에 캐싱된 OG 이미지를 강제 갱신하고 싶을 때
|
|
162
|
+
* URL의 `v` 파라미터에 이 값을 넣으세요.
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```ts
|
|
166
|
+
* import { getOGVersion } from "@m1kapp/seo";
|
|
167
|
+
*
|
|
168
|
+
* // OG 갱신 버튼 핸들러
|
|
169
|
+
* const freshUrl = `/og?title=${title}&v=${getOGVersion()}`;
|
|
170
|
+
* // → /og?title=...&v=20260415152347
|
|
171
|
+
* ```
|
|
172
|
+
*/
|
|
173
|
+
declare function getOGVersion(): string;
|
|
174
|
+
|
|
175
|
+
export { type EmojiStyle, type OGArticleTemplate, type OGConfig, type OGDefaultTemplate, type OGFont, type OGIconTemplate, OGImage, type OGMatchTemplate, type OGProductTemplate, type OGProps, type OGSquareTemplate, type OGStatTemplate, type OGTemplate, createEmojiLoader, getOGVersion, loadFont, loadGoogleFont, loadPretendard };
|
package/dist/ogimage.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
"use strict";var v=Object.defineProperty;var M=Object.getOwnPropertyDescriptor;var j=Object.getOwnPropertyNames;var D=Object.prototype.hasOwnProperty;var E=(o,e)=>{for(var n in e)v(o,n,{get:e[n],enumerable:!0})},A=(o,e,n,r)=>{if(e&&typeof e=="object"||typeof e=="function")for(let i of j(e))!D.call(o,i)&&i!==n&&v(o,i,{get:()=>e[i],enumerable:!(r=M(e,i))||r.enumerable});return o};var N=o=>A(v({},"__esModule",{value:!0}),o);var rt={};E(rt,{OGImage:()=>w,createEmojiLoader:()=>$,getOGVersion:()=>W,loadFont:()=>B,loadGoogleFont:()=>R,loadPretendard:()=>k});module.exports=N(rt);var t=require("react/jsx-runtime");function H(o){let e=[],n=/\p{Extended_Pictographic}/gu,r=0;for(let a of o.matchAll(n)){let l=o.slice(r,a.index).trim();l&&e.push(l),e.push(a[0]),r=a.index+a[0].length}let i=o.slice(r).trim();return i&&e.push(i),e}function p({text:o,style:e}){let n=H(o);return n.length<=1?(0,t.jsx)("span",{style:{display:"flex",...e},children:o}):(0,t.jsx)("span",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",...e},children:n.map((r,i)=>(0,t.jsx)("span",{children:r},i))})}function x(o){let e=o.replace("#",""),n=parseInt(e.length===3?e.split("").map(r=>r+r).join(""):e,16);return{r:n>>16&255,g:n>>8&255,b:n&255}}function y(o,e){let{r:n,g:r,b:i}=x(o);return`rgba(${n},${r},${i},${e})`}function L(o,e,n){o/=255,e/=255,n/=255;let r=Math.max(o,e,n),i=Math.min(o,e,n),a=(r+i)/2;if(r===i)return{h:0,s:0,l:a};let l=r-i,f=a>.5?l/(2-r-i):l/(r+i),s=0;return r===o?s=60*(((e-n)/l+(e<n?6:0))%6):r===e?s=60*(((n-o)/l+2)%6):s=60*(((o-e)/l+4)%6),{h:s,s:f,l:a}}function q(o,e,n){let r=(1-Math.abs(2*n-1))*e,i=r*(1-Math.abs(o/60%2-1)),a=n-r/2,l=0,f=0,s=0;return o<60?[l,f,s]=[r,i,0]:o<120?[l,f,s]=[i,r,0]:o<180?[l,f,s]=[0,r,i]:o<240?[l,f,s]=[0,i,r]:o<300?[l,f,s]=[i,0,r]:[l,f,s]=[r,0,i],{r:Math.round((l+a)*255),g:Math.round((f+a)*255),b:Math.round((s+a)*255)}}function m(o,e=45){let{r:n,g:r,b:i}=x(o),{h:a,s:l,l:f}=L(n,r,i),s=(a+e)%360,{r:g,g:d,b:c}=q(s,l,f);return`rgb(${g},${d},${c})`}function G(o,e){let{r:n,g:r,b:i}=x(o),a=l=>Math.max(0,Math.min(255,l));return`rgb(${a(n+e)},${a(r+e)},${a(i+e)})`}function O(o,e=.5){let{r:n,g:r,b:i}=x(o),a=l=>Math.round(l+(255-l)*e);return`rgb(${a(n)},${a(r)},${a(i)})`}function b({text:o,color:e,bg:n="dark"}){let r=n==="gradient",i=n==="blend";return(0,t.jsx)("div",{style:{display:"flex"},children:(0,t.jsx)("div",{style:{display:"flex",backgroundColor:i||r?"rgba(255,255,255,0.2)":y(e,.12),borderRadius:24,paddingLeft:18,paddingRight:18,paddingTop:8,paddingBottom:8},children:(0,t.jsx)(p,{text:o,style:{fontSize:22,fontWeight:700,color:i||r?"#ffffff":e,letterSpacing:"0.2px"}})})})}function U({appName:o,color:e="#007B5F",domain:n,bg:r="dark",logoUrl:i,children:a}){let l=o||"m1k",f=r==="gradient",s=r==="blend",g="#ffffff",d=s?"rgba(255,255,255,0.2)":f?"rgba(255,255,255,0.18)":e,c="#ffffff",u=s?"#ffffff":f?"rgba(255,255,255,0.95)":"#e4e4e7",h=s?"rgba(255,255,255,0.75)":f?"rgba(255,255,255,0.5)":"#52525b",C=s?"rgba(255,255,255,0.6)":f?"rgba(255,255,255,0.5)":e,z=e,F=m(e,50),I=m(e,-50);return(0,t.jsxs)("div",{style:{width:"100%",height:"100%",display:"flex",flexDirection:"column",backgroundColor:s?O(e,.55):f?"#06060a":"#0a0a0c",background:!f&&!s?"linear-gradient(180deg, #1a1a1f 0%, #0a0a0c 100%)":void 0,padding:"72px 80px",fontFamily:"Pretendard, system-ui, sans-serif",position:"relative",overflow:"hidden"},children:[s?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{position:"absolute",top:-500,left:-400,width:1400,height:1300,borderRadius:"50%",backgroundColor:z,opacity:.7,filter:"blur(240px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",bottom:-480,right:-380,width:1380,height:1280,borderRadius:"50%",backgroundColor:F,opacity:.65,filter:"blur(235px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:"20%",right:-200,width:1e3,height:900,borderRadius:"50%",backgroundColor:I,opacity:.6,filter:"blur(220px)",display:"flex"}})]}):f?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{position:"absolute",bottom:-180,left:-80,width:700,height:560,borderRadius:"50%",backgroundColor:e,opacity:.8,filter:"blur(130px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:-160,right:-60,width:580,height:480,borderRadius:"50%",backgroundColor:G(e,70),opacity:.6,filter:"blur(110px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:-80,left:"20%",width:340,height:260,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.07,filter:"blur(70px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",bottom:-60,right:"10%",width:380,height:300,borderRadius:"50%",backgroundColor:G(e,-50),opacity:.4,filter:"blur(90px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0,0,0,0.52)",display:"flex"}})]}):(0,t.jsx)("div",{style:{position:"absolute",bottom:-200,left:"30%",width:500,height:300,borderRadius:"50%",backgroundColor:e,opacity:.08,filter:"blur(80px)",display:"flex"}}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:18,position:"relative",zIndex:1},children:[i?(0,t.jsx)("img",{src:i,width:52,height:52,style:{borderRadius:14,objectFit:"cover",display:"flex"}}):(0,t.jsx)("div",{style:{width:52,height:52,borderRadius:14,backgroundColor:d,display:"flex",alignItems:"center",justifyContent:"center",fontSize:24,fontWeight:900,color:c},children:l[0].toUpperCase()}),(0,t.jsx)("span",{style:{fontSize:30,fontWeight:800,color:u,letterSpacing:"-0.5px"},children:l})]}),(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",flex:1,justifyContent:"center",position:"relative",zIndex:1},children:a}),n&&(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:10,position:"relative",zIndex:1},children:[(0,t.jsx)("div",{style:{width:8,height:8,borderRadius:"50%",backgroundColor:C,display:"flex"}}),(0,t.jsx)("span",{style:{fontSize:22,color:h,fontWeight:600},children:n})]})]})}function _({title:o,sub:e,badge:n,color:r="#007B5F",bg:i="dark"}){let a=i==="blend";return(0,t.jsxs)(t.Fragment,{children:[n&&(0,t.jsx)("div",{style:{display:"flex",marginBottom:20},children:(0,t.jsx)(b,{text:n,color:r,bg:i})}),(0,t.jsx)(p,{text:o,style:{fontSize:72,fontWeight:900,color:"#ffffff",letterSpacing:"-2px",lineHeight:1.1}}),e&&(0,t.jsx)(p,{text:e,style:{fontSize:34,color:i==="gradient"?"rgba(255,255,255,0.72)":a?"rgba(255,255,255,0.85)":"#a1a1aa",marginTop:22,fontWeight:500}})]})}function V({home:o,away:e,score:n,sub:r,badge:i,color:a="#007B5F",bg:l="dark"}){let f=l==="gradient",s=l==="blend",g="#ffffff",d=f?"rgba(255,255,255,0.9)":s?"rgba(255,255,255,0.85)":a,c=f?"rgba(255,255,255,0.6)":s?"rgba(255,255,255,0.9)":y(a,.6),u=f?"rgba(255,255,255,0.35)":s?y(a,.5):y(a,.35);return(0,t.jsxs)(t.Fragment,{children:[r&&(0,t.jsx)(p,{text:r,style:{fontSize:28,color:d,fontWeight:700,marginBottom:24}}),(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:28},children:[(0,t.jsx)("span",{style:{fontSize:64,fontWeight:900,color:g,letterSpacing:"-1.5px"},children:o}),n?(0,t.jsx)("span",{style:{fontSize:48,fontWeight:900,color:c,letterSpacing:"3px"},children:n}):(0,t.jsx)("span",{style:{fontSize:36,fontWeight:700,color:u},children:"vs"}),(0,t.jsx)("span",{style:{fontSize:64,fontWeight:900,color:"#ffffff",letterSpacing:"-1.5px"},children:e})]}),i&&(0,t.jsx)("div",{style:{display:"flex",marginTop:24},children:(0,t.jsx)(b,{text:i,color:a,bg:l})})]})}function J({title:o,sub:e,badge:n,color:r="#007B5F",bg:i="dark"}){let a=i==="blend";return(0,t.jsxs)(t.Fragment,{children:[n&&(0,t.jsx)("div",{style:{display:"flex",marginBottom:24},children:(0,t.jsx)(b,{text:n,color:r,bg:i})}),(0,t.jsx)(p,{text:o,style:{fontSize:80,fontWeight:900,color:"#ffffff",letterSpacing:"-2px",lineHeight:1.15}}),e&&(0,t.jsx)(p,{text:e,style:{fontSize:38,color:i==="gradient"?"rgba(255,255,255,0.72)":a?"rgba(255,255,255,0.85)":"#71717a",marginTop:28,fontWeight:500}})]})}function Y({letter:o,radius:e=96,appName:n="m1k",color:r="#007B5F",bg:i="dark"}){let l=o??(n||"m1k")[0].toUpperCase(),f=i==="gradient",s=i==="blend",g=s?O(r,.55):f?"#06060a":r,d=r,c=m(r,50),u=m(r,-50);return(0,t.jsxs)("div",{style:{width:"100%",height:"100%",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:g,borderRadius:e,fontFamily:"Pretendard, system-ui, sans-serif",position:"relative",overflow:"hidden"},children:[s?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{position:"absolute",top:-280,left:-250,width:800,height:750,borderRadius:"50%",backgroundColor:d,opacity:.62,filter:"blur(200px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",bottom:-260,right:-220,width:780,height:730,borderRadius:"50%",backgroundColor:c,opacity:.58,filter:"blur(195px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:"25%",right:-100,width:600,height:550,borderRadius:"50%",backgroundColor:u,opacity:.55,filter:"blur(180px)",display:"flex"}})]}):f?(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{position:"absolute",bottom:-100,left:-80,width:420,height:380,borderRadius:"50%",backgroundColor:r,opacity:.7,filter:"blur(100px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:-80,right:-60,width:350,height:320,borderRadius:"50%",backgroundColor:G(r,70),opacity:.45,filter:"blur(90px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",top:-40,left:"25%",width:200,height:150,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.07,filter:"blur(60px)",display:"flex"}})]}):(0,t.jsxs)(t.Fragment,{children:[(0,t.jsx)("div",{style:{position:"absolute",top:-80,right:-80,width:300,height:300,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.1,filter:"blur(80px)",display:"flex"}}),(0,t.jsx)("div",{style:{position:"absolute",bottom:-60,left:-60,width:250,height:250,borderRadius:"50%",backgroundColor:"#000000",opacity:.15,filter:"blur(60px)",display:"flex"}})]}),(0,t.jsx)("span",{style:{fontSize:240,fontWeight:900,color:"#ffffff",letterSpacing:"-6px",lineHeight:1,textAlign:"center",display:"flex",alignItems:"center",justifyContent:"center",textShadow:s?"0 2px 8px rgba(0,0,0,0.3)":void 0},children:l})]})}function K({title:o,author:e,date:n,category:r,sub:i,color:a="#007B5F",bg:l="dark"}){let f=l==="gradient",s=l==="blend",g="#ffffff",d=f?"rgba(255,255,255,0.55)":s?"rgba(255,255,255,0.8)":"#71717a",c=f?"rgba(255,255,255,0.9)":s?"rgba(255,255,255,0.6)":a,u=s?"#000000":f?"#18181b":"#fff",h=f?"rgba(255,255,255,0.3)":s?"rgba(255,255,255,0.5)":"#3f3f46";return(0,t.jsxs)(t.Fragment,{children:[r&&(0,t.jsx)("div",{style:{display:"flex",marginBottom:20},children:(0,t.jsx)(b,{text:r,color:a,bg:l})}),(0,t.jsx)(p,{text:o,style:{fontSize:64,fontWeight:900,color:g,letterSpacing:"-1.5px",lineHeight:1.15}}),i&&(0,t.jsx)(p,{text:i,style:{fontSize:30,color:d,marginTop:18,fontWeight:500}}),(e||n)&&(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:16,marginTop:28},children:[e&&(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:8},children:[(0,t.jsx)("div",{style:{width:32,height:32,borderRadius:"50%",backgroundColor:c,display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:u},children:e[0].toUpperCase()}),(0,t.jsx)("span",{style:{fontSize:22,color:d,fontWeight:600},children:e})]}),e&&n&&(0,t.jsx)("span",{style:{fontSize:20,color:h,display:"flex"},children:"\xB7"}),n&&(0,t.jsx)("span",{style:{fontSize:22,color:d,fontWeight:500,display:"flex"},children:n})]})]})}function Q({stat:o,label:e,sub:n,badge:r,color:i="#007B5F",bg:a="dark"}){let l=a==="gradient",f=a==="blend";return(0,t.jsxs)(t.Fragment,{children:[r&&(0,t.jsx)("div",{style:{display:"flex",marginBottom:20},children:(0,t.jsx)(b,{text:r,color:i,bg:a})}),(0,t.jsx)(p,{text:o,style:{fontSize:110,fontWeight:900,color:f||l?"#ffffff":i,letterSpacing:"-4px",lineHeight:1}}),(0,t.jsx)("div",{style:{fontSize:36,fontWeight:700,color:"#ffffff",marginTop:12,display:"flex"},children:e}),n&&(0,t.jsx)(p,{text:n,style:{fontSize:26,color:f?"rgba(255,255,255,0.8)":l?"rgba(255,255,255,0.55)":"#71717a",marginTop:14,fontWeight:500}})]})}function X({title:o,tagline:e,features:n,badge:r,color:i="#007B5F",bg:a="dark"}){let l=a==="gradient",f=a==="blend",s="#ffffff",g=l?"rgba(255,255,255,0.75)":f?"rgba(255,255,255,0.85)":"#a1a1aa",d=l?"rgba(255,255,255,0.7)":f?"rgba(255,255,255,0.8)":"#a1a1aa",c=l?"rgba(255,255,255,0.5)":f?"rgba(255,255,255,0.6)":i,u=(n??[]).slice(0,3);return(0,t.jsxs)(t.Fragment,{children:[r&&(0,t.jsx)("div",{style:{display:"flex",marginBottom:20},children:(0,t.jsx)(b,{text:r,color:i,bg:a})}),(0,t.jsx)(p,{text:o,style:{fontSize:72,fontWeight:900,color:s,letterSpacing:"-2px",lineHeight:1.1}}),e&&(0,t.jsx)(p,{text:e,style:{fontSize:32,color:g,marginTop:16,fontWeight:500}}),u.length>0&&(0,t.jsx)("div",{style:{display:"flex",flexDirection:"column",gap:10,marginTop:24},children:u.map((h,C)=>(0,t.jsxs)("div",{style:{display:"flex",alignItems:"center",gap:12},children:[(0,t.jsx)("div",{style:{width:8,height:8,borderRadius:"50%",backgroundColor:c,display:"flex",flexShrink:0}}),(0,t.jsx)(p,{text:h,style:{fontSize:24,color:d,fontWeight:500}})]},C))})]})}function w(o){let{appName:e,color:n,domain:r,bg:i,logoUrl:a}=o,l=o.type??"default";return l==="icon"?(0,t.jsx)(Y,{...o,appName:e,color:n,bg:i}):(0,t.jsx)(U,{appName:e,color:n,domain:r,bg:i,logoUrl:a,children:l==="match"?(0,t.jsx)(V,{...o,color:n,bg:i}):l==="square"?(0,t.jsx)(J,{...o,color:n,bg:i}):l==="article"?(0,t.jsx)(K,{...o,color:n,bg:i}):l==="stat"?(0,t.jsx)(Q,{...o,color:n,bg:i}):l==="product"?(0,t.jsx)(X,{...o,color:n,bg:i}):(0,t.jsx)(_,{...o,color:n,bg:i})})}var Z="https://cdn.jsdelivr.net/gh/fonts-archive/Pretendard",tt={400:"Pretendard-Regular.otf",700:"Pretendard-Bold.otf",900:"Pretendard-Black.otf"},T=new Map;function S(o){let e=T.get(o);if(e)return e;let n=fetch(o).then(r=>{if(!r.ok)throw new Error(`Font fetch failed: ${r.status} ${o}`);return r.arrayBuffer()});return T.set(o,n),n}async function k(o=[700,900]){return await Promise.all(o.map(async n=>{let r=tt[n];return{name:"Pretendard",data:await S(`${Z}/${r}`),weight:n,style:"normal"}}))}async function B(o){let e=await S(o.url);return{name:o.name,data:e,weight:o.weight??400,style:o.style??"normal"}}async function R(o,e=[400,700]){let n=e.map(s=>`${s}`).join(";"),r=`https://fonts.googleapis.com/css2?family=${encodeURIComponent(o)}:wght@${n}&display=swap`,i=await fetch(r,{headers:{"User-Agent":"Mozilla/5.0"}}).then(s=>{if(!s.ok)throw new Error(`Google Fonts fetch failed: ${s.status}`);return s.text()}),a=[...i.matchAll(/src:\s*url\(([^)]+)\)\s*format\(['"]?(truetype|opentype|woff2?)['"]?\)/g)],l=[...i.matchAll(/font-weight:\s*(\d+)/g)],f=[];for(let s=0;s<a.length;s++){let g=a[s][1].replace(/['"]/g,""),d=l[s]?Number(l[s][1]):e[s]??400,c=await S(g);f.push({name:o,data:c,weight:d,style:"normal"})}if(f.length===0)throw new Error(`No fonts found for "${o}"`);return f}var et="https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg",P=new Map;function ot(o){let e=[];for(let n=0;n<o.length;n++){let r=o.codePointAt(n);r>65535&&n++,r!==65039&&e.push(r.toString(16))}return e.join("-")}async function nt(o){let e=ot(o),n=`${et}/${e}.svg`,r=P.get(n);if(r)return r;let i=fetch(n).then(async a=>a.ok?a.text():"");return P.set(n,i),i}function $(){return async(o,e)=>{if(o==="emoji"){let n=await nt(e);return n?`data:image/svg+xml;base64,${btoa(n)}`:void 0}}}function W(){let o=new Date,e=o.getFullYear(),n=String(o.getMonth()+1).padStart(2,"0"),r=String(o.getDate()).padStart(2,"0"),i=String(o.getHours()).padStart(2,"0"),a=String(o.getMinutes()).padStart(2,"0"),l=String(o.getSeconds()).padStart(2,"0");return`${e}${n}${r}${i}${a}${l}`}0&&(module.exports={OGImage,createEmojiLoader,getOGVersion,loadFont,loadGoogleFont,loadPretendard});
|
package/dist/ogimage.mjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
import{Fragment as b,jsx as r,jsxs as d}from"react/jsx-runtime";function $(t){let e=[],o=/\p{Extended_Pictographic}/gu,n=0;for(let a of t.matchAll(o)){let l=t.slice(n,a.index).trim();l&&e.push(l),e.push(a[0]),n=a.index+a[0].length}let i=t.slice(n).trim();return i&&e.push(i),e}function u({text:t,style:e}){let o=$(t);return o.length<=1?r("span",{style:{display:"flex",...e},children:t}):r("span",{style:{display:"flex",alignItems:"center",gap:10,flexWrap:"wrap",...e},children:o.map((n,i)=>r("span",{children:n},i))})}function v(t){let e=t.replace("#",""),o=parseInt(e.length===3?e.split("").map(n=>n+n).join(""):e,16);return{r:o>>16&255,g:o>>8&255,b:o&255}}function x(t,e){let{r:o,g:n,b:i}=v(t);return`rgba(${o},${n},${i},${e})`}function W(t,e,o){t/=255,e/=255,o/=255;let n=Math.max(t,e,o),i=Math.min(t,e,o),a=(n+i)/2;if(n===i)return{h:0,s:0,l:a};let l=n-i,f=a>.5?l/(2-n-i):l/(n+i),s=0;return n===t?s=60*(((e-o)/l+(e<o?6:0))%6):n===e?s=60*(((o-t)/l+2)%6):s=60*(((t-e)/l+4)%6),{h:s,s:f,l:a}}function z(t,e,o){let n=(1-Math.abs(2*o-1))*e,i=n*(1-Math.abs(t/60%2-1)),a=o-n/2,l=0,f=0,s=0;return t<60?[l,f,s]=[n,i,0]:t<120?[l,f,s]=[i,n,0]:t<180?[l,f,s]=[0,n,i]:t<240?[l,f,s]=[0,i,n]:t<300?[l,f,s]=[i,0,n]:[l,f,s]=[n,0,i],{r:Math.round((l+a)*255),g:Math.round((f+a)*255),b:Math.round((s+a)*255)}}function C(t,e=45){let{r:o,g:n,b:i}=v(t),{h:a,s:l,l:f}=W(o,n,i),s=(a+e)%360,{r:c,g,b:p}=z(s,l,f);return`rgb(${c},${g},${p})`}function S(t,e){let{r:o,g:n,b:i}=v(t),a=l=>Math.max(0,Math.min(255,l));return`rgb(${a(o+e)},${a(n+e)},${a(i+e)})`}function w(t,e=.5){let{r:o,g:n,b:i}=v(t),a=l=>Math.round(l+(255-l)*e);return`rgb(${a(o)},${a(n)},${a(i)})`}function y({text:t,color:e,bg:o="dark"}){let n=o==="gradient",i=o==="blend";return r("div",{style:{display:"flex"},children:r("div",{style:{display:"flex",backgroundColor:i||n?"rgba(255,255,255,0.2)":x(e,.12),borderRadius:24,paddingLeft:18,paddingRight:18,paddingTop:8,paddingBottom:8},children:r(u,{text:t,style:{fontSize:22,fontWeight:700,color:i||n?"#ffffff":e,letterSpacing:"0.2px"}})})})}function F({appName:t,color:e="#007B5F",domain:o,bg:n="dark",logoUrl:i,children:a}){let l=t||"m1k",f=n==="gradient",s=n==="blend",c="#ffffff",g=s?"rgba(255,255,255,0.2)":f?"rgba(255,255,255,0.18)":e,p="#ffffff",h=s?"#ffffff":f?"rgba(255,255,255,0.95)":"#e4e4e7",m=s?"rgba(255,255,255,0.75)":f?"rgba(255,255,255,0.5)":"#52525b",G=s?"rgba(255,255,255,0.6)":f?"rgba(255,255,255,0.5)":e,B=e,R=C(e,50),P=C(e,-50);return d("div",{style:{width:"100%",height:"100%",display:"flex",flexDirection:"column",backgroundColor:s?w(e,.55):f?"#06060a":"#0a0a0c",background:!f&&!s?"linear-gradient(180deg, #1a1a1f 0%, #0a0a0c 100%)":void 0,padding:"72px 80px",fontFamily:"Pretendard, system-ui, sans-serif",position:"relative",overflow:"hidden"},children:[s?d(b,{children:[r("div",{style:{position:"absolute",top:-500,left:-400,width:1400,height:1300,borderRadius:"50%",backgroundColor:B,opacity:.7,filter:"blur(240px)",display:"flex"}}),r("div",{style:{position:"absolute",bottom:-480,right:-380,width:1380,height:1280,borderRadius:"50%",backgroundColor:R,opacity:.65,filter:"blur(235px)",display:"flex"}}),r("div",{style:{position:"absolute",top:"20%",right:-200,width:1e3,height:900,borderRadius:"50%",backgroundColor:P,opacity:.6,filter:"blur(220px)",display:"flex"}})]}):f?d(b,{children:[r("div",{style:{position:"absolute",bottom:-180,left:-80,width:700,height:560,borderRadius:"50%",backgroundColor:e,opacity:.8,filter:"blur(130px)",display:"flex"}}),r("div",{style:{position:"absolute",top:-160,right:-60,width:580,height:480,borderRadius:"50%",backgroundColor:S(e,70),opacity:.6,filter:"blur(110px)",display:"flex"}}),r("div",{style:{position:"absolute",top:-80,left:"20%",width:340,height:260,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.07,filter:"blur(70px)",display:"flex"}}),r("div",{style:{position:"absolute",bottom:-60,right:"10%",width:380,height:300,borderRadius:"50%",backgroundColor:S(e,-50),opacity:.4,filter:"blur(90px)",display:"flex"}}),r("div",{style:{position:"absolute",top:0,left:0,right:0,bottom:0,backgroundColor:"rgba(0,0,0,0.52)",display:"flex"}})]}):r("div",{style:{position:"absolute",bottom:-200,left:"30%",width:500,height:300,borderRadius:"50%",backgroundColor:e,opacity:.08,filter:"blur(80px)",display:"flex"}}),d("div",{style:{display:"flex",alignItems:"center",gap:18,position:"relative",zIndex:1},children:[i?r("img",{src:i,width:52,height:52,style:{borderRadius:14,objectFit:"cover",display:"flex"}}):r("div",{style:{width:52,height:52,borderRadius:14,backgroundColor:g,display:"flex",alignItems:"center",justifyContent:"center",fontSize:24,fontWeight:900,color:p},children:l[0].toUpperCase()}),r("span",{style:{fontSize:30,fontWeight:800,color:h,letterSpacing:"-0.5px"},children:l})]}),r("div",{style:{display:"flex",flexDirection:"column",flex:1,justifyContent:"center",position:"relative",zIndex:1},children:a}),o&&d("div",{style:{display:"flex",alignItems:"center",gap:10,position:"relative",zIndex:1},children:[r("div",{style:{width:8,height:8,borderRadius:"50%",backgroundColor:G,display:"flex"}}),r("span",{style:{fontSize:22,color:m,fontWeight:600},children:o})]})]})}function I({title:t,sub:e,badge:o,color:n="#007B5F",bg:i="dark"}){let a=i==="blend";return d(b,{children:[o&&r("div",{style:{display:"flex",marginBottom:20},children:r(y,{text:o,color:n,bg:i})}),r(u,{text:t,style:{fontSize:72,fontWeight:900,color:"#ffffff",letterSpacing:"-2px",lineHeight:1.1}}),e&&r(u,{text:e,style:{fontSize:34,color:i==="gradient"?"rgba(255,255,255,0.72)":a?"rgba(255,255,255,0.85)":"#a1a1aa",marginTop:22,fontWeight:500}})]})}function M({home:t,away:e,score:o,sub:n,badge:i,color:a="#007B5F",bg:l="dark"}){let f=l==="gradient",s=l==="blend",c="#ffffff",g=f?"rgba(255,255,255,0.9)":s?"rgba(255,255,255,0.85)":a,p=f?"rgba(255,255,255,0.6)":s?"rgba(255,255,255,0.9)":x(a,.6),h=f?"rgba(255,255,255,0.35)":s?x(a,.5):x(a,.35);return d(b,{children:[n&&r(u,{text:n,style:{fontSize:28,color:g,fontWeight:700,marginBottom:24}}),d("div",{style:{display:"flex",alignItems:"center",gap:28},children:[r("span",{style:{fontSize:64,fontWeight:900,color:c,letterSpacing:"-1.5px"},children:t}),o?r("span",{style:{fontSize:48,fontWeight:900,color:p,letterSpacing:"3px"},children:o}):r("span",{style:{fontSize:36,fontWeight:700,color:h},children:"vs"}),r("span",{style:{fontSize:64,fontWeight:900,color:"#ffffff",letterSpacing:"-1.5px"},children:e})]}),i&&r("div",{style:{display:"flex",marginTop:24},children:r(y,{text:i,color:a,bg:l})})]})}function j({title:t,sub:e,badge:o,color:n="#007B5F",bg:i="dark"}){let a=i==="blend";return d(b,{children:[o&&r("div",{style:{display:"flex",marginBottom:24},children:r(y,{text:o,color:n,bg:i})}),r(u,{text:t,style:{fontSize:80,fontWeight:900,color:"#ffffff",letterSpacing:"-2px",lineHeight:1.15}}),e&&r(u,{text:e,style:{fontSize:38,color:i==="gradient"?"rgba(255,255,255,0.72)":a?"rgba(255,255,255,0.85)":"#71717a",marginTop:28,fontWeight:500}})]})}function D({letter:t,radius:e=96,appName:o="m1k",color:n="#007B5F",bg:i="dark"}){let l=t??(o||"m1k")[0].toUpperCase(),f=i==="gradient",s=i==="blend",c=s?w(n,.55):f?"#06060a":n,g=n,p=C(n,50),h=C(n,-50);return d("div",{style:{width:"100%",height:"100%",display:"flex",alignItems:"center",justifyContent:"center",backgroundColor:c,borderRadius:e,fontFamily:"Pretendard, system-ui, sans-serif",position:"relative",overflow:"hidden"},children:[s?d(b,{children:[r("div",{style:{position:"absolute",top:-280,left:-250,width:800,height:750,borderRadius:"50%",backgroundColor:g,opacity:.62,filter:"blur(200px)",display:"flex"}}),r("div",{style:{position:"absolute",bottom:-260,right:-220,width:780,height:730,borderRadius:"50%",backgroundColor:p,opacity:.58,filter:"blur(195px)",display:"flex"}}),r("div",{style:{position:"absolute",top:"25%",right:-100,width:600,height:550,borderRadius:"50%",backgroundColor:h,opacity:.55,filter:"blur(180px)",display:"flex"}})]}):f?d(b,{children:[r("div",{style:{position:"absolute",bottom:-100,left:-80,width:420,height:380,borderRadius:"50%",backgroundColor:n,opacity:.7,filter:"blur(100px)",display:"flex"}}),r("div",{style:{position:"absolute",top:-80,right:-60,width:350,height:320,borderRadius:"50%",backgroundColor:S(n,70),opacity:.45,filter:"blur(90px)",display:"flex"}}),r("div",{style:{position:"absolute",top:-40,left:"25%",width:200,height:150,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.07,filter:"blur(60px)",display:"flex"}})]}):d(b,{children:[r("div",{style:{position:"absolute",top:-80,right:-80,width:300,height:300,borderRadius:"50%",backgroundColor:"#ffffff",opacity:.1,filter:"blur(80px)",display:"flex"}}),r("div",{style:{position:"absolute",bottom:-60,left:-60,width:250,height:250,borderRadius:"50%",backgroundColor:"#000000",opacity:.15,filter:"blur(60px)",display:"flex"}})]}),r("span",{style:{fontSize:240,fontWeight:900,color:"#ffffff",letterSpacing:"-6px",lineHeight:1,textAlign:"center",display:"flex",alignItems:"center",justifyContent:"center",textShadow:s?"0 2px 8px rgba(0,0,0,0.3)":void 0},children:l})]})}function E({title:t,author:e,date:o,category:n,sub:i,color:a="#007B5F",bg:l="dark"}){let f=l==="gradient",s=l==="blend",c="#ffffff",g=f?"rgba(255,255,255,0.55)":s?"rgba(255,255,255,0.8)":"#71717a",p=f?"rgba(255,255,255,0.9)":s?"rgba(255,255,255,0.6)":a,h=s?"#000000":f?"#18181b":"#fff",m=f?"rgba(255,255,255,0.3)":s?"rgba(255,255,255,0.5)":"#3f3f46";return d(b,{children:[n&&r("div",{style:{display:"flex",marginBottom:20},children:r(y,{text:n,color:a,bg:l})}),r(u,{text:t,style:{fontSize:64,fontWeight:900,color:c,letterSpacing:"-1.5px",lineHeight:1.15}}),i&&r(u,{text:i,style:{fontSize:30,color:g,marginTop:18,fontWeight:500}}),(e||o)&&d("div",{style:{display:"flex",alignItems:"center",gap:16,marginTop:28},children:[e&&d("div",{style:{display:"flex",alignItems:"center",gap:8},children:[r("div",{style:{width:32,height:32,borderRadius:"50%",backgroundColor:p,display:"flex",alignItems:"center",justifyContent:"center",fontSize:14,fontWeight:800,color:h},children:e[0].toUpperCase()}),r("span",{style:{fontSize:22,color:g,fontWeight:600},children:e})]}),e&&o&&r("span",{style:{fontSize:20,color:m,display:"flex"},children:"\xB7"}),o&&r("span",{style:{fontSize:22,color:g,fontWeight:500,display:"flex"},children:o})]})]})}function A({stat:t,label:e,sub:o,badge:n,color:i="#007B5F",bg:a="dark"}){let l=a==="gradient",f=a==="blend";return d(b,{children:[n&&r("div",{style:{display:"flex",marginBottom:20},children:r(y,{text:n,color:i,bg:a})}),r(u,{text:t,style:{fontSize:110,fontWeight:900,color:f||l?"#ffffff":i,letterSpacing:"-4px",lineHeight:1}}),r("div",{style:{fontSize:36,fontWeight:700,color:"#ffffff",marginTop:12,display:"flex"},children:e}),o&&r(u,{text:o,style:{fontSize:26,color:f?"rgba(255,255,255,0.8)":l?"rgba(255,255,255,0.55)":"#71717a",marginTop:14,fontWeight:500}})]})}function N({title:t,tagline:e,features:o,badge:n,color:i="#007B5F",bg:a="dark"}){let l=a==="gradient",f=a==="blend",s="#ffffff",c=l?"rgba(255,255,255,0.75)":f?"rgba(255,255,255,0.85)":"#a1a1aa",g=l?"rgba(255,255,255,0.7)":f?"rgba(255,255,255,0.8)":"#a1a1aa",p=l?"rgba(255,255,255,0.5)":f?"rgba(255,255,255,0.6)":i,h=(o??[]).slice(0,3);return d(b,{children:[n&&r("div",{style:{display:"flex",marginBottom:20},children:r(y,{text:n,color:i,bg:a})}),r(u,{text:t,style:{fontSize:72,fontWeight:900,color:s,letterSpacing:"-2px",lineHeight:1.1}}),e&&r(u,{text:e,style:{fontSize:32,color:c,marginTop:16,fontWeight:500}}),h.length>0&&r("div",{style:{display:"flex",flexDirection:"column",gap:10,marginTop:24},children:h.map((m,G)=>d("div",{style:{display:"flex",alignItems:"center",gap:12},children:[r("div",{style:{width:8,height:8,borderRadius:"50%",backgroundColor:p,display:"flex",flexShrink:0}}),r(u,{text:m,style:{fontSize:24,color:g,fontWeight:500}})]},G))})]})}function H(t){let{appName:e,color:o,domain:n,bg:i,logoUrl:a}=t,l=t.type??"default";return l==="icon"?r(D,{...t,appName:e,color:o,bg:i}):r(F,{appName:e,color:o,domain:n,bg:i,logoUrl:a,children:l==="match"?r(M,{...t,color:o,bg:i}):l==="square"?r(j,{...t,color:o,bg:i}):l==="article"?r(E,{...t,color:o,bg:i}):l==="stat"?r(A,{...t,color:o,bg:i}):l==="product"?r(N,{...t,color:o,bg:i}):r(I,{...t,color:o,bg:i})})}var L="https://cdn.jsdelivr.net/gh/fonts-archive/Pretendard",q={400:"Pretendard-Regular.otf",700:"Pretendard-Bold.otf",900:"Pretendard-Black.otf"},T=new Map;function O(t){let e=T.get(t);if(e)return e;let o=fetch(t).then(n=>{if(!n.ok)throw new Error(`Font fetch failed: ${n.status} ${t}`);return n.arrayBuffer()});return T.set(t,o),o}async function U(t=[700,900]){return await Promise.all(t.map(async o=>{let n=q[o];return{name:"Pretendard",data:await O(`${L}/${n}`),weight:o,style:"normal"}}))}async function _(t){let e=await O(t.url);return{name:t.name,data:e,weight:t.weight??400,style:t.style??"normal"}}async function V(t,e=[400,700]){let o=e.map(s=>`${s}`).join(";"),n=`https://fonts.googleapis.com/css2?family=${encodeURIComponent(t)}:wght@${o}&display=swap`,i=await fetch(n,{headers:{"User-Agent":"Mozilla/5.0"}}).then(s=>{if(!s.ok)throw new Error(`Google Fonts fetch failed: ${s.status}`);return s.text()}),a=[...i.matchAll(/src:\s*url\(([^)]+)\)\s*format\(['"]?(truetype|opentype|woff2?)['"]?\)/g)],l=[...i.matchAll(/font-weight:\s*(\d+)/g)],f=[];for(let s=0;s<a.length;s++){let c=a[s][1].replace(/['"]/g,""),g=l[s]?Number(l[s][1]):e[s]??400,p=await O(c);f.push({name:t,data:p,weight:g,style:"normal"})}if(f.length===0)throw new Error(`No fonts found for "${t}"`);return f}var J="https://cdn.jsdelivr.net/gh/twitter/twemoji@14.0.2/assets/svg",k=new Map;function Y(t){let e=[];for(let o=0;o<t.length;o++){let n=t.codePointAt(o);n>65535&&o++,n!==65039&&e.push(n.toString(16))}return e.join("-")}async function K(t){let e=Y(t),o=`${J}/${e}.svg`,n=k.get(o);if(n)return n;let i=fetch(o).then(async a=>a.ok?a.text():"");return k.set(o,i),i}function Q(){return async(t,e)=>{if(t==="emoji"){let o=await K(e);return o?`data:image/svg+xml;base64,${btoa(o)}`:void 0}}}function X(){let t=new Date,e=t.getFullYear(),o=String(t.getMonth()+1).padStart(2,"0"),n=String(t.getDate()).padStart(2,"0"),i=String(t.getHours()).padStart(2,"0"),a=String(t.getMinutes()).padStart(2,"0"),l=String(t.getSeconds()).padStart(2,"0");return`${e}${o}${n}${i}${a}${l}`}export{H as OGImage,Q as createEmojiLoader,X as getOGVersion,_ as loadFont,V as loadGoogleFont,U as loadPretendard};
|
package/dist/server.d.mts
CHANGED
|
@@ -22,29 +22,48 @@ declare function conflict(message?: string): never;
|
|
|
22
22
|
/** 500 Internal Server Error — throw inside handler() */
|
|
23
23
|
declare function serverError(message?: string): never;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
/**
|
|
26
|
+
* Route context — `any` so the wrapper compiles against all Next.js versions:
|
|
27
|
+
* - Next.js 14: `{ params: Record<string, string | string[]> }`
|
|
28
|
+
* - Next.js 15/16: `{ params: Promise<Record<string, string | string[]>> }`
|
|
29
|
+
*
|
|
30
|
+
* Callers narrow the type themselves inside their handler function.
|
|
31
|
+
*/
|
|
32
|
+
type RouteContext = any;
|
|
29
33
|
/**
|
|
30
34
|
* Wraps a Next.js route handler with automatic error handling.
|
|
35
|
+
* Compatible with Next.js 14, 15, and 16.
|
|
31
36
|
*
|
|
32
37
|
* - HttpError (thrown by unauthorized/notFound/etc.) → proper HTTP response
|
|
33
38
|
* - Any other thrown error → 500
|
|
34
39
|
* - No try/catch needed in your route
|
|
35
40
|
*
|
|
36
41
|
* @example
|
|
42
|
+
* // No params
|
|
37
43
|
* export const GET = handler(async (req) => {
|
|
38
|
-
*
|
|
39
|
-
*
|
|
44
|
+
* if (!auth) unauthorized();
|
|
45
|
+
* return ok(await db.findAll());
|
|
46
|
+
* });
|
|
40
47
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
48
|
+
* // Next.js 15/16 — async params
|
|
49
|
+
* export const GET = handler(async (_req, ctx) => {
|
|
50
|
+
* const { id } = await ctx.params;
|
|
51
|
+
* return ok(await db.find(id));
|
|
52
|
+
* });
|
|
43
53
|
*
|
|
44
|
-
*
|
|
54
|
+
* // Next.js 14 — sync params
|
|
55
|
+
* export const GET = handler(async (_req, ctx) => {
|
|
56
|
+
* const { id } = ctx.params;
|
|
57
|
+
* return ok(await db.find(id));
|
|
45
58
|
* });
|
|
46
59
|
*/
|
|
47
|
-
declare function handler(fn: (req:
|
|
60
|
+
declare function handler(fn: (req: Request) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
61
|
+
declare function handler<P extends Record<string, string | string[]>>(fn: (req: Request, ctx: {
|
|
62
|
+
params: Promise<P>;
|
|
63
|
+
}) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
64
|
+
declare function handler<P extends Record<string, string | string[]>>(fn: (req: Request, ctx: {
|
|
65
|
+
params: P;
|
|
66
|
+
}) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
48
67
|
|
|
49
68
|
type SafeOk<T> = {
|
|
50
69
|
ok: true;
|
package/dist/server.d.ts
CHANGED
|
@@ -22,29 +22,48 @@ declare function conflict(message?: string): never;
|
|
|
22
22
|
/** 500 Internal Server Error — throw inside handler() */
|
|
23
23
|
declare function serverError(message?: string): never;
|
|
24
24
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
}
|
|
25
|
+
/**
|
|
26
|
+
* Route context — `any` so the wrapper compiles against all Next.js versions:
|
|
27
|
+
* - Next.js 14: `{ params: Record<string, string | string[]> }`
|
|
28
|
+
* - Next.js 15/16: `{ params: Promise<Record<string, string | string[]>> }`
|
|
29
|
+
*
|
|
30
|
+
* Callers narrow the type themselves inside their handler function.
|
|
31
|
+
*/
|
|
32
|
+
type RouteContext = any;
|
|
29
33
|
/**
|
|
30
34
|
* Wraps a Next.js route handler with automatic error handling.
|
|
35
|
+
* Compatible with Next.js 14, 15, and 16.
|
|
31
36
|
*
|
|
32
37
|
* - HttpError (thrown by unauthorized/notFound/etc.) → proper HTTP response
|
|
33
38
|
* - Any other thrown error → 500
|
|
34
39
|
* - No try/catch needed in your route
|
|
35
40
|
*
|
|
36
41
|
* @example
|
|
42
|
+
* // No params
|
|
37
43
|
* export const GET = handler(async (req) => {
|
|
38
|
-
*
|
|
39
|
-
*
|
|
44
|
+
* if (!auth) unauthorized();
|
|
45
|
+
* return ok(await db.findAll());
|
|
46
|
+
* });
|
|
40
47
|
*
|
|
41
|
-
*
|
|
42
|
-
*
|
|
48
|
+
* // Next.js 15/16 — async params
|
|
49
|
+
* export const GET = handler(async (_req, ctx) => {
|
|
50
|
+
* const { id } = await ctx.params;
|
|
51
|
+
* return ok(await db.find(id));
|
|
52
|
+
* });
|
|
43
53
|
*
|
|
44
|
-
*
|
|
54
|
+
* // Next.js 14 — sync params
|
|
55
|
+
* export const GET = handler(async (_req, ctx) => {
|
|
56
|
+
* const { id } = ctx.params;
|
|
57
|
+
* return ok(await db.find(id));
|
|
45
58
|
* });
|
|
46
59
|
*/
|
|
47
|
-
declare function handler(fn: (req:
|
|
60
|
+
declare function handler(fn: (req: Request) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
61
|
+
declare function handler<P extends Record<string, string | string[]>>(fn: (req: Request, ctx: {
|
|
62
|
+
params: Promise<P>;
|
|
63
|
+
}) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
64
|
+
declare function handler<P extends Record<string, string | string[]>>(fn: (req: Request, ctx: {
|
|
65
|
+
params: P;
|
|
66
|
+
}) => Promise<Response>): (req: Request, ctx?: RouteContext) => Promise<Response>;
|
|
48
67
|
|
|
49
68
|
type SafeOk<T> = {
|
|
50
69
|
ok: true;
|
package/dist/server.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
"use strict";var u=Object.defineProperty;var
|
|
1
|
+
"use strict";var u=Object.defineProperty;var q=Object.getOwnPropertyDescriptor;var w=Object.getOwnPropertyNames;var P=Object.prototype.hasOwnProperty;var y=(e,r)=>{for(var o in r)u(e,o,{get:r[o],enumerable:!0})},T=(e,r,o,n)=>{if(r&&typeof r=="object"||typeof r=="function")for(let s of w(r))!P.call(e,s)&&s!==o&&u(e,s,{get:()=>r[s],enumerable:!(n=q(r,s))||n.enumerable});return e};var E=e=>T(u({},"__esModule",{value:!0}),e);var b={};y(b,{HttpError:()=>t,badRequest:()=>c,conflict:()=>x,created:()=>i,forbidden:()=>f,handler:()=>m,noContent:()=>p,notFound:()=>R,ok:()=>a,safely:()=>h,serverError:()=>l,unauthorized:()=>d});module.exports=E(b);var t=class extends Error{constructor(o,n){super(`HTTP ${o}`);this.status=o;this.body=n;this.name="HttpError"}};function a(e,r=200){return Response.json(e,{status:r})}function i(e){return Response.json(e,{status:201})}function p(){return new Response(null,{status:204})}function c(e="Bad Request",r){throw new t(400,{error:e,...r?{errors:r}:{}})}function d(e="Unauthorized"){throw new t(401,{error:e})}function f(e="Forbidden"){throw new t(403,{error:e})}function R(e="Not Found"){throw new t(404,{error:e})}function x(e="Conflict"){throw new t(409,{error:e})}function l(e="Internal Server Error"){throw new t(500,{error:e})}function m(e){return async(r,o)=>{try{return await e(r,o)}catch(n){return n instanceof t?Response.json(n.body,{status:n.status}):(console.error("[handler] Unhandled error:",n),Response.json({error:"Internal Server Error"},{status:500}))}}}async function h(e){try{return{ok:!0,data:await e(),error:null}}catch(r){return{ok:!1,data:null,error:r instanceof Error?r:new Error(String(r))}}}0&&(module.exports={HttpError,badRequest,conflict,created,forbidden,handler,noContent,notFound,ok,safely,serverError,unauthorized});
|
package/dist/server.mjs
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
var t=class extends Error{constructor(n,o){super(`HTTP ${n}`);this.status=n;this.body=o;this.name="HttpError"}};function s(e,r=200){return Response.json(e,{status:r})}function u(e){return Response.json(e,{status:201})}function a(){return new Response(null,{status:204})}function i(e="Bad Request",r){throw new t(400,{error:e,...r?{errors:r}:{}})}function p(e="Unauthorized"){throw new t(401,{error:e})}function c(e="Forbidden"){throw new t(403,{error:e})}function d(e="Not Found"){throw new t(404,{error:e})}function f(e="Conflict"){throw new t(409,{error:e})}function
|
|
1
|
+
var t=class extends Error{constructor(n,o){super(`HTTP ${n}`);this.status=n;this.body=o;this.name="HttpError"}};function s(e,r=200){return Response.json(e,{status:r})}function u(e){return Response.json(e,{status:201})}function a(){return new Response(null,{status:204})}function i(e="Bad Request",r){throw new t(400,{error:e,...r?{errors:r}:{}})}function p(e="Unauthorized"){throw new t(401,{error:e})}function c(e="Forbidden"){throw new t(403,{error:e})}function d(e="Not Found"){throw new t(404,{error:e})}function f(e="Conflict"){throw new t(409,{error:e})}function R(e="Internal Server Error"){throw new t(500,{error:e})}function x(e){return async(r,n)=>{try{return await e(r,n)}catch(o){return o instanceof t?Response.json(o.body,{status:o.status}):(console.error("[handler] Unhandled error:",o),Response.json({error:"Internal Server Error"},{status:500}))}}}async function l(e){try{return{ok:!0,data:await e(),error:null}}catch(r){return{ok:!1,data:null,error:r instanceof Error?r:new Error(String(r))}}}export{t as HttpError,i as badRequest,f as conflict,u as created,c as forbidden,x as handler,a as noContent,d as notFound,s as ok,l as safely,R as serverError,p as unauthorized};
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@m1kapp/kit",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.4",
|
|
4
4
|
"description": "UI, SEO, and PWA utilities for side projects",
|
|
5
5
|
"main": "./dist/index.js",
|
|
6
6
|
"module": "./dist/index.mjs",
|
|
@@ -15,6 +15,11 @@
|
|
|
15
15
|
"types": "./dist/server.d.ts",
|
|
16
16
|
"import": "./dist/server.mjs",
|
|
17
17
|
"require": "./dist/server.js"
|
|
18
|
+
},
|
|
19
|
+
"./ogimage": {
|
|
20
|
+
"types": "./dist/ogimage.d.ts",
|
|
21
|
+
"import": "./dist/ogimage.mjs",
|
|
22
|
+
"require": "./dist/ogimage.js"
|
|
18
23
|
}
|
|
19
24
|
},
|
|
20
25
|
"files": [
|