From c570d1e49cb0e75d2ecfde8471715a3ced5e778f Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Tue, 10 Jun 2025 00:11:53 -0700 Subject: [PATCH 01/14] Import ChatLog and pass messages to ChatLog --- src/App.jsx | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/App.jsx b/src/App.jsx index 14a7f684d..962f4442d 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,14 +1,20 @@ import './App.css'; +import chatMessages from './data/messages.json'; +import ChatLog from './components/ChatLog.jsx'; const App = () => { return (
-

Application title

+

Chat between Vladimir and Estragon

+
+

22

+
{/* Wave 01: Render one ChatEntry component Wave 02: Render ChatLog component */} +
); From ed2f42bbbfd12a96e66fa8c40bc540ad1cac657a Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Tue, 10 Jun 2025 00:15:42 -0700 Subject: [PATCH 02/14] Use props to render ChatEntry and add PropTypes validation --- src/components/ChatEntry.jsx | 16 +++++++++++----- 1 file changed, 11 insertions(+), 5 deletions(-) diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index 15c56f96b..8f3bcfb79 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -1,12 +1,16 @@ +import PropTypes from 'prop-types'; import './ChatEntry.css'; +import TimeStamp from './TimeStamp'; -const ChatEntry = () => { +const ChatEntry = (props) => { return (
-

Replace with name of sender

+

{props.sender}

-

Replace with body of ChatEntry

-

Replace with TimeStamp component

+

{props.body}

+

+ +

@@ -14,7 +18,9 @@ const ChatEntry = () => { }; ChatEntry.propTypes = { - // Fill with correct proptypes + sender:PropTypes.string.isRequired, + body:PropTypes.string.isRequired, + timeStamp:PropTypes.string.isRequired }; export default ChatEntry; From b229075aaa612c0c7d22feae198602340d9709b7 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Tue, 10 Jun 2025 00:16:10 -0700 Subject: [PATCH 03/14] Remove bullet points --- src/components/ChatLog.css | 1 + 1 file changed, 1 insertion(+) diff --git a/src/components/ChatLog.css b/src/components/ChatLog.css index 378848d1f..737960384 100644 --- a/src/components/ChatLog.css +++ b/src/components/ChatLog.css @@ -1,4 +1,5 @@ .chat-log { margin: auto; max-width: 50rem; + list-style-type: none; } From a891b115f969c90cd35e935a09eeb23237869402 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Tue, 10 Jun 2025 00:17:07 -0700 Subject: [PATCH 04/14] Use props to render ChatLog and add PropTypes for validation --- src/components/ChatLog.jsx | 34 ++++++++++++++++++++++++++++++++++ 1 file changed, 34 insertions(+) create mode 100644 src/components/ChatLog.jsx diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx new file mode 100644 index 000000000..04443e566 --- /dev/null +++ b/src/components/ChatLog.jsx @@ -0,0 +1,34 @@ +import './ChatLog.css'; +import ChatEntry from './ChatEntry'; +import PropTypes from 'prop-types'; + +const ChatLog = ({entries}) => { + const chatEntryComponents = entries.map((chatEntry) => { + return ( +
  • + + +
  • + ); + }); + + return ( +
      + {chatEntryComponents} +
    + ); +}; + +ChatLog.propTypes = { + entries:PropTypes.shape({ + id: PropTypes.number.isRequired, + sender:PropTypes.string.isRequired, + body:PropTypes.string.isRequired, + timeStamp:PropTypes.string.isRequired + }) +}; + +export default ChatLog; \ No newline at end of file From d320c4bd2bb2899ed32a4c032c938b6fc72ae06e Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 17:02:47 -0700 Subject: [PATCH 05/14] fix ChatLog validation --- src/App.jsx | 2 +- src/components/ChatLog.jsx | 14 ++++++++------ 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 962f4442d..3cf31ef07 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -8,7 +8,7 @@ const App = () => {

    Chat between Vladimir and Estragon

    -

    22

    + 0🤍s
    diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index 04443e566..be19e14f1 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -23,12 +23,14 @@ const ChatLog = ({entries}) => { }; ChatLog.propTypes = { - entries:PropTypes.shape({ - id: PropTypes.number.isRequired, - sender:PropTypes.string.isRequired, - body:PropTypes.string.isRequired, - timeStamp:PropTypes.string.isRequired - }) + entries:PropTypes.arrayOf( + PropTypes.shape({ + id: PropTypes.number.isRequired, + sender:PropTypes.string.isRequired, + body:PropTypes.string.isRequired, + timeStamp:PropTypes.string.isRequired, + }) + ).isRequired, }; export default ChatLog; \ No newline at end of file From c883ee377cdc2ca71f8832fc6c0ef5aa07562912 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 21:00:26 -0700 Subject: [PATCH 06/14] Add toggleLiked event handler to ChatEntry --- src/components/ChatEntry.jsx | 11 +++++++++-- src/components/ChatLog.jsx | 1 + 2 files changed, 10 insertions(+), 2 deletions(-) diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index 8f3bcfb79..eb602257d 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -1,8 +1,14 @@ import PropTypes from 'prop-types'; import './ChatEntry.css'; import TimeStamp from './TimeStamp'; +import {useState} from 'react'; const ChatEntry = (props) => { + const [liked, setLiked] = useState(props.liked); + const toggleLiked = () => { + setLiked(!liked); + }; + const nameColor = liked ? '❤️' : '🤍'; return (

    {props.sender}

    @@ -11,7 +17,7 @@ const ChatEntry = (props) => {

    - +
    ); @@ -20,7 +26,8 @@ const ChatEntry = (props) => { ChatEntry.propTypes = { sender:PropTypes.string.isRequired, body:PropTypes.string.isRequired, - timeStamp:PropTypes.string.isRequired + timeStamp:PropTypes.string.isRequired, + liked: PropTypes.bool.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index be19e14f1..3a48ad148 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -29,6 +29,7 @@ ChatLog.propTypes = { sender:PropTypes.string.isRequired, body:PropTypes.string.isRequired, timeStamp:PropTypes.string.isRequired, + liked: PropTypes.bool.isRequired, }) ).isRequired, }; From 081b1d7157e38f76e05913bb2045038ed82a07ea Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 22:00:58 -0700 Subject: [PATCH 07/14] Lift up chatLiked to App and add likeCount --- src/App.css | 4 ++-- src/App.jsx | 22 ++++++++++++++++++++-- src/components/ChatEntry.jsx | 11 ++++------- src/components/ChatLog.jsx | 16 ++++++++++------ 4 files changed, 36 insertions(+), 17 deletions(-) diff --git a/src/App.css b/src/App.css index d97beb4e6..c9ce38c28 100644 --- a/src/App.css +++ b/src/App.css @@ -27,7 +27,7 @@ } #App header section { - background-color: #e0ffff; + background-color: #222 /*#e0ffff*/; } #App .widget { @@ -46,7 +46,7 @@ } #App span { - display: inline-block + display: inline-block; } .red { diff --git a/src/App.jsx b/src/App.jsx index 3cf31ef07..ee40a2473 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -1,20 +1,38 @@ import './App.css'; import chatMessages from './data/messages.json'; import ChatLog from './components/ChatLog.jsx'; +import { useState } from 'react'; const App = () => { + const [chatData, setChatData] = useState(chatMessages); + const chatLiked = (id) => { + setChatData(chatData => { + return chatData.map(chat => { + if (chat.id === id) { + return {...chat, liked: !chat.liked}; + } else { + return chat; + } + }); + }); + }; + + const getLikeCount = (data) => { + return data.filter(chat => chat.liked).length; + }; + return (

    Chat between Vladimir and Estragon

    - 0🤍s + {getLikeCount(chatData)}❤️s
    {/* Wave 01: Render one ChatEntry component Wave 02: Render ChatLog component */} - +
    ); diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index eb602257d..da804ce9c 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -1,14 +1,9 @@ import PropTypes from 'prop-types'; import './ChatEntry.css'; import TimeStamp from './TimeStamp'; -import {useState} from 'react'; const ChatEntry = (props) => { - const [liked, setLiked] = useState(props.liked); - const toggleLiked = () => { - setLiked(!liked); - }; - const nameColor = liked ? '❤️' : '🤍'; + const nameColor = props.liked ? '❤️' : '🤍'; return (

    {props.sender}

    @@ -17,17 +12,19 @@ const ChatEntry = (props) => {

    - +
    ); }; ChatEntry.propTypes = { + id:PropTypes.number.isRequired, sender:PropTypes.string.isRequired, body:PropTypes.string.isRequired, timeStamp:PropTypes.string.isRequired, liked: PropTypes.bool.isRequired, + onLike: PropTypes.func.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index 3a48ad148..5d1bb40a5 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -2,14 +2,17 @@ import './ChatLog.css'; import ChatEntry from './ChatEntry'; import PropTypes from 'prop-types'; -const ChatLog = ({entries}) => { - const chatEntryComponents = entries.map((chatEntry) => { +const ChatLog = ({entries, onLike}) => { + const chatEntryComponents = entries.map((entry) => { return ( -
  • +
  • + id={entry.id} + sender={entry.sender} + body={entry.body} + timeStamp={entry.timeStamp} + liked={entry.liked} + onLike={onLike}>
  • ); @@ -32,6 +35,7 @@ ChatLog.propTypes = { liked: PropTypes.bool.isRequired, }) ).isRequired, + onLike: PropTypes.func.isRequired, }; export default ChatLog; \ No newline at end of file From a4f6c4891d3e99b50d7009bc97d236ae396f8242 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 22:05:53 -0700 Subject: [PATCH 08/14] Move utility function getLikeCount outside of App component --- src/App.jsx | 10 ++++------ 1 file changed, 4 insertions(+), 6 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index ee40a2473..b76e0afc6 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,6 +3,10 @@ import chatMessages from './data/messages.json'; import ChatLog from './components/ChatLog.jsx'; import { useState } from 'react'; +const getLikeCount = (data) => { + return data.filter(chat => chat.liked).length; +}; + const App = () => { const [chatData, setChatData] = useState(chatMessages); const chatLiked = (id) => { @@ -17,10 +21,6 @@ const App = () => { }); }; - const getLikeCount = (data) => { - return data.filter(chat => chat.liked).length; - }; - return (
    @@ -30,8 +30,6 @@ const App = () => {
    - {/* Wave 01: Render one ChatEntry component - Wave 02: Render ChatLog component */}
    From ba923fe1d1d0964d11a92f6d1d635ffe2286b1a2 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 22:10:03 -0700 Subject: [PATCH 09/14] Add space in span --- src/App.jsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/App.jsx b/src/App.jsx index b76e0afc6..c4569f266 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -26,7 +26,7 @@ const App = () => {

    Chat between Vladimir and Estragon

    - {getLikeCount(chatData)}❤️s + {getLikeCount(chatData)} ❤️s
    From 5cef66754a867bf1244c2f7887e8878e4ab7089e Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sat, 14 Jun 2025 23:20:49 -0700 Subject: [PATCH 10/14] Add sender-based alignment (local/remote) and color styling to chat entries --- src/App.jsx | 18 ++++++++++++++++-- src/components/ChatEntry.css | 8 ++++++++ src/components/ChatEntry.jsx | 12 ++++++++---- src/components/ChatLog.jsx | 13 ++++++++++--- 4 files changed, 42 insertions(+), 9 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index c4569f266..fa520bc81 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -7,6 +7,18 @@ const getLikeCount = (data) => { return data.filter(chat => chat.liked).length; }; +const extractUniqueSenders = (chatLog) => { + const uniqueSenders = []; + + for (const message of chatLog) { + if (!uniqueSenders.includes(message.sender)) { + uniqueSenders.push(message.sender); + } + } + + return uniqueSenders; +}; + const App = () => { const [chatData, setChatData] = useState(chatMessages); const chatLiked = (id) => { @@ -21,16 +33,18 @@ const App = () => { }); }; + const uniqueSenders = extractUniqueSenders(chatData); + return (
    -

    Chat between Vladimir and Estragon

    +

    {`Chat between ${uniqueSenders[0]} and ${uniqueSenders[1]}`}

    {getLikeCount(chatData)} ❤️s
    - +
    ); diff --git a/src/components/ChatEntry.css b/src/components/ChatEntry.css index 05c3baa44..2013303ed 100644 --- a/src/components/ChatEntry.css +++ b/src/components/ChatEntry.css @@ -58,6 +58,10 @@ button { text-align: left; } +.chat-entry.local .entry-body { + color: green; +} + .chat-entry.local .entry-time { text-align: right; } @@ -76,6 +80,10 @@ button { text-align: right; } +.chat-entry.remote .entry-body{ + color: blue; +} + .chat-entry.remote .entry-bubble { background-color: #e0ffff; margin-left: auto; diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index da804ce9c..16108935a 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -2,13 +2,16 @@ import PropTypes from 'prop-types'; import './ChatEntry.css'; import TimeStamp from './TimeStamp'; + + const ChatEntry = (props) => { const nameColor = props.liked ? '❤️' : '🤍'; + return ( -
    +

    {props.sender}

    -

    {props.body}

    +

    {props.body}

    @@ -23,8 +26,9 @@ ChatEntry.propTypes = { sender:PropTypes.string.isRequired, body:PropTypes.string.isRequired, timeStamp:PropTypes.string.isRequired, - liked: PropTypes.bool.isRequired, - onLike: PropTypes.func.isRequired, + liked:PropTypes.bool.isRequired, + onLike:PropTypes.func.isRequired, + position:PropTypes.string.isRequired, }; export default ChatEntry; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index 5d1bb40a5..a26a6cf18 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -2,7 +2,12 @@ import './ChatLog.css'; import ChatEntry from './ChatEntry'; import PropTypes from 'prop-types'; -const ChatLog = ({entries, onLike}) => { +const ChatLog = ({entries, onLike, uniqueSenders}) => { + const getPosition = (sender) => { + if (!uniqueSenders || uniqueSenders.length < 2) return 'local'; + return sender === uniqueSenders[1] ? 'remote' : 'local'; + }; + const chatEntryComponents = entries.map((entry) => { return (
  • @@ -12,7 +17,8 @@ const ChatLog = ({entries, onLike}) => { body={entry.body} timeStamp={entry.timeStamp} liked={entry.liked} - onLike={onLike}> + onLike={onLike} + position={getPosition(entry.sender)}>
  • ); @@ -35,7 +41,8 @@ ChatLog.propTypes = { liked: PropTypes.bool.isRequired, }) ).isRequired, - onLike: PropTypes.func.isRequired, + onLike:PropTypes.func.isRequired, + uniqueSenders:PropTypes.array.isRequired, }; export default ChatLog; \ No newline at end of file From 149c79c38939af10be39cbba6eb5326775e5480d Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Sun, 15 Jun 2025 08:11:55 -0700 Subject: [PATCH 11/14] Update header section color --- src/App.css | 2 +- src/App.jsx | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/App.css b/src/App.css index c9ce38c28..9bfee6fa9 100644 --- a/src/App.css +++ b/src/App.css @@ -27,7 +27,7 @@ } #App header section { - background-color: #222 /*#e0ffff*/; + background-color: #e0ffff; } #App .widget { diff --git a/src/App.jsx b/src/App.jsx index fa520bc81..7c86ba534 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -40,7 +40,7 @@ const App = () => {

    {`Chat between ${uniqueSenders[0]} and ${uniqueSenders[1]}`}

    - {getLikeCount(chatData)} ❤️s + {getLikeCount(chatData)} ❤️s
    From cbc789227e85842ab24f17a4185ccd25dc512f4d Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Mon, 16 Jun 2025 00:34:53 -0700 Subject: [PATCH 12/14] Successfully configured Vite React app for GitHub Pages deployment --- package-lock.json | 571 ++++++++++++++++++++++++++++++++++++++++++++++ package.json | 6 +- vite.config.js | 6 +- 3 files changed, 581 insertions(+), 2 deletions(-) diff --git a/package-lock.json b/package-lock.json index 2a6ed1d5b..a319eacca 100644 --- a/package-lock.json +++ b/package-lock.json @@ -27,6 +27,7 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.12", "eslint-plugin-vitest-globals": "^1.5.0", + "gh-pages": "^6.3.0", "globals": "^15.11.0", "jest-extended": "^4.0.2", "jsdom": "^25.0.1", @@ -1119,6 +1120,44 @@ "@jridgewell/sourcemap-codec": "^1.4.14" } }, + "node_modules/@nodelib/fs.scandir": { + "version": "2.1.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.scandir/-/fs.scandir-2.1.5.tgz", + "integrity": "sha512-vq24Bq3ym5HEQm2NKCr3yXDwjc7vTsEThRDnkp2DK9p1uqLR+DHurm/NOTo0KG7HYHU7eppKZj3MyqYuMBf62g==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "2.0.5", + "run-parallel": "^1.1.9" + }, + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.stat": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/@nodelib/fs.stat/-/fs.stat-2.0.5.tgz", + "integrity": "sha512-RkhPPp2zrqDAQA/2jNhnztcPAlv64XdhIp7a7454A5ovI7Bukxgt7MX7udwAu3zg1DcpPU0rz3VV1SeaqvY4+A==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/@nodelib/fs.walk": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/@nodelib/fs.walk/-/fs.walk-1.2.8.tgz", + "integrity": "sha512-oGB+UxlgWcgQkgwo8GcEGwemoTFt3FIO9ababBmaGwXIoBKZ+GTy0pP185beGg7Llih/NSHSV2XAs1lnznocSg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.scandir": "2.1.5", + "fastq": "^1.6.0" + }, + "engines": { + "node": ">= 8" + } + }, "node_modules/@rollup/rollup-android-arm-eabi": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/@rollup/rollup-android-arm-eabi/-/rollup-android-arm-eabi-4.24.0.tgz", @@ -1819,6 +1858,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/array-union": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/array-union/-/array-union-2.1.0.tgz", + "integrity": "sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/array.prototype.findlast": { "version": "1.2.5", "resolved": "https://registry.npmjs.org/array.prototype.findlast/-/array.prototype.findlast-1.2.5.tgz", @@ -1928,6 +1977,13 @@ "node": ">=12" } }, + "node_modules/async": { + "version": "3.2.6", + "resolved": "https://registry.npmjs.org/async/-/async-3.2.6.tgz", + "integrity": "sha512-htCUDlxyyCLMgaM3xXg0C0LW2xqfuQ6p05pCEIsXuyQ+a1koYKTuBMzRNwmybfLgvJDMd0r1LTn4+E0Ti6C2AA==", + "dev": true, + "license": "MIT" + }, "node_modules/asynckit": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", @@ -1969,6 +2025,19 @@ "concat-map": "0.0.1" } }, + "node_modules/braces": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz", + "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==", + "dev": true, + "license": "MIT", + "dependencies": { + "fill-range": "^7.1.1" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/browserslist": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.24.0.tgz", @@ -2140,6 +2209,23 @@ "node": ">= 0.8" } }, + "node_modules/commander": { + "version": "13.1.0", + "resolved": "https://registry.npmjs.org/commander/-/commander-13.1.0.tgz", + "integrity": "sha512-/rFeCpNJQbhSZjGVwO9RFV3xPqbnERS8MmIQzCtD/zl6gpJuV/bMLuN92oG3F7d8oDEHHRrujSXNUr8fpjntKw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=18" + } + }, + "node_modules/commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha512-W9pAhw0ja1Edb5GVdIF1mjZw/ASI0AlShXM83UUGe2DVr5TdAPEA1OA8m/g8zWp9x6On7gqufY+FatDbC3MDQg==", + "dev": true, + "license": "MIT" + }, "node_modules/concat-map": { "version": "0.0.1", "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", @@ -2372,6 +2458,19 @@ "node": "^14.15.0 || ^16.10.0 || >=18.0.0" } }, + "node_modules/dir-glob": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/dir-glob/-/dir-glob-3.0.1.tgz", + "integrity": "sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA==", + "dev": true, + "license": "MIT", + "dependencies": { + "path-type": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/doctrine": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-2.1.0.tgz", @@ -2400,6 +2499,13 @@ "dev": true, "license": "ISC" }, + "node_modules/email-addresses": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/email-addresses/-/email-addresses-5.0.0.tgz", + "integrity": "sha512-4OIPYlA6JXqtVn8zpHpGiI7vE6EQOAg16aGnDMIAlZVinnoZ8208tW1hAbjWydgN/4PLTT9q+O1K6AH/vALJGw==", + "dev": true, + "license": "MIT" + }, "node_modules/entities": { "version": "4.5.0", "resolved": "https://registry.npmjs.org/entities/-/entities-4.5.0.tgz", @@ -2876,6 +2982,36 @@ "dev": true, "license": "MIT" }, + "node_modules/fast-glob": { + "version": "3.3.3", + "resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.3.tgz", + "integrity": "sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "@nodelib/fs.stat": "^2.0.2", + "@nodelib/fs.walk": "^1.2.3", + "glob-parent": "^5.1.2", + "merge2": "^1.3.0", + "micromatch": "^4.0.8" + }, + "engines": { + "node": ">=8.6.0" + } + }, + "node_modules/fast-glob/node_modules/glob-parent": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz", + "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==", + "dev": true, + "license": "ISC", + "dependencies": { + "is-glob": "^4.0.1" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -2890,6 +3026,16 @@ "dev": true, "license": "MIT" }, + "node_modules/fastq": { + "version": "1.19.1", + "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.19.1.tgz", + "integrity": "sha512-GwLTyxkCXjXbxqIhTsMI2Nui8huMPtnxg7krajPJAjnEG/iiOS7i+zCtWGZR9G0NBKbXKh6X9m9UIsYX/N6vvQ==", + "dev": true, + "license": "ISC", + "dependencies": { + "reusify": "^1.0.4" + } + }, "node_modules/file-entry-cache": { "version": "8.0.0", "resolved": "https://registry.npmjs.org/file-entry-cache/-/file-entry-cache-8.0.0.tgz", @@ -2903,6 +3049,65 @@ "node": ">=16.0.0" } }, + "node_modules/filename-reserved-regex": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/filename-reserved-regex/-/filename-reserved-regex-2.0.0.tgz", + "integrity": "sha512-lc1bnsSr4L4Bdif8Xb/qrtokGbq5zlsms/CYH8PP+WtCkGNF65DPiQY8vG3SakEdRn8Dlnm+gW/qWKKjS5sZzQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=4" + } + }, + "node_modules/filenamify": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/filenamify/-/filenamify-4.3.0.tgz", + "integrity": "sha512-hcFKyUG57yWGAzu1CMt/dPzYZuv+jAJUT85bL8mrXvNe6hWj6yEHEc4EdcgiA6Z3oi1/9wXJdZPXF2dZNgwgOg==", + "dev": true, + "license": "MIT", + "dependencies": { + "filename-reserved-regex": "^2.0.0", + "strip-outer": "^1.0.1", + "trim-repeated": "^1.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/fill-range": { + "version": "7.1.1", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz", + "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==", + "dev": true, + "license": "MIT", + "dependencies": { + "to-regex-range": "^5.0.1" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/find-cache-dir": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-3.3.2.tgz", + "integrity": "sha512-wXZV5emFEjrridIgED11OoUKLxiYjAcqot/NJdAkOhlJ+vGzwhOAfcG5OX1jP+S0PcjEn8bdMJv+g2jwQ3Onig==", + "dev": true, + "license": "MIT", + "dependencies": { + "commondir": "^1.0.1", + "make-dir": "^3.0.2", + "pkg-dir": "^4.1.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/avajs/find-cache-dir?sponsor=1" + } + }, "node_modules/find-up": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/find-up/-/find-up-5.0.0.tgz", @@ -2966,6 +3171,21 @@ "node": ">= 6" } }, + "node_modules/fs-extra": { + "version": "11.3.0", + "resolved": "https://registry.npmjs.org/fs-extra/-/fs-extra-11.3.0.tgz", + "integrity": "sha512-Z4XaCL6dUDHfP/jT25jJKMmtxvuwbkrD1vNSMFlo9lNLY2c5FHYSQgHPRZUjAB26TpDEoW9HCOgplrdbaPV/ew==", + "dev": true, + "license": "MIT", + "dependencies": { + "graceful-fs": "^4.2.0", + "jsonfile": "^6.0.1", + "universalify": "^2.0.0" + }, + "engines": { + "node": ">=14.14" + } + }, "node_modules/fsevents": { "version": "2.3.3", "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz", @@ -3068,6 +3288,29 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/gh-pages": { + "version": "6.3.0", + "resolved": "https://registry.npmjs.org/gh-pages/-/gh-pages-6.3.0.tgz", + "integrity": "sha512-Ot5lU6jK0Eb+sszG8pciXdjMXdBJ5wODvgjR+imihTqsUWF2K6dJ9HST55lgqcs8wWcw6o6wAsUzfcYRhJPXbA==", + "dev": true, + "license": "MIT", + "dependencies": { + "async": "^3.2.4", + "commander": "^13.0.0", + "email-addresses": "^5.0.0", + "filenamify": "^4.3.0", + "find-cache-dir": "^3.3.1", + "fs-extra": "^11.1.1", + "globby": "^11.1.0" + }, + "bin": { + "gh-pages": "bin/gh-pages.js", + "gh-pages-clean": "bin/gh-pages-clean.js" + }, + "engines": { + "node": ">=10" + } + }, "node_modules/glob-parent": { "version": "6.0.2", "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz", @@ -3111,6 +3354,27 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/globby": { + "version": "11.1.0", + "resolved": "https://registry.npmjs.org/globby/-/globby-11.1.0.tgz", + "integrity": "sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g==", + "dev": true, + "license": "MIT", + "dependencies": { + "array-union": "^2.1.0", + "dir-glob": "^3.0.1", + "fast-glob": "^3.2.9", + "ignore": "^5.2.0", + "merge2": "^1.4.1", + "slash": "^3.0.0" + }, + "engines": { + "node": ">=10" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, "node_modules/gopd": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz", @@ -3124,6 +3388,13 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/graceful-fs": { + "version": "4.2.11", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz", + "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==", + "dev": true, + "license": "ISC" + }, "node_modules/has-bigints": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz", @@ -3530,6 +3801,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/is-number": { + "version": "7.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz", + "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.12.0" + } + }, "node_modules/is-number-object": { "version": "1.0.7", "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz", @@ -3911,6 +4192,19 @@ "node": ">=6" } }, + "node_modules/jsonfile": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/jsonfile/-/jsonfile-6.1.0.tgz", + "integrity": "sha512-5dgndWOriYSm5cnYaJNhalLNDKOqFwyDB/rr1E9ZsGciGvKPs8R2xYGCacuf3z6K1YKDz182fd+fY3cn3pMqXQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "universalify": "^2.0.0" + }, + "optionalDependencies": { + "graceful-fs": "^4.1.6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -4040,6 +4334,46 @@ "@jridgewell/sourcemap-codec": "^1.5.0" } }, + "node_modules/make-dir": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-3.1.0.tgz", + "integrity": "sha512-g3FeP20LNwhALb/6Cz6Dd4F2ngze0jz7tbzrD2wAV+o9FeNHe4rL+yK2md0J/fiSf1sa1ADhXqi5+oVwOM/eGw==", + "dev": true, + "license": "MIT", + "dependencies": { + "semver": "^6.0.0" + }, + "engines": { + "node": ">=8" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/merge2": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/merge2/-/merge2-1.4.1.tgz", + "integrity": "sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 8" + } + }, + "node_modules/micromatch": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz", + "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==", + "dev": true, + "license": "MIT", + "dependencies": { + "braces": "^3.0.3", + "picomatch": "^2.3.1" + }, + "engines": { + "node": ">=8.6" + } + }, "node_modules/mime-db": { "version": "1.52.0", "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", @@ -4287,6 +4621,16 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=6" + } + }, "node_modules/parent-module": { "version": "1.0.1", "resolved": "https://registry.npmjs.org/parent-module/-/parent-module-1.0.1.tgz", @@ -4340,6 +4684,16 @@ "dev": true, "license": "MIT" }, + "node_modules/path-type": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-4.0.0.tgz", + "integrity": "sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/pathe": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/pathe/-/pathe-1.1.2.tgz", @@ -4364,6 +4718,88 @@ "dev": true, "license": "ISC" }, + "node_modules/picomatch": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz", + "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8.6" + }, + "funding": { + "url": "https://github.com/sponsors/jonschlinkert" + } + }, + "node_modules/pkg-dir": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-4.2.0.tgz", + "integrity": "sha512-HRDzbaKjC+AOWVXxAU/x54COGeIv9eb+6CkDSQoNTt4XyWoIJvuPsXizxu/Fr23EiekbtZwmh1IcIG/l/a10GQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "find-up": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/find-up": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-4.1.0.tgz", + "integrity": "sha512-PpOwAdQ/YlXQ2vj8a3h8IipDuYRi3wceVQQGYWxNINccq40Anw7BlsEXCMbt1Zt+OLA6Fq9suIpIWD0OsnISlw==", + "dev": true, + "license": "MIT", + "dependencies": { + "locate-path": "^5.0.0", + "path-exists": "^4.0.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/locate-path": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-5.0.0.tgz", + "integrity": "sha512-t7hw9pI+WvuwNJXwk5zVHpyhIqzg2qTlklJOf0mVxGSbe3Fp2VieZcduNYjaLDoy6p9uGpQEGWG87WpMKlNq8g==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-locate": "^4.1.0" + }, + "engines": { + "node": ">=8" + } + }, + "node_modules/pkg-dir/node_modules/p-limit": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.3.0.tgz", + "integrity": "sha512-//88mFWSJx8lxCzwdAABTJL2MyWB12+eIY7MDL2SqLmAkeKU9qxRvWuSyTjm3FUmpBEMuFfckAIqEaVGUDxb6w==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-try": "^2.0.0" + }, + "engines": { + "node": ">=6" + }, + "funding": { + "url": "https://github.com/sponsors/sindresorhus" + } + }, + "node_modules/pkg-dir/node_modules/p-locate": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-4.1.0.tgz", + "integrity": "sha512-R79ZZ/0wAxKGu3oYMlz8jy/kbhsNrS7SKZ7PxEHBgJ5+F2mtFW2fK2cOtBh1cHYkQsbzFV7I+EoRKe6Yt0oK7A==", + "dev": true, + "license": "MIT", + "dependencies": { + "p-limit": "^2.2.0" + }, + "engines": { + "node": ">=8" + } + }, "node_modules/possible-typed-array-names": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz", @@ -4472,6 +4908,27 @@ "node": ">=6" } }, + "node_modules/queue-microtask": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/queue-microtask/-/queue-microtask-1.2.3.tgz", + "integrity": "sha512-NuaNSa6flKT5JaSYQzJok04JzTL1CA6aGhv5rfLW3PgqA+M2ChpZQnAC8h8i4ZFkBS8X5RqkDBHA7r4hej3K9A==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT" + }, "node_modules/react": { "version": "18.3.1", "resolved": "https://registry.npmjs.org/react/-/react-18.3.1.tgz", @@ -4605,6 +5062,17 @@ "node": ">=4" } }, + "node_modules/reusify": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.1.0.tgz", + "integrity": "sha512-g6QUff04oZpHs0eG5p83rFLhHeV00ug/Yf9nZM6fLeUrPguBTkTQOdpAWWspMh55TZfVQDPaN3NQJfbVRAxdIw==", + "dev": true, + "license": "MIT", + "engines": { + "iojs": ">=1.0.0", + "node": ">=0.10.0" + } + }, "node_modules/rollup": { "version": "4.24.0", "resolved": "https://registry.npmjs.org/rollup/-/rollup-4.24.0.tgz", @@ -4648,6 +5116,30 @@ "dev": true, "license": "MIT" }, + "node_modules/run-parallel": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/run-parallel/-/run-parallel-1.2.0.tgz", + "integrity": "sha512-5l4VyZR86LZ/lDxZTR6jqL8AFE2S0IFLMP26AbjsLVADxHdhB/c0GUsH+y39UfCi3dzz8OlQuPmnaJOMoDHQBA==", + "dev": true, + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ], + "license": "MIT", + "dependencies": { + "queue-microtask": "^1.2.2" + } + }, "node_modules/safe-array-concat": { "version": "1.1.2", "resolved": "https://registry.npmjs.org/safe-array-concat/-/safe-array-concat-1.1.2.tgz", @@ -4807,6 +5299,16 @@ "dev": true, "license": "ISC" }, + "node_modules/slash": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/slash/-/slash-3.0.0.tgz", + "integrity": "sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=8" + } + }, "node_modules/source-map-js": { "version": "1.2.1", "resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz", @@ -4947,6 +5449,29 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/strip-outer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-outer/-/strip-outer-1.0.1.tgz", + "integrity": "sha512-k55yxKHwaXnpYGsOzg4Vl8+tDrWylxDEpknGjhTiZB8dFRU5rTo9CAzeycivxV3s+zlTKwrs6WxMxR95n26kwg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/strip-outer/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/supports-color": { "version": "7.2.0", "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz", @@ -5061,6 +5586,19 @@ "node": ">=4" } }, + "node_modules/to-regex-range": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz", + "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==", + "dev": true, + "license": "MIT", + "dependencies": { + "is-number": "^7.0.0" + }, + "engines": { + "node": ">=8.0" + } + }, "node_modules/tough-cookie": { "version": "5.0.0", "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-5.0.0.tgz", @@ -5087,6 +5625,29 @@ "node": ">=18" } }, + "node_modules/trim-repeated": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-repeated/-/trim-repeated-1.0.0.tgz", + "integrity": "sha512-pkonvlKk8/ZuR0D5tLW8ljt5I8kmxp2XKymhepUeOdCEfKpZaktSArkLHZt76OB1ZvO9bssUsDty4SWhLvZpLg==", + "dev": true, + "license": "MIT", + "dependencies": { + "escape-string-regexp": "^1.0.2" + }, + "engines": { + "node": ">=0.10.0" + } + }, + "node_modules/trim-repeated/node_modules/escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">=0.8.0" + } + }, "node_modules/type-check": { "version": "0.4.0", "resolved": "https://registry.npmjs.org/type-check/-/type-check-0.4.0.tgz", @@ -5193,6 +5754,16 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/universalify": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/universalify/-/universalify-2.0.1.tgz", + "integrity": "sha512-gptHNQghINnc/vTGIk0SOFGFNXw7JVrlRUtConJRlvaw6DuX0wO5Jeko9sWrMBhh+PsYAZ7oXAiOnf/UKogyiw==", + "dev": true, + "license": "MIT", + "engines": { + "node": ">= 10.0.0" + } + }, "node_modules/update-browserslist-db": { "version": "1.1.1", "resolved": "https://registry.npmjs.org/update-browserslist-db/-/update-browserslist-db-1.1.1.tgz", diff --git a/package.json b/package.json index 1a053dda4..0cb2f8a77 100644 --- a/package.json +++ b/package.json @@ -3,12 +3,15 @@ "private": true, "version": "0.0.0", "type": "module", + "homepage": "https://wendyww9.github.io/react-chatlog/", "scripts": { "dev": "vite", "build": "vite build", "lint": "eslint . --report-unused-disable-directives --max-warnings 0", "preview": "vite preview", - "test": "vitest --run" + "test": "vitest --run", + "predeploy": "npm run build && cp build/index.html build/404.html", + "deploy": "gh-pages -d build" }, "dependencies": { "luxon": "^2.5.2", @@ -30,6 +33,7 @@ "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.12", "eslint-plugin-vitest-globals": "^1.5.0", + "gh-pages": "^6.3.0", "globals": "^15.11.0", "jest-extended": "^4.0.2", "jsdom": "^25.0.1", diff --git a/vite.config.js b/vite.config.js index 2e8881a23..60862b5e8 100644 --- a/vite.config.js +++ b/vite.config.js @@ -11,4 +11,8 @@ export default defineConfig({ globals: true, setupFiles: ['./vitest.setup.js'], }, -}) \ No newline at end of file + base: '/react-chatlog/', + build: { + outDir: 'build', // Or 'dist' if you've changed the default + }, +}); \ No newline at end of file From f7196679bf6ae221fc4c0412ead08df59dac44f9 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Mon, 16 Jun 2025 00:48:54 -0700 Subject: [PATCH 13/14] Fix test files to include required props and function --- src/components/ChatEntry.test.jsx | 2 ++ src/components/ChatLog.test.jsx | 4 ++-- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/ChatEntry.test.jsx b/src/components/ChatEntry.test.jsx index 85eff9256..42d58e9e0 100644 --- a/src/components/ChatEntry.test.jsx +++ b/src/components/ChatEntry.test.jsx @@ -11,6 +11,8 @@ describe('Wave 01: ChatEntry', () => { body="Get out by 8am. I'll count the silverware" timeStamp="2018-05-18T22:12:03Z" liked={false} + onLike={() => {}} + position="local" /> ); }); diff --git a/src/components/ChatLog.test.jsx b/src/components/ChatLog.test.jsx index dfcfeda99..db5dd6777 100644 --- a/src/components/ChatLog.test.jsx +++ b/src/components/ChatLog.test.jsx @@ -42,7 +42,7 @@ const LOG = [ describe('Wave 02: ChatLog', () => { beforeEach(() => { - render(); + render( {}} uniqueSenders={[]}/>); }); test('renders without crashing and shows all the names', () => { @@ -66,7 +66,7 @@ describe('Wave 02: ChatLog', () => { }); test('renders an empty list without crashing', () => { - const element = render(); + const element = render( {}} uniqueSenders={[]}/>); expect(element).not.toBeNull(); }); }); From 4d466809d0ddc5bc94e7388ba1f85b116b08dbc1 Mon Sep 17 00:00:00 2001 From: wendyww9 Date: Thu, 19 Jun 2025 11:20:44 -0700 Subject: [PATCH 14/14] Refactor code to be more semantic and more clear --- src/App.jsx | 47 ++++++++++++++++++------------------ src/components/ChatEntry.jsx | 4 +-- src/components/ChatLog.jsx | 21 ++++++++-------- 3 files changed, 35 insertions(+), 37 deletions(-) diff --git a/src/App.jsx b/src/App.jsx index 7c86ba534..8710698a3 100644 --- a/src/App.jsx +++ b/src/App.jsx @@ -3,36 +3,31 @@ import chatMessages from './data/messages.json'; import ChatLog from './components/ChatLog.jsx'; import { useState } from 'react'; -const getLikeCount = (data) => { - return data.filter(chat => chat.liked).length; -}; - -const extractUniqueSenders = (chatLog) => { - const uniqueSenders = []; - - for (const message of chatLog) { - if (!uniqueSenders.includes(message.sender)) { - uniqueSenders.push(message.sender); - } - } - - return uniqueSenders; -}; - const App = () => { const [chatData, setChatData] = useState(chatMessages); - const chatLiked = (id) => { + const setChatLiked = (id) => { setChatData(chatData => { return chatData.map(chat => { - if (chat.id === id) { - return {...chat, liked: !chat.liked}; - } else { - return chat; - } + return (chat.id === id) ? { ...chat, liked: !chat.liked } : chat; }); }); }; + const likeCount = chatData.reduce((totalLikes, currentChat) => { + return totalLikes + (currentChat.liked ? 1 : 0); + }, 0); + + const extractUniqueSenders = (chatLog) => { + const uniqueSenders = []; + + for (const message of chatLog) { + if (!uniqueSenders.includes(message.sender)) { + uniqueSenders.push(message.sender); + } + } + + return uniqueSenders; + }; const uniqueSenders = extractUniqueSenders(chatData); return ( @@ -40,11 +35,15 @@ const App = () => {

    {`Chat between ${uniqueSenders[0]} and ${uniqueSenders[1]}`}

    - {getLikeCount(chatData)} ❤️s +

    {likeCount} ❤️s

    - +
    ); diff --git a/src/components/ChatEntry.jsx b/src/components/ChatEntry.jsx index 16108935a..a27d92b75 100644 --- a/src/components/ChatEntry.jsx +++ b/src/components/ChatEntry.jsx @@ -8,7 +8,7 @@ const ChatEntry = (props) => { const nameColor = props.liked ? '❤️' : '🤍'; return ( -
    +
  • {props.sender}

    {props.body}

    @@ -17,7 +17,7 @@ const ChatEntry = (props) => {

    -
  • + ); }; diff --git a/src/components/ChatLog.jsx b/src/components/ChatLog.jsx index a26a6cf18..7b8cbe541 100644 --- a/src/components/ChatLog.jsx +++ b/src/components/ChatLog.jsx @@ -10,17 +10,16 @@ const ChatLog = ({entries, onLike, uniqueSenders}) => { const chatEntryComponents = entries.map((entry) => { return ( -
  • - - -
  • + + ); });