├── .gitignore ├── .prettierignore ├── .prettierrc ├── LICENSE ├── README.md ├── gatsby-config.js ├── package.json ├── src ├── components │ ├── CodeBlock.js │ ├── ControlsForm.js │ ├── Input │ │ ├── NumInputs.js │ │ └── num-input.css │ ├── Slider │ │ ├── SliderArrows.js │ │ ├── SliderCard.js │ │ ├── SliderOptions.json │ │ └── slick-slider.css │ ├── SocialIcons.js │ ├── button.js │ ├── card.js │ ├── footer.js │ └── header.js ├── constants.js ├── favicon.png ├── img │ └── Logo-Icon.png ├── layouts │ ├── index.css │ └── index.js └── pages │ ├── 404.js │ └── index.js └── yarn.lock /.gitignore: -------------------------------------------------------------------------------- 1 | # Project dependencies 2 | .cache 3 | node_modules 4 | yarn-error.log 5 | 6 | # Build directory 7 | /public 8 | .DS_Store 9 | -------------------------------------------------------------------------------- /.prettierignore: -------------------------------------------------------------------------------- 1 | src/components/CodeBlock.js -------------------------------------------------------------------------------- /.prettierrc: -------------------------------------------------------------------------------- 1 | { 2 | "semi": false, 3 | "singleQuote": true, 4 | "trailingComma": "es5" 5 | } 6 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2015 gatsbyjs 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 | # Card Surge 2 | UI Playground for designing beautiful Cards 3 | 4 | ![gif](https://ph-files.imgix.net/bdfeb893-7fbb-4c05-b696-cbbe5c5af8a6?auto=format&auto=compress&codec=mozjpeg&cs=strip) 5 | 6 | Check out the launch on [Product Hunt:](https://www.producthunt.com/posts/card-surge/)! 7 | 8 | ## Install 9 | 10 | Make sure that you have the Gatsby CLI program installed: 11 | ```sh 12 | npm install --global gatsby-cli 13 | ``` 14 | 15 | Then you can install dependencies with: 16 | ```sh 17 | npm install 18 | ``` 19 | 20 | And run: 21 | ```sh 22 | gatsby develop 23 | ``` 24 | 25 | ## Deploy 26 | 27 | [![Deploy to Netlify](https://www.netlify.com/img/deploy/button.svg)](https://app.netlify.com/start/deploy?repository=https://github.com/gillkyle/card-surge) 28 | -------------------------------------------------------------------------------- /gatsby-config.js: -------------------------------------------------------------------------------- 1 | module.exports = { 2 | siteMetadata: { 3 | title: 'Card Surge', 4 | }, 5 | plugins: [ 6 | 'gatsby-plugin-react-helmet', 7 | 'gatsby-plugin-offline', 8 | { 9 | resolve: `gatsby-plugin-manifest`, 10 | options: { 11 | name: 'Card Surge', 12 | short_name: 'Card Surge', 13 | start_url: '/', 14 | background_color: '#2BE1F2', 15 | theme_color: '#2BE1F2', 16 | display: 'standalone', 17 | icon: 'src/img/Logo-Icon.png', 18 | }, 19 | }, 20 | { 21 | resolve: `gatsby-plugin-favicon`, 22 | options: { 23 | logo: './src/favicon.png', 24 | injectHTML: true, 25 | icons: { 26 | android: true, 27 | appleIcon: true, 28 | appleStartup: true, 29 | coast: false, 30 | favicons: true, 31 | firefox: true, 32 | twitter: false, 33 | yandex: false, 34 | windows: false, 35 | }, 36 | }, 37 | }, 38 | ], 39 | } 40 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Card Surge", 3 | "description": "UI playground for beautiful cards", 4 | "version": "1.0.0", 5 | "author": "Kyle Gill ", 6 | "dependencies": { 7 | "gatsby": "^1.9.247", 8 | "gatsby-link": "^1.6.40", 9 | "gatsby-plugin-favicon": "^2.1.1", 10 | "gatsby-plugin-manifest": "^1.0.27", 11 | "gatsby-plugin-offline": "^1.0.18", 12 | "gatsby-plugin-react-helmet": "^2.0.10", 13 | "rc-input-number": "^4.0.8", 14 | "react-color": "^2.14.1", 15 | "react-copy-to-clipboard": "^5.0.1", 16 | "react-helmet": "^5.2.0", 17 | "react-icons": "^2.2.7", 18 | "react-slick": "^0.23.1", 19 | "slick-carousel": "^1.8.1", 20 | "styled-components": "^3.3.2" 21 | }, 22 | "keywords": [ 23 | "gatsby" 24 | ], 25 | "license": "MIT", 26 | "scripts": { 27 | "build": "gatsby build", 28 | "develop": "gatsby develop", 29 | "format": "prettier --write 'src/**/*.js'", 30 | "test": "echo \"Error: no test specified\" && exit 1" 31 | }, 32 | "devDependencies": { 33 | "prettier": "^1.12.0" 34 | }, 35 | "repository": { 36 | "type": "git", 37 | "url": "https://github.com/gatsbyjs/gatsby-starter-default" 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /src/components/CodeBlock.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | import {CopyToClipboard} from 'react-copy-to-clipboard'; 4 | 5 | import { COLORS, BORDER_RADIUS } from '../constants' 6 | 7 | import Card from '../components/card' 8 | 9 | const CodeAttr = styled.span` 10 | color: ${COLORS['gold']}; 11 | ` 12 | const CodeCard = styled(Card)` 13 | display: flex; 14 | flex-direction: row; 15 | border-bottom-left-radius: 0px; 16 | border-bottom-right-radius: 0px; 17 | box-shadow: 0px 0px #fff; 18 | width: 100%; 19 | ` 20 | const CodeColumn = styled.div` 21 | border-top-left-radius: ${BORDER_RADIUS}px; 22 | border-bottom-left-radius: 0px; 23 | color: ${COLORS['secondaryBlue']}; 24 | background-color: ${COLORS['secondaryBlueT']}; 25 | padding: 1rem 0.5rem 1rem 1.5rem; 26 | user-select: none; 27 | ` 28 | const CodeContent = styled.div` 29 | padding: 1rem 0.5rem; 30 | color: ${COLORS['gray']}; 31 | white-space: pre-line; 32 | ` 33 | const CodeCopyButton =styled(Card)` 34 | border-top-left-radius: 0px; 35 | border-top-right-radius: 0px; 36 | background-color: ${COLORS['secondaryBlue']}; 37 | color: ${COLORS['white']}; 38 | text-align: center; 39 | cursor: pointer; 40 | user-select: none; 41 | &:hover { 42 | background-color: #6aBfFa; 43 | } 44 | &:active { 45 | background-color: #c2e7ff; 46 | } 47 | ` 48 | 49 | const CodeBlock = class extends React.Component { 50 | constructor(props) { 51 | super(props); 52 | } 53 | 54 | render() { 55 | const { border, normal, hover, shadowColor, hoverStyles } = this.props; 56 | const customCodeBlock = `border-width: ${border.top ? border.width : 0}px ${border.right ? border.width : 0}px ${border.bottom ? border.width : 0}px ${border.left ? border.width : 0}px; border-color: rgba(${border.color.r}, ${border.color.g}, ${border.color.b}, ${border.color.a}); border-radius: ${border.radius}; border-style: solid; box-shadow: ${normal.x}px ${normal.y}px ${normal.blur}px ${normal.spread}px rgba(${shadowColor.r}, ${shadowColor.g}, ${shadowColor.b}, ${shadowColor.a}); /* hover styles */ border-style: solid; box-shadow: ${hover.x}px ${hover.y}px ${hover.blur}px ${hover.spread}px rgba(${shadowColor.r}, ${shadowColor.g}, ${shadowColor.b}, ${hover.opacity});` 57 | 58 | console.log(customCodeBlock) 59 | 60 | return ( 61 |
62 | 63 | 64 |
0
65 |
1
66 |
2
67 |
3
68 |
4
69 |
5
70 |
6
71 |
7
72 | {/*
8
73 |
9
74 |
10
*/} 75 |
76 | 77 | {`border-width: `}{`${border.top ? border.width : 0}px ${border.right ? border.width : 0}px ${border.bottom ? border.width : 0}px ${border.left ? border.width : 0}px;`} 78 | {`\nborder-color: `}{`rgba(${border.color.r}, ${border.color.g}, ${border.color.b}, ${border.color.a});`} 79 | {`\nborder-radius: `}{`${border.radius}px;`} 80 | {`\nborder-style: `}{`solid;`} 81 | {`\nbox-shadow: `}{`${normal.x}px ${normal.y}px ${normal.blur}px ${normal.spread}px rgba(${shadowColor.r}, ${shadowColor.g}, ${shadowColor.b}, ${shadowColor.a});`} 82 | {`\n/* hover styles */ `} 83 | {`\nborder-style: `}{`solid;`} 84 | {`\nbox-shadow: `}{`${hover.x}px ${hover.y}px ${hover.blur}px ${hover.spread}px rgba(${shadowColor.r}, ${shadowColor.g}, ${shadowColor.b}, ${hover.opacity});`} 85 | 86 |
87 | 88 | 89 | Copy Code to Clipboard 90 | 91 | 92 |
93 | ); 94 | } 95 | } 96 | 97 | export default CodeBlock 98 | -------------------------------------------------------------------------------- /src/components/ControlsForm.js: -------------------------------------------------------------------------------- 1 | import React from 'react' 2 | import styled from 'styled-components' 3 | import { CirclePicker, ChromePicker, SketchPicker } from 'react-color' 4 | import * as MD from 'react-icons/lib/md' 5 | 6 | import { COLORS, MEDIA_QUERIES, BORDER_RADIUS } from '../constants' 7 | 8 | import NumberInput from './Input/NumInputs' 9 | import Button from './button' 10 | 11 | const FormGrid = styled.div` 12 | display: grid; 13 | grid-template-columns: 1fr 1fr; 14 | grid-template-rows: 0px 1fr 1fr 10px 1fr 1fr 1fr; 15 | grid-gap: 1rem 2rem; 16 | align-items: center; 17 | margin: 2rem 2.5rem 2.5rem 2.5rem; 18 | color: ${COLORS['gray']}; 19 | @media (max-width: ${MEDIA_QUERIES['mobile']}px) { 20 | grid-template-columns: 1fr; 21 | grid-template-rows: 0px 1fr 1fr 1fr 1fr 10px 1fr 1fr 1fr; 22 | margin: 1rem 1.5rem 1.5rem 1.5rem; 23 | } 24 | ` 25 | const baseInputGrid = styled.div` 26 | display: grid; 27 | grid-template-columns: 1.5fr 1fr 1fr; 28 | grid-gap: 1rem; 29 | ` 30 | const InputGrid = styled(baseInputGrid)` 31 | align-items: center; 32 | ` 33 | const InputLabel = styled.div` 34 | letter-spacing: 2px; 35 | font-size: 0.8rem; 36 | ` 37 | const ColumnGrid = styled(InputGrid)` 38 | align-items: flex-end; 39 | justify-items: center; 40 | @media (max-width: ${MEDIA_QUERIES['mobile']}px) { 41 | display: ${props => (props.hide ? 'none' : 'inherit')}; 42 | } 43 | ` 44 | const ColumnHeader = styled.span` 45 | position: relative; 46 | font-size: 0.5rem; 47 | letter-spacing: 2px; 48 | color: ${COLORS['primaryBlue']}; 49 | top: 0.5rem; 50 | ` 51 | const QuadGrid = styled.div` 52 | display: grid; 53 | grid-column: span 2; 54 | grid-template-columns: 1fr 1fr 1fr 1fr; 55 | grid-gap: 1rem; 56 | ` 57 | const SwatchSelector = styled.div` 58 | min-height: 30px; 59 | background-color: ${props => 60 | `rgba(${props.color.r}, ${props.color.g}, ${props.color.b}, ${ 61 | props.color.a 62 | })`}; 63 | grid-column: span 2; 64 | border-radius: ${BORDER_RADIUS}px; 65 | border: 1px solid ${COLORS['gray']}; 66 | cursor: pointer; 67 | ` 68 | const ColorPopover = styled.div` 69 | position: absolute; 70 | z-index: 2; 71 | ` 72 | 73 | const ControlsForm = class extends React.Component { 74 | state = { 75 | displayColorPicker: false, 76 | displayShadowColorPicker: false, 77 | } 78 | 79 | handleColorOpen = () => this.setState({ displayColorPicker: true }) 80 | handleColorClose = () => this.setState({ displayColorPicker: false }) 81 | 82 | handleShadowColorOpen = () => 83 | this.setState({ displayShadowColorPicker: true }) 84 | handleShadowColorClose = () => 85 | this.setState({ displayShadowColorPicker: false }) 86 | 87 | handleColorChange = (color, e) => { 88 | this.props.onChangeBorderColor(color) 89 | } 90 | handleShadowColorChange = (color, e) => { 91 | this.props.onChangeShadowColor(color) 92 | } 93 | 94 | render() { 95 | const { 96 | normal, 97 | hover, 98 | border, 99 | hoverStyles, 100 | shadowColor, 101 | onChangeNum, 102 | onChangeOpacity, 103 | onHoverToggle, 104 | onBorderToggle, 105 | } = this.props 106 | const { displayColorPicker, displayShadowColorPicker } = this.state 107 | 108 | return ( 109 |
110 | 111 | 112 |
113 | BORDER 114 |
115 |
116 | RADIUS 117 |
118 |
119 | WIDTH 120 |
121 |
122 | 123 |
124 |
125 |
126 | 127 | 128 | BORDER SIZES 129 | `${value}px`} 134 | parser={value => value.replace('px', '')} 135 | name="radius" 136 | type="border" 137 | max={25} 138 | min={0} 139 | /> 140 | `${value}px`} 145 | parser={value => value.replace('px', '')} 146 | name="width" 147 | type="border" 148 | max={10} 149 | min={0} 150 | /> 151 | 152 | 153 | HOVER STYLES 154 |
341 | ) 342 | } 343 | } 344 | 345 | export default IndexPage 346 | --------------------------------------------------------------------------------