add chat list section

This commit is contained in:
marlon-erler
2024-07-09 15:15:17 +02:00
parent f48ea3d5d1
commit dae32fa6e7
9 changed files with 389 additions and 222 deletions
+271 -206
View File
@@ -364,6 +364,7 @@
cannotSetChannel;
// init
constructor(id = UUID()) {
this.id = id;
this.primaryChannelInput = restoreState(
storageKeys.primaryChannel(id),
""
@@ -380,12 +381,12 @@
this.newSecondaryChannelName = new State("");
this.cannotSendMessage = createProxyState(
[
this.primaryChannelInput,
this.currentChannel,
this.composingMessage,
this.isSubscribed,
isConnected
],
() => this.primaryChannelInput.value == "" || this.composingMessage.value == "" || this.isSubscribed.value == false || isConnected.value == false
() => this.currentChannel.value == "" || this.composingMessage.value == "" || this.isSubscribed.value == false || isConnected.value == false
);
this.cannotAddSecondaryChannel = createProxyState(
[this.newSecondaryChannelName],
@@ -418,7 +419,7 @@
...this.secondaryChannels.value.values()
].map((channel) => channel);
const allChannelNames = [
this.primaryChannelInput.value,
this.currentChannel.value,
...secondaryChannelNames
];
const encrypted = await encryptString(
@@ -463,206 +464,20 @@
}
};
var chatIds = restoreListState("chat-ids");
var chatArray = [...chatIds.value.values()].map((id) => new Chat(id));
var chats = new ListState(chatArray);
// node_modules/udn-frontend/index.ts
var UDNFrontend = class {
ws;
// HANDLERS
connectionHandler = () => {
};
disconnectionHandler = () => {
};
messageHandler = (data) => {
};
mailboxHandler = (mailboxId2) => {
};
mailboxConnectionHandler = (mailboxId2) => {
};
mailboxDeleteHandler = (mailboxId2) => {
};
// INIT
set onconnect(handler) {
this.connectionHandler = handler;
}
set ondisconnect(handler) {
this.disconnectionHandler = handler;
}
set onmessage(handler) {
this.messageHandler = handler;
}
set onmailboxcreate(handler) {
this.mailboxHandler = handler;
}
set onmailboxconnect(handler) {
this.mailboxConnectionHandler = handler;
}
set onmailboxdelete(handler) {
this.mailboxDeleteHandler = handler;
}
// UTILITY METHODS
send(messageObject) {
if (this.ws == void 0) return false;
const messageString = JSON.stringify(messageObject);
this.ws.send(messageString);
return true;
}
// PUBLIC METHODS
// connection
connect(address) {
try {
this.disconnect();
this.ws = new WebSocket(address);
this.ws.addEventListener("open", this.connectionHandler);
this.ws.addEventListener("close", this.disconnectionHandler);
this.ws.addEventListener("message", (message) => {
const dataString = message.data.toString();
const data = JSON.parse(dataString);
if (data.assignedMailboxId) {
return this.mailboxHandler(data.assignedMailboxId);
} else if (data.connectedMailboxId) {
return this.mailboxConnectionHandler(data.connectedMailboxId);
} else if (data.deletedMailbox) {
return this.mailboxDeleteHandler(data.deletedMailbox);
} else {
this.messageHandler(data);
}
});
} catch (error) {
console.error(error);
}
}
disconnect() {
this.ws?.close();
}
// message
sendMessage(channel, body) {
const messageObject = {
messageChannel: channel,
messageBody: body
};
return this.send(messageObject);
}
// subscription
subscribe(channel) {
const messageObject = {
subscribeChannel: channel
};
return this.send(messageObject);
}
unsubscribe(channel) {
const messageObject = {
unsubscribeChannel: channel
};
return this.send(messageObject);
}
// mailbox
requestMailbox() {
const messageObject = {
requestingMailboxSetup: true
};
return this.send(messageObject);
}
connectMailbox(mailboxId2) {
const messageObject = {
requestedMailbox: mailboxId2
};
return this.send(messageObject);
}
deleteMailbox(mailboxId2) {
const messageObject = {
deletingMailbox: mailboxId2
};
return this.send(messageObject);
}
};
// src/Model/model.ts
var UDN = new UDNFrontend();
var isConnected = new State(false);
var serverAddressInput = restoreState("socket-address", "");
var didRequestConnection = restoreState(
"did-request-connection",
false
);
var currentAddress = restoreState("current-address", "");
var cannotDisonnect = createProxyState(
[isConnected],
() => isConnected.value == false
);
var cannotConnect = createProxyState(
[serverAddressInput, currentAddress, isConnected],
() => serverAddressInput.value == "" || currentAddress.value == serverAddressInput.value && isConnected.value == true
);
var cannotResetAddress = createProxyState(
[serverAddressInput, currentAddress],
() => serverAddressInput.value == currentAddress.value
);
function connect() {
if (cannotConnect.value == true) return;
currentAddress.value = serverAddressInput.value;
isConnected.value = false;
didRequestConnection.value = true;
UDN.connect(serverAddressInput.value);
var chats = new ListState();
chatIds.value.forEach((id) => chats.add(new Chat(id)));
function createChatWithName(name) {
const newChat = new Chat();
newChat.currentChannel.value = name;
chatIds.add(newChat.id);
chats.add(newChat);
}
function disconnect() {
didRequestConnection.value = false;
if (cannotDisonnect.value == true) return;
UDN.disconnect();
}
function resetAddressInput() {
serverAddressInput.value = currentAddress.value;
}
UDN.onconnect = () => {
isConnected.value = true;
};
UDN.onmessage = (data) => {
chats.value.forEach((chat) => {
chat.onmessage(data);
function removeChat(chat) {
Object.values(storageKeys).forEach((cb) => {
localStorage.removeItem(cb(chat.id));
});
};
UDN.ondisconnect = () => {
isConnected.value = false;
};
var mailboxId = restoreState("mailbox-id", "");
var isMailboxActive = new State(false);
var cannotDeleteMailbox = createProxyState(
[mailboxId, isMailboxActive],
() => mailboxId.value == "" || isMailboxActive.value == false
);
var cannotRequestMailbox = createProxyState(
[isConnected, isMailboxActive],
() => isConnected.value == false || isMailboxActive.value == true
);
function requestMailbox() {
if (cannotRequestMailbox.value == true) return;
UDN.requestMailbox();
}
function deleteMailbox() {
if (cannotDeleteMailbox.value == true) return;
UDN.deleteMailbox(mailboxId.value);
}
UDN.onmailboxcreate = (id) => {
mailboxId.value = id;
UDN.connectMailbox(id);
};
UDN.onmailboxconnect = () => {
isMailboxActive.value = true;
};
UDN.onmailboxdelete = () => {
isMailboxActive.value = false;
mailboxId.value = "";
};
var isEncryptionUnavailable = window.crypto.subtle == void 0;
var senderName = restoreState("sender-name", "");
var selectedChat = new State(void 0);
function closeChat() {
selectedChat.value = void 0;
document.getElementById("settings-tab")?.scrollIntoView();
}
if (serverAddressInput.value != "" && didRequestConnection.value == true) {
connect();
chats.remove(chat);
chatIds.remove(chat.id);
}
// src/translations.ts
@@ -673,13 +488,17 @@
// overview
overview: "Overview",
connection: "Connection",
communication: "Communication",
encryption: "Encryption",
chats: "Chats",
serverAddress: "Server Address",
serverAddressPlaceholder: "wss://192.168.0.69:3000",
connectToServer: "Connect",
disconnect: "Disonnect",
resetAddress: "Reset address",
newChatPrimaryChannel: "Primary channel",
newChatNamePlaceholder: "my-channel",
addChat: "Add",
removeChat: "Remove chat",
// messages
noChatSelected: "No chat selected",
primaryChannel: "Primary channel",
leaveChannel: "Leave",
@@ -857,7 +676,7 @@
function clearMessageHistory() {
chat.clearMessages();
}
return /* @__PURE__ */ createElement("article", { id: "message-tab" }, /* @__PURE__ */ createElement("header", { class: "padding-0" }, /* @__PURE__ */ createElement("span", { class: "flex-row align-center" }, /* @__PURE__ */ createElement("button", { "aria-label": translation.back, "on:click": closeChat }, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")), /* @__PURE__ */ createElement("span", { "subscribe:innerText": chat.currentChannel })), /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement(
return /* @__PURE__ */ createElement("article", { id: "message-tab" }, /* @__PURE__ */ createElement("header", { class: "padding-0" }, /* @__PURE__ */ createElement("span", { class: "flex-row align-center" }, /* @__PURE__ */ createElement("button", { "aria-label": translation.back, "on:click": closeChatView }, /* @__PURE__ */ createElement("span", { class: "icon" }, "arrow_back")), /* @__PURE__ */ createElement("span", { "subscribe:innerText": chat.currentChannel })), /* @__PURE__ */ createElement("span", null, /* @__PURE__ */ createElement(
"button",
{
"aria-label": translation.clearHistory,
@@ -869,9 +688,44 @@
return /* @__PURE__ */ createElement("div", { "children:set": messageTabContent });
}
// src/Views/chatListSection.tsx
var chatConverter = (chat) => {
function remove() {
removeChat(chat);
}
return /* @__PURE__ */ createElement("div", { class: "tile padding-0" }, /* @__PURE__ */ createElement("div", { class: "flex-row width-100 justify-apart align-center" }, /* @__PURE__ */ createElement("span", { class: "padding-h ellipsis", "subscribe:innerText": chat.currentChannel }), /* @__PURE__ */ createElement(
"button",
{
class: "danger",
"aria-label": translation.removeChat,
"on:click": remove
},
/* @__PURE__ */ createElement("span", { class: "icon" }, "delete")
)));
};
function ChatListSection() {
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("h2", null, translation.chats), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "forum"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.newChatPrimaryChannel), /* @__PURE__ */ createElement(
"input",
{
"bind:value": newChatName,
placeholder: translation.newChatNamePlaceholder,
"on:enter": createChat
}
))), /* @__PURE__ */ createElement("div", { class: "flex-row justify-end" }, /* @__PURE__ */ createElement(
"button",
{
class: "primary width-50",
"toggle:disabled": cannotCreateChat,
"on:click": createChat
},
translation.addChat,
/* @__PURE__ */ createElement("span", { class: "icon" }, "add")
)), /* @__PURE__ */ createElement("hr", null), /* @__PURE__ */ createElement("div", { class: "flex-column gap", "children:append": [chats, chatConverter] }));
}
// src/Views/connectionSection.tsx
function ConnectionSection() {
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.serverAddress), /* @__PURE__ */ createElement(
return /* @__PURE__ */ createElement("div", { class: "flex-column" }, /* @__PURE__ */ createElement("h2", null, translation.connection), /* @__PURE__ */ createElement("label", { class: "tile" }, /* @__PURE__ */ createElement("span", { class: "icon" }, "cell_tower"), /* @__PURE__ */ createElement("div", null, /* @__PURE__ */ createElement("span", null, translation.serverAddress), /* @__PURE__ */ createElement(
"input",
{
"bind:value": serverAddressInput,
@@ -927,10 +781,221 @@
// src/Tabs/settingsTab.tsx
function SettingsTab() {
return /* @__PURE__ */ createElement("article", { id: "settings-tab", "toggle:connected": isConnected }, /* @__PURE__ */ createElement("header", null, translation.overview), /* @__PURE__ */ createElement("div", null, ConnectionSection()));
return /* @__PURE__ */ createElement("article", { id: "settings-tab", "toggle:connected": isConnected }, /* @__PURE__ */ createElement("header", null, translation.overview), /* @__PURE__ */ createElement("div", { class: "flex-column large-gap" }, ConnectionSection(), ChatListSection()));
}
// node_modules/udn-frontend/index.ts
var UDNFrontend = class {
ws;
// HANDLERS
connectionHandler = () => {
};
disconnectionHandler = () => {
};
messageHandler = (data) => {
};
mailboxHandler = (mailboxId2) => {
};
mailboxConnectionHandler = (mailboxId2) => {
};
mailboxDeleteHandler = (mailboxId2) => {
};
// INIT
set onconnect(handler) {
this.connectionHandler = handler;
}
set ondisconnect(handler) {
this.disconnectionHandler = handler;
}
set onmessage(handler) {
this.messageHandler = handler;
}
set onmailboxcreate(handler) {
this.mailboxHandler = handler;
}
set onmailboxconnect(handler) {
this.mailboxConnectionHandler = handler;
}
set onmailboxdelete(handler) {
this.mailboxDeleteHandler = handler;
}
// UTILITY METHODS
send(messageObject) {
if (this.ws == void 0) return false;
const messageString = JSON.stringify(messageObject);
this.ws.send(messageString);
return true;
}
// PUBLIC METHODS
// connection
connect(address) {
try {
this.disconnect();
this.ws = new WebSocket(address);
this.ws.addEventListener("open", this.connectionHandler);
this.ws.addEventListener("close", this.disconnectionHandler);
this.ws.addEventListener("message", (message) => {
const dataString = message.data.toString();
const data = JSON.parse(dataString);
if (data.assignedMailboxId) {
return this.mailboxHandler(data.assignedMailboxId);
} else if (data.connectedMailboxId) {
return this.mailboxConnectionHandler(data.connectedMailboxId);
} else if (data.deletedMailbox) {
return this.mailboxDeleteHandler(data.deletedMailbox);
} else {
this.messageHandler(data);
}
});
} catch (error) {
console.error(error);
}
}
disconnect() {
this.ws?.close();
}
// message
sendMessage(channel, body) {
const messageObject = {
messageChannel: channel,
messageBody: body
};
return this.send(messageObject);
}
// subscription
subscribe(channel) {
const messageObject = {
subscribeChannel: channel
};
return this.send(messageObject);
}
unsubscribe(channel) {
const messageObject = {
unsubscribeChannel: channel
};
return this.send(messageObject);
}
// mailbox
requestMailbox() {
const messageObject = {
requestingMailboxSetup: true
};
return this.send(messageObject);
}
connectMailbox(mailboxId2) {
const messageObject = {
requestedMailbox: mailboxId2
};
return this.send(messageObject);
}
deleteMailbox(mailboxId2) {
const messageObject = {
deletingMailbox: mailboxId2
};
return this.send(messageObject);
}
};
// src/index.tsx
var UDN = new UDNFrontend();
var isConnected = new State(false);
var serverAddressInput = restoreState("socket-address", "");
var didRequestConnection = restoreState(
"did-request-connection",
false
);
var currentAddress = restoreState("current-address", "");
var cannotDisonnect = createProxyState(
[isConnected],
() => isConnected.value == false
);
var cannotConnect = createProxyState(
[serverAddressInput, currentAddress, isConnected],
() => serverAddressInput.value == "" || currentAddress.value == serverAddressInput.value && isConnected.value == true
);
var cannotResetAddress = createProxyState(
[serverAddressInput, currentAddress],
() => serverAddressInput.value == currentAddress.value
);
function connect() {
if (cannotConnect.value == true) return;
currentAddress.value = serverAddressInput.value;
isConnected.value = false;
didRequestConnection.value = true;
UDN.connect(serverAddressInput.value);
}
function disconnect() {
didRequestConnection.value = false;
if (cannotDisonnect.value == true) return;
UDN.disconnect();
}
function resetAddressInput() {
serverAddressInput.value = currentAddress.value;
}
UDN.onconnect = () => {
isConnected.value = true;
};
UDN.onmessage = (data) => {
chats.value.forEach((chat) => {
chat.onmessage(data);
});
};
UDN.ondisconnect = () => {
isConnected.value = false;
};
var mailboxId = restoreState("mailbox-id", "");
var isMailboxActive = new State(false);
var cannotDeleteMailbox = createProxyState(
[mailboxId, isMailboxActive],
() => mailboxId.value == "" || isMailboxActive.value == false
);
var cannotRequestMailbox = createProxyState(
[isConnected, isMailboxActive],
() => isConnected.value == false || isMailboxActive.value == true
);
function requestMailbox() {
if (cannotRequestMailbox.value == true) return;
UDN.requestMailbox();
}
function deleteMailbox() {
if (cannotDeleteMailbox.value == true) return;
UDN.deleteMailbox(mailboxId.value);
}
function updateMailbox() {
deleteMailbox();
updateMailbox();
}
UDN.onmailboxcreate = (id) => {
mailboxId.value = id;
UDN.connectMailbox(id);
};
UDN.onmailboxconnect = () => {
isMailboxActive.value = true;
};
UDN.onmailboxdelete = () => {
isMailboxActive.value = false;
mailboxId.value = "";
};
var isEncryptionUnavailable = window.crypto.subtle == void 0;
var senderName = restoreState("sender-name", "");
var selectedChat = new State(void 0);
var newChatName = new State("");
var cannotCreateChat = createProxyState(
[newChatName],
() => newChatName.value == ""
);
function createChat() {
if (cannotCreateChat.value == true) return;
createChatWithName(newChatName.value);
newChatName.value = "";
}
function closeChatView() {
selectedChat.value = void 0;
document.getElementById("settings-tab")?.scrollIntoView();
}
if (serverAddressInput.value != "" && didRequestConnection.value == true) {
connect();
}
document.querySelector("main").append(SettingsTab(), MessageTab());
document.querySelector("main").classList.add("split");
})();
+5
View File
@@ -214,6 +214,7 @@ SIZES
--gap-between-tiles: 4px;
--gap-in-tab-links: 1rem;
--gap-in-controls: 1.2rem;
--large-gap: 2rem;
/* margin */
--label-top-padding: 0.25rem;
@@ -448,6 +449,10 @@ label.inline,
gap: var(--gap-between-tiles) !important;
}
.large-gap {
gap: var(--large-gap) !important;
}
header,
button {
justify-content: space-between;
+14 -7
View File
@@ -1,6 +1,6 @@
import * as React from "bloatless-react";
import { UDN, isConnected, senderName } from "./model";
import { UDN, isConnected, senderName } from "../Model/model";
import { decryptString, encryptString } from "../cryptUtility";
import { Message } from "udn-frontend";
@@ -37,6 +37,9 @@ export class Chat {
// init
constructor(id: string = React.UUID()) {
this.id = id;
// channels
this.primaryChannelInput = React.restoreState(
storageKeys.primaryChannel(id),
""
@@ -45,6 +48,7 @@ export class Chat {
storageKeys.secondaryChannels(id)
);
// messaging
this.encryptionKey = React.restoreState(storageKeys.encyptionKey(id), "");
this.messages = React.restoreListState(storageKeys.messages(id));
@@ -54,15 +58,16 @@ export class Chat {
);
this.newSecondaryChannelName = new React.State("");
// guards
this.cannotSendMessage = React.createProxyState(
[
this.primaryChannelInput,
this.currentChannel,
this.composingMessage,
this.isSubscribed,
isConnected,
],
() =>
this.primaryChannelInput.value == "" ||
this.currentChannel.value == "" ||
this.composingMessage.value == "" ||
this.isSubscribed.value == false ||
isConnected.value == false
@@ -108,7 +113,7 @@ export class Chat {
...this.secondaryChannels.value.values(),
].map((channel) => channel);
const allChannelNames: string[] = [
this.primaryChannelInput.value,
this.currentChannel.value,
...secondaryChannelNames,
];
@@ -171,14 +176,16 @@ export class Chat {
// INIT
const chatIds = React.restoreListState<string>("chat-ids");
const chatArray = [...chatIds.value.values()].map((id) => new Chat(id));
export const chats = new React.ListState<Chat>(chatArray);
export const chats = new React.ListState<Chat>();
chatIds.value.forEach((id) => chats.add(new Chat(id)));
// METHODS
export function createChatWithName(name: string): void {
const newChat = new Chat();
newChat.primaryChannelInput.value = name;
newChat.currentChannel.value = name;
chatIds.add(newChat.id);
chats.add(newChat);
}
export function removeChat(chat: Chat): void {
+21 -4
View File
@@ -1,13 +1,12 @@
import * as React from "bloatless-react";
import { Chat, chats } from "./chatModel";
import { Chat, chats, createChatWithName } from "./chatModel";
import UDNFrontend from "udn-frontend";
export const UDN = new UDNFrontend();
// CONNECTION
// state
export const isConnected = new React.State(false);
export const serverAddressInput = React.restoreState("socket-address", "");
@@ -38,7 +37,7 @@ export const cannotResetAddress = React.createProxyState(
// methods
export function connect(): void {
if (cannotConnect.value == true) return;
currentAddress.value = serverAddressInput.value;
isConnected.value = false;
@@ -95,6 +94,11 @@ export function deleteMailbox(): void {
UDN.deleteMailbox(mailboxId.value);
}
export function updateMailbox(): void {
deleteMailbox();
updateMailbox();
}
UDN.onmailboxcreate = (id) => {
mailboxId.value = id;
UDN.connectMailbox(id);
@@ -114,8 +118,21 @@ export const isEncryptionUnavailable = window.crypto.subtle == undefined;
export const senderName = React.restoreState("sender-name", "");
export const selectedChat = new React.State<Chat | undefined>(undefined);
export const newChatName = new React.State("");
export function closeChat() {
export const cannotCreateChat = React.createProxyState(
[newChatName],
() => newChatName.value == ""
);
export function createChat() {
if (cannotCreateChat.value == true) return;
createChatWithName(newChatName.value);
newChatName.value = "";
}
export function closeChatView() {
selectedChat.value = undefined;
document.getElementById("settings-tab")?.scrollIntoView();
}
+2 -2
View File
@@ -1,6 +1,6 @@
import * as React from "bloatless-react";
import { closeChat, selectedChat } from "../Model/model";
import { closeChatView, selectedChat } from "../Model/model";
import { MessageComposer } from "../Views/messageComposer";
import { ThreadView } from "../Views/threadView";
@@ -25,7 +25,7 @@ export function MessageTab() {
<article id="message-tab">
<header class="padding-0">
<span class="flex-row align-center">
<button aria-label={translation.back} on:click={closeChat}>
<button aria-label={translation.back} on:click={closeChatView}>
<span class="icon">arrow_back</span>
</button>
+5 -1
View File
@@ -1,5 +1,6 @@
import * as React from "bloatless-react";
import { ChatListSection } from "../Views/chatListSection";
import { ConnectionSection } from "../Views/connectionSection";
import { isConnected } from "../Model/model";
import { translation } from "../translations";
@@ -8,7 +9,10 @@ export function SettingsTab() {
return (
<article id="settings-tab" toggle:connected={isConnected}>
<header>{translation.overview}</header>
<div>{ConnectionSection()}</div>
<div class="flex-column large-gap">
{ConnectionSection()}
{ChatListSection()}
</div>
</article>
);
}
+62
View File
@@ -0,0 +1,62 @@
import * as React from "bloatless-react";
import { Chat, chats, removeChat } from "../Model/chatModel";
import { cannotCreateChat, createChat, newChatName } from "../Model/model";
import { translation } from "../translations";
const chatConverter: React.ListItemConverter<Chat> = (chat) => {
function remove() {
removeChat(chat);
}
return (
<div class="tile padding-0">
<div class="flex-row width-100 justify-apart align-center">
<span class="padding-h ellipsis" subscribe:innerText={chat.currentChannel}></span>
<button
class="danger"
aria-label={translation.removeChat}
on:click={remove}
>
<span class="icon">delete</span>
</button>
</div>
</div>
);
};
export function ChatListSection() {
return (
<div class="flex-column">
<h2>{translation.chats}</h2>
<label class="tile">
<span class="icon">forum</span>
<div>
<span>{translation.newChatPrimaryChannel}</span>
<input
bind:value={newChatName}
placeholder={translation.newChatNamePlaceholder}
on:enter={createChat}
></input>
</div>
</label>
<div class="flex-row justify-end">
<button
class="primary width-50"
toggle:disabled={cannotCreateChat}
on:click={createChat}
>
{translation.addChat}
<span class="icon">add</span>
</button>
</div>
<hr></hr>
<div class="flex-column gap" children:append={[chats, chatConverter]}></div>
</div>
);
}
+2
View File
@@ -19,6 +19,8 @@ import { translation } from "../translations";
export function ConnectionSection() {
return (
<div class="flex-column">
<h2>{translation.connection}</h2>
<label class="tile">
<span class="icon">cell_tower</span>
<div>
+7 -2
View File
@@ -7,8 +7,7 @@ const englishTranslations = {
overview: "Overview",
connection: "Connection",
communication: "Communication",
encryption: "Encryption",
chats: "Chats",
serverAddress: "Server Address",
serverAddressPlaceholder: "wss://192.168.0.69:3000",
@@ -16,7 +15,13 @@ const englishTranslations = {
connectToServer: "Connect",
disconnect: "Disonnect",
resetAddress: "Reset address",
newChatPrimaryChannel: "Primary channel",
newChatNamePlaceholder: "my-channel",
addChat: "Add",
removeChat: "Remove chat",
// messages
noChatSelected: "No chat selected",
primaryChannel: "Primary channel",