diff --git a/fonts/selawk.ttf b/fonts/selawk.ttf
new file mode 100644
index 0000000..736bac3
Binary files /dev/null and b/fonts/selawk.ttf differ
diff --git a/fonts/selawkb.ttf b/fonts/selawkb.ttf
new file mode 100644
index 0000000..2134a76
Binary files /dev/null and b/fonts/selawkb.ttf differ
diff --git a/fonts/selawkl.ttf b/fonts/selawkl.ttf
new file mode 100644
index 0000000..cbfaaf9
Binary files /dev/null and b/fonts/selawkl.ttf differ
diff --git a/fonts/selawksb.ttf b/fonts/selawksb.ttf
new file mode 100644
index 0000000..5ec501d
Binary files /dev/null and b/fonts/selawksb.ttf differ
diff --git a/fonts/selawksl.ttf b/fonts/selawksl.ttf
new file mode 100644
index 0000000..bc3fa08
Binary files /dev/null and b/fonts/selawksl.ttf differ
diff --git a/index.html b/index.html
index 97d55cf..1f455f7 100644
--- a/index.html
+++ b/index.html
@@ -16,10 +16,11 @@
-
-
+
+
diff --git a/js/app.js b/js/app.js
index 43ad99d..8f5a749 100644
--- a/js/app.js
+++ b/js/app.js
@@ -2,8 +2,8 @@ import { config } from "./config.js";
import { waha } from "./waha.js";
import { ui, elements } from "./ui.js";
import { websocket } from "./websocket.js";
-import { compensateMessageOrdering, formatTime, normalizeId } from "./utils.js";
-import { fetchChats, getAppUser, getChatMessages, getChats, updateOnlineStatus } from "./storage.js";
+import { compensateMessageOrdering, debounce, formatTime, normalizeId } from "./utils.js";
+import { fetchChats, getAppUser, getChatMessages, getChatPicture, getChats, getUser, getUserAbout, sendStatus, updateOnlineStatus } from "./storage.js";
import { upsertMessages } from "./db.js";
let activeChatState = null;
@@ -20,7 +20,7 @@ document.addEventListener('DOMContentLoaded', async () => {
await updateOnlineStatus();
setupEventListeners();
try {
- elements.loggedUserName.textContent = (await getAppUser()).pushName;
+ setupElementsData();
loadChats();
checkWahaStatus();
initWebSocket();
@@ -29,6 +29,25 @@ document.addEventListener('DOMContentLoaded', async () => {
}
});
+async function setupElementsData() {
+ const usr = await getAppUser();
+ const usrPic = (await getChatPicture(usr.id))?.url;
+ const usrInfo = await getUser(usr.id);
+ const usrAbout = (await getUserAbout(usr.id)).about;
+ elements.contentUserName.forEach(e => {
+ e.innerHTML = usr.pushName;
+ })
+ elements.contentUserNumber.forEach(async e => {
+ e.innerHTML = usrInfo.number;
+ })
+ elements.resourceUserPic.forEach(async e => {
+ e.src = usrPic;
+ })
+ elements.valueUserStatus.forEach(async e => {
+ e.value = usrAbout.trim();
+ })
+}
+
function loadChats() {
elements.chatsLoader.classList.remove('hidden');
try {
@@ -168,6 +187,17 @@ function setupEventListeners() {
})
elements.saveSettingsBtn.addEventListener('click', saveSettings);
+
+ elements.inputUserStatus.addEventListener('input', debounce(async function() {
+ const result = await sendStatus(elements.inputUserStatus.value);
+ console.log(result);
+ }, 2000))
+
+ // elements.selectable.forEach(e => {
+ // e.addEventListener('pointerdown', () => {
+
+ // })
+ // })
}
function initWebSocket() {
diff --git a/js/storage.js b/js/storage.js
index f83d66c..238b4b9 100644
--- a/js/storage.js
+++ b/js/storage.js
@@ -43,8 +43,20 @@ export function getGroups() {
return chats.filter(c => c.id.endsWith("@g.us"));
}
-export function getUser(number) {
- return users.find(user => user.id === number);
+export async function getUser(number) {
+ if (online) {
+ return await waha.getUser(number);
+ } else {
+ return;
+ }
+}
+
+export async function getUserAbout(userId) {
+ if (online) {
+ return await waha.getUserAbout(userId);
+ } else {
+ return;
+ }
}
export function getChats() {
@@ -125,4 +137,14 @@ export async function getChatPicture(chatId) {
export function isOnline() {
return online;
+}
+
+export async function sendStatus(text) {
+ if (online) {
+ return await waha.setStatus(text);
+ } else {
+ return {
+ success: false
+ }
+ }
}
\ No newline at end of file
diff --git a/js/ui.js b/js/ui.js
index 698cd6a..d2e1261 100644
--- a/js/ui.js
+++ b/js/ui.js
@@ -33,7 +33,13 @@ export const elements = {
attachmentInput: document.getElementById('attachment-input'),
attachmentBtn: document.getElementById('attachment-btn'),
extraPages: document.querySelectorAll('.extra-page'),
- desktopSidebarButtons: document.querySelectorAll("#desktop-aside button")
+ desktopSidebarButtons: document.querySelectorAll("#desktop-aside button"),
+ contentUserName: document.querySelectorAll('[data-content="app-user"]'),
+ contentUserNumber: document.querySelectorAll('[data-content="app-user-number"]'),
+ resourceUserPic: document.querySelectorAll('[data-resource="app-user-image"]'),
+ valueUserStatus: document.querySelectorAll('[data-value="app-user-status"]'),
+ inputUserStatus: document.getElementById('profile-page-status-input'),
+ selectable: document.querySelectorAll('.selectable'),
};
export const ui = {
@@ -92,7 +98,7 @@ export const ui = {
for (const chat of chats) {
const li = document.createElement('li');
- li.className = `chat-item ${activeChat && activeChat.id === chat.id ? 'active' : ''}`;
+ li.className = `chat-item selectable ${activeChat && activeChat.id === chat.id ? 'active' : ''}`;
li.dataset.id = chat.id;
const initials = chat.name ? chat.name.substring(0, 1).toUpperCase() : '?';
@@ -235,7 +241,7 @@ export const ui = {
const prevMsgEl = getPrevMessageElem();
const groupDiv = document.createElement('div');
- groupDiv.className = `message-group ${isOutgoing ? 'outgoing' : 'incoming'}`;
+ groupDiv.className = `message-group selectable ${isOutgoing ? 'outgoing' : 'incoming'}`;
groupDiv.id = normalizeId(msg._serialized ? msg : msg.id);
groupDiv.dataset.timestamp = msg.timestamp;
groupDiv.dataset.from = msg.participant || msg.from;
diff --git a/js/utils.js b/js/utils.js
index 9e8418b..81f05f0 100644
--- a/js/utils.js
+++ b/js/utils.js
@@ -112,4 +112,12 @@ export function normalizeId(raw) {
return raw._serialized || raw.user || JSON.stringify(raw);
}
return raw;
+}
+
+export function debounce(func, delay) {
+ let timeoutId;
+ return function() {
+ clearTimeout(timeoutId);
+ timeoutId = setTimeout(func, delay);
+ };
}
\ No newline at end of file
diff --git a/js/waha.js b/js/waha.js
index 66683b1..2c5c077 100644
--- a/js/waha.js
+++ b/js/waha.js
@@ -102,6 +102,14 @@ export const waha = {
return request(`/api/${config.session}/chats/${chatId}/picture`);
},
+ async getUser(chatId) {
+ return request(`/api/${config.session}/contacts/${chatId}`);
+ },
+
+ async getUserAbout(chatId) {
+ return request(`/api/contacts/about?contactId=${chatId}&session=${config.session}`);
+ },
+
async readChat(chatId) {
return request('/api/sendSeen', {
method: 'POST',
@@ -143,6 +151,15 @@ export const waha = {
});
},
+ async setStatus(text) {
+ return request(`/api/${config.session}/profile/status`, {
+ method: 'PUT',
+ body: JSON.stringify({
+ status: text
+ })
+ });
+ },
+
async sendFileMessage(chatId, file) {
const fileBase64 = await getBase64(file);
const body = {
diff --git a/style.css b/style.css
index 1c17b27..c1ae0e3 100644
--- a/style.css
+++ b/style.css
@@ -1,3 +1,33 @@
+@font-face {
+ font-family: Selawik;
+ src: url(./fonts/selawk.ttf);
+ font-weight: normal;
+}
+
+@font-face {
+ font-family: Selawik;
+ src: url(./fonts/selawkl.ttf);
+ font-weight: 200;
+}
+
+@font-face {
+ font-family: Selawik;
+ src: url(./fonts/selawksl.ttf);
+ font-weight: 300;
+}
+
+@font-face {
+ font-family: Selawik;
+ src: url(./fonts/selawkb.ttf);
+ font-weight: bold;
+}
+
+@font-face {
+ font-family: Selawik;
+ src: url(./fonts/selawkb.ttf);
+ font-weight: 800;
+}
+
:root {
--bg-main: black;
--bg-secondary: #242424;
@@ -44,7 +74,7 @@ body.light {
margin: 0;
padding: 0;
box-sizing: border-box;
- font-family: 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
+ font-family: Selawik, 'Segoe UI', Tahoma, Geneva, Verdana, sans-serif;
user-select: none;
}
@@ -106,7 +136,7 @@ input:focus {
}
.app-name {
- font-weight: bolder;
+ font-weight: bold;
}
/* Sidebar Styling */
@@ -299,15 +329,28 @@ input:focus {
border: 1px solid transparent;
}
+.selected {
+ background: rgba(255, 255, 255, 0.04);
+ transform: scale(0.98) skewX(10deg);
+ filter: blur(.1px);
+ opacity: .6;
+}
+
@media (hover: hover) {
- .chat-item:hover {
- background: rgba(255, 255, 255, 0.04); transform: scale(0.98) skewX(10deg); filter: blur(.1px); opacity: .6;
+ .selectable:hover {
+ background: rgba(255, 255, 255, 0.04);
+ transform: scale(0.98) skewX(10deg);
+ filter: blur(.1px);
+ opacity: .6;
}
}
@media (hover: none) {
- .chat-item:active {
- background: rgba(255, 255, 255, 0.04); transform: scale(0.98) skewX(10deg); filter: blur(.1px); opacity: .6;
+ .selectable:active {
+ background: rgba(255, 255, 255, 0.04);
+ transform: scale(0.98) skewX(10deg);
+ filter: blur(.1px);
+ opacity: .6;
}
}
@@ -351,6 +394,7 @@ input:focus {
white-space: nowrap;
overflow: hidden;
text-overflow: ellipsis;
+ font-weight: 300;
flex: 1;
}
@@ -403,11 +447,6 @@ input:focus {
}
/* Sidebar Footer */
-.sidebar-footer {
- padding: 14px 20px;
- background: var(--bg-secondary);
-}
-
.api-status-badge {
display: flex;
align-items: center;
@@ -555,7 +594,7 @@ input:focus {
.active-contact-info h3 {
font-size: 1rem;
- font-weight: bolder;
+ font-weight: bold;
}
.contact-status {
@@ -604,6 +643,7 @@ input:focus {
display: flex;
flex-direction: column;
max-width: 65%;
+ transition: .1s;
}
.message-group.incoming {
@@ -826,6 +866,49 @@ input:focus {
display: flex;
}
+#profile-page {
+ flex-direction: column;
+ background-color: var(--bg-main);
+}
+
+#profile-page .content {
+ padding: 1.4rem;
+ display: flex;
+ gap: 1em;
+}
+
+#profile-page-user-info {
+ flex: 1;
+}
+
+#profile-page h2 {
+ padding: 1.4rem;
+ font-size: 5rem;
+ text-wrap-mode: nowrap;
+ overflow: hidden;
+ font-weight: 200;
+}
+
+#profile-page-picture {
+ width: 100%;
+ max-width: 10%;
+ height: auto;
+ aspect-ratio: 1/1;
+}
+
+#profile-page-status-input {
+ width: 100%;
+ background-color: var(--bg-main);
+ font-size: xx-large;
+ border-bottom: medium solid transparent;
+ padding: 0;
+}
+
+#profile-page-status-input:focus {
+ color: var(--text-primary);
+ border-bottom-color: var(--text-primary);
+}
+
@media (max-width: 768px) {
.app-container {
width: 100%;
@@ -901,6 +984,19 @@ input:focus {
#desktop-aside {
display: none;
}
+
+ #profile-page .content {
+ flex-direction: column;
+ }
+
+ #profile-page-picture {
+ max-width: 50%;
+ margin: auto;
+ }
+
+ #profile-page-user-number {
+ text-align: center;
+ }
}
/* Modal Styling */