├── .editorconfig ├── .gitignore ├── .prettierrc ├── LICENSE ├── README.md ├── components ├── CodeBlock.js ├── Editor.js ├── HeadFonts.js ├── Loading.js ├── OGPreview.js ├── ProjectSwitcher.js ├── Sparkles.js ├── Start.js ├── layouts │ └── MainLayout.js ├── react-color │ ├── Slider.js │ ├── Twitter.js │ ├── components │ │ ├── common │ │ │ ├── Alpha.js │ │ │ ├── Checkboard.js │ │ │ ├── ColorWrap.js │ │ │ ├── EditableInput.js │ │ │ ├── Hue.js │ │ │ ├── Raised.js │ │ │ ├── Saturation.js │ │ │ ├── Swatch.js │ │ │ ├── __snapshots__ │ │ │ │ └── spec.js.snap │ │ │ ├── index.js │ │ │ └── spec.js │ │ ├── slider │ │ │ ├── Slider.js │ │ │ ├── SliderPointer.js │ │ │ ├── SliderSwatch.js │ │ │ ├── SliderSwatches.js │ │ │ ├── __snapshots__ │ │ │ │ └── spec.js.snap │ │ │ └── spec.js │ │ └── twitter │ │ │ ├── Twitter.js │ │ │ ├── __snapshots__ │ │ │ └── spec.js.snap │ │ │ ├── spec.js │ │ │ └── story.js │ ├── helpers │ │ ├── alpha.js │ │ ├── checkboard.js │ │ ├── color.js │ │ ├── hue.js │ │ ├── index.js │ │ ├── interaction.js │ │ ├── saturation.js │ │ └── spec.js │ └── index.js └── supabase │ └── Auth.js ├── jsconfig.json ├── lib ├── a11yDark.js ├── helpers.js └── supabaseClient.js ├── next.config.js ├── package-lock.json ├── package.json ├── pages ├── _app.js ├── api │ ├── _lib │ │ ├── chromium.js │ │ ├── options.js │ │ ├── parser.js │ │ ├── sanitizer.js │ │ └── types.js │ └── v1.js ├── index.js ├── preview.js └── projects │ ├── [projectId].js │ ├── index.js │ └── new.js ├── postcss.config.js ├── public ├── favicon.ico ├── gd.png ├── geometry.png ├── geometry_@2X.png ├── geot@2x.png ├── gl.png ├── gp.png ├── light_toast-50.png ├── light_toast.png ├── light_toast_@2X.png ├── no-og.png ├── og.png ├── ogimage.png ├── ogsupa-MI-shadow.png ├── ogsupa-MI.png ├── ogsupa-MII-shadow.png ├── ogsupa-MIII-shadow-alt.png ├── ogsupa-MIII-shadow.png ├── ogsupa-MIV-shadow.png ├── ogsupa-MV-shadow.png ├── ogsupa-MV.png ├── playstation-pattern.png └── vercel.svg ├── styles └── index.css └── tailwind.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # http://editorconfig.org 2 | root = true 3 | 4 | [*] 5 | charset = utf-8 6 | end_of_line = lf 7 | indent_size = 2 8 | indent_style = space 9 | insert_final_newline = true 10 | trim_trailing_whitespace = true 11 | 12 | [*.md] 13 | trim_trailing_whitespace = false 14 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # See https://help.github.com/articles/ignoring-files/ for more about ignoring files. 2 | 3 | # dependencies 4 | /node_modules 5 | /.pnp 6 | .pnp.js 7 | 8 | # testing 9 | /coverage 10 | 11 | # next.js 12 | /.next/ 13 | /out/ 14 | 15 | # production 16 | /build 17 | 18 | # misc 19 | .DS_Store 20 | *.pem 21 | 22 | # debug 23 | npm-debug.log* 24 | yarn-debug.log* 25 | yarn-error.log* 26 | 27 | # local env files 28 | .env.local 29 | .env.development.local 30 | .env.test.local 31 | .env.production.local 32 | 33 | # vercel 34 | .vercel 35 | 36 | # Created by https://www.toptal.com/developers/gitignore/api/NextJS,Node,macOS,react 37 | # Edit at https://www.toptal.com/developers/gitignore?templates=NextJS,Node,macOS,react 38 | 39 | ### macOS ### 40 | # General 41 | .DS_Store 42 | .AppleDouble 43 | .LSOverride 44 | 45 | # Icon must end with two \r 46 | Icon 47 | 48 | # Thumbnails 49 | ._* 50 | 51 | # Files that might appear in the root of a volume 52 | .DocumentRevisions-V100 53 | .fseventsd 54 | .Spotlight-V100 55 | .TemporaryItems 56 | .Trashes 57 | .VolumeIcon.icns 58 | .com.apple.timemachine.donotpresent 59 | 60 | # Directories potentially created on remote AFP share 61 | .AppleDB 62 | .AppleDesktop 63 | Network Trash Folder 64 | Temporary Items 65 | .apdisk 66 | 67 | #!! ERROR: nextjs is undefined. Use list command to see defined gitignore types !!# 68 | 69 | ### Node ### 70 | # Logs 71 | logs 72 | *.log 73 | npm-debug.log* 74 | yarn-debug.log* 75 | yarn-error.log* 76 | lerna-debug.log* 77 | .pnpm-debug.log* 78 | 79 | # Diagnostic reports (https://nodejs.org/api/report.html) 80 | report.[0-9]*.[0-9]*.[0-9]*.[0-9]*.json 81 | 82 | # Runtime data 83 | pids 84 | *.pid 85 | *.seed 86 | *.pid.lock 87 | 88 | # Directory for instrumented libs generated by jscoverage/JSCover 89 | lib-cov 90 | 91 | # Coverage directory used by tools like istanbul 92 | coverage 93 | *.lcov 94 | 95 | # nyc test coverage 96 | .nyc_output 97 | 98 | # Grunt intermediate storage (https://gruntjs.com/creating-plugins#storing-task-files) 99 | .grunt 100 | 101 | # Bower dependency directory (https://bower.io/) 102 | bower_components 103 | 104 | # node-waf configuration 105 | .lock-wscript 106 | 107 | # Compiled binary addons (https://nodejs.org/api/addons.html) 108 | build/Release 109 | 110 | # Dependency directories 111 | node_modules/ 112 | jspm_packages/ 113 | 114 | # Snowpack dependency directory (https://snowpack.dev/) 115 | web_modules/ 116 | 117 | # TypeScript cache 118 | *.tsbuildinfo 119 | 120 | # Optional npm cache directory 121 | .npm 122 | 123 | # Optional eslint cache 124 | .eslintcache 125 | 126 | # Microbundle cache 127 | .rpt2_cache/ 128 | .rts2_cache_cjs/ 129 | .rts2_cache_es/ 130 | .rts2_cache_umd/ 131 | 132 | # Optional REPL history 133 | .node_repl_history 134 | 135 | # Output of 'npm pack' 136 | *.tgz 137 | 138 | # Yarn Integrity file 139 | .yarn-integrity 140 | 141 | # dotenv environment variables file 142 | .env 143 | .env.test 144 | .env.production 145 | 146 | # parcel-bundler cache (https://parceljs.org/) 147 | .cache 148 | .parcel-cache 149 | 150 | # Next.js build output 151 | .next 152 | out 153 | 154 | # Nuxt.js build / generate output 155 | .nuxt 156 | dist 157 | 158 | # Gatsby files 159 | .cache/ 160 | # Comment in the public line in if your project uses Gatsby and not Next.js 161 | # https://nextjs.org/blog/next-9-1#public-directory-support 162 | # public 163 | 164 | # vuepress build output 165 | .vuepress/dist 166 | 167 | # Serverless directories 168 | .serverless/ 169 | 170 | # FuseBox cache 171 | .fusebox/ 172 | 173 | # DynamoDB Local files 174 | .dynamodb/ 175 | 176 | # TernJS port file 177 | .tern-port 178 | 179 | # Stores VSCode versions used for testing VSCode extensions 180 | .vscode-test 181 | 182 | # yarn v2 183 | .yarn/cache 184 | .yarn/unplugged 185 | .yarn/build-state.yml 186 | .yarn/install-state.gz 187 | .pnp.* 188 | 189 | ### Node Patch ### 190 | # Serverless Webpack directories 191 | .webpack/ 192 | 193 | ### react ### 194 | .DS_* 195 | **/*.backup.* 196 | **/*.back.* 197 | 198 | node_modules 199 | 200 | *.sublime* 201 | 202 | psd 203 | thumb 204 | sketch 205 | 206 | # End of https://www.toptal.com/developers/gitignore/api/NextJS,Node,macOS,react 207 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "singleQuote": true 3 | } 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2021 Jannik Siebert 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | 23 | --- 24 | 25 | Some source-code parts obtained from https://github.com/vercel/og-image 26 | MIT License 27 | 28 | Copyright (c) 2019-2020 Vercel, Inc. 29 | 30 | Permission is hereby granted, free of charge, to any person obtaining a copy 31 | of this software and associated documentation files (the "Software"), to deal 32 | in the Software without restriction, including without limitation the rights 33 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 34 | copies of the Software, and to permit persons to whom the Software is 35 | furnished to do so, subject to the following conditions: 36 | 37 | The above copyright notice and this permission notice shall be included in all 38 | copies or substantial portions of the Software. 39 | 40 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 41 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 42 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 43 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 44 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 45 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 46 | SOFTWARE. 47 | 48 | --- 49 | 50 | Some source-code parts obtained from https://github.com/casesandberg/react-color 51 | The MIT License (MIT) 52 | 53 | Copyright (c) 2015 Case Sandberg 54 | 55 | Permission is hereby granted, free of charge, to any person obtaining a copy 56 | of this software and associated documentation files (the "Software"), to deal 57 | in the Software without restriction, including without limitation the rights 58 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 59 | copies of the Software, and to permit persons to whom the Software is 60 | furnished to do so, subject to the following conditions: 61 | 62 | The above copyright notice and this permission notice shall be included in all 63 | copies or substantial portions of the Software. 64 | 65 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 66 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 67 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 68 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 69 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 70 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 71 | SOFTWARE. 72 | 73 | --- 74 | 75 | Some source-code parts obtained from https://github.com/react-syntax-highlighter/react-syntax-highlighter 76 | MIT License 77 | 78 | Copyright (c) 2019 Conor Hastings 79 | 80 | Permission is hereby granted, free of charge, to any person obtaining a copy 81 | of this software and associated documentation files (the "Software"), to deal 82 | in the Software without restriction, including without limitation the rights 83 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 84 | copies of the Software, and to permit persons to whom the Software is 85 | furnished to do so, subject to the following conditions: 86 | 87 | The above copyright notice and this permission notice shall be included in all 88 | copies or substantial portions of the Software. 89 | 90 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 91 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 92 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 93 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 94 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 95 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 96 | SOFTWARE. 97 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 |
2 | Logo 3 |
4 | 5 | Follow on Twitter 6 | 7 |
8 |
9 | 10 |

