diff --git a/assets/images/icons/add.png b/assets/images/icons/add.png new file mode 100644 index 0000000..dc1d6d0 Binary files /dev/null and b/assets/images/icons/add.png differ diff --git a/assets/images/icons/image.png b/assets/images/icons/image.png new file mode 100644 index 0000000..a698876 Binary files /dev/null and b/assets/images/icons/image.png differ diff --git a/assets/images/icons/profile.png b/assets/images/icons/profile.png new file mode 100644 index 0000000..44f169b Binary files /dev/null and b/assets/images/icons/profile.png differ diff --git a/assets/images/icons/search.png b/assets/images/icons/search.png new file mode 100644 index 0000000..1e7d0dd Binary files /dev/null and b/assets/images/icons/search.png differ diff --git a/assets/images/icons/send.png b/assets/images/icons/send.png new file mode 100644 index 0000000..1ca4cb0 Binary files /dev/null and b/assets/images/icons/send.png differ diff --git a/assets/images/icons/user.png b/assets/images/icons/user.png new file mode 100644 index 0000000..bd07199 Binary files /dev/null and b/assets/images/icons/user.png differ diff --git a/assets/images/logo.png b/assets/images/logo.png new file mode 100644 index 0000000..e084b2a Binary files /dev/null and b/assets/images/logo.png differ diff --git a/index.html b/index.html new file mode 100644 index 0000000..c8e2e6b --- /dev/null +++ b/index.html @@ -0,0 +1,34 @@ + + + + Authenticate | LocalChat + + + +
+
+
+ logo image +

Welcome Back...

+

LocalChat is a local chat app
+ Your data is stored securely in your own
computer, no one but you will be able to access the data

