');
28 | console.error(e);
29 | }
30 | }
31 |
--------------------------------------------------------------------------------
/CONTRIBUTING.md:
--------------------------------------------------------------------------------
1 | # Contributing
2 |
3 | There are two pieces to `og-image` that are worth noting before you begin development.
4 |
5 | 1. The backend image generator located in [/api/index.ts](https://github.com/vercel/og-image/blob/main/api/index.ts)
6 | 2. The frontend inputs located in [/web/index.ts](https://github.com/vercel/og-image/blob/main/web/index.ts)
7 |
8 | Vercel handles [routing](https://github.com/vercel/og-image/blob/main/vercel.json#L6) in an elegant way for us so deployment is easy.
9 |
10 | To start hacking, do the following:
11 |
12 | 1. Clone this repo with `git clone https://github.com/vercel/og-image`
13 | 2. Change directory with `cd og-image`
14 | 3. Run `yarn` or `npm install` to install all dependencies
15 | 4. Run locally with `vercel dev` and visit [localhost:3000](http://localhost:3000) (if nothing happens, run `npm install -g vercel`)
16 | 5. If necessary, edit the `exePath` in [options.ts](https://github.com/vercel/og-image/blob/main/api/_lib/options.ts) to point to your local Chrome executable
17 |
18 | Now you're ready to start local development!
19 |
20 | You can set an environment variable to assist with debugging `export OG_HTML_DEBUG=1`. This will render the image as HTML so you can play around with your browser's dev tools before committing changes to the template.
21 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 |
2 |
3 | # [Social Images for PHP Packages](https://banners.beyondco.de)
4 |
5 | 
6 |
7 | Serverless service that generates dynamic Open Graph images that you can embed in your `` tags.
8 |
9 | For each keystroke, headless chromium is used to render an HTML page and take a screenshot of the result which gets cached.
10 |
11 | See the image embedded in the tweet for a real use case.
12 |
13 |
14 | ## What is an Open Graph Image?
15 |
16 | Have you ever posted a hyperlink to Twitter, Facebook, or Slack and seen an image popup?
17 | How did your social network know how to "unfurl" the URL and get an image?
18 | The answer is in your ``.
19 |
20 | The [Open Graph protocol](http://ogp.me) says you can put a `` tag in the `` of a webpage to define this image.
21 |
22 | It looks like the following:
23 |
24 | ```html
25 |
26 | Title
27 |
28 |
29 | ```
30 |
31 | ## Why use this service?
32 |
33 | This service lets you generate beautiful looking social images for your PHP, Javascript, Python and Laravel packages. You have already put a lot of time and effort into your package, so why not make it look beautiful using this service.
34 |
35 | ## Authors
36 |
37 | - Steven ([@styfle](https://twitter.com/styfle)) - [Vercel](https://vercel.com)
38 | - Evil Rabbit ([@evilrabbit_](https://twitter.com/evilrabbit_)) - [Vercel](https://vercel.com)
39 | - Marcel Pociot ([@marcelpociot](https://twitter.com/marcelpociot)) - [Beyond Code](https://beyondco.de)
40 |
--------------------------------------------------------------------------------
/api/_lib/parser.ts:
--------------------------------------------------------------------------------
1 | import { IncomingMessage } from 'http';
2 | import { parse } from 'url';
3 | import { ParsedRequest } from './types';
4 |
5 | export function parseRequest(req: IncomingMessage) {
6 | console.log('HTTP ' + req.url);
7 | const { pathname, query } = parse(req.url || '/', true);
8 | const { fontSize, images, widths, heights, theme, md, showWatermark, pattern, packageManager, packageName, description, style } = (query || {});
9 |
10 | if (Array.isArray(fontSize)) {
11 | throw new Error('Expected a single fontSize');
12 | }
13 | if (Array.isArray(theme)) {
14 | throw new Error('Expected a single theme');
15 | }
16 | if (Array.isArray(style)) {
17 | throw new Error('Expected a single style');
18 | }
19 | if (Array.isArray(pattern)) {
20 | throw new Error('Expected a single pattern');
21 | }
22 | if (Array.isArray(packageManager)) {
23 | throw new Error('Expected a single package manager');
24 | }
25 | if (Array.isArray(packageName)) {
26 | throw new Error('Expected a single package name');
27 | }
28 | if (Array.isArray(description)) {
29 | throw new Error('Expected a single package name');
30 | }
31 |
32 | const arr = (pathname || '/').slice(1).split('.');
33 | let extension = '';
34 | let text = '';
35 | if (arr.length === 0) {
36 | text = '';
37 | } else if (arr.length === 1) {
38 | text = arr[0];
39 | } else {
40 | extension = arr.pop() as string;
41 | text = arr.join('.');
42 | }
43 |
44 | const parsedRequest: ParsedRequest = {
45 | fileType: extension === 'jpeg' ? extension : 'png',
46 | text: decodeURIComponent(text),
47 | theme: theme === 'dark' ? 'dark' : 'light',
48 | style: style === 'style_2' ? 'style_2' : 'style_1',
49 | md: md === '1' || md === 'true',
50 | showWatermark: showWatermark === '1' || showWatermark === 'true',
51 | fontSize: fontSize || '96px',
52 | pattern: pattern || 'circuitBoard',
53 | packageManager: packageManager || '',
54 | packageName: packageName || '',
55 | description: description || '',
56 | images: getArray(images),
57 | widths: getArray(widths),
58 | heights: getArray(heights),
59 | };
60 | parsedRequest.images = getDefaultImages(parsedRequest.images);
61 | return parsedRequest;
62 | }
63 |
64 | function getArray(stringOrArray: string[] | string | undefined): string[] {
65 | if (typeof stringOrArray === 'undefined') {
66 | return [];
67 | } else if (Array.isArray(stringOrArray)) {
68 | return stringOrArray;
69 | } else {
70 | return [stringOrArray];
71 | }
72 | }
73 |
74 | function getDefaultImages(images: string[]): string[] {
75 | const defaultImage = 'https://laravel.com/img/logomark.min.svg';
76 |
77 | if (!images || !images[0]) {
78 | return [defaultImage];
79 | }
80 | return images;
81 | }
82 |
--------------------------------------------------------------------------------
/api/_fonts/Inter-License.txt:
--------------------------------------------------------------------------------
1 | Copyright (c) 2016-2018 The Inter Project Authors (me@rsms.me)
2 |
3 | This Font Software is licensed under the SIL Open Font License, Version 1.1.
4 | This license is copied below, and is also available with a FAQ at:
5 | http://scripts.sil.org/OFL
6 |
7 | -----------------------------------------------------------
8 | SIL OPEN FONT LICENSE Version 1.1 - 26 February 2007
9 | -----------------------------------------------------------
10 |
11 | PREAMBLE
12 | The goals of the Open Font License (OFL) are to stimulate worldwide
13 | development of collaborative font projects, to support the font creation
14 | efforts of academic and linguistic communities, and to provide a free and
15 | open framework in which fonts may be shared and improved in partnership
16 | with others.
17 |
18 | The OFL allows the licensed fonts to be used, studied, modified and
19 | redistributed freely as long as they are not sold by themselves. The
20 | fonts, including any derivative works, can be bundled, embedded,
21 | redistributed and/or sold with any software provided that any reserved
22 | names are not used by derivative works. The fonts and derivatives,
23 | however, cannot be released under any other type of license. The
24 | requirement for fonts to remain under this license does not apply
25 | to any document created using the fonts or their derivatives.
26 |
27 | DEFINITIONS
28 | "Font Software" refers to the set of files released by the Copyright
29 | Holder(s) under this license and clearly marked as such. This may
30 | include source files, build scripts and documentation.
31 |
32 | "Reserved Font Name" refers to any names specified as such after the
33 | copyright statement(s).
34 |
35 | "Original Version" refers to the collection of Font Software components as
36 | distributed by the Copyright Holder(s).
37 |
38 | "Modified Version" refers to any derivative made by adding to, deleting,
39 | or substituting -- in part or in whole -- any of the components of the
40 | Original Version, by changing formats or by porting the Font Software to a
41 | new environment.
42 |
43 | "Author" refers to any designer, engineer, programmer, technical
44 | writer or other person who contributed to the Font Software.
45 |
46 | PERMISSION AND CONDITIONS
47 | Permission is hereby granted, free of charge, to any person obtaining
48 | a copy of the Font Software, to use, study, copy, merge, embed, modify,
49 | redistribute, and sell modified and unmodified copies of the Font
50 | Software, subject to the following conditions:
51 |
52 | 1) Neither the Font Software nor any of its individual components,
53 | in Original or Modified Versions, may be sold by itself.
54 |
55 | 2) Original or Modified Versions of the Font Software may be bundled,
56 | redistributed and/or sold with any software, provided that each copy
57 | contains the above copyright notice and this license. These can be
58 | included either as stand-alone text files, human-readable headers or
59 | in the appropriate machine-readable metadata fields within text or
60 | binary files as long as those fields can be easily viewed by the user.
61 |
62 | 3) No Modified Version of the Font Software may use the Reserved Font
63 | Name(s) unless explicit written permission is granted by the corresponding
64 | Copyright Holder. This restriction only applies to the primary font name as
65 | presented to the users.
66 |
67 | 4) The name(s) of the Copyright Holder(s) or the Author(s) of the Font
68 | Software shall not be used to promote, endorse or advertise any
69 | Modified Version, except to acknowledge the contribution(s) of the
70 | Copyright Holder(s) and the Author(s) or with their explicit written
71 | permission.
72 |
73 | 5) The Font Software, modified or unmodified, in part or in whole,
74 | must be distributed entirely under this license, and must not be
75 | distributed under any other license. The requirement for fonts to
76 | remain under this license does not apply to any document created
77 | using the Font Software.
78 |
79 | TERMINATION
80 | This license becomes null and void if any of the above conditions are
81 | not met.
82 |
83 | DISCLAIMER
84 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
85 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
86 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
87 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL THE
88 | COPYRIGHT HOLDER BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
89 | INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL, OR CONSEQUENTIAL
90 | DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
91 | FROM, OUT OF THE USE OR INABILITY TO USE THE FONT SOFTWARE OR FROM
92 | OTHER DEALINGS IN THE FONT SOFTWARE.
93 |
--------------------------------------------------------------------------------
/api/_fonts/Vera-License.txt:
--------------------------------------------------------------------------------
1 | Bitstream Vera Fonts Copyright
2 |
3 | The fonts have a generous copyright, allowing derivative works (as
4 | long as "Bitstream" or "Vera" are not in the names), and full
5 | redistribution (so long as they are not *sold* by themselves). They
6 | can be be bundled, redistributed and sold with any software.
7 |
8 | The fonts are distributed under the following copyright:
9 |
10 | Copyright
11 | =========
12 |
13 | Copyright (c) 2003 by Bitstream, Inc. All Rights Reserved. Bitstream
14 | Vera is a trademark of Bitstream, Inc.
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of the fonts accompanying this license ("Fonts") and associated
18 | documentation files (the "Font Software"), to reproduce and distribute
19 | the Font Software, including without limitation the rights to use,
20 | copy, merge, publish, distribute, and/or sell copies of the Font
21 | Software, and to permit persons to whom the Font Software is furnished
22 | to do so, subject to the following conditions:
23 |
24 | The above copyright and trademark notices and this permission notice
25 | shall be included in all copies of one or more of the Font Software
26 | typefaces.
27 |
28 | The Font Software may be modified, altered, or added to, and in
29 | particular the designs of glyphs or characters in the Fonts may be
30 | modified and additional glyphs or characters may be added to the
31 | Fonts, only if the fonts are renamed to names not containing either
32 | the words "Bitstream" or the word "Vera".
33 |
34 | This License becomes null and void to the extent applicable to Fonts
35 | or Font Software that has been modified and is distributed under the
36 | "Bitstream Vera" names.
37 |
38 | The Font Software may be sold as part of a larger software package but
39 | no copy of one or more of the Font Software typefaces may be sold by
40 | itself.
41 |
42 | THE FONT SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
43 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO ANY WARRANTIES OF
44 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT
45 | OF COPYRIGHT, PATENT, TRADEMARK, OR OTHER RIGHT. IN NO EVENT SHALL
46 | BITSTREAM OR THE GNOME FOUNDATION BE LIABLE FOR ANY CLAIM, DAMAGES OR
47 | OTHER LIABILITY, INCLUDING ANY GENERAL, SPECIAL, INDIRECT, INCIDENTAL,
48 | OR CONSEQUENTIAL DAMAGES, WHETHER IN AN ACTION OF CONTRACT, TORT OR
49 | OTHERWISE, ARISING FROM, OUT OF THE USE OR INABILITY TO USE THE FONT
50 | SOFTWARE OR FROM OTHER DEALINGS IN THE FONT SOFTWARE.
51 |
52 | Except as contained in this notice, the names of Gnome, the Gnome
53 | Foundation, and Bitstream Inc., shall not be used in advertising or
54 | otherwise to promote the sale, use or other dealings in this Font
55 | Software without prior written authorization from the Gnome Foundation
56 | or Bitstream Inc., respectively. For further information, contact:
57 | fonts at gnome dot org.
58 |
59 | Copyright FAQ
60 | =============
61 |
62 | 1. I don't understand the resale restriction... What gives?
63 |
64 | Bitstream is giving away these fonts, but wishes to ensure its
65 | competitors can't just drop the fonts as is into a font sale system
66 | and sell them as is. It seems fair that if Bitstream can't make money
67 | from the Bitstream Vera fonts, their competitors should not be able to
68 | do so either. You can sell the fonts as part of any software package,
69 | however.
70 |
71 | 2. I want to package these fonts separately for distribution and
72 | sale as part of a larger software package or system. Can I do so?
73 |
74 | Yes. A RPM or Debian package is a "larger software package" to begin
75 | with, and you aren't selling them independently by themselves.
76 | See 1. above.
77 |
78 | 3. Are derivative works allowed?
79 | Yes!
80 |
81 | 4. Can I change or add to the font(s)?
82 | Yes, but you must change the name(s) of the font(s).
83 |
84 | 5. Under what terms are derivative works allowed?
85 |
86 | You must change the name(s) of the fonts. This is to ensure the
87 | quality of the fonts, both to protect Bitstream and Gnome. We want to
88 | ensure that if an application has opened a font specifically of these
89 | names, it gets what it expects (though of course, using fontconfig,
90 | substitutions could still could have occurred during font
91 | opening). You must include the Bitstream copyright. Additional
92 | copyrights can be added, as per copyright law. Happy Font Hacking!
93 |
94 | 6. If I have improvements for Bitstream Vera, is it possible they might get
95 | adopted in future versions?
96 |
97 | Yes. The contract between the Gnome Foundation and Bitstream has
98 | provisions for working with Bitstream to ensure quality additions to
99 | the Bitstream Vera font family. Please contact us if you have such
100 | additions. Note, that in general, we will want such additions for the
101 | entire family, not just a single font, and that you'll have to keep
102 | both Gnome and Jim Lyles, Vera's designer, happy! To make sense to add
103 | glyphs to the font, they must be stylistically in keeping with Vera's
104 | design. Vera cannot become a "ransom note" font. Jim Lyles will be
105 | providing a document describing the design elements used in Vera, as a
106 | guide and aid for people interested in contributing to Vera.
107 |
108 | 7. I want to sell a software package that uses these fonts: Can I do so?
109 |
110 | Sure. Bundle the fonts with your software and sell your software
111 | with the fonts. That is the intent of the copyright.
112 |
113 | 8. If applications have built the names "Bitstream Vera" into them,
114 | can I override this somehow to use fonts of my choosing?
115 |
116 | This depends on exact details of the software. Most open source
117 | systems and software (e.g., Gnome, KDE, etc.) are now converting to
118 | use fontconfig (see www.fontconfig.org) to handle font configuration,
119 | selection and substitution; it has provisions for overriding font
120 | names and subsituting alternatives. An example is provided by the
121 | supplied local.conf file, which chooses the family Bitstream Vera for
122 | "sans", "serif" and "monospace". Other software (e.g., the XFree86
123 | core server) has other mechanisms for font substitution.
124 |
125 |
--------------------------------------------------------------------------------
/public/style.css:
--------------------------------------------------------------------------------
1 | body {
2 | font-family: "SF Pro Text", "SF Pro Icons", "Helvetica Neue", "Helvetica", "Arial", sans-serif;
3 | margin: 20px;
4 | }
5 |
6 | .center, h1 {
7 | text-align: center;
8 | }
9 |
10 | .container {
11 | display: flex;
12 | justify-content: center;
13 | width: 100%;
14 | }
15 |
16 | .split {
17 | display: flex;
18 | justify-content: center;
19 | width: 100%;
20 | }
21 |
22 | .pull-left {
23 | min-width: 50%;
24 | display: flex;
25 | justify-content: flex-end;
26 | }
27 |
28 | .pull-right {
29 | min-width: 50%;
30 | }
31 |
32 | button {
33 | appearance: none;
34 | align-items: center;
35 | color: #fff;
36 | background: #000;
37 | display: inline-flex;
38 | width: 100px;
39 | height: 40px;
40 | padding: 0 25px;
41 | outline: none;
42 | border: 1px solid #000;
43 | font-size: 12px;
44 | justify-content: center;
45 | text-transform: uppercase;
46 | cursor: pointer;
47 | text-align: center;
48 | user-select: none;
49 | font-weight: 100;
50 | position: relative;
51 | overflow: hidden;
52 | transition: border 0.2s,background 0.2s,color 0.2s ease-out;
53 | border-radius: 5px;
54 | white-space: nowrap;
55 | text-decoration: none;
56 | line-height: 0;
57 |
58 | height: 24px;
59 | width: calc(100% + 2px);
60 | padding: 0 10px;
61 | font-size: 12px;
62 | background: #fff;
63 | border: 1px solid #eaeaea;
64 | color: #666;
65 | }
66 |
67 | button:hover {
68 | color: #000;
69 | border-color: #000;
70 | background: #fff;
71 | }
72 |
73 | .input-outer-wrapper {
74 | align-items: center;
75 | border-radius: 5px;
76 | border: 1px solid #e1e1e1;
77 | display: inline-flex;
78 | height: 37px;
79 | position: relative;
80 | transition: border 0.2s ease,color 0.2s ease;
81 | vertical-align: middle;
82 | width: 100%;
83 | }
84 |
85 | .input-outer-wrapper:hover {
86 | box-shadow: 0 2px 6px rgba(0,0,0,0.1);
87 | border-color: #ddd;
88 | }
89 |
90 | .input-inner-wrapper {
91 | display: block;
92 | margin: 4px 10px;
93 | position: relative;
94 | width: 100%;
95 | }
96 |
97 | .input-inner-wrapper input {
98 | background-color: transparent;
99 | border-radius: 0;
100 | border: none;
101 | box-shadow: none;
102 | box-sizing: border-box;
103 | display: block;
104 | font-family: -apple-system, BlinkMacSystemFont, "Segoe UI", "Roboto", "Oxygen", "Ubuntu", "Cantarell", "Fira Sans", "Droid Sans", "Helvetica Neue", sans-serif;
105 | font-size: 14px;
106 | line-height: 27px;
107 | outline: 0;
108 | width: 100%;
109 | }
110 |
111 | .select-wrapper {
112 | appearance: none;
113 | color: #000;
114 | background: #fff;
115 | display: inline-flex;
116 | height: 40px;
117 | outline: none;
118 | border: 1px solid #eaeaea;
119 | font-size: 12px;
120 | text-transform: uppercase;
121 | user-select: none;
122 | font-weight: 100;
123 | position: relative;
124 | overflow: hidden;
125 | transition: border 0.2s,background 0.2s,color 0.2s ease-out, box-shadow 0.2s ease;
126 | border-radius: 5px;
127 | white-space: nowrap;
128 | line-height: 0;
129 | width: auto;
130 | min-width: 100%;
131 | }
132 |
133 | .select-wrapper:hover {
134 | box-shadow: 0 2px 6px rgba(0,0,0,0.1);
135 | border-color: #ddd;
136 | }
137 |
138 | .select-wrapper.small {
139 | height: 30px;
140 | min-width: 100px;
141 | width: 100px;
142 | }
143 |
144 | .select-arrow {
145 | border-left: 1px solid #eaeaea;
146 | background: #fff;
147 | width: 40px;
148 | height: 100%;
149 | position: absolute;
150 | right: 0;
151 | pointer-events: none;
152 | display: flex;
153 | align-items: center;
154 | justify-content: center;
155 | }
156 |
157 | .select-arrow.small {
158 | width: 22px;
159 | }
160 |
161 | select {
162 | height: 100%;
163 | border: none;
164 | box-shadow: none;
165 | background: transparent;
166 | background-image: none;
167 | color: #000;
168 | line-height: 40px;
169 | font-size: 14px;
170 | margin-right: -20px;
171 | width: calc(100% + 20px);
172 | padding: 0 0 0 16px;
173 | text-transform: none;
174 | }
175 |
176 | .field-flex {
177 | display: flex;
178 | margin-top: 10px;
179 | }
180 |
181 | .field-value {
182 | margin: 10px 80px;
183 | }
184 |
185 | .field-label {
186 | display: inline-block;
187 | width: 100px;
188 | margin-right: 20px;
189 | text-align: right;
190 | }
191 |
192 | .field-value {
193 | width: 200px;
194 | display: inline-block;
195 | }
196 |
197 | label {
198 | display: flex;
199 | align-items: center;
200 | }
201 |
202 | .toast-area {
203 | position: fixed;
204 | bottom: 10px;
205 | right: 20px;
206 | max-width: 420px;
207 | z-index: 2000;
208 | transition: transform 0.4s ease;
209 | }
210 |
211 | .toast-outer {
212 | width: 420px;
213 | height: 72px;
214 | position: absolute;
215 | bottom: 0;
216 | right: 0;
217 | transition: all 0.4s ease;
218 | transform: translate3d(0,130%,0px) scale(1);
219 | animation: show-jsx-1861505484 0.4s ease forwards;
220 | opacity: 1;
221 | }
222 |
223 | .toast-inner {
224 | width: 420px;
225 | background: black;
226 | color: white;
227 | border: 0;
228 | border-radius: 5px;
229 | height: 60px;
230 | align-items: center;
231 | justify-content: space-between;
232 |
233 | box-shadow: 0 4px 9px rgba(0,0,0,0.12);
234 | font-size: 14px;
235 | display: flex;
236 | }
237 |
238 | .toast-message {
239 | text-overflow: ellipsis;
240 | white-space: nowrap;
241 | width: 100%;
242 | overflow: hidden;
243 | margin-top: -1px;
244 | margin-left: 20px;
245 | }
246 |
247 | img {
248 | max-width: 100%;
249 | transition: all 0.3s ease-in 0s;
250 | }
251 |
252 | .image-wrapper {
253 | display: block;
254 | cursor: pointer;
255 | text-decoration: none;
256 | background: #fff;
257 | box-shadow: 0px 1px 5px 0px rgba(0,0,0,0.12);
258 | border-radius: 5px;
259 | margin-bottom: 50px;
260 | transition: all 0.2s ease;
261 | max-width: 100%;
262 | }
263 |
264 | .image-wrapper:hover {
265 | box-shadow: 0 1px 16px rgba(0,0,0,0.1);
266 | border-color: #ddd;
267 | }
268 |
269 |
270 | @media (max-width: 1000px) {
271 | .field {
272 | margin: 20px 10px;
273 | }
274 | }
275 |
276 | @media (max-width: 900px) {
277 | label {
278 | display: flex;
279 | flex-direction: column;
280 | align-items: stretch;
281 | }
282 | .split {
283 | flex-wrap: wrap;
284 | }
285 |
286 | .field-label {
287 | width: 200px;
288 | margin: 10px 80px;
289 | text-align: left;
290 | font-size: 13px;
291 | }
292 | }
293 |
294 | .github-corner:hover .octo-arm {
295 | animation: octocat-wave 560ms ease-in-out
296 | }
297 |
298 | @keyframes octocat-wave {
299 | 0%,100% { transform:rotate(0) }
300 | 20%,60% { transform:rotate(-25deg) }
301 | 40%,80% { transform:rotate(10deg) }
302 | }
303 |
304 | @media (max-width:500px) {
305 | .github-corner:hover .octo-arm { animation:none }
306 | .github-corner .octo-arm { animation:octocat-wave 560ms ease-in-out }
307 | }
308 |
--------------------------------------------------------------------------------
/api/_lib/template.ts:
--------------------------------------------------------------------------------
1 |
2 | import marked from 'marked';
3 | import { sanitizeHtml } from './sanitizer';
4 | import { ParsedRequest, Style, Theme } from './types';
5 | import * as hero from 'hero-patterns';
6 | import fs from 'fs';
7 |
8 | const twemoji = require('twemoji');
9 | const twOptions = { folder: 'svg', ext: '.svg' };
10 | const emojify = (text: string) => twemoji.parse(text, twOptions);
11 |
12 | function getCss(theme: string, pattern: string, fontSize: string) {
13 | let foreground = '#000000';
14 | let background = '#ffffff';
15 | let opacity = 0.07;
16 |
17 | if (theme === 'dark') {
18 | foreground = '#ffffff';
19 | background = '#000000';
20 | opacity = 0.15;
21 | }
22 | return `
23 | body {
24 | font-family: Inter;
25 | background-color: ${background};
26 | background-image: ${hero[pattern](foreground, opacity)}
27 | }
28 |
29 | code {
30 | color: #ff2d20;
31 | font-size: 2vw;
32 | font-family: 'Space Mono';
33 | font-weight: bold;
34 | white-space: pre-wrap;
35 | }
36 |
37 | code:before, code:after {
38 | content: '\`';
39 | }
40 |
41 | .logo-wrapper {
42 | display: flex;
43 | align-items: center;
44 | align-content: center;
45 | justify-content: center;
46 | justify-items: center;
47 | }
48 |
49 | .logo {
50 | margin: 0 75px;
51 | }
52 |
53 | .spacer {
54 | margin: 150px;
55 | }
56 |
57 | .emoji {
58 | height: 1em;
59 | width: 1em;
60 | margin: 0 .05em 0 .1em;
61 | vertical-align: -0.1em;
62 | }
63 |
64 | .heading {
65 | font-size: ${sanitizeHtml(fontSize)};
66 | font-style: normal;
67 | color: ${foreground};
68 | font-family: 'Inter', sans-serif;
69 | font-weight: 800;
70 | line-height: 1.2;
71 | }
72 |
73 | .description {
74 | color: ${foreground};
75 | }
76 |
77 | .text-laravel {
78 | color: #ff2d20;
79 | }
80 | `;
81 | }
82 |
83 | function getDescription(description: string) {
84 | if (description === '' || description === undefined) {
85 | return '';
86 | }
87 |
88 | return `
89 |
76 | Open Source Packages
77 | Open Source Packages
78 |
79 |
80 |
81 | You put all your work into creating an awesome Open Source package - now it's time to make it shine! Use this generator to create beautiful looking social images for your package.
82 |