11 | Features 12 | · 13 | Demo 14 | · 15 | Roadmap 16 | · 17 | License 18 | 19 |

20 | 21 | # og:supa ⚡️ 22 | 23 | Generate og:images for free! og:supa is an open-source og:image generator! All you have to do is 24 | add our`` tag to your HTML `` and you're good to go! 25 | 26 | ## Features 27 | 28 | - 🎉 Empty link previews are a thing of the past! 29 | - 🎨 Generate customizable og:images in realtime 30 | - 🚀 Save many different project styles for editing 31 | 32 | ## [Demo](https://ogsupa.com) 33 | 34 | ## Roadmap 🚂 35 | 36 | - [x] Add basic text, description, etc. with background color 37 | - [ ] Fix scroll bar layout shift bug on some browsers 38 | - [ ] Add background gradients 39 | - [ ] Add different styles with borders 40 | - [ ] Add image upload for logos and background images 41 | 42 | ### Hackathon Information 43 | 44 | - [link to hosted demo](https://ogsupa.com) 45 | - list of team members handles: [GitHub @janniks](https://github.com/janniks), [Twitter @jnnksbrt](https://twitter.com/jnnksbrt) 46 | - a brief description of how you used Supabase: 47 | - [x] to store data? 48 | - [x] auth? 49 | - [ ] storage? **COMING SOON** 50 | - [ ] realtime? **NOT PLANNED** 51 | 52 | ## License ⚖️ 53 | 54 | [MIT](https://github.com/janniks/ogsupa/raw/main/LICENSE) 55 | -------------------------------------------------------------------------------- /components/CodeBlock.js: -------------------------------------------------------------------------------- 1 | import { Prism as SyntaxHighlighter } from 'react-syntax-highlighter'; 2 | import a11yDark from 'lib/a11yDark'; 3 | import toast from 'react-hot-toast'; 4 | 5 | const CodeBlock = ({ code, className, copy = true }) => { 6 | return ( 7 |
8 | 13 | {code} 14 | 15 | {copy && ( 16 | 17 | 27 | 28 | )} 29 |
30 | ); 31 | }; 32 | 33 | export default CodeBlock; 34 | -------------------------------------------------------------------------------- /components/Editor.js: -------------------------------------------------------------------------------- 1 | import { ClipboardIcon, PhotographIcon } from '@heroicons/react/solid'; 2 | import cn from 'classnames'; 3 | import OGPreview from 'components/OGPreview'; 4 | import { SliderPicker, TwitterPicker } from 'components/react-color'; 5 | import { supabase } from 'lib/supabaseClient'; 6 | import { useState } from 'react'; 7 | import toast from 'react-hot-toast'; 8 | import CodeBlock from './CodeBlock'; 9 | import Loading from './Loading'; 10 | 11 | export default function Editor({ projectId, projectData }) { 12 | const [project, setProject] = useState(projectData); 13 | const [isSaving, setIsSaving] = useState(false); 14 | const [hasChanges, setHasChanges] = useState(false); 15 | 16 | const setProperty = (key, value) => { 17 | setProject((project) => ({ ...project, [key]: value })); 18 | setHasChanges(true); 19 | }; 20 | 21 | if (!project) return ; 22 | 23 | const previewProps = { 24 | title: project.title, 25 | description: project.description, 26 | background_color: project.background_color, 27 | font_style: project.font_style, 28 | left_meta: project.left_meta, 29 | right_meta: project.right_meta, 30 | }; 31 | 32 | const previewQuery = new URLSearchParams(previewProps).toString(); 33 | const ogImageUrl = `https://ogsupa.com/api/v1?${previewQuery}`; 34 | 35 | async function saveProject() { 36 | try { 37 | setIsSaving(true); 38 | const updates = { 39 | ...project, 40 | updated_at: new Date(), 41 | }; 42 | let { error } = await supabase.from('projects').upsert(updates, { 43 | returning: 'minimal', 44 | }); 45 | if (error) { 46 | throw error; 47 | } 48 | } catch (error) { 49 | console.error(error.message); 50 | } finally { 51 | setIsSaving(false); 52 | setHasChanges(false); 53 | } 54 | } 55 | 56 | return ( 57 |
58 | {/* FORM COLUMN */} 59 |
60 |
66 |
67 |
68 | 74 | setProperty('title', target.value)} 80 | /> 81 |
82 |
83 | 89 |