├── .nvmrc ├── .prettierrc ├── static ├── images │ ├── logo.png │ ├── favicon.ico │ └── favicon.png └── _redirects ├── src ├── pages │ ├── 404.tsx │ └── index.tsx └── components │ ├── forms │ ├── FormHEX.tsx │ ├── Input.tsx │ └── FormRGB.tsx │ ├── Codeblock.tsx │ ├── GitHubRibbon.tsx │ ├── Footer.tsx │ ├── Seo.tsx │ ├── Layout.tsx │ ├── ColorPicker.tsx │ └── Logo.tsx ├── tsconfig.json ├── README.md ├── LICENSE.md ├── .gitignore ├── gatsby-config.js └── package.json /.nvmrc: -------------------------------------------------------------------------------- 1 | 10.17.0 2 | -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | trailingComma: "es5" 2 | tabWidth: 2 3 | semi: true 4 | singleQuote: true 5 | -------------------------------------------------------------------------------- /static/images/logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manosim/ui-color/HEAD/static/images/logo.png -------------------------------------------------------------------------------- /static/images/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manosim/ui-color/HEAD/static/images/favicon.ico -------------------------------------------------------------------------------- /static/images/favicon.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/manosim/ui-color/HEAD/static/images/favicon.png -------------------------------------------------------------------------------- /static/_redirects: -------------------------------------------------------------------------------- 1 | https://www.uicolor.xyz/* https://www.uicolor.io/:splat 301! 2 | https://uicolor.xyz/* https://www.uicolor.io/:splat 301! 3 | -------------------------------------------------------------------------------- /src/pages/404.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | 3 | import { Layout } from '../components/Layout'; 4 | import { SEO } from '../components/Seo'; 5 | 6 | const NotFoundPage = () => ( 7 | 8 | 9 |

NOT FOUND

10 |

You just hit a route that doesn't exist... the sadness.

