diff options
author | Zhongheng Liu <z.liu@outlook.com.gr> | 2024-01-31 21:07:45 +0200 |
---|---|---|
committer | Zhongheng Liu <z.liu@outlook.com.gr> | 2024-01-31 21:07:45 +0200 |
commit | 4117c11c356652381a9564688139d9c3f25eb983 (patch) | |
tree | 153d1fa6951ca28c5a469e3d99a9be0cfa46f979 | |
parent | 7e5f5bdf774a2f3b5d65b90c55ced6553419a960 (diff) | |
download | epq-web-4117c11c356652381a9564688139d9c3f25eb983.tar.gz epq-web-4117c11c356652381a9564688139d9c3f25eb983.tar.bz2 epq-web-4117c11c356652381a9564688139d9c3f25eb983.zip |
CSS styling overhaul
FIXED Issue with rendering time - minutes now in fixed 2-digit format
ADD Sidebar Topbar components to help with UI/UX
ADD Avatar and Menu PNG files for style
TODO Improve styling
ET AL removed redundant code
-rw-r--r-- | src/App.css | 4 | ||||
-rw-r--r-- | src/App.tsx | 18 | ||||
-rw-r--r-- | src/Chat/Chat.css | 8 | ||||
-rw-r--r-- | src/Intl/strings.json | 2 | ||||
-rw-r--r-- | src/Login/Login.css | 1 | ||||
-rw-r--r-- | src/MessageDisplay/MessageDisplay.tsx | 115 | ||||
-rw-r--r-- | src/Sidebar/Components/Avatar.css | 5 | ||||
-rw-r--r-- | src/Sidebar/Components/Avatar.tsx | 9 | ||||
-rw-r--r-- | src/Sidebar/Components/SidebarMenu.tsx | 50 | ||||
-rw-r--r-- | src/Sidebar/Components/placeholder.jpg | bin | 0 -> 17203 bytes | |||
-rw-r--r-- | src/Sidebar/Sidebar.css | 47 | ||||
-rw-r--r-- | src/Sidebar/Sidebar.tsx | 24 | ||||
-rw-r--r-- | src/Topbar/Topbar.css | 10 | ||||
-rw-r--r-- | src/Topbar/Topbar.tsx | 33 | ||||
-rw-r--r-- | src/Topbar/menu.png | bin | 0 -> 10450 bytes | |||
-rw-r--r-- | src/type/messageTypes.ts | 1 |
16 files changed, 261 insertions, 66 deletions
diff --git a/src/App.css b/src/App.css index e4849cc..bb372cd 100644 --- a/src/App.css +++ b/src/App.css @@ -1,6 +1,6 @@ body { - background-color: black; - color: #00FF33; + /* background-color: black; + color: #00FF33; */ margin: 1%; min-height: 100vh; } diff --git a/src/App.tsx b/src/App.tsx index 7d908e3..a5f11ac 100644 --- a/src/App.tsx +++ b/src/App.tsx @@ -7,6 +7,8 @@ import strings from "./Intl/strings.json"; import { LangContext, LoginContext, LoginType } from "./context"; import { contentTypes, domain, endpoints, port } from "./consts"; import { Login } from "./Login/Login"; +import { Sidebar } from "./Sidebar/Sidebar"; +import { Topbar } from "./Topbar/Topbar"; // what we "in the business" call type gymnastics const Wrapper = (): React.ReactElement => { const [lang, setLang] = useState<LangType>("en_US"); @@ -16,11 +18,19 @@ const Wrapper = (): React.ReactElement => { ? `IRC logged in as ${login.username}` : "IRC Chat"; }, [login]); + const [sidebarEnabled, setSidebarEnabled] = useState(false); return ( <LangContext.Provider value={lang}> - <h1>{strings[lang].homepage.title}</h1> - <p>{strings[lang].homepage.description}</p> <LoginContext.Provider value={login}> + <Topbar + setSidebarEnable={(enabled: boolean) => + setSidebarEnabled(enabled) + } + ></Topbar> + <Sidebar + isEnabled={sidebarEnabled} + setEnable={(enabled: boolean) => setSidebarEnabled(enabled)} + ></Sidebar> {/* callbacks for altering the Lang/Login contexts */} <Login setLogin={(value) => { @@ -97,8 +107,8 @@ const App = ({ }) .then((responseBody: { success: boolean }) => { if (responseBody.success) { - // TODO Put new username response true handler method stub - } else { + // TODO Put new username response true handler method stub + } else { console.error( "Server POST message failed." ); diff --git a/src/Chat/Chat.css b/src/Chat/Chat.css index 76b19f6..cc5dd7b 100644 --- a/src/Chat/Chat.css +++ b/src/Chat/Chat.css @@ -12,6 +12,14 @@ } .chat { + /* float: left; */ /* min-height: 80vh; */ position: relative; + box-shadow: + 0 2.8px 2.2px rgba(0, 0, 0, 0.034), + 0 6.7px 5.3px rgba(0, 0, 0, 0.048), + 0 12.5px 10px rgba(0, 0, 0, 0.06), + 0 22.3px 17.9px rgba(0, 0, 0, 0.072), + 0 41.8px 33.4px rgba(0, 0, 0, 0.086), + 0 100px 80px rgba(0, 0, 0, 0.12) } diff --git a/src/Intl/strings.json b/src/Intl/strings.json index ceff215..e5081b5 100644 --- a/src/Intl/strings.json +++ b/src/Intl/strings.json @@ -1,6 +1,6 @@ { "variableNames": ["userName", "content"], - "acceptedLangs": ["en_US", "zh_TW", "el_GR"], + "acceptedLangs": ["en_US", "zh_TW", "el_GR", "ar_SA"], "en_US": { "homepage": { "userNamePrompt": "Your username: ", diff --git a/src/Login/Login.css b/src/Login/Login.css index 21bceff..2776f45 100644 --- a/src/Login/Login.css +++ b/src/Login/Login.css @@ -1,3 +1,4 @@ .uname-error-text { color: red; } +.login {}
\ No newline at end of file diff --git a/src/MessageDisplay/MessageDisplay.tsx b/src/MessageDisplay/MessageDisplay.tsx index 18a9277..3ebf8af 100644 --- a/src/MessageDisplay/MessageDisplay.tsx +++ b/src/MessageDisplay/MessageDisplay.tsx @@ -5,64 +5,61 @@ import strings from "../Intl/strings.json"; import "./MessageDisplay.css"; import { queryByRole } from "@testing-library/react"; export const MessageDisplay = ({ - type, - fromUserId, - toUserId, - content, - timeMillis, + type, + fromUserId, + toUserId, + content, + timeMillis, }: Message): React.ReactElement<Message> => { - const dateTime: Date = new Date(timeMillis); - const lang = useContext(LangContext); - const msgPage = strings[lang].chat; - /* FIXED funny error - * DESCRIPTION - * The line below was - * return (<p>[{dateTime.toLocaleString(Intl.DateTimeFormat().resolvedOptions().timeZone)}]...</p>) - * The line incorrectly generated a value of "UTC" as the parameter to toLocaleString() - * While "UTC" is an accepted string value, in EEST, aka. "Europe/Athens" timezone string is not an acceptable parameter. - * This caused the return statement to fail, and the message fails to render, despite it being correctly committed to the db. - * Funny clown moment 🤡 - */ - const timeString = `${ - dateTime.getHours() > 12 - ? dateTime.getHours() - 12 - : dateTime.getHours() - }:${dateTime.getMinutes()} ${dateTime.getHours() > 12 ? "PM" : "AM"}`; - switch (type) { - case MessageType.HELLO as MessageType: - return ( - <p className="msg"> - [{timeString}]{" "} - {msgPage.joinMessage.replace( - "$userName", - fromUserId - )} - </p> - ); - case MessageType.MESSAGE as MessageType: - return ( - <p className="msg"> - [{timeString}]{" "} - {msgPage.serverMessage - .replace( - "$userName", - fromUserId - ) - .replace("$content", content)} - </p> - ); - case MessageType.DATA as MessageType: - return <></>; - case MessageType.CHNAME as MessageType: - return <></>; - default: - console.error("Illegal MessageType reported!"); - return ( - <p className="msg-err"> - [{timeString}] **THIS MESSAGE CANNOT BE - CORRECTLY SHOWN BECAUSE THE CLIENT - ENCOUNTERED AN ERROR** - </p> - ); - } + const dateTime: Date = new Date(timeMillis); + const lang = useContext(LangContext); + const msgPage = strings[lang].chat; + /* FIXED funny error + * DESCRIPTION + * The line below was + * return (<p>[{dateTime.toLocaleString(Intl.DateTimeFormat().resolvedOptions().timeZone)}]...</p>) + * The line incorrectly generated a value of "UTC" as the parameter to toLocaleString() + * While "UTC" is an accepted string value, in EEST, aka. "Europe/Athens" timezone string is not an acceptable parameter. + * This caused the return statement to fail, and the message fails to render, despite it being correctly committed to the db. + * Funny clown moment 🤡 + */ + const timeString = `${ + dateTime.getHours() > 12 + ? dateTime.getHours() - 12 + : dateTime.getHours() + }:${ + dateTime.getMinutes() >= 10 + ? dateTime.getMinutes() + : `0${dateTime.getMinutes().toString()}` + } ${dateTime.getHours() > 12 ? "PM" : "AM"}`; + switch (type) { + case MessageType.HELLO as MessageType: + return ( + <p className="msg"> + [{timeString}]{" "} + {msgPage.joinMessage.replace("$userName", fromUserId)} + </p> + ); + case MessageType.MESSAGE as MessageType: + return ( + <p className="msg"> + [{timeString}]{" "} + {msgPage.serverMessage + .replace("$userName", fromUserId) + .replace("$content", content)} + </p> + ); + case MessageType.DATA as MessageType: + return <></>; + case MessageType.CHNAME as MessageType: + return <></>; + default: + console.error("Illegal MessageType reported!"); + return ( + <p className="msg-err"> + [{timeString}] **THIS MESSAGE CANNOT BE CORRECTLY SHOWN + BECAUSE THE CLIENT ENCOUNTERED AN ERROR** + </p> + ); + } }; diff --git a/src/Sidebar/Components/Avatar.css b/src/Sidebar/Components/Avatar.css new file mode 100644 index 0000000..f2da859 --- /dev/null +++ b/src/Sidebar/Components/Avatar.css @@ -0,0 +1,5 @@ +.avatar { + width: 100%; + display: flex; + justify-content:center; +}
\ No newline at end of file diff --git a/src/Sidebar/Components/Avatar.tsx b/src/Sidebar/Components/Avatar.tsx new file mode 100644 index 0000000..700f20d --- /dev/null +++ b/src/Sidebar/Components/Avatar.tsx @@ -0,0 +1,9 @@ +import "./Avatar.css"; +import placeholderImage from "./placeholder.jpg"; +export const Avatar = () => { + return ( + <div className="avatar"> + <img src={placeholderImage} width="75px"></img> + </div> + ); +}; diff --git a/src/Sidebar/Components/SidebarMenu.tsx b/src/Sidebar/Components/SidebarMenu.tsx new file mode 100644 index 0000000..be176d2 --- /dev/null +++ b/src/Sidebar/Components/SidebarMenu.tsx @@ -0,0 +1,50 @@ +import "../Sidebar.css"; +import { Avatar } from "./Avatar"; +export const SidebarMenuItem = ({ + text, + href, + handler, +}: { + text: string; + href?: string; + handler?: () => void; +}) => { + return ( + <div + className="sidebar-menu-item" + onClick={ + handler + ? () => { + handler(); + } + : () => {} + } + > + <li> + <span> + <i>{href ? <a href={href}>{text}</a> : text}</i> + </span> + </li> + <hr></hr> + </div> + ); +}; +export const SidebarMenu = ({ + exitHandler, +}: { + exitHandler: (enabled: boolean) => void; +}) => { + return ( + <div className="sidebar-menu"> + <Avatar></Avatar> + <SidebarMenuItem text="My Account"></SidebarMenuItem> + <SidebarMenuItem text="Personalisation"></SidebarMenuItem> + <SidebarMenuItem text="Language"></SidebarMenuItem> + <SidebarMenuItem text="Server Configuration"></SidebarMenuItem> + <SidebarMenuItem + text="Return to homepage" + handler={() => exitHandler(false)} + ></SidebarMenuItem> + </div> + ); +}; diff --git a/src/Sidebar/Components/placeholder.jpg b/src/Sidebar/Components/placeholder.jpg Binary files differnew file mode 100644 index 0000000..6789d3b --- /dev/null +++ b/src/Sidebar/Components/placeholder.jpg diff --git a/src/Sidebar/Sidebar.css b/src/Sidebar/Sidebar.css new file mode 100644 index 0000000..baa1161 --- /dev/null +++ b/src/Sidebar/Sidebar.css @@ -0,0 +1,47 @@ + +.sidebar { + width: 100%; + height: 100%; + position: absolute; + top: 0; + left: 0; + background-color: rgba(0, 0, 0, 0.5); + animation: fadeIn, 5s; + z-index: 10; +} +.sidebar-menu-item { + margin: 5px; + transition: all 0.5s; +} + +.sidebar-menu-item:hover { + background-color: rgba(0, 0, 0, 0.2); + box-shadow: 5px 5px rgba(0, 0, 0, 0.5); +} +.sidebar-content { + background-color: white; + width: max(15%, 200px); + height: 100%; + box-shadow: 10px 10px rgba(0, 0, 0, 0.5); +} +@keyframes fadeIn { + 0% {background-color: transparent;} + 100% {background-color: rgba(0, 0, 0, 0.5);;} +} +@-moz-keyframes fadeIn { + 0% {background-color: transparent;} + 100% {background-color: rgba(0, 0, 0, 0.5);;} +} + @-webkit-keyframes fadeIn { + 0% {background-color: transparent;} + 100% {background-color: rgba(0, 0, 0, 0.5);;} +} + + @-o-keyframes fadeIn { + 0% {background-color: transparent;} + 100% {background-color: rgba(0, 0, 0, 0.5);;} +} + @-ms-keyframes fadeIn { + 0% {background-color: transparent;} + 100% {background-color: rgba(0, 0, 0, 0.5);;} +}
\ No newline at end of file diff --git a/src/Sidebar/Sidebar.tsx b/src/Sidebar/Sidebar.tsx new file mode 100644 index 0000000..ea5dfed --- /dev/null +++ b/src/Sidebar/Sidebar.tsx @@ -0,0 +1,24 @@ +import { useState } from "react"; +import "./Sidebar.css"; +import { SidebarMenu } from "./Components/SidebarMenu"; +export const Sidebar = ({ + isEnabled, + setEnable, +}: { + isEnabled: boolean; + setEnable: (enabled: boolean) => void; +}) => { + return isEnabled ? ( + <div className="sidebar"> + <div className="sidebar-content"> + <SidebarMenu + exitHandler={(value) => { + setEnable(value); + }} + ></SidebarMenu> + </div> + </div> + ) : ( + <></> + ); +}; diff --git a/src/Topbar/Topbar.css b/src/Topbar/Topbar.css new file mode 100644 index 0000000..ffd3d68 --- /dev/null +++ b/src/Topbar/Topbar.css @@ -0,0 +1,10 @@ +.topbar { + width: 100vw; + height: 10%; + z-index: 5; + display: flex; + justify-content: baseline; +} +.topbar-span .children { + margin-left: 10px; +}
\ No newline at end of file diff --git a/src/Topbar/Topbar.tsx b/src/Topbar/Topbar.tsx new file mode 100644 index 0000000..0c4022f --- /dev/null +++ b/src/Topbar/Topbar.tsx @@ -0,0 +1,33 @@ +import "./Topbar.css"; +import strings from "../Intl/strings.json"; +import { useContext } from "react"; +import { LangContext } from "../context"; +import menu from "./menu.png"; +export const Topbar = ({ + setSidebarEnable, +}: { + setSidebarEnable: (enabled: boolean) => void; +}) => { + const lang = useContext(LangContext); + return ( + <div className="topbar"> + <img + onClick={() => { + setSidebarEnable(true); + }} + src={menu} + width="100px" + height="100px" + alt="Open Selection Menu" + ></img> + <span className="topbar-span"> + <h1 className="topbar-span children"> + {strings[lang].homepage.title} + </h1> + {/* <p className="topbar-span children"> + {strings[lang].homepage.description} + </p> */} + </span> + </div> + ); +}; diff --git a/src/Topbar/menu.png b/src/Topbar/menu.png Binary files differnew file mode 100644 index 0000000..ae9b91a --- /dev/null +++ b/src/Topbar/menu.png diff --git a/src/type/messageTypes.ts b/src/type/messageTypes.ts index f83594a..0bc76ee 100644 --- a/src/type/messageTypes.ts +++ b/src/type/messageTypes.ts @@ -42,5 +42,6 @@ export type Message = { content: string; timeMillis: number; }; +// Type gymnastics to provide dynamic ESLint support export const acceptedLangs = ["en_US", "zh_TW", "el_GR", "ar_SA"] as const; export type LangType = (typeof acceptedLangs)[number]; |