├── .gitignore ├── .idea ├── .gitignore ├── codeStyles │ └── codeStyleConfig.xml ├── graphite.iml ├── inspectionProfiles │ └── Project_Default.xml ├── misc.xml ├── modules.xml ├── php.xml └── vcs.xml ├── .prettierrc.js ├── LICENSE ├── README.md ├── package-lock.json ├── package.json ├── public ├── icon16.png ├── icon192.png ├── icon512.png ├── index.html ├── manifest.json └── robots.txt ├── src ├── App.tsx ├── Nav.tsx ├── components │ ├── Dropzone.tsx │ ├── Window.tsx │ ├── inputs │ │ └── ColorPicker.tsx │ └── toolbar │ │ ├── ScaleSelect.tsx │ │ ├── SelectionToolbar.tsx │ │ ├── Settings.tsx │ │ ├── ShadowSelector.tsx │ │ └── Toolbar.tsx ├── hooks.ts ├── icons │ ├── add.svg │ ├── cog.svg │ ├── cross.svg │ ├── direction.svg │ └── download.svg ├── index.css ├── index.js ├── react-app-env.d.ts ├── serviceWorker.js ├── store │ ├── index.ts │ ├── reducer.ts │ └── windows.ts └── utils │ └── image.ts └── tsconfig.json /.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 | # production 12 | /build 13 | 14 | # misc 15 | .DS_Store 16 | .env.local 17 | .env.development.local 18 | .env.test.local 19 | .env.production.local 20 | 21 | npm-debug.log* 22 | yarn-debug.log* 23 | yarn-error.log* 24 | -------------------------------------------------------------------------------- /.idea/.gitignore: -------------------------------------------------------------------------------- 1 | # Default ignored files 2 | /shelf/ 3 | /workspace.xml 4 | # Datasource local storage ignored files 5 | /dataSources/ 6 | /dataSources.local.xml 7 | # Editor-based HTTP Client requests 8 | /httpRequests/ 9 | -------------------------------------------------------------------------------- /.idea/codeStyles/codeStyleConfig.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 5 | -------------------------------------------------------------------------------- /.idea/graphite.iml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 15 | 16 | -------------------------------------------------------------------------------- /.idea/inspectionProfiles/Project_Default.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 6 | -------------------------------------------------------------------------------- /.idea/misc.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 9 | 10 | 11 | 12 | 13 | 15 | 16 | 17 | 18 | -------------------------------------------------------------------------------- /.idea/modules.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /.idea/php.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | -------------------------------------------------------------------------------- /.idea/vcs.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /.prettierrc.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | trailingComma: "es5", 3 | tabWidth: 4, 4 | semi: true, 5 | useTabs: true, 6 | bracketSpacing: false, 7 | jsxBracketSameLine: true, 8 | }; 9 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2020 Simone Masiero 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 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | ## Graphite Shot 2 | 3 | #### Motivation 4 | 5 | There are quite a few tools to create nice looking images from code. Some examples that inspired this tool are: 6 | - [Carbon](https://carbon.now.sh) 7 | - [Polacode](https://marketplace.visualstudio.com/items?itemName=pnp.polacode) 8 | - [Codeimg](https://codeimg.io/) 9 | 10 | But all of these require that you actually write the code in them. I wanted something where I could write my code in the editor and just add the fancy window to the screenshot. 11 | Graphite Shot lets you do just that. 12 | 13 | #### Features 14 | 15 | - Drop, Paste or use dialog to select your image. 16 | - Add windows horizontally and vertically 17 | - Automatically choose the window color based on the most common color of the image 18 | - Change window and background colors 19 | 20 | #### Dev 21 | 22 | React App with Typescript and Styled-Components. 23 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "graphite-shot", 3 | "version": "0.1.2", 4 | "license": "MIT", 5 | "devDependencies": { 6 | "@types/file-saver": "^2.0.3", 7 | "@types/node": "^16.10.2", 8 | "@types/react-color": "^3.0.5", 9 | "@types/react-redux": "^7.1.18", 10 | "@types/styled-components": "^5.1.14", 11 | "@types/uuid": "^8.3.1", 12 | "@types/webpack-env": "^1.16.2", 13 | "prettier": "^2.4.1", 14 | "react-scripts": "4.0.3", 15 | "typescript": "^4.4.3" 16 | }, 17 | "dependencies": { 18 | "@reduxjs/toolkit": "^1.6.1", 19 | "file-saver": "^2.0.5", 20 | "html-to-image": "^1.8.5", 21 | "jimp": "^0.16.1", 22 | "react": "^17.0.2", 23 | "react-color": "^2.19.3", 24 | "react-dom": "^17.0.2", 25 | "react-dropzone": "^11.4.2", 26 | "react-is": "^17.0.2", 27 | "react-redux": "^7.2.5", 28 | "react-shadow-picker": "^1.0.6", 29 | "react-tippy": "^1.4.0", 30 | "redux": "^4.1.1", 31 | "styled-components": "^5.3.1", 32 | "uuid": "^8.3.2" 33 | }, 34 | "scripts": { 35 | "start": "react-scripts start", 36 | "build": "react-scripts build", 37 | "test": "react-scripts test", 38 | "eject": "react-scripts eject", 39 | "checkfmt": "prettier -l \"**/*.{js,json,jsx,ts,tsx}\"", 40 | "fmt": "prettier --write \"**/*.{js,json,jsx,ts,tsx}\"" 41 | }, 42 | "eslintConfig": { 43 | "extends": "react-app" 44 | }, 45 | "browserslist": { 46 | "production": [ 47 | ">0.2%", 48 | "not dead", 49 | "not op_mini all" 50 | ], 51 | "development": [ 52 | "last 1 chrome version", 53 | "last 1 firefox version", 54 | "last 1 safari version" 55 | ] 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /public/icon16.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duiker101/graphite-shot/3357ab3cd5070864a42c1130d9a8f28a275b317f/public/icon16.png -------------------------------------------------------------------------------- /public/icon192.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duiker101/graphite-shot/3357ab3cd5070864a42c1130d9a8f28a275b317f/public/icon192.png -------------------------------------------------------------------------------- /public/icon512.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/duiker101/graphite-shot/3357ab3cd5070864a42c1130d9a8f28a275b317f/public/icon512.png -------------------------------------------------------------------------------- /public/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 7 | 8 | 12 | 13 | 17 | 18 | 27 | Graphite 28 | 29 | 30 | 31 |
32 | 42 | 43 | 45 | 46 | 47 | 48 | -------------------------------------------------------------------------------- /public/manifest.json: -------------------------------------------------------------------------------- 1 | { 2 | "short_name": "Graphite", 3 | "name": "Graphite allows you create nice images from your screenshots", 4 | "icons": [ 5 | { 6 | "src": "icon16.png", 7 | "sizes": "64x64 32x32 24x24 16x16", 8 | "type": "image/x-icon" 9 | }, 10 | { 11 | "src": "icon192.png", 12 | "type": "image/png", 13 | "sizes": "192x192" 14 | }, 15 | { 16 | "src": "icon512.png", 17 | "type": "image/png", 18 | "sizes": "512x512" 19 | } 20 | ], 21 | "start_url": ".", 22 | "display": "standalone", 23 | "theme_color": "#000000", 24 | "background_color": "#ffffff" 25 | } 26 | -------------------------------------------------------------------------------- /public/robots.txt: -------------------------------------------------------------------------------- 1 | # https://www.robotstxt.org/robotstxt.html 2 | User-agent: * 3 | Disallow: 4 | -------------------------------------------------------------------------------- /src/App.tsx: -------------------------------------------------------------------------------- 1 | import React, {useRef, useState} from "react"; 2 | import styled from "styled-components"; 3 | import Toolbar from "./components/toolbar/Toolbar"; 4 | import Window from "./components/Window"; 5 | import {useWindows} from "./store/windows"; 6 | import Nav from "./Nav"; 7 | 8 | const Wrapper = styled.div` 9 | display: flex; 10 | flex-direction: column; 11 | min-height: 100vh; 12 | height: 100vh; 13 | `; 14 | 15 | const Main = styled.div` 16 | flex: 1; 17 | min-width: 200px; 18 | display: flex; 19 | flex-direction: column; 20 | align-items: center; 21 | justify-content: center; 22 | min-width: min-content; 23 | `; 24 | 25 | /** 26 | * This border element is needed so that it will not be saved in the image 27 | * and the result will not have rounded corners 28 | */ 29 | const Border = styled.div` 30 | border: 2px solid white; 31 | border-radius: 4px; 32 | `; 33 | 34 | const Content = styled.div<{bg: string; horizontal: boolean}>` 35 | margin: auto; 36 | padding: 10px; 37 | background: ${p => p.bg}; 38 | padding: 64px; 39 | display: grid; 40 | grid-auto-flow: ${({horizontal}) => (horizontal ? "column" : "row")}; 41 | grid-gap: 64px; 42 | align-items: center; 43 | justify-items: center; 44 | `; 45 | 46 | export default () => { 47 | const [bgColor, setBgColor] = useState("cadetblue"); 48 | const contentRef = useRef(null); 49 | const windows = useWindows(); 50 | const [horizontal, setIsHorizontal] = useState(true); 51 | 52 | return ( 53 | 54 |
55 |
56 | setIsHorizontal(d)} 58 | horizontal={horizontal} 59 | bgColor={bgColor} 60 | onBgColor={setBgColor} 61 | content={contentRef.current} 62 | /> 63 | 64 | 65 | 69 | {Object.entries(windows).map(([id, w]) => ( 70 | 71 | ))} 72 | 73 | 74 |
75 |
76 |