11 |
12 | ); 13 | 14 | export default NotFoundPage; 15 | -------------------------------------------------------------------------------- /tsconfig.json: -------------------------------------------------------------------------------- 1 | { 2 | "include": ["./src/**/*"], 3 | "compilerOptions": { 4 | "target": "esnext", 5 | "module": "commonjs", 6 | "lib": ["dom", "es2017"], 7 | // "allowJs": true, 8 | // "checkJs": true, 9 | "jsx": "react", 10 | "strict": true, 11 | "esModuleInterop": true, 12 | "experimentalDecorators": true, 13 | "emitDecoratorMetadata": true, 14 | "noEmit": true, 15 | "skipLibCheck": true 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # UIColor.io [![Build Status](https://travis-ci.org/manosim/ui-color.svg?branch=master)](https://travis-ci.org/manosim/ui-color) 2 | 3 | ## Getting Started 4 | 5 | First, run the development server: 6 | 7 | ```bash 8 | yarn start 9 | ``` 10 | 11 | Open [http://localhost:8000](http://localhost:8000) with your browser to see the result. 12 | 13 | You can start editing the page by modifying `src/pages/index.js`. The page auto-updates as you edit the file. 14 | 15 | ## Learning Gatsby 16 | 17 | Looking for more guidance? Full documentation for Gatsby lives [on the website](https://www.gatsbyjs.org/). Here are some places to start: 18 | 19 | - **For most developers, we recommend starting with our [in-depth tutorial for creating a site with Gatsby](https://www.gatsbyjs.org/tutorial/).** It starts with zero assumptions about your level of ability and walks through every step of the process. 20 | 21 | - **To dive straight into code samples, head [to our documentation](https://www.gatsbyjs.org/docs/).** In particular, check out the _Guides_, _API Reference_, and _Advanced Tutorials_ sections in the sidebar. 22 | -------------------------------------------------------------------------------- /src/components/forms/FormHEX.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components'; 3 | import Color from 'color'; 4 | 5 | import { Input } from './Input'; 6 | import { ColorPicker } from '../ColorPicker'; 7 | 8 | const Container = styled.div` 9 | display: flex; 10 | flex: 1; 11 | flex-direction: row; 12 | 13 | div:first-of-type { 14 | margin-top: 0; 15 | } 16 | `; 17 | 18 | export interface IProps { 19 | value?: Color; 20 | onColorChange: any; 21 | } 22 | 23 | export const FormHEX: React.FC = props => { 24 | const [inputValue, setInputValue] = React.useState(''); 25 | 26 | const parseColor = value => { 27 | setInputValue(value); 28 | try { 29 | const parsed = Color(value); 30 | return props.onColorChange(parsed); 31 | } catch (_) {} 32 | }; 33 | 34 | return ( 35 | 36 | 43 | 44 | parseColor(color.hex())} /> 45 | 46 | ); 47 | }; 48 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License 2 | ======================= 3 | 4 | Copyright (c) 2020 Emmanouil Konstantinidis. https://www.manos.im/ 5 | 6 | Permission is hereby granted, free of charge, to any person obtaining a copy 7 | of this software and associated documentation files (the "Software"), to deal 8 | in the Software without restriction, including without limitation the rights 9 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | copies of the Software, and to permit persons to whom the Software is 11 | furnished to do so, subject to the following conditions: 12 | 13 | The above copyright notice and this permission notice shall be included in 14 | all copies or substantial portions of the Software. 15 | 16 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | THE SOFTWARE. 23 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Logs 2 | logs 3 | *.log 4 | npm-debug.log* 5 | yarn-debug.log* 6 | yarn-error.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | *.pid.lock 13 | 14 | # Directory for instrumented libs generated by jscoverage/JSCover 15 | lib-cov 16 | 17 | # Coverage directory used by tools like istanbul 18 | coverage 19 | 20 | # nyc test coverage 21 | .nyc_output 22 | 23 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 24 | .grunt 25 | 26 | # Bower dependency directory (https://bower.io/) 27 | bower_components 28 | 29 | # node-waf configuration 30 | .lock-wscript 31 | 32 | # Compiled binary addons (http://nodejs.org/api/addons.html) 33 | build/Release 34 | 35 | # Dependency directories 36 | node_modules/ 37 | jspm_packages/ 38 | 39 | # Typescript v1 declaration files 40 | typings/ 41 | 42 | # Optional npm cache directory 43 | .npm 44 | 45 | # Optional eslint cache 46 | .eslintcache 47 | 48 | # Optional REPL history 49 | .node_repl_history 50 | 51 | # Output of 'npm pack' 52 | *.tgz 53 | 54 | # dotenv environment variable files 55 | .env* 56 | 57 | # gatsby files 58 | .cache/ 59 | public 60 | 61 | # Mac files 62 | .DS_Store 63 | 64 | # Yarn 65 | yarn-error.log 66 | .pnp/ 67 | .pnp.js 68 | # Yarn Integrity file 69 | .yarn-integrity 70 | -------------------------------------------------------------------------------- /src/components/Codeblock.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Color from 'color'; 3 | import copy from 'copy-to-clipboard'; 4 | import styled from 'styled-components'; 5 | import { Box, Button, Flex, Heading, Text } from 'rebass/styled-components'; 6 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 7 | import { faCopy } from '@fortawesome/free-solid-svg-icons'; 8 | 9 | const Container = styled(Box)` 10 | position: relative; 11 | border-radius: 5px; 12 | padding: 0.75rem 1.5rem; 13 | `; 14 | 15 | const Code = styled.div` 16 | padding: 0.75rem 0 0.25rem; 17 | font-family: ${props => props.theme.fonts.monospace}; 18 | font-size: 15px; 19 | font-weight: bold; 20 | `; 21 | 22 | const Icon = styled(FontAwesomeIcon)` 23 | width: 0.75rem; 24 | height: 0.75rem; 25 | `; 26 | 27 | const CopyButton = styled(Button)` 28 | position: absolute; 29 | padding: 0.5rem 0.75rem; 30 | top: 0; 31 | right: 0; 32 | border: 0; 33 | border-radius: 0 5px 0; 34 | `; 35 | 36 | export interface IProps { 37 | colorString: string; 38 | language: string; 39 | } 40 | 41 | export const Codeblock: React.FC = ({ colorString, language }) => { 42 | const onCopy = () => copy(colorString); 43 | 44 | return ( 45 | 46 | {language} 47 | {colorString} 48 | 49 | 50 | 51 | 52 | 53 | ); 54 | }; 55 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: `UIColor.io`, 4 | description: `UIColor.io is a website that helps you convert HEX & RGB colors to UIColor for Objective-C, Swift and Xamarin featuring a colorpicker and copy to clipboard functionality to make things easier.`, 5 | author: `@manosim_`, 6 | keywords: `uicolor,ui,color,colour,convert,converter,hex,rgb,rgba,swift,objective-c,objective,c,apple,ios`, 7 | }, 8 | plugins: [ 9 | `gatsby-plugin-typescript`, 10 | `gatsby-plugin-styled-components`, 11 | `gatsby-plugin-react-helmet`, 12 | { 13 | resolve: `gatsby-plugin-manifest`, 14 | options: { 15 | name: `UIColor.io`, 16 | short_name: `starter`, 17 | start_url: `/`, 18 | background_color: `#4A5899`, 19 | theme_color: `#4A5899`, 20 | display: `minimal-ui`, 21 | icon: `static/images/favicon.png`, 22 | }, 23 | }, 24 | // this (optional) plugin enables Progressive Web App + Offline functionality 25 | // To learn more, visit: https://gatsby.dev/offline 26 | // `gatsby-plugin-offline`, 27 | { 28 | resolve: 'gatsby-plugin-web-font-loader', 29 | options: { 30 | google: { 31 | families: ['Sen'], 32 | }, 33 | }, 34 | }, 35 | { 36 | resolve: `gatsby-plugin-google-analytics`, 37 | options: { 38 | // The property ID; the tracking code won't be generated without it 39 | trackingId: 'UA-6891078-41', 40 | // Defines where to place the tracking script - `true` in the head and `false` in the body 41 | head: false, 42 | }, 43 | }, 44 | ], 45 | }; 46 | -------------------------------------------------------------------------------- /src/components/forms/Input.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | const Container = styled.div` 5 | display: flex; 6 | flex-direction: column; 7 | flex: 1; 8 | margin: 0 0.5rem; 9 | `; 10 | 11 | const InputField = styled.input` 12 | flex: 1; 13 | width: 100%; 14 | font-size: 20px; 15 | font-weight: 600; 16 | border: 0px; 17 | outline: none; 18 | box-shadow: inset 0 0 0 1px #ddd; 19 | border-radius: 4px; 20 | padding: 0.75rem; 21 | 22 | ::placeholder { 23 | color: #777; 24 | font-size: 14px; 25 | font-weight: normal; 26 | } 27 | `; 28 | 29 | const Label = styled.div` 30 | font-size: 1.25rem; 31 | font-weight: 600; 32 | line-height: 1.75rem; 33 | margin: 0.75rem 1rem 0.25rem 0; 34 | `; 35 | 36 | interface IProps { 37 | type?: string; 38 | min?: string; 39 | max?: string; 40 | step?: string; 41 | maxLength?: string; 42 | value?: string; 43 | label: string; 44 | placeholder: string; 45 | onChange: (value: string) => void; 46 | } 47 | 48 | export const Input: React.FC = props => { 49 | return ( 50 | 51 | 52 | props.onChange(value)} 60 | placeholder={props.placeholder} 61 | spellCheck="false" 62 | /> 63 | 64 | ); 65 | }; 66 | 67 | Input.defaultProps = { 68 | type: 'text', 69 | }; 70 | -------------------------------------------------------------------------------- /src/components/GitHubRibbon.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components'; 3 | 4 | import { DEFAULT_COLOR } from './Layout'; 5 | 6 | const Svg = styled.svg` 7 | fill: ${props => (props.color ? 'rgba(0, 0, 0, 0.5)' : DEFAULT_COLOR)}; 8 | color: ${props => (props.color ? props.color : 'white')}; 9 | position: absolute; 10 | top: 0; 11 | border: 0; 12 | right: 0; 13 | `; 14 | 15 | export interface IProps { 16 | color: string; 17 | } 18 | 19 | export const GitHubRibbon: React.FC = ({ color }) => { 20 | return ( 21 | 27 | 28 | 29 | 30 | 34 | 35 | 39 | 40 | 41 | ); 42 | }; 43 | -------------------------------------------------------------------------------- /src/components/Footer.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components'; 3 | import { Box, Flex, Link } from 'rebass/styled-components'; 4 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 5 | import { faGithub, faTwitter } from '@fortawesome/free-brands-svg-icons'; 6 | 7 | const FooterWrapper = styled.div` 8 | display: flex; 9 | padding: 2rem; 10 | font-size: 0.8rem; 11 | 12 | text-align: center; 13 | 14 | margin-top: 3rem; 15 | padding: 1rem 3rem; 16 | `; 17 | 18 | const Icon = styled(FontAwesomeIcon)` 19 | width: 1.25rem; 20 | height: 1.25rem; 21 | margin: 0.5rem 0.25rem; 22 | `; 23 | 24 | export interface IProps {} 25 | 26 | export const Footer: React.FC = props => { 27 | return ( 28 | 36 | 44 | 45 | 51 | 52 | 53 | 54 | 59 | 60 | 61 | 62 | 63 | 64 | Copyright ©{' '} 65 | 66 | UIColor.io 67 | {' '} 68 | {new Date().getFullYear()}.
69 | Developed by{' '} 70 | 71 | Emmanouil Konstantinidis 72 | 73 | . 74 |
75 |
76 |
77 | ); 78 | }; 79 | -------------------------------------------------------------------------------- /src/components/Seo.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import Helmet from 'react-helmet'; 4 | import { useStaticQuery, graphql } from 'gatsby'; 5 | 6 | export const SEO = ({ description, lang, meta, title }: any) => { 7 | const { site } = useStaticQuery( 8 | graphql` 9 | query { 10 | site { 11 | siteMetadata { 12 | title 13 | description 14 | author 15 | keywords 16 | } 17 | } 18 | } 19 | ` 20 | ); 21 | 22 | const metaDescription = description || site.siteMetadata.description; 23 | 24 | return ( 25 | 70 | ); 71 | }; 72 | 73 | SEO.defaultProps = { 74 | lang: `en`, 75 | meta: [], 76 | description: ``, 77 | }; 78 | 79 | SEO.propTypes = { 80 | description: PropTypes.string, 81 | lang: PropTypes.string, 82 | meta: PropTypes.arrayOf(PropTypes.object), 83 | title: PropTypes.string.isRequired, 84 | }; 85 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "ui-color", 3 | "version": "0.0.1", 4 | "description": "Convert HEX & RGB colors to UIColor for both Objective-C and Swift.", 5 | "private": true, 6 | "scripts": { 7 | "build": "gatsby build", 8 | "develop": "gatsby develop", 9 | "format": "prettier --write \"**/*.{js,jsx,json,md}\"", 10 | "start": "npm run develop", 11 | "serve": "gatsby serve", 12 | "clean": "gatsby clean", 13 | "test": "echo \"Write tests! -> https://gatsby.dev/unit-testing\" && exit 1" 14 | }, 15 | "repository": { 16 | "type": "git", 17 | "url": "https://github.com/manosim/ui-color.git" 18 | }, 19 | "keywords": [ 20 | "uicolor", 21 | "converter", 22 | "swift", 23 | "objective-c" 24 | ], 25 | "author": "Emmanouil Konstantinidis", 26 | "license": "MIT", 27 | "bugs": { 28 | "url": "https://github.com/manosim/ui-color/issues" 29 | }, 30 | "homepage": "http://www.uicolor.io/", 31 | "dependencies": { 32 | "@fortawesome/fontawesome-svg-core": "^1.2.27", 33 | "@fortawesome/free-brands-svg-icons": "^5.12.1", 34 | "@fortawesome/free-solid-svg-icons": "^5.12.1", 35 | "@fortawesome/react-fontawesome": "^0.1.9", 36 | "@rebass/forms": "^4.0.6", 37 | "@types/color": "^3.0.1", 38 | "color": "^3.1.2", 39 | "copy-to-clipboard": "^3.3.1", 40 | "gatsby": "^2.19.45", 41 | "gatsby-image": "^2.2.44", 42 | "gatsby-plugin-google-analytics": "^2.1.38", 43 | "gatsby-plugin-manifest": "^2.2.48", 44 | "gatsby-plugin-offline": "^3.0.41", 45 | "gatsby-plugin-react-helmet": "^3.1.24", 46 | "gatsby-plugin-styled-components": "^3.1.21", 47 | "gatsby-plugin-typescript": "^2.2.5", 48 | "gatsby-plugin-web-font-loader": "^1.0.4", 49 | "prop-types": "^15.7.2", 50 | "react": "^16.12.0", 51 | "react-color": "^2.18.0", 52 | "react-dom": "^16.12.0", 53 | "react-helmet": "^5.2.1", 54 | "react-toggle-component": "^3.0.8", 55 | "rebass": "^4.0.7", 56 | "styled-components": "^5.0.1" 57 | }, 58 | "devDependencies": { 59 | "@types/node": "^13.9.0", 60 | "@types/react": "^16.9.23", 61 | "@types/react-helmet": "^5.0.15", 62 | "@types/rebass": "^4.0.4", 63 | "@types/styled-components": "^5.0.1", 64 | "prettier": "^1.19.1", 65 | "typescript": "^3.8.3" 66 | } 67 | } 68 | -------------------------------------------------------------------------------- /src/components/Layout.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import PropTypes from 'prop-types'; 3 | import { useStaticQuery, graphql } from 'gatsby'; 4 | import { createGlobalStyle, ThemeProvider } from 'styled-components'; 5 | 6 | export const DEFAULT_COLOR = '#4A5899'; 7 | 8 | const GlobalStyle = createGlobalStyle` 9 | html, 10 | body { 11 | margin: 0; 12 | padding: 0; 13 | font-family: -apple-system, BlinkMacSystemFont, Segoe UI, Roboto, Helvetica Neue, Arial, Noto Sans, sans-serif, Apple Color Emoji, Segoe UI Emoji, Segoe UI Symbol, Noto Color Emoji; 14 | font-size: 1rem; 15 | font-weight: 400; 16 | line-height: 1.5; 17 | background-color: #fff; 18 | -webkit-font-smoothing: antialiased; 19 | } 20 | 21 | * { 22 | box-sizing: border-box; 23 | } 24 | `; 25 | 26 | const theme = { 27 | colors: { 28 | primary: DEFAULT_COLOR, 29 | grayLight: '#F5F7F5', 30 | }, 31 | fonts: { 32 | heading: "'Sen', sans-serif", 33 | monospace: "Menlo, Monaco, Consolas, 'Courier New', monospace", 34 | }, 35 | variants: { 36 | link: { 37 | backgroundColor: 'none', 38 | color: 'primary', 39 | textDecoration: 'none', 40 | }, 41 | }, 42 | buttons: { 43 | picker: { 44 | variant: 'buttons.primary', 45 | color: 'primary', 46 | bg: 'transparent', 47 | ':hover,:focus,:active': { 48 | cursor: 'pointer', 49 | outline: 'none', 50 | color: '#000', 51 | }, 52 | }, 53 | transparent: { 54 | variant: 'buttons.primary', 55 | color: 'primary', 56 | bg: 'transparent', 57 | ':hover,:focus': { 58 | cursor: 'pointer', 59 | outline: 'none', 60 | }, 61 | ':active': { 62 | backgroundColor: 'primary', 63 | color: 'white', 64 | }, 65 | }, 66 | }, 67 | }; 68 | 69 | export const Layout = ({ children }) => { 70 | const data = useStaticQuery(graphql` 71 | query SiteTitleQuery { 72 | site { 73 | siteMetadata { 74 | title 75 | } 76 | } 77 | } 78 | `); 79 | 80 | return ( 81 | 82 | 83 | {children} 84 | 85 | ); 86 | }; 87 | 88 | Layout.propTypes = { 89 | children: PropTypes.node.isRequired, 90 | }; 91 | -------------------------------------------------------------------------------- /src/components/ColorPicker.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Color from 'color'; 3 | import styled from 'styled-components'; 4 | import { Box, Button } from 'rebass/styled-components'; 5 | import { FontAwesomeIcon } from '@fortawesome/react-fontawesome'; 6 | import { faEyeDropper } from '@fortawesome/free-solid-svg-icons'; 7 | import { GithubPicker } from 'react-color'; 8 | 9 | import { CustomPicker } from 'react-color'; 10 | 11 | const PickerButton = styled(Button)` 12 | border: 0; 13 | outline: none; 14 | padding: 0.5rem; 15 | background: transparent; 16 | `; 17 | 18 | const Icon = styled(FontAwesomeIcon)` 19 | width: 1.25rem; 20 | height: 1.25rem; 21 | color: ${props => props.theme.colors.primary}; 22 | `; 23 | 24 | const Popover = styled.div` 25 | position: relative; 26 | z-index: 2; 27 | `; 28 | 29 | const Cover = styled.div` 30 | position: fixed; 31 | top: 0; 32 | right: 0; 33 | bottom: 0; 34 | left: 0; 35 | `; 36 | 37 | const PickerWrapper = styled.div` 38 | position: absolute; 39 | top: 5px; 40 | right: 0; 41 | `; 42 | 43 | export interface IProps { 44 | onSelectColor: (color: Color) => void; 45 | } 46 | 47 | export const Picker: React.FC = props => { 48 | const [showPicker, setShowPicker] = React.useState(false); 49 | 50 | const handleClick = () => { 51 | setShowPicker(!showPicker); 52 | }; 53 | 54 | const handleClose = () => { 55 | setShowPicker(false); 56 | }; 57 | 58 | return ( 59 | 64 | 65 | 66 | 67 | 68 | {showPicker ? ( 69 | 70 | 71 | 72 | 73 | { 77 | const color: Color = Color(hex); 78 | props.onSelectColor(color); 79 | }} 80 | /> 81 | 82 | 83 | ) : null} 84 | 85 | ); 86 | }; 87 | 88 | export const ColorPicker = CustomPicker(Picker); 89 | -------------------------------------------------------------------------------- /src/components/forms/FormRGB.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import styled from 'styled-components'; 3 | import Color from 'color'; 4 | import { Flex } from 'rebass/styled-components'; 5 | 6 | import { ColorPicker } from '../ColorPicker'; 7 | import { Input } from './Input'; 8 | 9 | const Container = styled(Flex)` 10 | div:first-of-type { 11 | margin-top: 0; 12 | } 13 | `; 14 | 15 | export interface IProps { 16 | value: any; 17 | onColorChange: any; 18 | } 19 | 20 | export const FormRGB: React.FC = props => { 21 | const [redValue, setRedValue] = React.useState(null); 22 | const [greenValue, setGreenValue] = React.useState(null); 23 | const [blueValue, setBlueValue] = React.useState(null); 24 | const [alphaValue, setAlphaValue] = React.useState(`1.00`); 25 | 26 | const parseColor = () => { 27 | try { 28 | if (!redValue || !greenValue || !blueValue || !alphaValue) { 29 | throw new Error('Incomplete RBG Color.'); 30 | } 31 | const newColor = { 32 | r: redValue, 33 | g: greenValue, 34 | b: blueValue, 35 | }; 36 | const alpha = parseFloat(alphaValue); 37 | const parsed = Color(newColor).alpha(alpha); 38 | return props.onColorChange(parsed); 39 | } catch (_) {} 40 | }; 41 | 42 | const parseAlphaValue = () => { 43 | try { 44 | if (!props.value) { 45 | throw new Error('No color to set Alpha.'); 46 | } 47 | const alpha = parseFloat(alphaValue); 48 | const parsed = props.value.alpha(alpha); 49 | return props.onColorChange(parsed); 50 | } catch (_) {} 51 | }; 52 | 53 | React.useEffect(parseColor, [redValue, greenValue, blueValue, alphaValue]); 54 | 55 | return ( 56 | 57 | setRedValue(inputValue)} 65 | /> 66 | 67 | { 75 | setGreenValue(`${inputValue}`); 76 | }} 77 | /> 78 | 79 | { 87 | setBlueValue(inputValue); 88 | }} 89 | /> 90 | 91 | { 100 | setAlphaValue(`${inputValue}`); 101 | }} 102 | /> 103 | 104 | { 106 | setRedValue(`${color.rgb().object().r}`); 107 | setGreenValue(`${color.rgb().object().g}`); 108 | setBlueValue(`${color.rgb().object().b}`); 109 | }} 110 | /> 111 | 112 | ); 113 | }; 114 | -------------------------------------------------------------------------------- /src/pages/index.tsx: -------------------------------------------------------------------------------- 1 | import * as React from 'react'; 2 | import Color from 'color'; 3 | import styled from 'styled-components'; 4 | import { Box, Flex, Heading, Text } from 'rebass/styled-components'; 5 | import { Toggle } from 'react-toggle-component'; 6 | 7 | import { Codeblock } from '../components/Codeblock'; 8 | import { DEFAULT_COLOR } from '../components/Layout'; 9 | import { Footer } from '../components/Footer'; 10 | import { FormHEX } from '../components/forms/FormHEX'; 11 | import { FormRGB } from '../components/forms/FormRGB'; 12 | import { GitHubRibbon } from '../components/GitHubRibbon'; 13 | import { Layout } from '../components/Layout'; 14 | import { Logo } from '../components/Logo'; 15 | import { SEO } from '../components/Seo'; 16 | 17 | const Container: any = styled.div` 18 | background-color: ${(props: any) => props.bgColor || '#FFF'}; 19 | transition: background-color 500ms ease; 20 | `; 21 | 22 | const Main = styled(Box)` 23 | padding: 3rem 1rem 1rem; 24 | flex: 1; 25 | display: flex; 26 | flex-direction: column; 27 | justify-content: center; 28 | align-items: center; 29 | `; 30 | 31 | const FormsWrapper = styled(Box)` 32 | display: flex; 33 | flex-direction: column; 34 | background-color: ${props => props.theme.colors.grayLight}; 35 | border-radius: 5px; 36 | padding: 1.25rem 0.75rem; 37 | margin: 1rem 0; 38 | `; 39 | 40 | const Home = () => { 41 | const [color, setColor] = React.useState(null); 42 | const [showHexForm, setShowHexForm] = React.useState(true); 43 | const hasDarkBg = color && color.isDark(); 44 | const textColor = hasDarkBg ? 'white' : 'inherit'; 45 | const Form = showHexForm ? FormHEX : FormRGB; 46 | 47 | const renderCodeBlocks = () => { 48 | if (!color) { 49 | return null; 50 | } 51 | const rgbColor = color.rgb().object(); 52 | const r = (rgbColor.r / 255).toFixed(2); 53 | const g = (rgbColor.g / 255).toFixed(2); 54 | const b = (rgbColor.b / 255).toFixed(2); 55 | const alpha = color.alpha().toFixed(2); 56 | 57 | return ( 58 | 59 | 63 | 67 | 71 | 72 | ); 73 | }; 74 | 75 | return ( 76 | 77 | 78 | 79 | 80 |
81 | 82 | 83 | 84 | 85 | 86 | Convert HEX & RGB colors to UIColor 87 | 88 | 89 | 90 | UIColor.io is a website that helps you convert HEX & RGB colors to 91 | UIColor for Objective-C, Swift and Xamarin featuring a colorpicker 92 | and copy to clipboard functionality to make things easier. 93 | 94 | 95 | 96 | 97 | HEX 98 | 99 | 100 | { 113 | setShowHexForm(!showHexForm); 114 | setColor(null); 115 | }} 116 | /> 117 | 118 | 119 | RGB 120 | 121 | 122 | 123 | 124 |
125 | 126 | 127 | {renderCodeBlocks()} 128 |
129 | 130 |