custom bubble colours

This commit is contained in:
Bash Elliott 2023-01-09 20:02:27 +11:00
parent 8a183604af
commit 5fabc2d5fb
8 changed files with 161 additions and 7 deletions

View file

@ -7,3 +7,5 @@ A tool for recording typing animations and sounds with imitated chat UI.
- [https://chat-bubbles.craftz.dog/](https://chat-bubbles.craftz.dog/) - [https://chat-bubbles.craftz.dog/](https://chat-bubbles.craftz.dog/)
- [Video tutorial](https://youtu.be/zu_vqAWHy_E) - [Video tutorial](https://youtu.be/zu_vqAWHy_E)
Customisable bubble colour by [rackodo](https://github.com/rackodo).

133
package-lock.json generated
View file

@ -7,9 +7,11 @@
"": { "": {
"name": "chat-bubbles", "name": "chat-bubbles",
"version": "0.1.0", "version": "0.1.0",
"license": "Apache-2.0",
"dependencies": { "dependencies": {
"framer-motion": "^6.2.8", "framer-motion": "^6.2.8",
"react": "^17.0.2", "react": "^17.0.2",
"react-color": "^2.19.3",
"react-dom": "^17.0.2" "react-dom": "^17.0.2"
}, },
"devDependencies": { "devDependencies": {
@ -439,6 +441,14 @@
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true "optional": true
}, },
"node_modules/@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
"peerDependencies": {
"react": "*"
}
},
"node_modules/@jridgewell/resolve-uri": { "node_modules/@jridgewell/resolve-uri": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
@ -1116,6 +1126,16 @@
"node": ">=6" "node": ">=6"
} }
}, },
"node_modules/lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"node_modules/lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"node_modules/loose-envify": { "node_modules/loose-envify": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -1127,6 +1147,11 @@
"loose-envify": "cli.js" "loose-envify": "cli.js"
} }
}, },
"node_modules/material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"node_modules/minimist": { "node_modules/minimist": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
@ -1230,6 +1255,16 @@
"node": ">=10.13.0" "node": ">=10.13.0"
} }
}, },
"node_modules/prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"dependencies": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"node_modules/react": { "node_modules/react": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@ -1242,6 +1277,23 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/react-color": {
"version": "2.19.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
"integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
"dependencies": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.15",
"lodash-es": "^4.17.15",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
},
"peerDependencies": {
"react": "*"
}
},
"node_modules/react-dom": { "node_modules/react-dom": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@ -1255,6 +1307,11 @@
"react": "17.0.2" "react": "17.0.2"
} }
}, },
"node_modules/react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"node_modules/react-refresh": { "node_modules/react-refresh": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
@ -1264,6 +1321,14 @@
"node": ">=0.10.0" "node": ">=0.10.0"
} }
}, },
"node_modules/reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"dependencies": {
"lodash": "^4.0.1"
}
},
"node_modules/resolve": { "node_modules/resolve": {
"version": "1.22.0", "version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@ -1371,6 +1436,11 @@
"url": "https://github.com/sponsors/ljharb" "url": "https://github.com/sponsors/ljharb"
} }
}, },
"node_modules/tinycolor2": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.5.2.tgz",
"integrity": "sha512-h80m9GPFGbcLzZByXlNSEhp1gf8Dy+VX/2JCGUZsWLo7lV1mnE/XlxGYgRBoMLJh1lIDXP0EMC4RPTjlRaV+Bg=="
},
"node_modules/to-fast-properties": { "node_modules/to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",
@ -1733,6 +1803,12 @@
"integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==", "integrity": "sha512-Ja/Vfqe3HpuzRsG1oBtWTHk2PGZ7GR+2Vz5iYGelAw8dx32K0y7PjVuxK6z1nMpZOqAFsRUPCkK1YjJ56qJlgw==",
"optional": true "optional": true
}, },
"@icons/material": {
"version": "0.2.4",
"resolved": "https://registry.npmjs.org/@icons/material/-/material-0.2.4.tgz",
"integrity": "sha512-QPcGmICAPbGLGb6F/yNf/KzKqvFx8z5qx3D1yFqVAjoFmXK35EgyW+cJ57Te3CNsmzblwtzakLGFqHPqrfb4Tw==",
"requires": {}
},
"@jridgewell/resolve-uri": { "@jridgewell/resolve-uri": {
"version": "3.0.5", "version": "3.0.5",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz", "resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.0.5.tgz",
@ -2140,6 +2216,16 @@
"minimist": "^1.2.5" "minimist": "^1.2.5"
} }
}, },
"lodash": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
"integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg=="
},
"lodash-es": {
"version": "4.17.21",
"resolved": "https://registry.npmjs.org/lodash-es/-/lodash-es-4.17.21.tgz",
"integrity": "sha512-mKnC+QJ9pWVzv+C4/U3rRsHapFfHvQFoFB92e52xeyGMcX6/OlIl78je1u8vePzYZSkkogMPJ2yjxxsb89cxyw=="
},
"loose-envify": { "loose-envify": {
"version": "1.4.0", "version": "1.4.0",
"resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz",
@ -2148,6 +2234,11 @@
"js-tokens": "^3.0.0 || ^4.0.0" "js-tokens": "^3.0.0 || ^4.0.0"
} }
}, },
"material-colors": {
"version": "1.2.6",
"resolved": "https://registry.npmjs.org/material-colors/-/material-colors-1.2.6.tgz",
"integrity": "sha512-6qE4B9deFBIa9YSpOc9O0Sgc43zTeVYbgDT5veRKSlB2+ZuHNoVVxA1L/ckMUayV9Ay9y7Z/SZCLcGteW9i7bg=="
},
"minimist": { "minimist": {
"version": "1.2.5", "version": "1.2.5",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz", "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.5.tgz",
@ -2223,6 +2314,16 @@
"integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==", "integrity": "sha512-vBZcPRUR5MZJwoyi3ZoyQlc1rXeEck8KgeC9AwwOn+exuxLxq5toTRDTSaVrXHxelDMHy9zlicw8u66yxoSUFg==",
"dev": true "dev": true
}, },
"prop-types": {
"version": "15.8.1",
"resolved": "https://registry.npmjs.org/prop-types/-/prop-types-15.8.1.tgz",
"integrity": "sha512-oj87CgZICdulUohogVAR7AjlC0327U4el4L6eAvOqCeudMDVU0NThNaV+b9Df4dXgSP1gXMTnPdhfe/2qDH5cg==",
"requires": {
"loose-envify": "^1.4.0",
"object-assign": "^4.1.1",
"react-is": "^16.13.1"
}
},
"react": { "react": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react/-/react-17.0.2.tgz",
@ -2232,6 +2333,20 @@
"object-assign": "^4.1.1" "object-assign": "^4.1.1"
} }
}, },
"react-color": {
"version": "2.19.3",
"resolved": "https://registry.npmjs.org/react-color/-/react-color-2.19.3.tgz",
"integrity": "sha512-LEeGE/ZzNLIsFWa1TMe8y5VYqr7bibneWmvJwm1pCn/eNmrabWDh659JSPn9BuaMpEfU83WTOJfnCcjDZwNQTA==",
"requires": {
"@icons/material": "^0.2.4",
"lodash": "^4.17.15",
"lodash-es": "^4.17.15",
"material-colors": "^1.2.1",
"prop-types": "^15.5.10",
"reactcss": "^1.2.0",
"tinycolor2": "^1.4.1"
}
},
"react-dom": { "react-dom": {
"version": "17.0.2", "version": "17.0.2",
"resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz", "resolved": "https://registry.npmjs.org/react-dom/-/react-dom-17.0.2.tgz",
@ -2242,12 +2357,25 @@
"scheduler": "^0.20.2" "scheduler": "^0.20.2"
} }
}, },
"react-is": {
"version": "16.13.1",
"resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz",
"integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ=="
},
"react-refresh": { "react-refresh": {
"version": "0.11.0", "version": "0.11.0",
"resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz", "resolved": "https://registry.npmjs.org/react-refresh/-/react-refresh-0.11.0.tgz",
"integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==", "integrity": "sha512-F27qZr8uUqwhWZboondsPx8tnC3Ct3SxZA3V5WyEvujRyyNv0VYPhoBg1gZ8/MV5tubQp76Trw8lTv9hzRBa+A==",
"dev": true "dev": true
}, },
"reactcss": {
"version": "1.2.3",
"resolved": "https://registry.npmjs.org/reactcss/-/reactcss-1.2.3.tgz",
"integrity": "sha512-KiwVUcFu1RErkI97ywr8nvx8dNOpT03rbnma0SSalTYjkrPYaEajR4a/MRt6DZ46K6arDRbWMNHF+xH7G7n/8A==",
"requires": {
"lodash": "^4.0.1"
}
},
"resolve": { "resolve": {
"version": "1.22.0", "version": "1.22.0",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz", "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.0.tgz",
@ -2325,6 +2453,11 @@
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==", "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true "dev": true
}, },
"tinycolor2": {
"version": "1.5.2",
"resolved": "https://registry.npmjs.org/tinycolor2/-/tinycolor2-1.5.2.tgz",
"integrity": "sha512-h80m9GPFGbcLzZByXlNSEhp1gf8Dy+VX/2JCGUZsWLo7lV1mnE/XlxGYgRBoMLJh1lIDXP0EMC4RPTjlRaV+Bg=="
},
"to-fast-properties": { "to-fast-properties": {
"version": "2.0.0", "version": "2.0.0",
"resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz", "resolved": "https://registry.npmjs.org/to-fast-properties/-/to-fast-properties-2.0.0.tgz",

View file

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"framer-motion": "^6.2.8", "framer-motion": "^6.2.8",
"react": "^17.0.2", "react": "^17.0.2",
"react-color": "^2.19.3",
"react-dom": "^17.0.2" "react-dom": "^17.0.2"
}, },
"devDependencies": { "devDependencies": {

View file

@ -1,7 +1,13 @@
.App { .App {
background-color: #00a000; background-color: #00a000;
width: 1920px; width: 100vw;
height: 1080px; height: 100vh;
display: flex; display: flex;
flex-direction: column-reverse; flex-direction: column-reverse;
} }
.picker {
position: fixed!important;
top: 0;
right: 0;
}

View file

@ -5,10 +5,13 @@ import Bubble from './bubble'
import BubbleInput from './bubble-input' import BubbleInput from './bubble-input'
import useMessages from './use-messages' import useMessages from './use-messages'
import { motion, AnimatePresence } from 'framer-motion' import { motion, AnimatePresence } from 'framer-motion'
import { SketchPicker } from 'react-color'
import React from 'react'
function App() { function App() {
const [messages, addMessage] = useMessages([]) const [messages, addMessage] = useMessages([])
const [newMessage, setNewMessage] = useState('') const [newMessage, setNewMessage] = useState('')
const [colour, setColour] = useState('#f00')
const handleSubmit = useCallback( const handleSubmit = useCallback(
bubbleHeight => { bubbleHeight => {
@ -24,6 +27,11 @@ function App() {
[newMessage, messages] [newMessage, messages]
) )
const handleColourChange = (color) => {
setColour(color.hex);
console.log(color);
};
const lastMessage = messages[messages.length - 1] const lastMessage = messages[messages.length - 1]
const dy = lastMessage ? lastMessage.height : 0 const dy = lastMessage ? lastMessage.height : 0
@ -32,7 +40,7 @@ function App() {
<Chat> <Chat>
<AnimatePresence> <AnimatePresence>
{messages.map(m => ( {messages.map(m => (
<Bubble key={m.id} id={m.id} dy={dy}> <Bubble key={m.id} id={m.id} dy={dy} colourClass={colour}>
{m.text} {m.text}
</Bubble> </Bubble>
))} ))}
@ -41,8 +49,11 @@ function App() {
value={newMessage} value={newMessage}
onChange={setNewMessage} onChange={setNewMessage}
onSubmit={handleSubmit} onSubmit={handleSubmit}
colourClass={colour}
/> />
</Chat> </Chat>
<SketchPicker className="picker" color={colour} onChange={handleColourChange}/>
</div> </div>
) )
} }

View file

@ -1,7 +1,7 @@
import React, { useCallback, useState, useRef, useEffect } from 'react' import React, { useCallback, useState, useRef, useEffect } from 'react'
import './bubble-input.css' import './bubble-input.css'
const BubbleInput = ({ onChange, onSubmit, value }) => { const BubbleInput = ({ onChange, onSubmit, value, colourClass }) => {
const refEditable = useRef() const refEditable = useRef()
const refContainer = useRef() const refContainer = useRef()
const [submitted, setSubmitted] = useState(false) const [submitted, setSubmitted] = useState(false)
@ -42,6 +42,7 @@ const BubbleInput = ({ onChange, onSubmit, value }) => {
ref={refEditable} ref={refEditable}
className="bubble-content" className="bubble-content"
contentEditable contentEditable
style={{backgroundColor: colourClass}}
spellCheck="false" spellCheck="false"
onBlur={handleBlur} onBlur={handleBlur}
onKeyDown={handleKeyDown} onKeyDown={handleKeyDown}

View file

@ -26,7 +26,7 @@
left: -12px; left: -12px;
height: 26px; height: 26px;
width: 30px; width: 30px;
background: #eee; background: inherit;
border-bottom-right-radius: 20px; border-bottom-right-radius: 20px;
} }

View file

@ -11,7 +11,7 @@ const transition = {
} }
} }
const Bubble = ({ id, children, sender, dy }) => { const Bubble = ({ id, children, sender, dy, colourClass }) => {
const [isPresent, safeToRemove] = usePresence() const [isPresent, safeToRemove] = usePresence()
const animations = { const animations = {
@ -32,7 +32,7 @@ const Bubble = ({ id, children, sender, dy }) => {
return ( return (
<motion.div key={id} className="bubble" {...animations}> <motion.div key={id} className="bubble" {...animations}>
<div className="bubble-content">{children}</div> <div className="bubble-content" style={{backgroundColor: colourClass}}>{children}</div>
</motion.div> </motion.div>
) )
} }