changed from input to textbox to keep text formatting, added daisyUI, refactored dropdown menu
This commit is contained in:
@@ -1,12 +1,15 @@
|
|||||||
import { sendMessage } from '../../socket/socket.tsx';
|
import { sendMessage } from '../../socket/socket.tsx';
|
||||||
import { useForm, SubmitHandler } from 'react-hook-form';
|
import { useForm, SubmitHandler } from 'react-hook-form';
|
||||||
|
|
||||||
type Input = {
|
type Input = {
|
||||||
message: string;
|
message: string;
|
||||||
};
|
};
|
||||||
|
|
||||||
type MessaFormProps = {
|
type MessaFormProps = {
|
||||||
contact: string;
|
contact: string;
|
||||||
};
|
};
|
||||||
function messageForm({ contact }: MessaFormProps) {
|
|
||||||
|
function MessageForm({ contact }: MessaFormProps) {
|
||||||
const {
|
const {
|
||||||
register,
|
register,
|
||||||
handleSubmit,
|
handleSubmit,
|
||||||
@@ -17,46 +20,59 @@ function messageForm({ contact }: MessaFormProps) {
|
|||||||
// Sending message
|
// Sending message
|
||||||
const submitMessage: SubmitHandler<Input> = (data) => {
|
const submitMessage: SubmitHandler<Input> = (data) => {
|
||||||
console.log(contact);
|
console.log(contact);
|
||||||
// block sending empty message
|
|
||||||
|
// Block sending empty message
|
||||||
if (!data.message) {
|
if (!data.message) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
// for (let i = 0; i <= 200; i++) {
|
|
||||||
// let ii = i.toString();
|
|
||||||
// sendMessage(ii, contact);
|
|
||||||
// }
|
|
||||||
sendMessage(data.message, contact);
|
|
||||||
|
|
||||||
|
sendMessage(data.message, contact);
|
||||||
reset({ message: '' });
|
reset({ message: '' });
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const adjustSize = (event) => {
|
||||||
|
const textarea = event.target;
|
||||||
|
|
||||||
|
// Adjust height
|
||||||
|
textarea.style.height = 'auto';
|
||||||
|
const maxHeight = 500;
|
||||||
|
|
||||||
|
if (textarea.scrollHeight > maxHeight) {
|
||||||
|
textarea.style.height = `${maxHeight}px`;
|
||||||
|
textarea.style.overflowY = 'auto';
|
||||||
|
} else {
|
||||||
|
textarea.style.height = `${textarea.scrollHeight}px`;
|
||||||
|
textarea.style.overflowY = 'hidden';
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<>
|
<form onSubmit={handleSubmit(submitMessage)}>
|
||||||
<form onSubmit={handleSubmit(submitMessage)}>
|
<div className="flex items-end">
|
||||||
<div className="flex">
|
<textarea
|
||||||
<input
|
className="resize-none overflow-y-hidden bg-green-50 text-black rounded-md w-full ml-1 mr-1 size-10"
|
||||||
className=" bg-green-50 text-black rounded-md w-full ml-1 mr-1 size-10"
|
autoFocus={!!contact}
|
||||||
type="text"
|
disabled={!contact}
|
||||||
autoFocus={!!contact}
|
placeholder="Enter message"
|
||||||
disabled={!contact}
|
onInput={adjustSize}
|
||||||
placeholder="Enter message"
|
rows={1}
|
||||||
{...register('message', {
|
{...register('message', {
|
||||||
maxLength: 500,
|
maxLength: 2000,
|
||||||
minLength: 1,
|
minLength: 1,
|
||||||
})}
|
})}
|
||||||
/>
|
/>
|
||||||
{errors?.message?.type === 'maxLength' && (
|
{errors?.message?.type === 'maxLength' && (
|
||||||
<p>Maximum length of the message is 500</p>
|
<p>Maximum length of the message is 2000</p>
|
||||||
)}
|
)}
|
||||||
<button
|
<button
|
||||||
className="text-black bg-green-500 hover:bg-green-400 font-bold py-2 px-4 rounded mr-1 w-24 "
|
className="text-black bg-green-500 hover:bg-green-400 font-bold py-2 px-4 rounded mr-1 w-24"
|
||||||
type="submit"
|
type="submit"
|
||||||
>
|
>
|
||||||
Send
|
Send
|
||||||
</button>
|
</button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</>
|
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
export default messageForm;
|
|
||||||
|
export default MessageForm;
|
||||||
|
|||||||
@@ -126,14 +126,17 @@ function MessagesArea({
|
|||||||
}, [messages]);
|
}, [messages]);
|
||||||
|
|
||||||
const messageList = messages.map((msg: ChatMessages) => (
|
const messageList = messages.map((msg: ChatMessages) => (
|
||||||
<li className="ml-2 rounded p-1 hover:bg-gray-800" key={msg.message_id}>
|
<li
|
||||||
|
className="whitespace-pre-wrap ml-2 rounded p-1 hover:bg-gray-800"
|
||||||
|
key={msg.message_id}
|
||||||
|
>
|
||||||
{msg.message_id} {msg.sender}: {msg.message}
|
{msg.message_id} {msg.sender}: {msg.message}
|
||||||
</li>
|
</li>
|
||||||
));
|
));
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div ref={containerRef} className="flex flex-col h-full overflow-y-auto">
|
<div ref={containerRef} className="flex flex-col h-full overflow-y-auto">
|
||||||
<p className="text-center text-gray-400">{errorMessage}</p>
|
<p className=" text-center text-gray-400">{errorMessage}</p>
|
||||||
<ul className="flex-grow list-none">
|
<ul className="flex-grow list-none">
|
||||||
{isLoading ? <LoadingWheel /> : null}
|
{isLoading ? <LoadingWheel /> : null}
|
||||||
{messageList}
|
{messageList}
|
||||||
|
|||||||
@@ -3,58 +3,49 @@ import logoutIcon from '../../../assets/logout.svg';
|
|||||||
import Cookies from 'js-cookie';
|
import Cookies from 'js-cookie';
|
||||||
import { useOutletContext } from 'react-router-dom';
|
import { useOutletContext } from 'react-router-dom';
|
||||||
import { UsernameType } from '../../utils/ProtectedRoutes.tsx';
|
import { UsernameType } from '../../utils/ProtectedRoutes.tsx';
|
||||||
import { useState } from 'react';
|
|
||||||
|
|
||||||
function UserProfile() {
|
function UserProfile() {
|
||||||
const { username }: UsernameType = useOutletContext();
|
const { username }: UsernameType = useOutletContext();
|
||||||
const [isOpen, setIsOpen] = useState(false);
|
|
||||||
|
|
||||||
const toggleDropdown = () => {
|
|
||||||
setIsOpen(!isOpen);
|
|
||||||
};
|
|
||||||
|
|
||||||
function logout() {
|
function logout() {
|
||||||
Cookies.remove('token');
|
Cookies.remove('token');
|
||||||
window.location.reload();
|
window.location.reload();
|
||||||
}
|
}
|
||||||
return (
|
return (
|
||||||
<div className="relative inline-block">
|
<div className="dropdown dropdown-top">
|
||||||
<div
|
<div
|
||||||
className="flex items-center cursor-pointer hs-dropdown-toggle"
|
tabIndex={0}
|
||||||
onClick={toggleDropdown}
|
className="flex items-center cursor-pointer"
|
||||||
|
role="button"
|
||||||
>
|
>
|
||||||
<div className="flex items-center justify-center m-3 w-12 h-12 overflow-hidden">
|
<div className="flex items-center justify-center m-3 w-12 h-12 overflow-hidden">
|
||||||
<img src={zdjecie} alt="Profile image" className="w-8 h-8 invert" />
|
<img src={zdjecie} alt="Profile image" className="w-8 h-8 invert" />
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div className="text-gray-200">
|
<div className="text-gray-200">
|
||||||
<p>{username}</p>
|
<p>{username}</p>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{isOpen && (
|
<ul
|
||||||
<div className="absolute bottom-full left-0 mb-2 w-48 rounded-md shadow-lg bg-white ring-1 ring-black ring-opacity-5">
|
tabIndex={0}
|
||||||
<div
|
className="m-2 dropdown-content menu p-2 shadow bg-gray-50 rounded-md w-52"
|
||||||
className="py-1"
|
>
|
||||||
role="menu"
|
<li>
|
||||||
aria-orientation="vertical"
|
<a
|
||||||
aria-labelledby="options-menu"
|
className="flex items-center px-4 py-2 text-sm text-black hover:bg-gray-200"
|
||||||
|
onClick={logout}
|
||||||
>
|
>
|
||||||
<a
|
<img
|
||||||
className="bg-green-50 cursor-pointer px-4 py-2 text-sm text-gray-700 hover:bg-gray-100 hover:text-gray-900 flex"
|
className="w-5 mr-2"
|
||||||
role="menuitem"
|
draggable={false}
|
||||||
onClick={logout}
|
src={logoutIcon}
|
||||||
>
|
alt="Log out icon"
|
||||||
<img
|
/>
|
||||||
className="w-5 mr-2"
|
<p>Log out</p>
|
||||||
draggable={false}
|
</a>
|
||||||
src={logoutIcon}
|
</li>
|
||||||
alt="log out ico"
|
</ul>
|
||||||
/>
|
|
||||||
<p>Log out</p>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
</div>
|
</div>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,12 +1,21 @@
|
|||||||
|
import daisyui from 'daisyui';
|
||||||
|
|
||||||
/** @type {import('tailwindcss').Config} */
|
/** @type {import('tailwindcss').Config} */
|
||||||
export default {
|
export default {
|
||||||
content: [
|
content: [
|
||||||
"./index.html",
|
'./index.html',
|
||||||
"./src/**/*.{js,ts,jsx,tsx}",
|
'./src/**/*.{js,ts,jsx,tsx}',
|
||||||
"node_modules/preline/dist/*.js",
|
'node_modules/preline/dist/*.js',
|
||||||
],
|
],
|
||||||
theme: {
|
theme: {
|
||||||
extend: {},
|
extend: {},
|
||||||
},
|
},
|
||||||
plugins: [require("@tailwindcss/forms"), require("preline/plugin")],
|
daisyui: {
|
||||||
|
themes: [],
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
require('@tailwindcss/forms'),
|
||||||
|
require('preline/plugin'),
|
||||||
|
require('daisyui'),
|
||||||
|
],
|
||||||
};
|
};
|
||||||
|
|||||||
162
package-lock.json
generated
162
package-lock.json
generated
@@ -8,7 +8,8 @@
|
|||||||
"name": "relay",
|
"name": "relay",
|
||||||
"version": "0.0.1",
|
"version": "0.0.1",
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.0.1"
|
"concurrently": "^9.0.1",
|
||||||
|
"daisyui": "^4.12.14"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/ansi-regex": {
|
"node_modules/ansi-regex": {
|
||||||
@@ -37,6 +38,16 @@
|
|||||||
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
"url": "https://github.com/chalk/ansi-styles?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/camelcase-css": {
|
||||||
|
"version": "2.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/camelcase-css/-/camelcase-css-2.0.1.tgz",
|
||||||
|
"integrity": "sha512-QOSvevhslijgYwRx6Rv7zKdMF8lbRmx+uQGx2+vDc+KI/eBnsy9kit5aj23AgGu3pa4t9AgwbnXWqS+iOY+2aA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": ">= 6"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/chalk": {
|
"node_modules/chalk": {
|
||||||
"version": "4.1.2",
|
"version": "4.1.2",
|
||||||
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
"resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
|
||||||
@@ -128,6 +139,60 @@
|
|||||||
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
"url": "https://github.com/open-cli-tools/concurrently?sponsor=1"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/css-selector-tokenizer": {
|
||||||
|
"version": "0.8.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/css-selector-tokenizer/-/css-selector-tokenizer-0.8.0.tgz",
|
||||||
|
"integrity": "sha512-Jd6Ig3/pe62/qe5SBPTN8h8LeUg/pT4lLgtavPf7updwwHpvFzxvOQBHYj2LZDMjUnBzgvIUSjRcf6oT5HzHFg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"cssesc": "^3.0.0",
|
||||||
|
"fastparse": "^1.1.2"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/cssesc": {
|
||||||
|
"version": "3.0.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/cssesc/-/cssesc-3.0.0.tgz",
|
||||||
|
"integrity": "sha512-/Tb/JcjK111nNScGob5MNtsntNM1aCNUDipB/TkwZFhyDrrE47SOx/18wF2bbjgc3ZzCSKW1T5nt5EbFoAz/Vg==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"bin": {
|
||||||
|
"cssesc": "bin/cssesc"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=4"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/culori": {
|
||||||
|
"version": "3.3.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/culori/-/culori-3.3.0.tgz",
|
||||||
|
"integrity": "sha512-pHJg+jbuFsCjz9iclQBqyL3B2HLCBF71BwVNujUYEvCeQMvV97R59MNK3R2+jgJ3a1fcZgI9B3vYgz8lzr/BFQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^12.20.0 || ^14.13.1 || >=16.0.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/daisyui": {
|
||||||
|
"version": "4.12.14",
|
||||||
|
"resolved": "https://registry.npmjs.org/daisyui/-/daisyui-4.12.14.tgz",
|
||||||
|
"integrity": "sha512-hA27cdBasdwd4/iEjn+aidoCrRroDuo3G5W9NDKaVCJI437Mm/3eSL/2u7MkZ0pt8a+TrYF3aT2pFVemTS3how==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"css-selector-tokenizer": "^0.8",
|
||||||
|
"culori": "^3",
|
||||||
|
"picocolors": "^1",
|
||||||
|
"postcss-js": "^4"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": ">=16.9.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/daisyui"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/emoji-regex": {
|
"node_modules/emoji-regex": {
|
||||||
"version": "8.0.0",
|
"version": "8.0.0",
|
||||||
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
"resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
|
||||||
@@ -145,6 +210,13 @@
|
|||||||
"node": ">=6"
|
"node": ">=6"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/fastparse": {
|
||||||
|
"version": "1.1.2",
|
||||||
|
"resolved": "https://registry.npmjs.org/fastparse/-/fastparse-1.1.2.tgz",
|
||||||
|
"integrity": "sha512-483XLLxTVIwWK3QTrMGRqUfUpoOs/0hbQrl2oz4J0pAcm3A3bu84wxTFqGqkJzewCLdME38xJLJAxBABfQT8sQ==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT"
|
||||||
|
},
|
||||||
"node_modules/get-caller-file": {
|
"node_modules/get-caller-file": {
|
||||||
"version": "2.0.5",
|
"version": "2.0.5",
|
||||||
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
"resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
|
||||||
@@ -182,6 +254,83 @@
|
|||||||
"dev": true,
|
"dev": true,
|
||||||
"license": "MIT"
|
"license": "MIT"
|
||||||
},
|
},
|
||||||
|
"node_modules/nanoid": {
|
||||||
|
"version": "3.3.7",
|
||||||
|
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.7.tgz",
|
||||||
|
"integrity": "sha512-eSRppjcPIatRIMC1U6UngP8XFcz8MQWGQdt1MTBQ7NaAmvXDfvNxbvWV3x2y6CdEUciCSsDHDQZbhYaB8QEo2g==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"bin": {
|
||||||
|
"nanoid": "bin/nanoid.cjs"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/picocolors": {
|
||||||
|
"version": "1.1.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/picocolors/-/picocolors-1.1.1.tgz",
|
||||||
|
"integrity": "sha512-xceH2snhtb5M9liqDsmEw56le376mTZkEX/jEb/RxNFyegNul7eNslCXP9FDj/Lcu0X8KEyMceP2ntpaHrDEVA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "ISC"
|
||||||
|
},
|
||||||
|
"node_modules/postcss": {
|
||||||
|
"version": "8.4.49",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss/-/postcss-8.4.49.tgz",
|
||||||
|
"integrity": "sha512-OCVPnIObs4N29kxTjzLfUryOkvZEq+pf8jTF0lg8E7uETuWHA+v7j3c/xJmiqpX450191LlmZfUKkXxkTry7nA==",
|
||||||
|
"dev": true,
|
||||||
|
"funding": [
|
||||||
|
{
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "tidelift",
|
||||||
|
"url": "https://tidelift.com/funding/github/npm/postcss"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"type": "github",
|
||||||
|
"url": "https://github.com/sponsors/ai"
|
||||||
|
}
|
||||||
|
],
|
||||||
|
"license": "MIT",
|
||||||
|
"peer": true,
|
||||||
|
"dependencies": {
|
||||||
|
"nanoid": "^3.3.7",
|
||||||
|
"picocolors": "^1.1.1",
|
||||||
|
"source-map-js": "^1.2.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^10 || ^12 || >=14"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
"node_modules/postcss-js": {
|
||||||
|
"version": "4.0.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/postcss-js/-/postcss-js-4.0.1.tgz",
|
||||||
|
"integrity": "sha512-dDLF8pEO191hJMtlHFPRa8xsizHaM82MLfNkUHdUtVEV3tgTp5oj+8qbEqYM57SLfc74KSbw//4SeJma2LRVIw==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "MIT",
|
||||||
|
"dependencies": {
|
||||||
|
"camelcase-css": "^2.0.1"
|
||||||
|
},
|
||||||
|
"engines": {
|
||||||
|
"node": "^12 || ^14 || >= 16"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"type": "opencollective",
|
||||||
|
"url": "https://opencollective.com/postcss/"
|
||||||
|
},
|
||||||
|
"peerDependencies": {
|
||||||
|
"postcss": "^8.4.21"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/require-directory": {
|
"node_modules/require-directory": {
|
||||||
"version": "2.1.1",
|
"version": "2.1.1",
|
||||||
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
"resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
|
||||||
@@ -212,6 +361,17 @@
|
|||||||
"url": "https://github.com/sponsors/ljharb"
|
"url": "https://github.com/sponsors/ljharb"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/source-map-js": {
|
||||||
|
"version": "1.2.1",
|
||||||
|
"resolved": "https://registry.npmjs.org/source-map-js/-/source-map-js-1.2.1.tgz",
|
||||||
|
"integrity": "sha512-UXWMKhLOwVKb728IUtQPXxfYU+usdybtUrK/8uGE8CQMvrhOpwvzDBwj0QhSL7MQc7vIsISBG8VQ8+IDQxpfQA==",
|
||||||
|
"dev": true,
|
||||||
|
"license": "BSD-3-Clause",
|
||||||
|
"peer": true,
|
||||||
|
"engines": {
|
||||||
|
"node": ">=0.10.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/string-width": {
|
"node_modules/string-width": {
|
||||||
"version": "4.2.3",
|
"version": "4.2.3",
|
||||||
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
"resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
|
||||||
|
|||||||
@@ -8,8 +8,8 @@
|
|||||||
"install:all": "concurrently \"npm install\" \"cd client && npm install\" \"cd server && npm install\"",
|
"install:all": "concurrently \"npm install\" \"cd client && npm install\" \"cd server && npm install\"",
|
||||||
"build": "npm run build"
|
"build": "npm run build"
|
||||||
},
|
},
|
||||||
|
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"concurrently": "^9.0.1"
|
"concurrently": "^9.0.1",
|
||||||
|
"daisyui": "^4.12.14"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user