├── .gitignore ├── .nvmrc ├── LICENSE ├── README.md ├── bsconfig.json ├── gatsby-browser.js ├── gatsby-config.js ├── gatsby-node.js ├── gatsby-ssr.js ├── package.json ├── patches └── html2canvas+1.0.0-rc.5.patch ├── screenshot.png ├── src ├── avatars │ └── checkered.svg ├── components │ ├── App.res │ ├── AvatarGenerator.css │ ├── AvatarGenerator.res │ ├── Button.css │ ├── Button.res │ ├── ColorSwatch.css │ ├── ColorSwatch.res │ ├── Helmet.res │ ├── Icon.res │ ├── IconLink.css │ ├── IconLink.res │ ├── Layout.res │ ├── Modal.css │ ├── Modal.res │ ├── Styler.css │ ├── Styler.res │ ├── SvgLoader.res │ ├── Types.res │ ├── Wordmark.res │ ├── fonts.css │ ├── layout.css │ └── text.css ├── data │ └── config.json ├── helpers │ └── exportImage.js ├── images │ └── favicon.png └── pages │ ├── Index.res │ ├── index.js │ └── page_404.res ├── static ├── avatars │ ├── Background │ │ ├── blue.svg │ │ ├── dark.svg │ │ ├── green.svg │ │ ├── grey.svg │ │ ├── pink.svg │ │ ├── purple.svg │ │ ├── red.svg │ │ ├── teal.svg │ │ ├── white.svg │ │ └── yellow.svg │ ├── Body │ │ ├── checkered.svg │ │ ├── oval.svg │ │ ├── round.svg │ │ ├── small.svg │ │ └── square.svg │ ├── Exports.js │ ├── Eyes │ │ ├── glasses.svg │ │ ├── happy.svg │ │ ├── open.svg │ │ ├── sleepy.svg │ │ ├── sunglasses.svg │ │ └── wink.svg │ ├── FacialHair │ │ ├── beardmustache-black.svg │ │ ├── beardmustache-blonde.svg │ │ ├── beardmustache-brunette.svg │ │ ├── beardmustache-copper.svg │ │ ├── beardmustache-grey.svg │ │ ├── beardmustache-pink.svg │ │ ├── beardmustache-red.svg │ │ ├── beardmustache-teal.svg │ │ ├── mustache-black.svg │ │ ├── mustache-blonde.svg │ │ ├── mustache-brunette.svg │ │ ├── mustache-copper.svg │ │ ├── mustache-grey.svg │ │ ├── mustache-pink.svg │ │ ├── mustache-red.svg │ │ └── mustache-teal.svg │ ├── Hair │ │ ├── bald.svg │ │ ├── balding.svg │ │ ├── bigcurls.svg │ │ ├── bobbangs.svg │ │ ├── bobcut.svg │ │ ├── buncurls-black.svg │ │ ├── buzzcut.svg │ │ ├── curlybun.svg │ │ ├── curlyhightop.svg │ │ ├── extralong.svg │ │ ├── hightopcurly-black.svg │ │ ├── long.svg │ │ ├── pigtails.svg │ │ └── shortcombover.svg │ ├── Mouth │ │ ├── bigsmile.svg │ │ ├── frown.svg │ │ ├── lips.svg │ │ ├── pacifier.svg │ │ ├── smile.svg │ │ ├── smirk.svg │ │ └── surprise.svg │ ├── NewBody │ │ └── checkered.svg │ ├── NewFacialHair │ │ ├── goatee.svg │ │ ├── shadow.svg │ │ ├── soulpatch.svg │ │ └── walrus.svg │ ├── NewHair │ │ ├── bald.svg │ │ ├── balding.svg │ │ ├── beanie.svg │ │ ├── bunundercut.svg │ │ ├── buzz.svg │ │ ├── extralong.svg │ │ ├── fade.svg │ │ ├── hat.svg │ │ ├── mohawk.svg │ │ ├── shortcomboverchops.svg │ │ ├── sidebuzz.svg │ │ └── straightbun.svg │ ├── Nose │ │ ├── mediumround.svg │ │ ├── smallround.svg │ │ └── wrinkles.svg │ ├── Skin │ │ ├── Skin.svg │ │ ├── head-skin1.svg │ │ ├── head-skin2.svg │ │ ├── head-skin3.svg │ │ ├── head-skin4.svg │ │ ├── head-skin5.svg │ │ └── head-skin6.svg │ ├── SvgLoader.js │ ├── array.js │ ├── beardmustache.svg │ ├── files.json │ ├── parse.js │ └── svg.js ├── fonts │ ├── CerebriSans-Bold.woff │ ├── CerebriSans-Bold.woff2 │ ├── CerebriSans-Light.woff │ ├── CerebriSans-Light.woff2 │ ├── CerebriSans-Medium.woff │ ├── CerebriSans-Medium.woff2 │ ├── CerebriSans-Regular.woff │ └── CerebriSans-Regular.woff2 ├── images │ ├── arrow.svg │ ├── checkmark.svg │ ├── close.svg │ ├── facebook.svg │ ├── github.svg │ ├── logo-bg.svg │ ├── producthunt.svg │ ├── randomize.svg │ ├── sketch.svg │ └── twitter.svg ├── web-preview-1x1.png └── web-preview.png └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | .cache 3 | node_modules 4 | 5 | .DS_Store 6 | .env.local 7 | .env.development.local 8 | .env.test.local 9 | .env.production.local 10 | .env.development 11 | 12 | npm-debug.log* 13 | yarn-debug.log* 14 | yarn-error.log* 15 | 16 | public 17 | build 18 | .merlin 19 | lib 20 | *.log 21 | .bsb.lock 22 | *.bs.js 23 | src/cache 24 | .sass-cache/ 25 | .gatsby-context.js 26 | -------------------------------------------------------------------------------- /.nvmrc: -------------------------------------------------------------------------------- 1 | 16 2 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) Draftbit 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # Personas by Draftbit 2 | 3 | A delightful avatar generator by the folks at Draftbit. Try it online at [https://personas.draftbit.com](https://personas.draftbit.com) 4 | 5 | ![Personas](screenshot.png) 6 | 7 | ## Contributing 8 | 9 | Personas is built using Gatsby and Rescript. Setup instructions are straight forward: 10 | 11 | - `yarn` 12 | - `yarn develop` starts the Gatsby server 13 | - `yarn re:watch` starts the Rescript compiler 14 | 15 | > Note that the first time you get set up you'll need to run `npx patch-package` 16 | > to fix an error with one of `avatar-generator`'s dependencies. 17 | 18 | ## Why 19 | 20 | - We were exploring Reason/Rescript 21 | - We wanted to put together an inclusive avatar generator for placeholders and profile photos 22 | -------------------------------------------------------------------------------- /bsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@draftbit/personas", 3 | "reason": { 4 | "react-jsx": 3 5 | }, 6 | "bsc-flags": ["-bs-super-errors"], 7 | "sources": { 8 | "dir": "src", 9 | "subdirs": true 10 | }, 11 | "package-specs": [ 12 | { 13 | "module": "es6", 14 | "in-source": true 15 | } 16 | ], 17 | "suffix": ".bs.js", 18 | "namespace": true, 19 | "bs-dependencies": ["@rescript/react"], 20 | "refmt": 3 21 | } 22 | -------------------------------------------------------------------------------- /gatsby-browser.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Browser APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/browser-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: 4 | 'Personas by Draftbit | A playful avatar generator for the modern age.', 5 | }, 6 | plugins: [ 7 | 'gatsby-plugin-react-helmet', 8 | { 9 | resolve: `gatsby-plugin-manifest`, 10 | options: { 11 | name: 'persona-avatar-generator-draftbit', 12 | short_name: 'avatar-generator', 13 | start_url: '/', 14 | background_color: '#5a45ff', 15 | theme_color: '#5a45ff', 16 | display: 'minimal-ui', 17 | icon: 'src/images/favicon.png', 18 | }, 19 | }, 20 | { 21 | resolve: `gatsby-plugin-google-analytics`, 22 | options: { 23 | trackingId: 'UA-96165051-4', 24 | respectDNT: true, 25 | }, 26 | }, 27 | { 28 | resolve: 'gatsby-plugin-react-svg', 29 | options: { 30 | rule: { 31 | include: /avatars/, 32 | }, 33 | }, 34 | }, 35 | `gatsby-transformer-json`, 36 | { 37 | resolve: `gatsby-source-filesystem`, 38 | options: { 39 | typeName: 'Config', 40 | path: `./src/data/`, 41 | }, 42 | }, 43 | 'gatsby-plugin-offline', 44 | `gatsby-plugin-netlify`, 45 | ], 46 | } 47 | -------------------------------------------------------------------------------- /gatsby-node.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's Node APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/node-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | 9 | const path = require('path') 10 | 11 | exports.createPages = async ({ actions }) => { 12 | const { createPage } = actions 13 | const page404 = path.resolve('src/pages/page_404.bs.js') 14 | createPage({ 15 | path: '404', 16 | component: page404, 17 | }) 18 | } 19 | -------------------------------------------------------------------------------- /gatsby-ssr.js: -------------------------------------------------------------------------------- 1 | /** 2 | * Implement Gatsby's SSR (Server Side Rendering) APIs in this file. 3 | * 4 | * See: https://www.gatsbyjs.org/docs/ssr-apis/ 5 | */ 6 | 7 | // You can delete this file if you're not using it 8 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@draftbit/personas", 3 | "description": "Avatar Generator by Draftbit", 4 | "version": "1.0.0", 5 | "dependencies": { 6 | "@rescript/react": "^0.10.3", 7 | "gatsby": "^2.21.31", 8 | "gatsby-plugin-google-analytics": "^2.3.1", 9 | "gatsby-plugin-manifest": "^2.4.3", 10 | "gatsby-plugin-netlify": "^2.3.2", 11 | "gatsby-plugin-offline": "^3.2.2", 12 | "gatsby-plugin-react-helmet": "^3.3.1", 13 | "gatsby-plugin-react-svg": "^3.0.0", 14 | "gatsby-source-filesystem": "^2.3.3", 15 | "gatsby-transformer-json": "^2.4.2", 16 | "html2canvas": "^1.0.0-rc.5", 17 | "normalize.css": "^8.0.0", 18 | "react": "^17.0.2", 19 | "react-dom": "^17.0.2", 20 | "react-helmet": "^6.0.0" 21 | }, 22 | "keywords": [ 23 | "personas", 24 | "persona-avatar-generator", 25 | "reasonml" 26 | ], 27 | "license": "MIT", 28 | "scripts": { 29 | "postinstall": "yarn yarn-deduplicate", 30 | "re:build": "rescript clean && rescript build", 31 | "re:watch": "rescript build -w", 32 | "build": "npm run re:build && npx patch-package && gatsby build", 33 | "develop": "gatsby develop", 34 | "format": "prettier --write 'src/**/*.js'", 35 | "test": "echo \"Error: no test specified\" && exit 1" 36 | }, 37 | "devDependencies": { 38 | "prettier": "2.5.1", 39 | "rescript": "^9.1.4", 40 | "yarn-deduplicate": "^3.1.0" 41 | }, 42 | "repository": { 43 | "type": "git", 44 | "url": "https://github.com/draftbit/persona-avatar-generator" 45 | }, 46 | "engines": { 47 | "node": "^16.13", 48 | "yarn": "^1.22.10" 49 | }, 50 | "resolutions": { 51 | "node-fetch": "^2.6.7" 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /patches/html2canvas+1.0.0-rc.5.patch: -------------------------------------------------------------------------------- 1 | diff --git a/node_modules/html2canvas/dist/html2canvas.esm.js b/node_modules/html2canvas/dist/html2canvas.esm.js 2 | index 4da8f10..e459cb9 100644 3 | --- a/node_modules/html2canvas/dist/html2canvas.esm.js 4 | +++ b/node_modules/html2canvas/dist/html2canvas.esm.js 5 | @@ -6898,7 +6898,9 @@ var html2canvas = function (element, options) { 6 | if (options === void 0) { options = {}; } 7 | return renderElement(element, options); 8 | }; 9 | -CacheStorage.setContext(window); 10 | +if (typeof window !== "undefined") { 11 | + CacheStorage.setContext(window); 12 | +} 13 | var renderElement = function (element, opts) { return __awaiter(_this, void 0, void 0, function () { 14 | var ownerDocument, defaultView, instanceName, _a, width, height, left, top, defaultResourceOptions, resourceOptions, defaultOptions, options, windowBounds, documentCloner, clonedElement, container, documentBackgroundColor, bodyBackgroundColor, bgColor, defaultBackgroundColor, backgroundColor, renderOptions, canvas, renderer, root, renderer; 15 | return __generator(this, function (_b) { 16 | -------------------------------------------------------------------------------- /screenshot.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/screenshot.png -------------------------------------------------------------------------------- /src/avatars/checkered.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/components/App.res: -------------------------------------------------------------------------------- 1 | @react.component 2 | let make = ( 3 | ~showModal, 4 | ~onToggleModal, 5 | ~onExport, 6 | ~onChange, 7 | ~randomize, 8 | ~styles: Types.styles, 9 | ~config: Types.config, 10 | ) => { 11 | let settings: array = [ 12 | { 13 | id: #Skin, 14 | label: "SKIN", 15 | colors: config.skinColors, 16 | styles: config.skinStyles, 17 | selectedColor: styles.skinColor, 18 | selectedStyle: styles.skin, 19 | }, 20 | { 21 | id: #Hair, 22 | label: "HAIR", 23 | colors: config.hairColors, 24 | styles: config.hairStyles, 25 | selectedColor: styles.hairColor, 26 | selectedStyle: styles.hair, 27 | }, 28 | { 29 | id: #FacialHair, 30 | label: "FACIAL HAIR", 31 | colors: config.facialHairColors, 32 | styles: config.facialHairStyles, 33 | selectedColor: styles.facialHairColor, 34 | selectedStyle: styles.facialHair, 35 | }, 36 | { 37 | id: #Body, 38 | label: "BODY", 39 | colors: config.bodyColors, 40 | styles: config.bodyStyles, 41 | selectedColor: styles.bodyColor, 42 | selectedStyle: styles.body, 43 | }, 44 | { 45 | id: #Eyes, 46 | label: "EYES", 47 | colors: config.disabledColors, 48 | styles: config.eyeStyles, 49 | selectedColor: "000000", 50 | selectedStyle: styles.eyes, 51 | }, 52 | { 53 | id: #Mouth, 54 | label: "MOUTH", 55 | colors: config.disabledColors, 56 | styles: config.mouthStyles, 57 | selectedColor: "000000", 58 | selectedStyle: styles.mouth, 59 | }, 60 | { 61 | id: #Nose, 62 | label: "NOSE", 63 | colors: config.disabledColors, 64 | styles: config.noseStyles, 65 | selectedColor: styles.skinColor, 66 | selectedStyle: styles.nose, 67 | }, 68 | { 69 | id: #Background, 70 | label: "BACKGROUND", 71 | colors: config.bgColors, 72 | styles: config.bgStyles, 73 | selectedColor: styles.bgColor, 74 | selectedStyle: "Background", 75 | }, 76 | ] 77 | <> 78 |
79 |
80 |
81 |
82 | 83 |

