Skip to content

Customize color #2

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Jun 11, 2020
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions config/template.html
Original file line number Diff line number Diff line change
@@ -90,6 +90,10 @@
<meta name="msapplication-TileColor" content="#ffffff" />
<meta name="msapplication-config" content="/favicons/browserconfig.xml" />
<meta name="theme-color" content="#ffffff" />
<link
href="https://fonts.googleapis.com/css2?family=Manrope:wght@500;800&display=swap"
rel="stylesheet"
/>
</head>
<body>
<div id="root"></div>
21 changes: 11 additions & 10 deletions config/webpack.dev.config.js
Original file line number Diff line number Diff line change
@@ -1,13 +1,14 @@
const webpackBaseConfig = require('./webpack.base.config');
const paths = require('./paths');
const webpackBaseConfig = require("./webpack.base.config");
const paths = require("./paths");

module.exports = {
mode: 'development',
devtool: 'eval-source-map',
...webpackBaseConfig({ plugins: [] }),
devServer: {
contentBase: paths.output,
port: 9000,
hot: true,
}
mode: "development",
devtool: "eval-source-map",
...webpackBaseConfig({ plugins: [] }),
devServer: {
contentBase: paths.output,
port: 9000,
host: "0.0.0.0",
hot: true,
},
};
6 changes: 2 additions & 4 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
{
"name": "blobs.app",
"version": "1.0.0",
"description": "Generate blob shapes for Web and Fluttter",
"version": "1.1.0",
"description": "Generate blob shapes for Web and Flutter",
"main": "index.js",
"scripts": {
"build": "rm -rf build && NODE_ENV=production npm run build:css && webpack ---config ./config/webpack.prod.config.js",
@@ -23,12 +23,10 @@
"@babel/preset-env": "^7.9.0",
"@babel/preset-react": "^7.9.4",
"@risingstack/react-easy-state": "^6.3.0",
"animejs": "^3.2.0",
"antd": "^4.2.4",
"autoprefixer": "^9.7.6",
"babel-loader": "^8.1.0",
"dynamics.js": "^1.1.5",
"kute.js": "^1.6.6",
"postcss-cli": "^7.1.0",
"prop-types": "^15.7.2",
"react": "^16.13.1",
59 changes: 56 additions & 3 deletions src/app.scss
Original file line number Diff line number Diff line change
@@ -1,4 +1,10 @@
html body {
line-height: 25px;
font-family: "Manrope", -apple-system, BlinkMacSystemFont, "Segoe UI", Roboto,
Oxygen, Ubuntu, Cantarell, "Open Sans", "Helvetica Neue", sans-serif;
button {
line-height: 25px;
}
.brand-bg {
margin-top: -16px;
transform: translate(-50%, 0);
@@ -9,8 +15,23 @@ html body {
max-width: 500px;
}

#blob {
fill: #d1d8e0;
.stroke {
border: 4px solid #d1d8e0;
&.stroke-fill {
position: relative;
display: flex;
align-items: center;
justify-content: center;
&:after {
content: "";

width: 100%;
height: 100%;
transform: scale(0.7);
border-radius: 100%;
background-color: #4a5568;
}
}
}

.ant-slider-step {
@@ -49,7 +70,39 @@ html body {

.ant-popover-inner {
max-width: 300px;
border-radius: 4px;
border-radius: 10px;
}

.ant-popover-arrow {
display: none;
}

.ant-popover-inner-content {
padding: 25px;
background: rgba(207, 214, 222, 0.15);
}

input.ant-input {
border-radius: 6px;
padding: 9px;
font-weight: bold;
color: #828b99;
border-color: #cfd8df;
border-width: 2px;
}

.ant-input:hover {
border-color: #4e566b;
border-right-width: 2px !important;
}

.ant-input:focus,
.ant-input-focused {
border-color: #4c5468;
border-right-width: 2px !important;
outline: 0;
-webkit-box-shadow: 0 0 0 2px rgba(78, 86, 107, 0.34);
box-shadow: 0 0 0 2px rgba(78, 86, 107, 0.34);
}

pre {
62 changes: 11 additions & 51 deletions src/assets/css/main.css
Original file line number Diff line number Diff line change
@@ -559,7 +559,7 @@ pre,
code,
kbd,
samp {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
font-family: SFMono-Regular, Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
}

/**
@@ -6431,16 +6431,8 @@ video {
clear: none;
}

.font-sans {
font-family: system-ui, -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";
}

.font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}

.font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
.font-body {
font-family: Manrope;
}

.font-hairline {
@@ -26385,16 +26377,8 @@ video {
clear: none;
}

.sm\:font-sans {
font-family: system-ui, -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";
}

.sm\:font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}

.sm\:font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
.sm\:font-body {
font-family: Manrope;
}

.sm\:font-hairline {
@@ -46338,16 +46322,8 @@ video {
clear: none;
}

.md\:font-sans {
font-family: system-ui, -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";
}

.md\:font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}

.md\:font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
.md\:font-body {
font-family: Manrope;
}

.md\:font-hairline {
@@ -66291,16 +66267,8 @@ video {
clear: none;
}

.lg\:font-sans {
font-family: system-ui, -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";
}

.lg\:font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}

.lg\:font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
.lg\:font-body {
font-family: Manrope;
}

.lg\:font-hairline {
@@ -86244,16 +86212,8 @@ video {
clear: none;
}

.xl\:font-sans {
font-family: system-ui, -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";
}

.xl\:font-serif {
font-family: Georgia, Cambria, "Times New Roman", Times, serif;
}

.xl\:font-mono {
font-family: Menlo, Monaco, Consolas, "Liberation Mono", "Courier New", monospace;
.xl\:font-body {
font-family: Manrope;
}

.xl\:font-hairline {
2 changes: 1 addition & 1 deletion src/components/actions/flutterCopy.jsx
Original file line number Diff line number Diff line change
@@ -4,7 +4,7 @@ import Button from "../common/button";
import { appStore } from "../../store";
import Modal from "../common/modal";
import Highlight from "../common/highlight";
import Copy from "../common/ copy";
import Copy from "../common/copy";

const FlutterCopy = view(({ onClose }) => {
const [isModalOpen, openModal] = useState(false);
10 changes: 4 additions & 6 deletions src/components/actions/svgCopy.jsx
Original file line number Diff line number Diff line change
@@ -4,17 +4,15 @@ import Button from "../common/button";
import { appStore } from "../../store";
import Modal from "../common/modal";
import Highlight from "../common/highlight";
import Copy from "../common/ copy";
import Copy from "../common/copy";
import Download from "../common/download";
import formatter from "../../services/formatter";

const SVGCopy = view(({ onClose }) => {
const [isModalOpen, openModal] = useState(false);
const ID = `${appStore.edges}-${appStore.growth}-${appStore.id}`;
const code = `
<svg viewBox="0 0 500 500" xmlns="http://www.w3.org/2000/svg">
<path d="${appStore.path}"></path>
</svg>
`;
const svgEl = document.getElementById("blobSvg");
const code = svgEl ? formatter(svgEl.outerHTML) : "";
return (
<>
<Button
24 changes: 23 additions & 1 deletion src/components/blob.jsx
Original file line number Diff line number Diff line change
@@ -4,14 +4,36 @@ import { appStore } from "../store";

const Blob = view(() => {
const size = appStore.size;
let props = {
fill: appStore.color,
};
if (appStore.type == "gradient") {
props.fill = "url(#gradient)";
}
if (appStore.stroke) {
props.strokeWidth = "7px";
props.fill = "none";
props.stroke = appStore.color;
}
if (appStore.type == "gradient" && appStore.stroke) {
props.stroke = "url(#gradient)";
}
return (
<svg
viewBox={`0 0 ${size} ${size}`}
xmlns="http://www.w3.org/2000/svg"
width={`100%`}
id="blobSvg"
>
<path id="blob" d={appStore.path} />
{appStore.type == "gradient" && (
<defs>
<linearGradient id="gradient" x1="0%" y1="0%" x2="0%" y2="100%">
<stop offset="0%" style={{ stopColor: appStore.gradient[0] }} />
<stop offset="100%" style={{ stopColor: appStore.gradient[1] }} />
</linearGradient>
</defs>
)}
<path id="blob" d={appStore.path} {...props} />
</svg>
);
});
3 changes: 1 addition & 2 deletions src/components/common/button.jsx
Original file line number Diff line number Diff line change
@@ -10,8 +10,7 @@ export default function Button({
}) {
let classNames = "";
if (isPrimary) {
classNames =
"shadow-lg bg-theme-400 text-white hover:bg-theme-900 transition duration-200 ease-in-out transform active:shadow-2xl active:translate-y-1";
classNames = "shadow-lg bg-theme-400 text-white hover:bg-theme-900";
} else {
classNames = "text-theme-600";
}
File renamed without changes.
2 changes: 1 addition & 1 deletion src/components/common/modal.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useState } from "react";
import { Modal as DefaultModal } from "antd";
import Button from "./button";
import Copy from "./ copy";
import Copy from "./copy";

export default function Modal({ isOpen, children, onClose }) {
return (
8 changes: 5 additions & 3 deletions src/components/common/settingsItem.jsx
Original file line number Diff line number Diff line change
@@ -6,9 +6,11 @@ export default function SettingsItem({ label, children, info }) {
<div className="block w-full py-6">
<div className="flex justify-between">
<h3>{label}</h3>
<Popover content={info} title={null} trigger="click">
<i className="ri-question-line text-gray-500 cursor-pointer"></i>
</Popover>
{info && (
<Popover content={info} title={null} trigger="click">
<i className="ri-question-line text-gray-500 cursor-pointer"></i>
</Popover>
)}
</div>
{children}
</div>
19 changes: 13 additions & 6 deletions src/components/layout/grid.jsx
Original file line number Diff line number Diff line change
@@ -7,20 +7,27 @@ import Settings from "../settings/settings";

export default function Grid() {
return (
<div className="app bg-gray-100">
<div className="app font-body">
<div className="flex flex-col w-full max-w-screen-xl mx-auto px-6 min-h-screen">
<Header />
<div className="md:flex flex-1">
<div className="md:w-9/12 flex flex-col items-center justify-center">
<div className="flex flex-1 w-full items-center flex-col">
<Blob />
<div className="py-10">
<ActionBar />
<div className="flex flex-1 w-full justify-center flex-col">
<div className="flex flex-col items-center">
<div className="block md:hidden">
<Header />
</div>
<Blob />
<div className="py-10">
<ActionBar />
</div>
</div>
</div>
</div>
<div className="md:w-3/12 flex items-center">
<div className="flex-1">
<div className="hidden md:block">
<Header />
</div>
<Settings />
</div>
</div>
5 changes: 4 additions & 1 deletion src/components/layout/header.jsx
Original file line number Diff line number Diff line change
@@ -4,8 +4,11 @@ import Logo from "assets/blobs_logo.png";
export default function Header() {
return (
<nav className="flex items-center justify-center flex-wrap p-6 my-4">
<div className="flex items-center flex-shrink-0 mr-6 leading-none">
<div className="flex flex-col items-center flex-shrink-0 mr-6 leading-none">
<img src={Logo} width="50" />
<h1 className="my-4 font-extrabold text-2xl tracking-tight text-gray-700">
Blob generator
</h1>
</div>
</nav>
);
70 changes: 70 additions & 0 deletions src/components/settings/colorPicker.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,70 @@
import React, { useState } from "react";
import { Popover, Divider, Input } from "antd";
import { view } from "@risingstack/react-easy-state";
import { appStore } from "../../store";
import hexValidator from "../../services/hex-validator";

const ColorPicker = view(() => {
const [val, setVal] = useState(appStore.color);
const colors = [
"#00cec9",
"#fab1a0",
"#fdcb6e",
"#fd79a8",
"#a29bfe",
"#B53471",
];
const content = () => {
return (
<div className="flex flex-col">
<div className="flex justify-center">
{colors.map((color, i) => {
return (
<div
className="w-6 h-6 rounded-full mx-1 cursor-pointer"
style={{ backgroundColor: color }}
onClick={() => {
setVal(color);
appStore.type = "color";
appStore.color = color;
}}
></div>
);
})}
</div>
<hr className="my-4" />
<Input
placeholder="#ffffff"
defaultValue={appStore.color}
value={val}
onChange={(e) => {
setVal(e.target.value);
}}
onPressEnter={(e) => {
if (!hexValidator(e.target.value)) return;
setVal(e.target.value);
appStore.type = "color";
appStore.color = e.target.value;
}}
/>
</div>
);
};

const getBgCss = () => {
if (appStore.type == "color") {
return { backgroundColor: appStore.color };
}
return { backgroundColor: "#d1d8e0" };
};
return (
<Popover content={content} trigger="click">
<div
className="w-8 h-8 rounded-full cursor-pointer"
style={getBgCss()}
></div>
</Popover>
);
});

export default ColorPicker;
94 changes: 94 additions & 0 deletions src/components/settings/gradientPicker.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,94 @@
import React, { useState } from "react";
import { Popover, Input } from "antd";
import { view } from "@risingstack/react-easy-state";
import { appStore } from "../../store";
import hexValidator from "../../services/hex-validator";

const GradientPicker = view(() => {
const [val, setVal] = useState(appStore.gradient);
const colors = [
["#e96443", "#904e95"],
["#FF5F6D", "#FFC371"],
["#EECDA3", "#EF629F"],
["#4CA1AF", "#C4E0E5"],
["#c2e59c", "#64b3f4"],
["#3CA55C", "#B5AC49"],
];
const getBgCss = (color = null) => {
let cols = color;
if (!cols)
cols =
appStore.type == "gradient"
? appStore.gradient
: ["#d1d8e0", "#4a5568"];
return {
background: `linear-gradient(
180deg,
${cols[0]} 0%,
${cols[1]} 100%
)`,
};
};
const content = () => {
return (
<div className="flex flex-col">
<div className="flex justify-center">
{colors.map((color, i) => {
return (
<div
className="w-6 h-6 rounded-full mx-1 cursor-pointer"
style={getBgCss(color)}
onClick={() => {
setVal(color);
appStore.type = "gradient";
appStore.gradient = color;
}}
></div>
);
})}
</div>
<hr className="my-4" />
<div className="flex">
<Input
placeholder="#ffffff"
className="mr-2"
defaultValue={appStore.gradient[0]}
value={val[0]}
onChange={(e) => {
setVal([e.target.value, val[1]]);
}}
onPressEnter={(e) => {
if (!hexValidator(e.target.value)) return;
appStore.gradient = val;
appStore.type = "gradient";
}}
/>
<div className="w-2"></div>
<Input
placeholder="#ffffff"
defaultValue={appStore.gradient[1]}
value={val[1]}
onChange={(e) => {
setVal([val[0], e.target.value]);
}}
onPressEnter={(e) => {
if (!hexValidator(e.target.value)) return;
appStore.gradient = val;
appStore.type = "gradient";
}}
/>
</div>
</div>
);
};
return (
<Popover content={content} trigger="click">
<div
className="w-8 h-8 rounded-full cursor-pointer gradient"
style={getBgCss()}
></div>
</Popover>
);
});

export default GradientPicker;
11 changes: 11 additions & 0 deletions src/components/settings/settings.jsx
Original file line number Diff line number Diff line change
@@ -3,6 +3,9 @@ import SettingsItem from "../common/settingsItem";
import EdgesSlider from "./edgesSlider";
import GrowthSlider from "./growthSlider";
import Links from "./links";
import ColorPicker from "./colorPicker";
import GradientPicker from "./gradientPicker";
import Stroke from "./stroke";

export default function Settings() {
const edgeInfo =
@@ -17,6 +20,14 @@ export default function Settings() {
<SettingsItem label="Complexity" info={edgeInfo}>
<EdgesSlider />
</SettingsItem>

<div className="flex justify-center mt-3">
<ColorPicker />
<div className="w-6"></div>
<GradientPicker />
<div className="w-6"></div>
<Stroke />
</div>
<Links />
</div>
);
19 changes: 19 additions & 0 deletions src/components/settings/stroke.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
import React, { useState } from "react";
import { Popover, Divider, Input } from "antd";
import { view } from "@risingstack/react-easy-state";
import { appStore } from "../../store";

const Stroke = view(() => {
return (
<div
className={`w-8 h-8 rounded-full cursor-pointer stroke ${
appStore.stroke ? "stroke-fill" : ""
}`}
onClick={() => {
appStore.stroke = !appStore.stroke;
}}
></div>
);
});

export default Stroke;
1 change: 0 additions & 1 deletion src/services/animator.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import * as dynamics from "dynamics.js";
import { appStore } from "../store";

export default function animator(path, id = "blob") {
const element = document.getElementById(id);
28 changes: 28 additions & 0 deletions src/services/formatter.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
const formatter = (string) => {
function format(node, level) {
let indentBefore = new Array(level++ + 1).join(" "),
indentAfter = new Array(level - 1).join(" "),
textNode;

for (let i = 0; i < node.children.length; i++) {
textNode = document.createTextNode("\n" + indentBefore);
node.insertBefore(textNode, node.children[i]);

format(node.children[i], level);

if (node.lastElementChild == node.children[i]) {
textNode = document.createTextNode("\n" + indentAfter);
node.appendChild(textNode);
}
}

return node;
}

const div = document.createElement("div");
div.innerHTML = string.trim();

return format(div, 0).innerHTML;
};

export default formatter;
15 changes: 15 additions & 0 deletions src/services/hex-validator.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
const hexValidator = (input) => {
let check, len;
if (typeof input != "string" || input[0] !== "#") return false;
len = input.length;
if (len === 4 || len === 7) {
input = input.toLowerCase(); // convert to lower case
check =
"#" +
("00000000" + parseInt(input.substr(1), 16).toString(16)).substr(1 - len);
return check === input;
}
return false;
};

export default hexValidator;
4 changes: 4 additions & 0 deletions src/store.js
Original file line number Diff line number Diff line change
@@ -7,6 +7,10 @@ const appStore = store({
size: 500,
path: "",
id: "",
color: "#d1d8e0",
type: "color",
gradient: ["#d1d8e0", "#4a5568"],
stroke: false,
});

export { appStore };