+
+
+ + +
+ + + + \ No newline at end of file diff --git a/js/helpers/create-message-tile.js b/js/helpers/create-message-tile.js new file mode 100644 index 0000000..250f349 --- /dev/null +++ b/js/helpers/create-message-tile.js @@ -0,0 +1,20 @@ +const createMessageTile = (message, isCurrentUser) => { + const tile=document.createElement('li'); + tile.id='message-tile'; + + const messageText=document.createElement('p'); + messageText.id='message-tile-text'; + messageText.innerText=message.content; + + const messageDate=document.createElement('p'); + messageDate.id='message-date'; + messageDate.textContent=new Date(message.timestamp).toDateString(); + + tile.style.backgroundColor=isCurrentUser?'rgb(244, 107, 107)' + :'rgb(169, 169, 169)'; + tile.append(messageText, messageDate); + + return tile; +}; + +export default createMessageTile; \ No newline at end of file diff --git a/js/helpers/create-user-tile.js b/js/helpers/create-user-tile.js new file mode 100644 index 0000000..75acdb3 --- /dev/null +++ b/js/helpers/create-user-tile.js @@ -0,0 +1,29 @@ +import getLastText from "./get-last-text.js"; +import openChat from "../main-page.js" + +const createUserTile=(currentUser, user)=>{ + const isGroup=user.participants!==undefined; + const tile=document.createElement('li'); + const profilePicture=document.createElement('img'); + const username=document.createElement('h3'); + const lastMessage=document.createElement('p'); + const onlineBadge=document.createElement('h4'); + + profilePicture.src='../assets/images/icons/image.png'; + username.textContent=isGroup?user.name:user.username; + lastMessage.textContent=getLastText(isGroup,user.id); + onlineBadge.textContent = '•'; + onlineBadge.style.color = 'green'; + onlineBadge.style.display = (user.isOnline && !isGroup) ? 'inline' : 'none'; + + tile.addEventListener('click',()=>{ + isGroup?openChat(user.id,null,'group') + :openChat(currentUser.id,user.id,'private'); + }); + tile.append(profilePicture, username, lastMessage, onlineBadge); + + return tile; + +} + +export default createUserTile; \ No newline at end of file diff --git a/js/helpers/display-messages.js b/js/helpers/display-messages.js new file mode 100644 index 0000000..28bc3f1 --- /dev/null +++ b/js/helpers/display-messages.js @@ -0,0 +1,24 @@ +import createMessageTile from "./create-message-tile.js"; + +const displayMessages=(chat,messagesCount,currentUser)=>{ + const chatsList=document.getElementById('chats-list'); + const noMessages=document.getElementById('no-messages'); + + if(messagesCount>0){ + chatsList.style.display='inline'; + noMessages.style.display='none'; + } + else{ + chatsList.style.display='none'; + noMessages.style.display='inline'; + return; + } + + chat.messages.forEach(currentMessage => { + const message= currentMessage; + const messageTile = createMessageTile(message, message.senderId === currentUser); + chatsList.appendChild(messageTile); + }); +} + +export default displayMessages; \ No newline at end of file diff --git a/js/helpers/get-chat-data.js b/js/helpers/get-chat-data.js new file mode 100644 index 0000000..73dc2e8 --- /dev/null +++ b/js/helpers/get-chat-data.js @@ -0,0 +1,25 @@ +import Chat from "../models/chat.js"; +import User from "../models/user.js"; +import LocalStorageService from "../services/local-storage.js"; + +const getChatData=(user1,user2,type)=>{ + const chatsList=document.getElementById('chats-list'); + chatsList.innerHTML=''; + let chatId,currentChat,messagesCount; + if(type==='private'){ + chatId=Chat.generateChatId(user1, user2); + const allChats=LocalStorageService.getChats(); + currentChat=allChats.find(chat=>chat.id===chatId); + } + else{ + const groups=LocalStorageService.getGroups(); + currentChat=groups.find(group=>group.id===user1); + chatId=user1; + } + + messagesCount=currentChat?.messages?.length||0; + + return {chatId,currentChat,messagesCount}; +} + +export default getChatData; \ No newline at end of file diff --git a/js/helpers/get-last-text.js b/js/helpers/get-last-text.js new file mode 100644 index 0000000..645c4c3 --- /dev/null +++ b/js/helpers/get-last-text.js @@ -0,0 +1,32 @@ +import LocalStorageService from "../services/local-storage.js"; +import SessionManager from "../services/session-manager.js"; +import Chat from "../models/chat.js"; + +function getLastText(isGroup,userId){ + let allChats = LocalStorageService.getChats(); + let allGroups = LocalStorageService.getGroups(); + let currentUserId = SessionManager.getUser().id; + let lastMsgText='No message yet' + + if (isGroup) { + let group = allGroups.find(g=>g.id===userId); + + if (group && group.messages && group.messages.length > 0) { + let lastMsg = group.messages[group.messages.length - 1]; + lastMsgText = lastMsg.content; + + } +} + else { + let chatId = Chat.generateChatId(currentUserId, userId); + let chat = allChats.find(c => c.id === chatId); + + if (chat && chat.messages && chat.messages.length > 0) { + let lastMsg = chat.messages[chat.messages.length - 1]; + lastMsgText = lastMsg.content; + } + } + return lastMsgText; +} + +export default getLastText; \ No newline at end of file diff --git a/js/helpers/set-up-send-message-handler.js b/js/helpers/set-up-send-message-handler.js new file mode 100644 index 0000000..afb53f8 --- /dev/null +++ b/js/helpers/set-up-send-message-handler.js @@ -0,0 +1,21 @@ +import LocalStorageService from "../services/local-storage.js"; +import openChat from "../main-page.js"; + +const setupSendMessageHandler = (userId1, userId2, type, chatId) => { + const sendIcon=document.getElementById('message-send'); + sendIcon.onclick = null; + sendIcon.onclick=()=>{ + const content= document.getElementById('message-text').value.trim(); + if (content==='') return; + + if (type==='group') { + LocalStorageService.messageGroup(chatId, content, 'none'); + } else { + LocalStorageService.sendMessage(chatId, content, 'none'); + } + document.getElementById('message-text').value = ''; + openChat(userId1, userId2, type); + }; +}; + +export default setupSendMessageHandler; \ No newline at end of file diff --git a/js/helpers/switch-views.js b/js/helpers/switch-views.js new file mode 100644 index 0000000..7bb16b5 --- /dev/null +++ b/js/helpers/switch-views.js @@ -0,0 +1,27 @@ +function switchMobileView(view){ + const nav = document.querySelector('nav'); + const main = document.querySelector('main'); + const aside = document.querySelector('aside'); + + const isMobile = window.matchMedia("(max-width:600px)").matches; + + if(!isMobile){ + return; + } + + nav.style.display = 'none'; + main.style.display = 'none'; + aside.style.display = 'none'; + + if(view === 'nav'){ + nav.style.display = 'block'; + } + else if(view === 'chat'){ + main.style.display = 'flex'; + } + else if(view === 'profile'){ + aside.style.display = 'block'; + } +} + +export default switchMobileView; diff --git a/js/helpers/update-header.js b/js/helpers/update-header.js new file mode 100644 index 0000000..ac83e3a --- /dev/null +++ b/js/helpers/update-header.js @@ -0,0 +1,25 @@ +import LocalStorageService from "../services/local-storage.js"; + +const updateChatHeader=(chateeId,chatData,type)=>{ + const chateeName=document.getElementById('chatee-name'); + const chateeSideName=document.getElementById('chatee-side-name'); + const chateeStatus=document.getElementById('chatee-status'); + const chateeSideStatus=document.getElementById('chatee-side-status'); + + if(type==='private'){ + const chatee=LocalStorageService.getUser(chateeId); + chateeName.textContent=chatee.username; + chateeSideName.textContent=chatee.username; + chateeStatus.textContent=chatee.isOnline?'Online':'Offline'; + chateeSideStatus.textContent=chateeStatus.textContent; + } + else{ + chateeName.textContent=chatData.currentChat.name; + chateeSideName.textContent=chatData.currentChat.name; + chateeStatus.textContent='Group'; + chateeSideStatus.textContent='Group'; + } + +} + +export default updateChatHeader; \ No newline at end of file diff --git a/js/landing-page.js b/js/landing-page.js new file mode 100644 index 0000000..07c51a3 --- /dev/null +++ b/js/landing-page.js @@ -0,0 +1,86 @@ +import LocalStorageService from "./services/local-storage.js"; +import SessionManager from "./services/session-manager.js"; +import User from "./models/user.js"; + + +console.log(LocalStorageService.getUsers()); +let isSignUp=true; +const defaultView=document.getElementById('toggle-action'); +let authButton=document.getElementById('submit-button'); + + +function toggleView(){ + let heading=document.getElementById('welcome-heading'); + let toggleQuestion=document.getElementById('toggle-question'); + let toggleView=document.getElementById('toggle-action'); + let toggleMessage=document.getElementById('welcome-message'); + let submitButton=document.getElementById('submit-button'); + + + + if(isSignUp){ + heading.textContent='Hey newbie...'; + toggleQuestion.textContent='Already have an account?'; + toggleMessage.innerHTML='LocalChat is a local chat app.
Your data is stored securely in your own
computer, no one but you will be able to access the data.'; + toggleView.textContent="Sign In"; + submitButton.textContent='Sign Up'; + + } + else{ + heading.textContent='Welcome Back...'; + toggleQuestion.textContent='Don’t have an account?'; + toggleMessage.innerHTML='LocalChat is a local chat app.
Your data is stored securely in your own
computer, no one but you will be able to access the data.'; + toggleView.textContent='Sign Up'; + submitButton.textContent='Sign In'; + + } + + isSignUp=!isSignUp; + console.log('done'); +} + + +function authenticate(){ + let username=document.getElementById('username-input').value; + let password=document.getElementById('password-input').value; + if(!isSignUp){ + if(User.isUserNameUnique(username)){ + //Create an account + LocalStorageService.createUser(username,password); + console.log(LocalStorageService.getUsers()); + } + else{ + alert('Please enter a new username, make it unique'); + return; + } + } + //Login + let user=SessionManager.login(username,password); + console.log(user); + if(user){ + console.log('logged in as '+ user.username); + //Navigate to the main page + window.location.replace('./pages/main.html'); + } + else{ + alert('Login failed, ensure you have entered correct credentials'); + return; + } +} + + + + + + + + + + +function main(){ + console.log('Main method test'); + defaultView.addEventListener('click',()=>toggleView()); + authButton.addEventListener('click', ()=>authenticate()); +} + +main(); \ No newline at end of file diff --git a/js/main-page.js b/js/main-page.js new file mode 100644 index 0000000..b4160ae --- /dev/null +++ b/js/main-page.js @@ -0,0 +1,155 @@ +import LocalStorageService from "./services/local-storage.js"; +import SessionManager from "./services/session-manager.js"; +import Chat from "./models/chat.js"; +import switchMobileView from "./helpers/switch-views.js"; +import createUserTile from "./helpers/create-user-tile.js"; +import User from "./models/user.js"; +import getChatData from "./helpers/get-chat-data.js"; +import updateChatHeader from "./helpers/update-header.js"; +import displayMessages from "./helpers/display-messages.js"; +import setupSendMessageHandler from "./helpers/set-up-send-message-handler.js"; + + +//State +let currentChatId=null; +let currentChatUser1=null; +let currentChatUser2=null; +let currentChatType='private'; + + +//Populate the users list with users from local storage +const populateUsersList=(users)=>{ + const usersList=document.getElementById('users-list'); + const noUsersText=document.getElementById('no-users'); + const currentUser=SessionManager.getUser(); + usersList.innerHTML=''; + + if(users.length===0){ + usersList.style.display='none'; + noUsersText.style.display='block'; + return; + } + + usersList.style.display='block'; + noUsersText.style.display='none'; + + users.forEach(user => { + const userTile=createUserTile(currentUser,user); + usersList.append(userTile); + }); +} + + +//What happens when we click on a tile from users list +const openChat=(userId1,userId2,type='private')=>{ + switchMobileView('chat'); + const chatData=getChatData(userId1,userId2,type); + updateChatHeader(userId2,chatData,type); + displayMessages(chatData.currentChat, chatData.messagesCount, SessionManager.getUser().id); + setupSendMessageHandler(userId1, userId2, type, chatData.chatId); + + currentChatId = chatData.chatId; + currentChatUser1 = userId1; + currentChatUser2 = userId2; + currentChatType = type; +} + + + + +const searchUsers = () => { + const users = LocalStorageService.getUsers(); + const searchText = document.getElementById('search-text').value.toLowerCase(); + const filteredUsers = users.filter(user => + user.username.toLowerCase().includes(searchText) + ); + populateUsersList(filteredUsers); +}; + +const updateProfile = () => { + const username = document.getElementById('username-input').value; + const password = document.getElementById('password-input').value; + if(username.length===0 || password.length===0){ + alert('Update failed. Please enter a valid username and password'); + return; + } + + if(!User.isUserNameUnique(username)){ + alert('Update failed. Username taken, please enter a different username'); + return; + } + LocalStorageService.updateProfile(username, password); +}; + +const createGroup = () => { + const input = prompt('Enter group name and member Ids(e.g "Group Name":id1,id2,id3...)'); + const [groupName, membersString] = input.split(':'); + const participants = membersString.split(','); + + if(groupName.trim().length===0 || participants.length<2){ + alert('Failed to create group. Ensure you set group name and add 1 or more participant'); + return; + } + + participants.push(SessionManager.getUser().username); + LocalStorageService.createGroup(groupName, participants); + location.reload(); +}; + +const showUserProfile = () => { + document.getElementById('current-user').style.display = 'block'; + document.getElementById('chatee').style.display = 'none'; + switchMobileView('profile'); +}; + +const showChateeProfile = () => { + document.getElementById('current-user').style.display = 'none'; + document.getElementById('chatee').style.display = 'block'; + switchMobileView('profile'); +}; + +const cancelEdits = () => { + switchMobileView('nav'); +}; + +const setupEventListeners = () => { + document.getElementById('search-icon').addEventListener('click', searchUsers); + document.getElementById('save-edits').addEventListener('click', updateProfile); + document.getElementById('logout').addEventListener('click', () => SessionManager.logout()); + document.getElementById('add-group-icon').addEventListener('click', createGroup); + document.getElementById('profile-icon').addEventListener('click', showUserProfile); + document.getElementById('chatee-info').addEventListener('click', showChateeProfile); + document.getElementById('cancel-edits').addEventListener('click', cancelEdits); + document.getElementById('profile-back').addEventListener('click', () => switchMobileView('nav')); +}; + +const loadInitialData = () => { + let users=LocalStorageService.getUsers(); + const groups=LocalStorageService.getGroups(); + const currentUser=SessionManager.getUser(); + + users=users.filter(user=>user.id !== currentUser.id); + const myGroups=groups.filter(group=>group.participants.includes(currentUser.username)); + + populateUsersList([...users, ...myGroups]); +}; + +const handleStorageChange = (event) => { + if (['chats', 'groups', 'users'].includes(event.key)) { + if (currentChatId !== null) { + openChat(currentChatUser1, currentChatUser2, currentChatType); + } + loadInitialData(); + } +}; + +const main = () => { + setupEventListeners(); + loadInitialData(); + window.addEventListener('storage', handleStorageChange); +}; + +main(); + + +export default openChat; \ No newline at end of file diff --git a/js/models/chat.js b/js/models/chat.js new file mode 100644 index 0000000..ee301d0 --- /dev/null +++ b/js/models/chat.js @@ -0,0 +1,19 @@ +class Chat{ + constructor(chatId){ + this.id=chatId; + this.user1Typing=false; + this.user2Typing=false; + this.messages=[]; + } + + static generateChatId(userId1,userId2){ + if(userId1>userId2){ + return userId1+'-'+userId2; + } + else{ + return userId2+'-'+userId1; + } + } +} + +export default Chat; \ No newline at end of file diff --git a/js/models/group.js b/js/models/group.js new file mode 100644 index 0000000..651c9e4 --- /dev/null +++ b/js/models/group.js @@ -0,0 +1,10 @@ +class Group{ + constructor(name,participants){ + this.id=Math.floor(Math.random()*99999); + this.name=name; + this.messages=[]; + this.participants=participants; + } +} + +export default Group; \ No newline at end of file diff --git a/js/models/message.js b/js/models/message.js new file mode 100644 index 0000000..6d0b28e --- /dev/null +++ b/js/models/message.js @@ -0,0 +1,12 @@ +import SessionManager from "../services/session-manager.js"; +class Message{ + constructor(content,replyTo){ + this.id=Math.floor(Math.random()*99999); + this.content=content; + this.senderId=SessionManager.getUser().id; + this.replyTo=replyTo; + this.timestamp=Date.now(); + } +} + +export default Message; diff --git a/js/models/user.js b/js/models/user.js new file mode 100644 index 0000000..4d79e3a --- /dev/null +++ b/js/models/user.js @@ -0,0 +1,24 @@ +import LocalStorageService from "../services/local-storage.js"; + +class User{ + constructor(username,password){ + + this.id=User.generateUserId(); + this.username=username; + this.password=password; + this.isLoggedIn=false; + this.isOnline=false; + this.lastSeen=Date.now(); + } + + static isUserNameUnique(username){ + let users=LocalStorageService.getUsers(); + return !(users.find(user=>user.username===username)); + } + + static generateUserId(){ + return LocalStorageService.getUsers().length+1; + } +} + +export default User; \ No newline at end of file diff --git a/js/services/local-storage.js b/js/services/local-storage.js new file mode 100644 index 0000000..3c6e1e0 --- /dev/null +++ b/js/services/local-storage.js @@ -0,0 +1,107 @@ +import Message from "../models/message.js"; +import User from "../models/user.js"; +import Chat from "../models/chat.js"; +import SessionManager from "./session-manager.js"; +import Group from "../models/group.js"; +class LocalStorageService{ + constructor(){ + + } + + static createUser(username,password){ + let users=JSON.parse(localStorage.getItem('users'))||[]; + const user=new User(username,password); + users.push(user); + localStorage.setItem('users',JSON.stringify(users)); + } + + static createChat(userId1,userId2){ + let chats=JSON.parse(localStorage.getItem('chats')); + let chatId=Chat.generateChatId(userId1,userId2) + let chat=new Chat(chatId); + chats.push(chat); + localStorage.setItem('chats',JSON.stringify(chats)); + } + + static sendMessage(chatId,content,replyTo){ + let message=new Message(content,replyTo); + let chats=LocalStorageService.getChats(); + let currentChat=chats.find(chat=>chat.id===chatId); + if(!currentChat){ + console.log('Creating chat'); + currentChat=new Chat(chatId); + chats.push(currentChat); + } + + currentChat.messages.push(message); + + for(let i=0;iuser.id===userId); + } + + + static updateProfile(username,password){ + let users=LocalStorageService.getUsers(); + let user=SessionManager.getUser(); + + if(user){ + for(let i=0;i(user.username===username && user.password===password)); + if(user){ + for(let i=0;i + + + Main | LocalChat + + + +
+ +
+ + + +
+
+ chatee profile picture +

+

+
+ +
+
    +

    No messages yet...

    +
    + +
    + + send-icon + +
    + +
    + + + + + + + + \ No newline at end of file diff --git a/styles/landing-page.css b/styles/landing-page.css new file mode 100644 index 0000000..bfe13d7 --- /dev/null +++ b/styles/landing-page.css @@ -0,0 +1,112 @@ +*{ + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; +} + +main{ + display: flex; + height: 100dvh; +} + +article{ + flex: 2; + display: flex; + flex-direction: column; + justify-content: center; + background-color: #ff383c; + color: white; + border-top-right-radius: 20px; + border-bottom-right-radius: 20px; + padding-top: 3%; + padding-left:2%; +} + +aside{ + flex: 1; + display: flex; + justify-content: center; + margin-top: 15%; + padding: 8px; + height: fit-content; +} + +#logo-image{ + width: 30%; + margin-bottom: 50px; +} + + +#welcome-heading{ + font-size: 3rem; + margin-bottom: 30px; +} + +#welcome-message{ + font-size: 1rem; +} + +#text-logo{ + font-size: 35px; + margin-bottom: 100px; +} + +#text-logo span{ + color:#ff383c +} + +input{ + display: block; + margin-bottom: 40px; + width: 100%; + height: 30px; + border: #d9d9d9 solid 1px; + border-radius: 6px; + background-color: #ffffff; + padding-left: 10px; +} + +button{ + display: block; + width: 100%; + background-color: #2c2c2c; + border: 6px solid #2c2c2c; + color: white; + margin-bottom: 60px; + height:40px; + border-radius: 6px; +} + + +#toggle-question{ + display: inline; + font-weight: bold; +} + +#toggle-action{ + display: inline; + color:#ff383c; + font-weight: bold; +} + +#landing-form{ + width: 55%; + text-align: center; +} + + + +@media (max-width:600px) { + article{ + display: none; + } + aside{ + flex: 1; + display: flex; + justify-content: center; + margin-top: 45%; + padding: 8px; + height: fit-content; +} + +} \ No newline at end of file diff --git a/styles/main-page.css b/styles/main-page.css new file mode 100644 index 0000000..c3cde0c --- /dev/null +++ b/styles/main-page.css @@ -0,0 +1,408 @@ +*{ + margin: 0; + padding: 0; + font-family: Arial, Helvetica, sans-serif; +} + +html{ + height: 100%; +} + +body{ + display: flex; + flex-direction: row; + height: 100vh; + overflow-x: hidden; +} + +nav{ + flex:0.9; + background-color: #f5f5f5; + height: 100vh; + overflow-y: auto; + overflow-x: hidden; +} + +main{ + flex: 1; + height: 100vh; +} + + +aside{ + flex:1; + height: 100vh; + overflow-y: hidden; + overflow-x: hidden; +} + +#text-logo{ + font-size: 25px; + display: inline; +} + +#text-logo span{ + color:#ff383c; +} + +img{ + display: inline; +} + +#nav-appbar{ + display: flex; + justify-content: space-between; + align-items: center; + position: sticky; + background-color: white; + padding: 10px; + top: 0; + z-index: 2; + height: 50px; +} + +.icon{ + height: 15px; + width: 15px; + color: grey; + margin-right: 5px; +} + +#search-container{ + display: flex; + justify-content: space-between; + margin-top: 10px; + background-color: white; + margin-left: 10px; + margin-right: 10px; + border-radius: 6px; + +} + +#search-container img{ + justify-content: flex-end; + padding: 10px; + +} + +input{ + border: none; + height: max-content; + padding: 10px; + border-bottom-left-radius: 6px; + border-top-left-radius: 6px; + width: 100%; + overflow: hidden; +} + + + +#filter-tags{ + margin-left: 10px; +} + +#filter-tags li{ + display: inline-flex; + align-items: center; + background-color: #dedede; + border-radius: 6px; + height: 15px; + color: #757575; + text-align: center; + padding: 8px; + margin-top: 10px; + margin-bottom: 10px; +} + +#filter-tag-all{ + background-color: #2c2c2c; + color: rgb(209, 209, 209); +} + + + +#users-list li{ + background-color: #ffffff; + margin: 5px 10px; + display: flex; + flex-direction: column; + height: 65px; + border-radius: 6px; + position: relative; +} + +#users-list li p{ + color: #636262; + display: block; + margin-left: 65px; + position: absolute; + margin-top: 36px; + font-size: 15px; +} + + +#users-list li h3{ + color: #636262; + display: block; + margin-left: 65px; + position: absolute; + font-size: 18px; + margin-top: 12px; +} + +#users-list li h4{ + color: green; + display: block; + margin-left: 40px; + position: absolute; + margin-top: 30px; + font-size: 40px; + height: 2px; +} + + +main{ + display: flex; + flex-direction: column; + background-color: #f5f5f5; +} + +#users-list li img{ + width: 50px; + height: 50px; + margin-left: 5px; + margin-top: 8px; +} + + +#chatee-info{ + display: flex; + justify-content: start; + flex-direction: column; + margin-left: 0px; + background-color: white; + padding-left: 10px; + height: 78px; + +} + +#messages-box{ + margin-top: 30px; + justify-content: center; + text-align: center; + overflow-y: scroll; +} + +#message-container{ + margin-top: auto; + justify-content:space-between ; + background-color: white; + display: flex; + margin-left: 10px; + margin-right: 10px; + margin-bottom: 10px; + border-radius: 6px; + align-items: center; +} + +#message-send{ + height: 30px; + width: 30px; + margin: 10px; +} + +#no-messages{ + font-weight: bold; + color: #cdcdcd; +} + +#chatee-profile-picture{ + height: 55px; + width: 55px; +} + +#chatee-name{ + color:#636262; + margin-top: 5px; + margin-left: 8px; + position: absolute; + margin-top: 7px; + margin-left: 70px; + font-size: 20px; +} + +#chatee-status{ + position: absolute; + margin-top: 33px; + margin-left: 70px; + font-size: 13px; +} + + +#message-tile{ + background-color: rgb(169, 169, 169); + text-align: left; + border-radius: 8px; + margin-left: 10px; + margin-right: 20%; + padding-left: 10px; + padding-top: 10px; + list-style-type: none; + margin-bottom: 15px; +} + +#message-tile-text{ + color: white; +} + +#message-date{ + color:#eeeeee; + margin-top: 10px; + text-align: end; + font-size: 13px; + margin-right: 10px; + padding-bottom: 10px; +} + + +#profile-appbar{ + display: flex; + align-items: center; + height: 60px; +} + +#chatee{ + display: flex; + display: none; +} + +#chatee-details{ + justify-content: center; + display: flex; + flex-direction: column; + align-items: center; + width: 100%; + margin-top: 20%; +} + +#chatee-side-status{ + margin-top: 20px; +} + +#chatee-side-name{ + margin-top: 30px; + font-size: 30px; + color: #636262; +} + +#chatee-side-profile-picture{ + height: 80px; + width: 80px; +} + +#current-user{ + height: 100%; +} + +#current-user-details{ + display: flex; + flex-direction: column; + margin-left: 20px; + margin-right: 20px; + height: 100%; +} + +#logout{ + display: inline; + width: 100%; + background-color: #ff383c; + border: 1px solid #cbcbcb; + color: white; + height:40px; + border-radius: 6px; + margin-right: 60px; +} + +#save-edits{ + display: inline; + width: 45%; + background-color: #2c2c2c; + border: 6px solid #2c2c2c; + color: white; + height:40px; + border-radius: 6px; + margin-right: 4%; + +} + +#cancel-edits{ + display: inline; + width: 45%; + background-color: #ffffff; + border: 1px solid #d3d3d3; + color: black; + margin-bottom: 10px; + height:40px; + border-radius: 6px; + margin-left: 4%; +} + +#user-profile-picture{ + height: 50px; + width: 50px; + margin-bottom: 20px; +} + +#username-input{ + margin-bottom: 20px; + border:1px solid #d3d3d3; + width: 80%; + border-radius: 6px; +} + +#password-input{ + margin-bottom: 20px; + border:1px solid #d3d3d3; + width: 80%; + border-radius: 6px; +} + + +#profile-actions{ + margin-top: auto; + justify-content: flex-end; + margin-bottom: 100px; +} + + +#profile-back{ + display: none; +} + +#add-group-icon{ + display: inline; + font-size: 30px; + margin-right: 10px; + color: grey; + +} + + +@media (max-width:1000px) { + aside{ + display: none; + } + +} + +@media (max-width:600px){ + main{ + display: none; + } + nav{ + flex:1; + } + #profile-back{ + display: inline; + } +} \ No newline at end of file