{React.string("Personas")}

84 | {React.string("Avatar Generator")} 85 |
86 |
87 |

88 | {React.string("A playful avatar generator for the modern age.")} 89 |

90 |
91 |
92 |
93 |
94 |
95 | {React.string("Built by")}
96 |
97 |
98 | 99 | {React.string("Visually build robust, native mobile apps with clean, reusable code.")} 100 | 101 |
102 | 108 |
109 |
110 |
111 |
113 | 114 | 115 | } 116 | -------------------------------------------------------------------------------- /src/components/AvatarGenerator.css: -------------------------------------------------------------------------------- 1 | .AvatarGenerator-container { 2 | position: relative; 3 | max-width: 780px; 4 | box-shadow: 0 4px 6px 0 rgba(24, 33, 45, 0.06); 5 | background-color: #ffffff; 6 | border: solid 1px rgba(24, 33, 45, 0.06); 7 | border-radius: 8px; 8 | display: flex; 9 | flex-direction: column; 10 | justify-content: space-between; 11 | align-items: center; 12 | padding-top: 110px; 13 | } 14 | 15 | .AvatarGenerator-pngContainer { 16 | position: fixed; 17 | top: 0; 18 | left: -512px; 19 | width: 512px; 20 | height: 512px; 21 | background-color: white; 22 | } 23 | 24 | .AvatarGenerator-png { 25 | position: absolute; 26 | top: 0; 27 | left: 0; 28 | width: 512px; 29 | height: 512px; 30 | } 31 | 32 | .AvatarGenerator-avatar { 33 | position: absolute; 34 | width: 150px; 35 | height: 150px; 36 | border-radius: 75px; 37 | background-color: transparent; 38 | overflow: hidden; 39 | top: -75px; 40 | } 41 | 42 | .AvatarGenerator-faceFeature { 43 | position: absolute; 44 | top: 0; 45 | left: 0; 46 | width: 150px; 47 | height: 150px; 48 | border-radius: 75px; 49 | overflow: hidden; 50 | } 51 | 52 | .AvatarGenerator-row { 53 | padding-left: 24px; 54 | padding-right: 24px; 55 | width: 100%; 56 | display: flex; 57 | flex-direction: row; 58 | align-items: flex-start; 59 | justify-content: space-around; 60 | flex-wrap: wrap; 61 | margin-bottom: 24px; 62 | } 63 | 64 | @media(min-width:768px) { 65 | .AvatarGenerator-row { 66 | padding-left: 48px; 67 | padding-right: 48px; 68 | width: 100%; 69 | display: flex; 70 | flex-direction: row; 71 | align-items: flex-start; 72 | justify-content: space-between; 73 | flex-wrap: wrap; 74 | margin-bottom: 48px; 75 | } 76 | } 77 | 78 | .AvatarGenerator-footer { 79 | width: 100%; 80 | background-color: #f9fafc; 81 | padding-top: 28px; 82 | padding-bottom: 28px; 83 | border-radius: 8px; 84 | text-align: center; 85 | margin-top: 24px; 86 | } 87 | 88 | @media(min-width:768px) { 89 | .AvatarGenerator-footerTop { 90 | margin-right: 48px; 91 | margin-left: 24px; 92 | } 93 | 94 | .AvatarGenerator-footer { 95 | width: 100%; 96 | background-color: #f9fafc; 97 | padding-top: 28px; 98 | padding-bottom: 28px; 99 | display: flex; 100 | justify-content: center; 101 | align-items: center; 102 | border-radius: 8px; 103 | margin-top: 32px; 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /src/components/AvatarGenerator.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./AvatarGenerator.css')`) 2 | 3 | let getZIndex = (id: Types.id) => 4 | switch id { 5 | | #Eyes => "110" 6 | | #Nose => "100" 7 | | #FacialHair => "90" 8 | | #Mouth => "80" 9 | | #Body => "75" 10 | | #Hair => "70" 11 | | #Head => "40" 12 | | #Skin => "30" 13 | | #Background => "20" 14 | } 15 | 16 | type state = {rotation: int} 17 | 18 | type action = Randomize 19 | 20 | @react.component 21 | let make = (~randomize, ~settings: array, ~onChange, ~onExport) => { 22 | let (state, dispatch) = React.useReducer((state, action) => 23 | switch action { 24 | | Randomize => 25 | randomize() 26 | {rotation: state.rotation + 1} 27 | } 28 | , {rotation: 0}) 29 | let rotation = "rotate(" ++ (string_of_int(state.rotation * 50) ++ "deg)") 30 | let pngImage = Belt.Array.map(settings, o => 31 | 39 | ) 40 | 41 | let faceFeatures = Belt.Array.map(settings, o => 42 | 50 | ) 51 | 52 |
53 |
{React.array(pngImage)}
54 |
{React.array(faceFeatures)}
55 | 59 |
60 | {Belt.Array.map(settings, o => 61 | { 70 | let key: Types.key = switch o.id { 71 | | #Skin => #SkinColor 72 | | #Hair => #HairColor 73 | | #FacialHair => #FacialHairColor 74 | | #Body => #BodyColor 75 | | #Background => #BackgroundColor 76 | | _ => Js.Exn.raiseError("ColorNotFound: " ++ Types.idToJs(o.id)) 77 | } 78 | 79 | onChange(key, color) 80 | }} 81 | onSelectStyle={style => { 82 | let key: Types.key = switch o.id { 83 | | #Skin => #SkinStyle 84 | | #Hair => #HairStyle 85 | | #FacialHair => #FacialHairStyle 86 | | #Body => #BodyStyle 87 | | #Eyes => #EyesStyle 88 | | #Mouth => #MouthStyle 89 | | #Nose => #NoseStyle 90 | | _ => Js.Exn.raiseError("StyleNotFound: " ++ Types.idToJs(o.id)) 91 | } 92 | onChange(key, style) 93 | }} 94 | /> 95 | )->React.array} 96 |
97 | 100 |
101 | 102 |
103 | {React.string("Want to make your own?")} 104 |
105 | 106 | {React.string("Get the Sketch file on Gumroad.")} 107 | 108 |
109 | 110 |
111 |
112 | } 113 | -------------------------------------------------------------------------------- /src/components/Button.css: -------------------------------------------------------------------------------- 1 | .Button { 2 | padding: 16px; 3 | border: none; 4 | border-radius: 8px; 5 | box-shadow: 0 2px 3px 0 rgba(16, 22, 64, 0.12); 6 | background-color: #ffffff; 7 | text-decoration: none; 8 | } 9 | 10 | @media (min-width: 768px) { 11 | .Button--github { 12 | position: absolute; 13 | top: 20px; 14 | right: 20px; 15 | } 16 | } 17 | 18 | .Button-icon { 19 | margin-right: 12px; 20 | display: inline-block; 21 | vertical-align: middle; 22 | } 23 | 24 | .Button-label { 25 | font-family: "CerebriSans-Medium"; 26 | font-size: 14px; 27 | font-weight: 500; 28 | font-style: normal; 29 | font-stretch: normal; 30 | line-height: normal; 31 | letter-spacing: normal; 32 | color: #73859d; 33 | vertical-align: middle; 34 | } 35 | -------------------------------------------------------------------------------- /src/components/Button.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./Button.css')`) 2 | 3 | @react.component 4 | let make = (~style=?, ~label, ~href) => 5 | 6 | 7 | {React.string(label)} 8 | 9 | -------------------------------------------------------------------------------- /src/components/ColorSwatch.css: -------------------------------------------------------------------------------- 1 | .ColorSwatch { 2 | width: 20px; 3 | height: 20px; 4 | border-radius: 4px; 5 | border: none; 6 | background: #eee; 7 | box-shadow: 0 1px 3px 0 rgba(16, 22, 64, 0.16); 8 | cursor: pointer; 9 | margin-left: 6px; 10 | margin-right: 6px; 11 | margin-bottom: 12px; 12 | padding: 0; 13 | } 14 | 15 | .ColorSwatch-disabled { 16 | width: 20px; 17 | height: 20px; 18 | border-radius: 4px; 19 | background: #EEEFF5; 20 | margin-left: 6px; 21 | margin-right: 6px; 22 | margin-bottom: 12px; 23 | } 24 | -------------------------------------------------------------------------------- /src/components/ColorSwatch.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./ColorSwatch.css')`) 2 | 3 | @react.component 4 | let make = (~value, ~selected, ~disabled=false, ~onSelect) => 5 | disabled 6 | ?
7 | : 13 | -------------------------------------------------------------------------------- /src/components/Helmet.res: -------------------------------------------------------------------------------- 1 | @deriving(abstract) 2 | type finalMetaItem = { 3 | @optional 4 | name: string, 5 | @optional 6 | property: string, 7 | @optional 8 | content: string, 9 | } 10 | 11 | type link = { 12 | rel: string, 13 | href: string, 14 | } 15 | 16 | @module("react-helmet") @react.component 17 | external make: ( 18 | ~async: bool=?, 19 | ~base: 'a=?, 20 | ~bodyAttributes: 'a=?, 21 | ~defaultTitle: string=?, 22 | ~defer: bool=?, 23 | ~encodeSpecialCharacters: bool=?, 24 | ~htmlAttributes: 'a=?, 25 | ~onChangeClientState: 'a=?, 26 | ~link: array=?, 27 | ~style: string=?, 28 | ~titleTemplate: string=?, 29 | ~meta: array=?, 30 | ~title: string=?, 31 | ~children: React.element=?, 32 | ) => React.element = "Helmet" 33 | -------------------------------------------------------------------------------- /src/components/Icon.res: -------------------------------------------------------------------------------- 1 | @react.component 2 | let make = (~style=?, ~name) => 3 | switch name { 4 | | "arrow" => 5 | 12 | 16 | 17 | | "randomize" => 18 | 25 | 30 | 31 | | "wordmark" => 32 | 33 | 34 | 39 | 43 | 44 | 45 | | _ => React.null 46 | } 47 | -------------------------------------------------------------------------------- /src/components/IconLink.css: -------------------------------------------------------------------------------- 1 | @media (max-width: 767px) { 2 | .IconLink-container { 3 | display: inline-block; 4 | margin-top: 8px; 5 | } 6 | } 7 | 8 | .IconLink-container { 9 | display: inline-block; 10 | vertical-align: middle; 11 | } 12 | 13 | .IconLink-icon { 14 | margin-left: 8px; 15 | } 16 | 17 | -------------------------------------------------------------------------------- /src/components/IconLink.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./IconLink.css')`) 2 | 3 | @react.component 4 | let make = (~rel=?, ~title=?, ~label, ~href, ~icon) => 5 | 6 | {React.string(label)} 7 | 8 | -------------------------------------------------------------------------------- /src/components/Layout.res: -------------------------------------------------------------------------------- 1 | open Helmet 2 | 3 | @module("gatsby") external useStaticQuery: string => 'a = "useStaticQuery" 4 | 5 | %%raw(` 6 | import {graphql} from "gatsby" 7 | import 'normalize.css' 8 | import './layout.css' 9 | import './fonts.css' 10 | import './text.css' 11 | `) 12 | 13 | type siteMetadataType = {title: string} 14 | type siteType = {siteMetadata: siteMetadataType} 15 | type queryResponseType = {site: siteType} 16 | 17 | type metaItem = 18 | | MetaWithName(string, string) 19 | | MetaWithProperty(string, string) 20 | 21 | type meta = array 22 | 23 | let meta = [ 24 | MetaWithName("description", "A playful avatar generator for the modern age."), 25 | MetaWithName("twitter:card", "summary"), 26 | MetaWithName("twitter:site", "@draftbit"), 27 | MetaWithName("twitter:title", "Personas by Draftbit"), 28 | MetaWithName("twitter:image", "https://personas.draftbit.com/web-preview-1x1.png"), 29 | MetaWithName("twitter:description", "A playful avatar generator for the modern age."), 30 | MetaWithName("keywords", "Avatar, Avatar Generator, Personas, Draftbit, Avatars"), 31 | MetaWithProperty("fb:app_id", "292869531545861"), 32 | MetaWithProperty("og:type", "website"), 33 | MetaWithProperty("og:image", "https://personas.draftbit.com/web-preview.png"), 34 | MetaWithProperty("og:title", "Personas by Draftbit"), 35 | MetaWithProperty("og:url", "https://personas.draftbit.com"), 36 | MetaWithProperty("og:description", "A playful avatar generator for the modern age."), 37 | ] 38 | 39 | let link = [{rel: "canonical", href: "https://personas.draftbit.com"}] 40 | 41 | let metaToHelmet = (item: metaItem) => 42 | switch item { 43 | | MetaWithName(name, content) => finalMetaItem(~name, ~content, ()) 44 | | MetaWithProperty(property, content) => finalMetaItem(~property, ~content, ()) 45 | } 46 | 47 | @react.component 48 | let make = (~children: React.element) => { 49 | let data: queryResponseType = useStaticQuery( 50 | %raw(` 51 | graphql\` 52 | query SiteTitleQuery { 53 | site { 54 | siteMetadata { 55 | title 56 | } 57 | } 58 | } 59 | \` 60 | `), 61 | ) 62 | 63 | <> 64 | Array.map(metaToHelmet)}> 65 | 66 | 67 | children 68 | 69 | } 70 | 71 | let default = make 72 | -------------------------------------------------------------------------------- /src/components/Modal.css: -------------------------------------------------------------------------------- 1 | .Modal-overlay { 2 | position: fixed; 3 | top: 0; 4 | left: 0; 5 | bottom: 0; 6 | right: 0; 7 | z-index: 0; 8 | border: none; 9 | background: #070b28; 10 | opacity: 0.5; 11 | z-index: 500; 12 | } 13 | 14 | .Modal-container { 15 | position: fixed; 16 | top: 0; 17 | bottom: 0; 18 | left: 0; 19 | right: 0; 20 | margin: auto; 21 | width: 500px; 22 | max-height: 370px; 23 | box-shadow: 0 6px 10px 0 rgba(24, 33, 45, 0.06); 24 | border: solid 1px rgba(24, 33, 45, 0.02); 25 | background-color: #ffffff; 26 | border-radius: 6px; 27 | padding: 56px; 28 | text-align: center; 29 | z-index: 1000; 30 | } 31 | 32 | .Modal-close { 33 | position: absolute; 34 | top: 20px; 35 | right: 20px; 36 | background: transparent; 37 | border: none; 38 | cursor: pointer; 39 | } 40 | 41 | .Modal-buttons { 42 | margin-top: 17px; 43 | } 44 | 45 | .Modal-button { 46 | text-decoration: none; 47 | display: inline-flex; 48 | justify-content: center; 49 | align-items: center; 50 | width: 142px; 51 | height: 48px; 52 | box-shadow: 0 2px 3px 0 rgba(16, 22, 64, 0.12); 53 | background: transparent; 54 | border: none; 55 | border-radius: 6px; 56 | color: #FFF; 57 | 58 | font-family: "CerebriSans-Medium"; 59 | font-size: 14px; 60 | font-weight: 500; 61 | font-style: normal; 62 | font-stretch: normal; 63 | line-height: normal; 64 | letter-spacing: 0.4px; 65 | color: #ffffff; 66 | } 67 | 68 | .Modal-button--ph { 69 | background-color: #da552f; 70 | } 71 | 72 | .Modal-button--twitter { 73 | background-color: #2baee7; 74 | margin-right: 16px; 75 | } 76 | 77 | .Modal-title { 78 | font-family: "CerebriSans-Medium"; 79 | font-size: 40px; 80 | font-weight: 500; 81 | font-style: normal; 82 | font-stretch: normal; 83 | line-height: normal; 84 | letter-spacing: normal; 85 | color: #070b28; 86 | } 87 | 88 | .Modal-subtitle { 89 | font-family: "CerebriSans-Light"; 90 | font-size: 18px; 91 | font-weight: 300; 92 | font-style: normal; 93 | font-stretch: normal; 94 | line-height: 1.56; 95 | letter-spacing: -0.4px; 96 | color: #73859d; 97 | } 98 | 99 | .Modal-shareIcon { 100 | display: inline-block; 101 | margin-right: 12px; 102 | } 103 | -------------------------------------------------------------------------------- /src/components/Modal.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./Modal.css')`) 2 | 3 | @react.component 4 | let make = (~visible, ~onToggle) => 5 | !visible 6 | ? React.null 7 | : <> 8 |
9 |
10 | 13 |

{React.string("Enjoy your avatar!")}

14 | 15 | {React.string( 16 | "Share it with your friends and see what ridiculousness they come up with!", 17 | )} 18 | 19 | 39 |
40 | 41 | -------------------------------------------------------------------------------- /src/components/Styler.css: -------------------------------------------------------------------------------- 1 | .Styler-container { 2 | text-align: center; 3 | width: 140px; 4 | margin-top: 32px; 5 | } 6 | 7 | .Styler-label { 8 | font-family: "CerebriSans-Regular"; 9 | font-size: 12px; 10 | font-weight: normal; 11 | font-style: normal; 12 | font-stretch: normal; 13 | line-height: normal; 14 | letter-spacing: 2.6px; 15 | color: #7c7f91; 16 | text-transform: uppercase; 17 | margin-bottom: 14px; 18 | display: inline-block; 19 | } 20 | 21 | .Styler-model { 22 | overflow: hidden; 23 | width: 64px; 24 | height: 64px; 25 | margin-bottom: 14px; 26 | } 27 | 28 | .Styler-model.svg-Background { 29 | border-radius: 32px; 30 | } 31 | 32 | .Styler-colors { 33 | width: 130px; 34 | display: flex; 35 | flex-wrap: wrap; 36 | justify-content: space-between; 37 | } 38 | 39 | .Styler-picker { 40 | display: flex; 41 | justify-content: space-between; 42 | } 43 | 44 | .Styler-arrow--right { 45 | transform: rotate(180deg); 46 | } 47 | 48 | .Styler-btn { 49 | cursor: pointer; 50 | background: transparent; 51 | border: none; 52 | padding: 0 10px; 53 | } 54 | -------------------------------------------------------------------------------- /src/components/Styler.res: -------------------------------------------------------------------------------- 1 | %raw(`require('./Styler.css')`) 2 | 3 | type state = {index: int} 4 | 5 | type action = 6 | | Increment 7 | | Decrement 8 | 9 | @react.component 10 | let make = ( 11 | ~id, 12 | ~label, 13 | ~colors, 14 | ~styles, 15 | ~selectedColor, 16 | ~selectedStyle, 17 | ~onSelectColor, 18 | ~onSelectStyle, 19 | ) => { 20 | let (_, dispatch) = React.useReducer((state, action) => 21 | switch action { 22 | | Increment => 23 | let inc = Belt.Array.length(styles) - 1 > state.index ? 1 : -Belt.Array.length(styles) + 1 24 | let index = state.index + inc 25 | let style = styles[index] 26 | onSelectStyle(j`$style`) 27 | {index: index} 28 | | Decrement => 29 | let inc = state.index > 0 ? 1 : -Belt.Array.length(styles) + 1 30 | let index = state.index - inc 31 | let style = styles[index] 32 | onSelectStyle(j`$style`) 33 | {index: index} 34 | } 35 | , {index: 0}) 36 | 37 | let colorSwatches = switch id { 38 | | #Eyes 39 | | #Nose 40 | | #Mouth => React.null 41 | | _ => 42 | Belt.Array.map(colors, color => 43 | onSelectColor(value)} 49 | /> 50 | )->React.array 51 | } 52 | let image = 53 | 54 | let showLeftArrow = 55 | Belt.Array.length(styles) > 1 56 | ? 59 | :
60 | 61 | let showRightArrow = 62 | Belt.Array.length(styles) > 1 63 | ? 66 | :
67 | 68 | let showImage = switch id { 69 | | #Background => React.null 70 | | _ =>
image
71 | } 72 | 73 |
74 | {React.string(label)} 75 |
showLeftArrow showImage showRightArrow
76 |
colorSwatches
77 |
78 | } 79 | -------------------------------------------------------------------------------- /src/components/SvgLoader.res: -------------------------------------------------------------------------------- 1 | let getBackground = (fill, size) => 2 | j`` 3 | let getBeardMustache = (fill, size) => 4 | j` 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 14 | 15 | 16 | 17 | 18 | 19 | 20 | 21 | ` 22 | let getSkin = (fill, size) => 23 | j` 24 | 25 | 26 | ` 27 | let getMustache = (fill, size) => 28 | j` ` 29 | let getGoatee = (fill, size) => 30 | j`` 31 | let getShadow = (fill, size) => 32 | j`` 33 | let getSoulpatch = (fill, size) => 34 | j`` 35 | let getWalrus = (fill, size) => 36 | j`` 37 | 38 | let getEyesGlasses = (_, size) => 39 | j`` 40 | let getEyesHappy = (_, size) => 41 | j`` 42 | let getEyesOpen = (_, size) => 43 | j`` 44 | let getEyesSleepy = (fill, size) => 45 | j`` 46 | let getEyesSunglasses = (fill, size) => 47 | j`` 48 | let getEyesWink = (fill, size) => 49 | j`` 50 | 51 | let getMouthBigsmile = (_, size) => 52 | j`` 53 | let getMouthFrown = (_, size) => 54 | j`` 55 | let getMouthLips = (_, size) => 56 | j`` 57 | let getMouthPacifier = (_, size) => 58 | j`` 59 | let getMouthSmile = (_, size) => 60 | j`` 61 | let getMouthSmirk = (_, size) => 62 | j`` 63 | let getMouthSurprise = (_, size) => 64 | j`` 65 | 66 | let getNoseMediumround = (fill, size) => 67 | j` 68 | 69 | ` 70 | 71 | let getNoseSmallround = (fill, size) => 72 | j` 73 | ` 74 | 75 | let getNoseWrinkles = (fill, size) => 76 | j` 77 | ` 78 | 79 | let getCheckered = (fill, size) => 80 | j` 81 | 82 | 83 | 84 | 85 | 86 | ` 87 | let getBodyOval = (fill, size) => 88 | j`` 89 | let getBodyRound = (fill, size) => 90 | j`` 91 | let getBodySquare = (fill, size) => 92 | j`` 93 | 94 | let getBald = (_, size) => 95 | j`` 96 | let getBalding = (fill, size) => 97 | j`` 98 | let getBigcurls = (fill, size) => 99 | j`` 100 | let getBobbangs = (fill, size) => 101 | j`` 102 | let getBobcut = (fill, size) => 103 | j`` 104 | let getBuncurls = (fill, size) => 105 | j`` 106 | let getBuzzcut = (fill, size) => 107 | j`` 108 | let getCurlybun = (_, size) => 109 | j`` 110 | let getCurlyhightop = (fill, size) => 111 | j`` 112 | let getHightopcurly = (fill, size) => 113 | j` 114 | 115 | 116 | 117 | 118 | 119 | 120 | 121 | 122 | 123 | ` 124 | 125 | let getLong = (fill, size) => 126 | j`` 127 | let getPigtails = (fill, size) => 128 | j`` 129 | let getShortcombover = (fill, size) => 130 | j`` 131 | 132 | let getBeanie = (fill, size) => 133 | j`` 134 | let getBunundercut = (fill, size) => 135 | j` 136 | 137 | 138 | 139 | 140 | 141 | 142 | 143 | 144 | 145 | 146 | ` 147 | 148 | let getExtralong = (fill, size) => 149 | j`` 150 | let getFade = (fill, size) => 151 | j` 152 | 153 | 154 | 155 | 156 | 157 | ` 158 | let getHat = (fill, size) => 159 | j` 160 | 161 | 162 | 163 | 164 | 165 | 166 | 167 | ` 168 | let getMohawk = (fill, size) => 169 | j`` 170 | let getShortcomboverchops = (fill, size) => 171 | j`` 172 | let getSidebuzz = (fill, size) => 173 | j` 174 | 175 | 176 | 177 | ` 178 | let getStraightbun = (fill, size) => 179 | j`` 180 | 181 | @react.component 182 | let make = (~style=?, ~className="", ~name, ~fill="#000", ~size="64") => { 183 | let getHtml = name => 184 | switch name { 185 | | "Skin" => getSkin(fill, size) 186 | | "Mustache" => getMustache(fill, size) 187 | | "BeardMustache" => getBeardMustache(fill, size) 188 | | "Goatee" => getGoatee(fill, size) 189 | | "Shadow" => getShadow(fill, size) 190 | | "Soulpatch" => getSoulpatch(fill, size) 191 | | "Walrus" => getWalrus(fill, size) 192 | | "Glasses" => getEyesGlasses(fill, size) 193 | | "Happy" => getEyesHappy(fill, size) 194 | | "Open" => getEyesOpen(fill, size) 195 | | "Sleepy" => getEyesSleepy(fill, size) 196 | | "Sunglasses" => getEyesSunglasses(fill, size) 197 | | "Wink" => getEyesWink(fill, size) 198 | | "Bigsmile" => getMouthBigsmile(fill, size) 199 | | "Frown" => getMouthFrown(fill, size) 200 | | "Lips" => getMouthLips(fill, size) 201 | | "Pacifier" => getMouthPacifier(fill, size) 202 | | "Smile" => getMouthSmile(fill, size) 203 | | "Smirk" => getMouthSmirk(fill, size) 204 | | "Surprise" => getMouthSurprise(fill, size) 205 | | "Mediumround" => getNoseMediumround(fill, size) 206 | | "Smallround" => getNoseSmallround(fill, size) 207 | | "Wrinkles" => getNoseWrinkles(fill, size) 208 | | "Oval" => getBodyOval(fill, size) 209 | | "Checkered" => getCheckered(fill, size) 210 | | "Round" => getBodyRound(fill, size) 211 | | "Square" => getBodySquare(fill, size) 212 | | "Bald" => getBald(fill, size) 213 | | "Balding" => getBalding(fill, size) 214 | | "Bigcurls" => getBigcurls(fill, size) 215 | | "Bobbangs" => getBobbangs(fill, size) 216 | | "Bobcut" => getBobcut(fill, size) 217 | | "Buncurls" => getBuncurls(fill, size) 218 | | "Buzzcut" => getBuzzcut(fill, size) 219 | | "Curlybun" => getCurlybun(fill, size) 220 | | "Hightopcurly" => getCurlyhightop(fill, size) 221 | | "Long" => getLong(fill, size) 222 | | "Pigtails" => getPigtails(fill, size) 223 | | "Shortcombover" => getShortcombover(fill, size) 224 | | "Hat" => getHat(fill, size) 225 | | "Beanie" => getBeanie(fill, size) 226 | | "Bunundercut" => getBunundercut(fill, size) 227 | | "Extralong" => getExtralong(fill, size) 228 | | "Fade" => getFade(fill, size) 229 | | "Mohawk" => getMohawk(fill, size) 230 | | "Shortcomboverchops" => getShortcomboverchops(fill, size) 231 | | "Sidebuzz" => getSidebuzz(fill, size) 232 | | "Straightbun" => getStraightbun(fill, size) 233 | | "Background" => getBackground(fill, size) 234 | | _ => "" 235 | } 236 | 237 | getHtml(name) == "" 238 | ? React.null 239 | :
240 | } 241 | -------------------------------------------------------------------------------- /src/components/Types.res: -------------------------------------------------------------------------------- 1 | @deriving(jsConverter) 2 | type id = [ 3 | | @as("Skin") #Skin 4 | | @as("Hair") #Hair 5 | | @as("FacialHair") #FacialHair 6 | | @as("Body") #Body 7 | | @as("Eyes") #Eyes 8 | | @as("Mouth") #Mouth 9 | | @as("Nose") #Nose 10 | | @as("Background") #Background 11 | | @as("Head") #Head 12 | ] 13 | 14 | type color = [ 15 | | #SkinColor 16 | | #HairColor 17 | | #FacialHairColor 18 | | #BodyColor 19 | | #BackgroundColor 20 | ] 21 | 22 | type style = [ 23 | | #SkinStyle 24 | | #HairStyle 25 | | #FacialHairStyle 26 | | #BodyStyle 27 | | #EyesStyle 28 | | #MouthStyle 29 | | #NoseStyle 30 | ] 31 | 32 | type key = [color | style] 33 | 34 | type styles = { 35 | skin: string, 36 | skinColor: string, 37 | hair: string, 38 | hairColor: string, 39 | facialHair: string, 40 | facialHairColor: string, 41 | body: string, 42 | bodyColor: string, 43 | eyes: string, 44 | mouth: string, 45 | nose: string, 46 | bgColor: string, 47 | head: string, 48 | } 49 | 50 | type setting = { 51 | id: id, 52 | label: string, 53 | colors: array, 54 | styles: array, 55 | selectedColor: string, 56 | selectedStyle: string, 57 | } 58 | 59 | type config = { 60 | skinColors: array, 61 | hairColors: array, 62 | facialHairColors: array, 63 | bodyColors: array, 64 | bgColors: array, 65 | disabledColors: array, 66 | skinStyles: array, 67 | hairStyles: array, 68 | facialHairStyles: array, 69 | bodyStyles: array, 70 | eyeStyles: array, 71 | mouthStyles: array, 72 | noseStyles: array, 73 | bgStyles: array, 74 | } 75 | 76 | @ocaml.doc(" Gatsby GraphQL types ") 77 | type edge = {node: config} 78 | type allDataJson = {edges: array} 79 | type queryResType = {allDataJson: allDataJson} 80 | -------------------------------------------------------------------------------- /src/components/Wordmark.res: -------------------------------------------------------------------------------- 1 | @react.component 2 | let make = () => 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /src/components/fonts.css: -------------------------------------------------------------------------------- 1 | @font-face { 2 | font-family: 'CerebriSans-Bold'; 3 | src: url('/fonts/CerebriSans-Bold.woff2') format('woff2'), 4 | url('/fonts/CerebriSans-Bold.woff') format('woff'); 5 | font-weight: normal; 6 | font-style: normal; 7 | 8 | } 9 | 10 | @font-face { 11 | font-family: 'CerebriSans-Medium'; 12 | src: url('/fonts/CerebriSans-Medium.woff2') format('woff2'), 13 | url('/fonts/CerebriSans-Medium.woff') format('woff'); 14 | font-weight: normal; 15 | font-style: normal; 16 | 17 | } 18 | 19 | @font-face { 20 | font-family: 'CerebriSans-Regular'; 21 | src: url('/fonts/CerebriSans-Regular.woff2') format('woff2'), 22 | url('/fonts/CerebriSans-Regular.woff') format('woff'); 23 | font-weight: normal; 24 | font-style: normal; 25 | 26 | } 27 | 28 | @font-face { 29 | font-family: 'CerebriSans-Light'; 30 | src: url('/fonts/CerebriSans-Light.woff2') format('woff2'), 31 | url('/fonts/CerebriSans-Light.woff') format('woff'); 32 | font-weight: normal; 33 | font-style: normal; 34 | 35 | } 36 | 37 | h1 { 38 | font-family: 'CerebriSans-Bold' 39 | } 40 | -------------------------------------------------------------------------------- /src/components/layout.css: -------------------------------------------------------------------------------- 1 | * { 2 | -webkit-font-smoothing: antialiased; 3 | -moz-osx-font-smoothing: grayscale; 4 | } 5 | 6 | html { 7 | box-sizing: border-box; 8 | } 9 | 10 | *, *:before, *:after { 11 | box-sizing: inherit; 12 | } 13 | 14 | @media (max-width: 767px) { 15 | html { 16 | background-color: #070b28; 17 | background-image: url("/images/logo-bg.svg"); 18 | background-size: cover; 19 | background-repeat: no-repeat; 20 | background-position: top center; 21 | } 22 | } 23 | 24 | @media (min-width: 768px) { 25 | .body-bg-left { 26 | width: 50vw; 27 | height: 100vh; 28 | background-color: #070b28; 29 | z-index: -1; 30 | position: fixed; 31 | top: 0; 32 | left: 0; 33 | bottom: 0; 34 | background-image: url("/images/logo-bg.svg"); 35 | background-size: cover; 36 | background-repeat: no-repeat; 37 | background-position: top center; 38 | } 39 | 40 | .body-bg-right { 41 | width: 50vw; 42 | height: 100vh; 43 | background-color: #F9FAFC; 44 | z-index: -1; 45 | position: fixed; 46 | top: 0; 47 | right: 0; 48 | bottom: 0; 49 | } 50 | } 51 | 52 | .Layout-footer, 53 | .Layout-header { 54 | text-align: center; 55 | } 56 | 57 | @media (max-width: 767px) { 58 | .Layout-header { 59 | padding-top: 48px; 60 | margin: auto; 61 | } 62 | 63 | .Layout-footer { 64 | padding-bottom: 48px; 65 | } 66 | 67 | .Layout-footer .Text-marketing, 68 | .Layout-header .Text-description { 69 | display: inline-block; 70 | padding-left: 24px; 71 | padding-right: 24px; 72 | } 73 | 74 | } 75 | 76 | @media (min-width: 768px) { 77 | .Layout-header { 78 | display: flex; 79 | align-items: center; 80 | padding-top: 84px; 81 | } 82 | 83 | .Layout-main { 84 | display: flex; 85 | justify-content: center; 86 | } 87 | 88 | .Layout-footer { 89 | display: flex; 90 | align-items: center; 91 | padding-bottom: 84px; 92 | } 93 | 94 | .Layout-left { 95 | flex: 1; 96 | padding-right: 48px; 97 | text-align: right; 98 | } 99 | 100 | .Layout-right { 101 | flex: 1; 102 | padding-left: 48px; 103 | text-align: left; 104 | } 105 | } 106 | 107 | .Layout-main { 108 | width: 100%; 109 | margin-top: 84px; 110 | margin-bottom: 84px; 111 | } 112 | 113 | .d-block { 114 | display: block; 115 | } 116 | 117 | .mb-1 { 118 | margin-bottom: 6px; 119 | } 120 | 121 | .mb-2 { 122 | margin-bottom: 12px; 123 | } 124 | 125 | .mb-4 { 126 | margin-bottom: 24px; 127 | } 128 | 129 | .ml-2 { 130 | margin-left: 12px; 131 | } 132 | 133 | .ml-4 { 134 | margin-left: 24px; 135 | } 136 | 137 | .mr-8 { 138 | margin-right: 48px; 139 | } 140 | -------------------------------------------------------------------------------- /src/components/text.css: -------------------------------------------------------------------------------- 1 | .Text-title { 2 | font-family: "CerebriSans-Regular"; 3 | font-size: 70px; 4 | font-weight: normal; 5 | font-style: normal; 6 | line-height: normal; 7 | letter-spacing: -1px; 8 | color: #ffffff; 9 | margin: 0; 10 | } 11 | 12 | @media (min-width: 768px) { 13 | .Text-title { 14 | font-size: 80px; 15 | } 16 | } 17 | 18 | .Text-subtitle { 19 | font-family: "CerebriSans-Regular"; 20 | font-size: 18px; 21 | font-weight: normal; 22 | font-style: normal; 23 | line-height: normal; 24 | letter-spacing: 2px; 25 | color: #5a45ff; 26 | text-transform: uppercase; 27 | } 28 | 29 | .Text-description { 30 | font-family: "CerebriSans-Light"; 31 | font-size: 28px; 32 | font-weight: 300; 33 | font-style: normal; 34 | font-stretch: normal; 35 | line-height: 1.43; 36 | letter-spacing: -0.6px; 37 | color: #73859d; 38 | } 39 | 40 | @media (min-width: 768px) { 41 | .Text-description { 42 | max-width: 330px; 43 | } 44 | } 45 | 46 | .Text-overline { 47 | font-family: "CerebriSans-Regular"; 48 | font-size: 14px; 49 | font-weight: normal; 50 | font-style: normal; 51 | font-stretch: normal; 52 | line-height: normal; 53 | letter-spacing: normal; 54 | color: #5d6493; 55 | margin-bottom: 6px; 56 | display: inline-block; 57 | } 58 | 59 | .Text-marketing { 60 | font-family: "CerebriSans-Light"; 61 | font-size: 22px; 62 | font-weight: 300; 63 | font-style: normal; 64 | font-stretch: normal; 65 | line-height: 1.45; 66 | letter-spacing: normal; 67 | color: #62738a; 68 | display: inline-block; 69 | max-width: 370px; 70 | } 71 | 72 | .Text-link { 73 | cursor: pointer; 74 | background: transparent; 75 | border: none; 76 | font-family: "CerebriSans-Medium"; 77 | font-size: 16px; 78 | font-weight: 500; 79 | font-style: normal; 80 | font-stretch: normal; 81 | line-height: normal; 82 | letter-spacing: normal; 83 | text-decoration: none; 84 | color: #5a45ff; 85 | } 86 | 87 | .Button-primary { 88 | padding: 17px 32px 17px 32px; 89 | background: #5a45ff; 90 | border: none; 91 | box-shadow: 0 2px 3px 0 rgba(16, 22, 64, 0.12); 92 | border-radius: 6px; 93 | cursor: pointer; 94 | } 95 | 96 | .Text-button { 97 | font-family: "CerebriSans-Medium"; 98 | font-size: 16px; 99 | font-weight: 500; 100 | font-style: normal; 101 | font-stretch: normal; 102 | line-height: normal; 103 | letter-spacing: 0.5px; 104 | color: #ffffff; 105 | } 106 | 107 | .Text-cta-title { 108 | font-family: "CerebriSans-Bold"; 109 | font-size: 18px; 110 | font-weight: normal; 111 | font-style: normal; 112 | font-stretch: normal; 113 | line-height: normal; 114 | letter-spacing: normal; 115 | color: #070b28; 116 | } 117 | 118 | .Text-cta-subtitle { 119 | font-family: "CerebriSans-Regular"; 120 | font-size: 16px; 121 | font-weight: normal; 122 | font-style: normal; 123 | font-stretch: normal; 124 | line-height: normal; 125 | letter-spacing: normal; 126 | color: #73859d; 127 | } 128 | -------------------------------------------------------------------------------- /src/data/config.json: -------------------------------------------------------------------------------- 1 | { 2 | "skinStyles": ["Skin"], 3 | "hairStyles": [ 4 | "Bald", 5 | "Hat", 6 | "Balding", 7 | "Bigcurls", 8 | "Bobbangs", 9 | "Bobcut", 10 | "Buncurls", 11 | "Buzzcut", 12 | "Hightopcurly", 13 | "Long", 14 | "Pigtails", 15 | "Shortcombover", 16 | "Beanie", 17 | "Bunundercut", 18 | "Extralong", 19 | "Fade", 20 | "Hat", 21 | "Mohawk", 22 | "Shortcomboverchops", 23 | "Sidebuzz", 24 | "Straightbun" 25 | ], 26 | "facialHairStyles": [ 27 | "BeardMustache", 28 | "Mustache", 29 | "None", 30 | "Goatee", 31 | "Shadow", 32 | "Soulpatch", 33 | "Walrus" 34 | ], 35 | "bodyStyles": [ 36 | "Oval", 37 | "Round", 38 | "Square", 39 | "Checkered" 40 | ], 41 | "eyeStyles": [ 42 | "Glasses", 43 | "Happy", 44 | "Open", 45 | "Sleepy", 46 | "Sunglasses", 47 | "Wink" 48 | ], 49 | "mouthStyles": [ 50 | "Bigsmile", 51 | "Frown", 52 | "Lips", 53 | "Pacifier", 54 | "Smile", 55 | "Smirk", 56 | "Surprise" 57 | ], 58 | "noseStyles": [ 59 | "Mediumround", 60 | "Smallround", 61 | "Wrinkles" 62 | ], 63 | "bgStyles": ["Background"], 64 | "skinColors": [ 65 | "FFCC22", 66 | "FBD2C7", 67 | "F2AD9B", 68 | "E58F7B", 69 | "E4A070", 70 | "B16A5B", 71 | "92594B", 72 | "623D36", 73 | "C9E6DC" 74 | ], 75 | "hairColors": [ 76 | "362C47", 77 | "675E97", 78 | "5AC4D4", 79 | "DEE1F5", 80 | "6C4545", 81 | "F29C65", 82 | "E16381", 83 | "E15C66" 84 | ], 85 | "facialHairColors": [ 86 | "362C47", 87 | "675E97", 88 | "5AC4D4", 89 | "DEE1F5", 90 | "6c4545", 91 | "F29C65", 92 | "E16381", 93 | "E15C66" 94 | ], 95 | "bodyColors": [ 96 | "456DFF", 97 | "5A45FF", 98 | "6DBB58", 99 | "F55D81", 100 | "7555CA", 101 | "E24553", 102 | "54D7C7", 103 | "F3B63A" 104 | ], 105 | "bgColors": [ 106 | "93A7FF", 107 | "A9E775", 108 | "FF7A9A", 109 | "B379F7", 110 | "FF6674", 111 | "89E6E4", 112 | "FFCC65", 113 | "F8FBFF" 114 | ], 115 | "disabledColors": [ 116 | "EEEFF5", 117 | "EEEFF5", 118 | "EEEFF5", 119 | "EEEFF5", 120 | "EEEFF5", 121 | "EEEFF5", 122 | "EEEFF5", 123 | "EEEFF5" 124 | ] 125 | } 126 | 127 | -------------------------------------------------------------------------------- /src/helpers/exportImage.js: -------------------------------------------------------------------------------- 1 | import html2canvas from "html2canvas"; 2 | 3 | export default async () => { 4 | const node = document.getElementsByClassName( 5 | "AvatarGenerator-pngContainer" 6 | )[0]; 7 | 8 | // There is an issue with html2cavas with off-screen renders due to scroll 9 | // position, or something similar. 10 | // - https://github.com/niklasvh/html2canvas/issues/2014 11 | // 12 | // If it is fixed, this simple workaround can be removed 13 | window.scroll(0, 0); 14 | // End workaround 15 | const canvas = await html2canvas(node); 16 | const dataUrl = canvas.toDataURL(); 17 | 18 | const link = document.createElement("a"); 19 | link.download = "avatar.png"; 20 | link.href = dataUrl; 21 | 22 | document.body.appendChild(link); 23 | link.click(); 24 | link.remove(); 25 | }; 26 | -------------------------------------------------------------------------------- /src/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/src/images/favicon.png -------------------------------------------------------------------------------- /src/pages/Index.res: -------------------------------------------------------------------------------- 1 | @module("gatsby") external useStaticQuery: string => 'a = "useStaticQuery" 2 | 3 | /* raw import used because no Reason support for Gatsby graphql queries */ 4 | %%raw(` import {graphql} from "gatsby" `) 5 | 6 | @module("../helpers/exportImage.js") 7 | external exportImageAsync: unit => unit = "default" 8 | 9 | let defaultStyles: Types.styles = { 10 | skin: "Skin", 11 | skinColor: "B16A5B", 12 | hair: "Balding", 13 | hairColor: "E16381", 14 | facialHair: "Mustache", 15 | facialHairColor: "6C4545", 16 | body: "Square", 17 | bodyColor: "5A45FF", 18 | eyes: "Glasses", 19 | mouth: "Pacifier", 20 | nose: "Smallround", 21 | bgColor: "FFCC65", 22 | head: "Head", 23 | } 24 | 25 | let randomizeStyles = (config: Types.config): Types.styles => { 26 | let getRandom = _list => { 27 | let len = Array.length(_list) 28 | _list[Js.Math.floor(Js.Math.random() *. float_of_int(len))] 29 | } 30 | 31 | { 32 | skin: "Skin", 33 | skinColor: getRandom(config.skinColors), 34 | hairColor: getRandom(config.hairColors), 35 | hair: getRandom(config.hairStyles), 36 | facialHair: getRandom(config.facialHairStyles), 37 | facialHairColor: getRandom(config.facialHairColors), 38 | body: getRandom(config.bodyStyles), 39 | bodyColor: getRandom(config.bodyColors), 40 | eyes: getRandom(config.eyeStyles), 41 | mouth: getRandom(config.mouthStyles), 42 | nose: getRandom(config.noseStyles), 43 | bgColor: getRandom(config.bgColors), 44 | head: "Head", 45 | } 46 | } 47 | 48 | @react.component 49 | let make = () => { 50 | let data: Types.queryResType = useStaticQuery( 51 | %raw(` 52 | graphql\` 53 | query ConfigQuery { 54 | allDataJson { 55 | edges { 56 | node { 57 | skinStyles 58 | skinColors 59 | hairStyles 60 | hairColors 61 | facialHairStyles 62 | facialHairColors 63 | bodyStyles 64 | bodyColors 65 | eyeStyles 66 | mouthStyles 67 | noseStyles 68 | bgStyles 69 | bgColors 70 | disabledColors 71 | } 72 | } 73 | } 74 | } 75 | \` 76 | `), 77 | ) 78 | 79 | let (styles, setStyles) = React.useState(_ => defaultStyles) 80 | let (showModal, setShowModal) = React.useState(_ => false) 81 | 82 | let onChange = (key: Types.key, value) => 83 | setStyles(styles => 84 | switch key { 85 | | #SkinStyle => {...styles, skin: value} 86 | | #SkinColor => {...styles, skinColor: value} 87 | | #HairStyle => {...styles, hair: value} 88 | | #HairColor => {...styles, hairColor: value} 89 | | #FacialHairStyle => {...styles, facialHair: value} 90 | | #FacialHairColor => {...styles, facialHairColor: value} 91 | | #BodyStyle => {...styles, body: value} 92 | | #BodyColor => {...styles, bodyColor: value} 93 | | #EyesStyle => {...styles, eyes: value} 94 | | #MouthStyle => {...styles, mouth: value} 95 | | #NoseStyle => {...styles, nose: value} 96 | | #BackgroundColor => {...styles, bgColor: value} 97 | } 98 | ) 99 | 100 | let randomize = () => { 101 | let config = data.allDataJson.edges[0].node 102 | setStyles(_ => randomizeStyles(config)) 103 | } 104 | 105 | let exportImage = () => { 106 | setShowModal(_ => true) 107 | exportImageAsync() 108 | } 109 | 110 | let config = data.allDataJson.edges[0].node 111 | 112 | 113 | setShowModal(_ => false)} 120 | onExport={_ => exportImage()} 121 | /> 122 | 123 | } 124 | -------------------------------------------------------------------------------- /src/pages/index.js: -------------------------------------------------------------------------------- 1 | import React from "react"; 2 | import { make as Index } from "./Index.bs"; 3 | 4 | export default function IndexPage() { 5 | return ; 6 | } 7 | -------------------------------------------------------------------------------- /src/pages/page_404.res: -------------------------------------------------------------------------------- 1 | @react.component 2 | let make = () => 3 | 4 |

{React.string("NOT FOUND")}

5 |

{React.string("You just hit a route that doesn't exist... the sadness.")}

6 |
7 | 8 | let default = make 9 | -------------------------------------------------------------------------------- /static/avatars/Background/blue.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/dark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/green.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/grey.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/pink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/purple.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/teal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/white.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Background/yellow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Body/checkered.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Body/oval.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Body/round.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Body/small.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Body/square.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Exports.js: -------------------------------------------------------------------------------- 1 | | "Mediumround" => getMediumround(fill, size)} 2 | | "Smallround" => getSmallround(fill, size)} 3 | | "Wrinkles" => getWrinkles(fill, size)} 4 | -------------------------------------------------------------------------------- /static/avatars/Eyes/glasses.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Eyes/happy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Eyes/open.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Eyes/sleepy.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Eyes/sunglasses.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Eyes/wink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-blonde.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-brunette.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-copper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-grey.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-pink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/beardmustache-teal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-blonde.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-brunette.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-copper.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-grey.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-pink.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-red.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/FacialHair/mustache-teal.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/bald.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/balding.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/bigcurls.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/bobbangs.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/bobcut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/buncurls-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/buzzcut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/curlybun.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/curlyhightop.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/extralong.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/hightopcurly-black.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/long.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/pigtails.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Hair/shortcombover.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/bigsmile.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/frown.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/lips.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/pacifier.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/smile.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/smirk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Mouth/surprise.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewBody/checkered.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewFacialHair/goatee.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewFacialHair/shadow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewFacialHair/soulpatch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewFacialHair/walrus.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/bald.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/balding.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/beanie.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/bunundercut.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/buzz.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/extralong.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/fade.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/hat.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/mohawk.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/shortcomboverchops.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/sidebuzz.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/NewHair/straightbun.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Nose/mediumround.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Nose/smallround.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Nose/wrinkles.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/Skin.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin1.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin2.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin3.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin4.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin5.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/Skin/head-skin6.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/SvgLoader.js: -------------------------------------------------------------------------------- 1 | let getMediumround = (fill, size) => { 2 | ;j | 3 | ( 4 | 5 | 6 | 10 | 15 | 16 | 17 | ) | 18 | j 19 | } 20 | let getSmallround = (fill, size) => { 21 | ;j | 22 | ( 23 | 24 | 25 | 29 | 34 | 35 | 36 | ) | 37 | j 38 | } 39 | let getWrinkles = (fill, size) => { 40 | ;j | 41 | ( 42 | 43 | 44 | 48 | 53 | 58 | 59 | 60 | ) | 61 | j 62 | } 63 | -------------------------------------------------------------------------------- /static/avatars/array.js: -------------------------------------------------------------------------------- 1 | "Mediumround", 2 | "Smallround", 3 | "Wrinkles", 4 | "Mediumround", 5 | "Smallround", 6 | "Wrinkles", 7 | -------------------------------------------------------------------------------- /static/avatars/beardmustache.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/avatars/files.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /static/avatars/parse.js: -------------------------------------------------------------------------------- 1 | const fs = require('fs') 2 | const { promisify } = require('util') 3 | 4 | const readdirAsync = promisify(fs.readdir) 5 | const readFileAsync = promisify(fs.readFile) 6 | 7 | const templ = (name, code) => ` 8 | import * as React from "react"; 9 | 10 | const Svg${name} = () => ( 11 | ${code} 12 | ) 13 | 14 | export default Svg${name} 15 | ` 16 | 17 | function capitalize(string) { 18 | return string.charAt(0).toUpperCase() + string.slice(1) 19 | } 20 | 21 | const ITEMS = {} 22 | 23 | async function readDir() { 24 | const folders = await readdirAsync('.') 25 | 26 | for (const f of folders) { 27 | if (f.indexOf('DS_Store') === -1) { 28 | try { 29 | const svgs = await readdirAsync(f) 30 | if (Array.isArray(svgs)) { 31 | const svgsToParse = svgs. 32 | for (const svg of svgs) { 33 | const path = `${process.cwd()}/${f}/${svg}` 34 | const res = await readFileAsync(path, 'utf8') 35 | const name = capitalize(svg.split('.')[0].split('-')[0]) 36 | const code = templ(name, res) 37 | 38 | console.log('name', name) 39 | console.log('code', code) 40 | } 41 | } 42 | } catch (e) { 43 | console.log('err', e) 44 | } 45 | } 46 | } 47 | 48 | return ITEMS 49 | } 50 | 51 | readDir() 52 | .then(console.log) 53 | // .then(items => fs.writeFileSync('files.json', JSON.stringify(items, null, 2))) 54 | .catch(console.error) 55 | -------------------------------------------------------------------------------- /static/avatars/svg.js: -------------------------------------------------------------------------------- 1 | const SVGO = require('svgo') 2 | const fs = require('fs') 3 | const { promisify } = require('util') 4 | 5 | const readdirAsync = promisify(fs.readdir) 6 | const readFileAsync = promisify(fs.readFile) 7 | const appendFileAsync = promisify(fs.appendFile) 8 | 9 | const svgo = new SVGO({ 10 | plugins: [ 11 | { 12 | cleanupAttrs: true, 13 | }, 14 | { 15 | removeDoctype: true, 16 | }, 17 | { 18 | removeXMLProcInst: true, 19 | }, 20 | { 21 | removeComments: true, 22 | }, 23 | { 24 | removeMetadata: true, 25 | }, 26 | { 27 | removeTitle: true, 28 | }, 29 | { 30 | removeDesc: true, 31 | }, 32 | { 33 | removeUselessDefs: true, 34 | }, 35 | { 36 | removeEditorsNSData: true, 37 | }, 38 | { 39 | removeEmptyAttrs: true, 40 | }, 41 | { 42 | removeHiddenElems: true, 43 | }, 44 | { 45 | removeEmptyText: true, 46 | }, 47 | { 48 | removeEmptyContainers: true, 49 | }, 50 | { 51 | removeViewBox: false, 52 | }, 53 | { 54 | cleanupEnableBackground: true, 55 | }, 56 | { 57 | convertStyleToAttrs: true, 58 | }, 59 | { 60 | convertColors: true, 61 | }, 62 | { 63 | convertPathData: true, 64 | }, 65 | { 66 | convertTransform: true, 67 | }, 68 | { 69 | removeUnknownsAndDefaults: true, 70 | }, 71 | { 72 | removeNonInheritableGroupAttrs: true, 73 | }, 74 | { 75 | removeUselessStrokeAndFill: true, 76 | }, 77 | { 78 | removeUnusedNS: true, 79 | }, 80 | { 81 | cleanupIDs: true, 82 | }, 83 | { 84 | cleanupNumericValues: true, 85 | }, 86 | { 87 | moveElemsAttrsToGroup: true, 88 | }, 89 | { 90 | moveGroupAttrsToElems: true, 91 | }, 92 | { 93 | collapseGroups: true, 94 | }, 95 | { 96 | removeRasterImages: false, 97 | }, 98 | { 99 | mergePaths: true, 100 | }, 101 | { 102 | convertShapeToPath: true, 103 | }, 104 | { 105 | sortAttrs: true, 106 | }, 107 | { 108 | removeDimensions: true, 109 | }, 110 | { 111 | removeAttrs: { attrs: '(xmlns|link)' }, 112 | }, 113 | { removeXMLNS: true }, 114 | { 115 | removePrefixedAttributes: { 116 | type: 'perItem', 117 | fn: (item) => { 118 | item.eachAttr((attr) => { 119 | if (attr.prefix && attr.local) { 120 | item.removeAttr(attr.name) 121 | } 122 | }) 123 | }, 124 | }, 125 | }, 126 | ], 127 | }) 128 | 129 | const createCode = (name, code) => 130 | `let get${name} = (fill, size) => {j|${code}|j};\n` 131 | const createExport = (name) => `| "${name}" => get${name}(fill, size)}\n` 132 | 133 | function capitalize(string) { 134 | return string.charAt(0).toUpperCase() + string.slice(1) 135 | } 136 | 137 | async function runSvgo(path) { 138 | const folder = process.cwd() 139 | const file = await readFileAsync(path) 140 | const result = await svgo.optimize(file, { path }) 141 | const location = `${folder}/${path}` 142 | const fileName = capitalize(path.split('/')[1].split('.')[0]) 143 | await appendFileAsync( 144 | 'SvgLoader.js', 145 | createCode(fileName, result.data), 146 | 'utf-8' 147 | ) 148 | await appendFileAsync('Exports.js', createExport(fileName), 'utf-8') 149 | await appendFileAsync('array.js', `"${fileName}",\n`, 'utf-8') 150 | fs.writeFileSync(`${folder}/${path}`, result.data, 'utf-8') 151 | return path 152 | } 153 | 154 | const file = process.argv[2] 155 | runSvgo(file).then((file) => { 156 | console.log('done', file) 157 | process.exit(0) 158 | }) 159 | -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Bold.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Bold.woff -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Bold.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Bold.woff2 -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Light.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Light.woff -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Light.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Light.woff2 -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Medium.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Medium.woff -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Medium.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Medium.woff2 -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Regular.woff: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Regular.woff -------------------------------------------------------------------------------- /static/fonts/CerebriSans-Regular.woff2: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/fonts/CerebriSans-Regular.woff2 -------------------------------------------------------------------------------- /static/images/arrow.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/images/checkmark.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/images/close.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/images/facebook.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /static/images/github.svg: -------------------------------------------------------------------------------- 1 | GitHub icon -------------------------------------------------------------------------------- /static/images/logo-bg.svg: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /static/images/producthunt.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/images/randomize.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/images/sketch.svg: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /static/images/twitter.svg: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | -------------------------------------------------------------------------------- /static/web-preview-1x1.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/web-preview-1x1.png -------------------------------------------------------------------------------- /static/web-preview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/draftbit/avatar-generator/b2899e8a24da3db7e90b5c2df1df6b4296c0177c/static/web-preview.png --------------------------------------------------------------------------------